Skip to main content

lvm_class/bytecode/
instruction.rs

1//! JVM bytecode instruction representation.
2//!
3//! The `Instruction` enum represents fully decoded bytecode instructions with their operands.
4
5use super::opcode::Opcode;
6use super::operand::{ArrayType, LookupSwitchData, TableSwitchData};
7use crate::error::InstructionErr;
8use lvm_common::utils::cursor::ByteCursor;
9use num_enum::TryFromPrimitive;
10use std::fmt::Formatter;
11
12/// A fully decoded JVM bytecode instruction with operands.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Instruction {
15    Aaload,
16    Aastore,
17    AconstNull,
18    Aload(u8),
19    Aload0,
20    Aload1,
21    Aload2,
22    Aload3,
23    Anewarray(u16),
24    Areturn,
25    ArrayLength,
26    Astore(u8),
27    Astore0,
28    Astore1,
29    Astore2,
30    Astore3,
31    Athrow,
32    Baload,
33    Bastore,
34    Bipush(i8),
35    Breakpoint,
36    Caload,
37    Castore,
38    Checkcast(u16),
39    D2f,
40    D2i,
41    D2l,
42    Dadd,
43    Daload,
44    Dastore,
45    Dcmpg,
46    Dcmpl,
47    Dconst0,
48    Dconst1,
49    Ddiv,
50    Dload(u8),
51    Dload0,
52    Dload1,
53    Dload2,
54    Dload3,
55    Dmul,
56    Dneg,
57    Drem,
58    Dreturn,
59    Dstore(u8),
60    Dstore0,
61    Dstore1,
62    Dstore2,
63    Dstore3,
64    Dsub,
65    Dup,
66    Dup2,
67    Dup2X1,
68    Dup2X2,
69    DupX1,
70    DupX2,
71    F2d,
72    F2i,
73    F2l,
74    Fadd,
75    Faload,
76    Fastore,
77    Fcmpg,
78    Fcmpl,
79    Fconst0,
80    Fconst1,
81    Fconst2,
82    Fdiv,
83    Fload(u8),
84    Fload0,
85    Fload1,
86    Fload2,
87    Fload3,
88    Fmul,
89    Fneg,
90    Frem,
91    Freturn,
92    Fstore(u8),
93    Fstore0,
94    Fstore1,
95    Fstore2,
96    Fstore3,
97    Fsub,
98    Getfield(u16),
99    Getstatic(u16),
100    Goto(i16),
101    GotoW(i32),
102    I2b,
103    I2c,
104    I2d,
105    I2f,
106    I2l,
107    I2s,
108    Iadd,
109    Iaload,
110    Iand,
111    Iastore,
112    IconstM1,
113    Iconst0,
114    Iconst1,
115    Iconst2,
116    Iconst3,
117    Iconst4,
118    Iconst5,
119    Idiv,
120    IfAcmpEq(i16),
121    IfAcmpNe(i16),
122    IfEq(i16),
123    IfGe(i16),
124    IfGt(i16),
125    IfIcmpeq(i16),
126    IfIcmpge(i16),
127    IfIcmpgt(i16),
128    IfIcmple(i16),
129    IfIcmplt(i16),
130    IfIcmpne(i16),
131    IfLe(i16),
132    IfLt(i16),
133    IfNe(i16),
134    Ifnonnull(i16),
135    Ifnull(i16),
136    Iinc(u8, i8),
137    Iload(u8),
138    Iload0,
139    Iload1,
140    Iload2,
141    Iload3,
142    Imul,
143    Ineg,
144    Lookupswitch(LookupSwitchData),
145    Instanceof(u16),
146    InvokeDynamic(u16),
147    InvokeInterface(u16, u8),
148    InvokeSpecial(u16),
149    InvokeStatic(u16),
150    InvokeVirtual(u16),
151    Ior,
152    Irem,
153    Ireturn,
154    Ishl,
155    Ishr,
156    Istore(u8),
157    Istore0,
158    Istore1,
159    Istore2,
160    Istore3,
161    Isub,
162    Iushr,
163    Ixor,
164    Jsr(i16),
165    JsrW(i32),
166    L2d,
167    L2f,
168    L2i,
169    Ladd,
170    Laload,
171    Land,
172    Lastore,
173    Lcmp,
174    Lconst0,
175    Lconst1,
176    Ldc(u16),
177    Ldc2W(u16),
178    LdcW(u16),
179    Ldiv,
180    Lload(u8),
181    Lload0,
182    Lload1,
183    Lload2,
184    Lload3,
185    Lmul,
186    Lneg,
187    Lor,
188    Lrem,
189    Lreturn,
190    Lshl,
191    Lshr,
192    Lstore(u8),
193    Lstore0,
194    Lstore1,
195    Lstore2,
196    Lstore3,
197    Lsub,
198    Lushr,
199    Lxor,
200    Monitorenter,
201    Monitorexit,
202    Multianewarray(u16, u8),
203    New(u16),
204    Newarray(ArrayType),
205    Nop,
206    Pop,
207    Pop2,
208    Putfield(u16),
209    Putstatic(u16),
210    Ret(u8),
211    Return,
212    Saload,
213    Sastore,
214    Sipush(i16),
215    Swap,
216    Impdep1,
217    Impdep2,
218    TableSwitch(TableSwitchData),
219}
220
221impl Instruction {
222    pub fn is_branch(&self) -> bool {
223        matches!(
224            self,
225            Self::Goto(_)
226                | Self::GotoW(_)
227                | Self::Jsr(_)
228                | Self::JsrW(_)
229                | Self::IfAcmpEq(_)
230                | Self::IfAcmpNe(_)
231                | Self::IfEq(_)
232                | Self::IfGe(_)
233                | Self::IfGt(_)
234                | Self::IfLe(_)
235                | Self::IfLt(_)
236                | Self::IfNe(_)
237                | Self::Ifnonnull(_)
238                | Self::Ifnull(_)
239                | Self::IfIcmpeq(_)
240                | Self::IfIcmpge(_)
241                | Self::IfIcmpgt(_)
242                | Self::IfIcmple(_)
243                | Self::IfIcmplt(_)
244                | Self::IfIcmpne(_)
245                | Self::Lookupswitch(_)
246                | Self::TableSwitch(_)
247        )
248    }
249
250    pub fn byte_size(&self) -> u16 {
251        match self {
252            // Variable-size instructions
253            Self::Lookupswitch(data) => {
254                // opcode (1) + padding (0-3) + default (4) + npairs (4) + pairs (8 * n)
255                1 + data.padding as u16 + 4 + 4 + (8 * data.pairs.len() as u16)
256            }
257            Self::TableSwitch(data) => {
258                // opcode (1) + padding (0-3) + default (4) + low (4) + high (4) + offsets (4 * n)
259                1 + data.padding as u16 + 4 + 4 + 4 + (4 * data.offsets.len() as u16)
260            }
261            // 5-byte instructions
262            Self::GotoW(_)
263            | Self::JsrW(_)
264            | Self::InvokeDynamic(_)
265            | Self::InvokeInterface(_, _) => 5,
266
267            // 4-byte instructions
268            Self::Multianewarray(_, _) => 4,
269
270            // 3-byte instructions
271            Self::Anewarray(_)
272            | Self::Checkcast(_)
273            | Self::Getfield(_)
274            | Self::Getstatic(_)
275            | Self::Goto(_)
276            | Self::IfAcmpEq(_)
277            | Self::IfAcmpNe(_)
278            | Self::IfEq(_)
279            | Self::IfGe(_)
280            | Self::IfGt(_)
281            | Self::IfLe(_)
282            | Self::IfLt(_)
283            | Self::IfNe(_)
284            | Self::Ifnonnull(_)
285            | Self::Ifnull(_)
286            | Self::IfIcmpeq(_)
287            | Self::IfIcmpge(_)
288            | Self::IfIcmpgt(_)
289            | Self::IfIcmple(_)
290            | Self::IfIcmplt(_)
291            | Self::IfIcmpne(_)
292            | Self::Iinc(_, _)
293            | Self::Instanceof(_)
294            | Self::InvokeSpecial(_)
295            | Self::InvokeStatic(_)
296            | Self::InvokeVirtual(_)
297            | Self::Ldc2W(_)
298            | Self::LdcW(_)
299            | Self::New(_)
300            | Self::Putfield(_)
301            | Self::Putstatic(_)
302            | Self::Sipush(_)
303            | Self::Jsr(_) => 3,
304
305            // 2-byte instructions
306            Self::Aload(_)
307            | Self::Astore(_)
308            | Self::Bipush(_)
309            | Self::Dload(_)
310            | Self::Dstore(_)
311            | Self::Fload(_)
312            | Self::Fstore(_)
313            | Self::Iload(_)
314            | Self::Istore(_)
315            | Self::Ldc(_)
316            | Self::Lload(_)
317            | Self::Lstore(_)
318            | Self::Newarray(_)
319            | Self::Ret(_) => 2,
320
321            // 1-byte instructions (everything else)
322            _ => 1,
323        }
324    }
325}
326
327impl Instruction {
328    fn switch_padding(pc: usize) -> u8 {
329        ((4 - ((pc + 1) & 3)) & 3) as u8
330    }
331
332    pub fn new_at(code: &[u8], pc: usize) -> Result<Instruction, InstructionErr> {
333        let mut cursor = ByteCursor::new(&code[pc..]);
334        let opcode_byte = cursor.u8()?;
335        let opcode = Opcode::try_from(opcode_byte)
336            .map_err(|_| InstructionErr::UnsupportedOpCode(opcode_byte))?;
337
338        let instruction = match opcode {
339            Opcode::Aaload => Self::Aaload,
340            Opcode::Aastore => Self::Aastore,
341            Opcode::AconstNull => Self::AconstNull,
342            Opcode::Aload => Self::Aload(cursor.u8()?),
343            Opcode::Aload0 => Self::Aload0,
344            Opcode::Aload1 => Self::Aload1,
345            Opcode::Aload2 => Self::Aload2,
346            Opcode::Aload3 => Self::Aload3,
347            Opcode::Anewarray => Self::Anewarray(cursor.u16()?),
348            Opcode::Areturn => Self::Areturn,
349            Opcode::ArrayLength => Self::ArrayLength,
350            Opcode::Astore => Self::Astore(cursor.u8()?),
351            Opcode::Astore0 => Self::Astore0,
352            Opcode::Astore1 => Self::Astore1,
353            Opcode::Astore2 => Self::Astore2,
354            Opcode::Astore3 => Self::Astore3,
355            Opcode::Athrow => Self::Athrow,
356            Opcode::Baload => Self::Baload,
357            Opcode::Bastore => Self::Bastore,
358            Opcode::Bipush => Self::Bipush(cursor.i8()?),
359            Opcode::Breakpoint => Self::Breakpoint,
360            Opcode::Caload => Self::Caload,
361            Opcode::Castore => Self::Castore,
362            Opcode::Checkcast => Self::Checkcast(cursor.u16()?),
363            Opcode::D2f => Self::D2f,
364            Opcode::D2i => Self::D2i,
365            Opcode::D2l => Self::D2l,
366            Opcode::Dadd => Self::Dadd,
367            Opcode::Daload => Self::Daload,
368            Opcode::Dastore => Self::Dastore,
369            Opcode::Dcmpg => Self::Dcmpg,
370            Opcode::Dcmpl => Self::Dcmpl,
371            Opcode::Dconst0 => Self::Dconst0,
372            Opcode::Dconst1 => Self::Dconst1,
373            Opcode::Ddiv => Self::Ddiv,
374            Opcode::Dload => Self::Dload(cursor.u8()?),
375            Opcode::Dload0 => Self::Dload0,
376            Opcode::Dload1 => Self::Dload1,
377            Opcode::Dload2 => Self::Dload2,
378            Opcode::Dload3 => Self::Dload3,
379            Opcode::Dmul => Self::Dmul,
380            Opcode::Dneg => Self::Dneg,
381            Opcode::Drem => Self::Drem,
382            Opcode::Dreturn => Self::Dreturn,
383            Opcode::Dstore => Self::Dstore(cursor.u8()?),
384            Opcode::Dstore0 => Self::Dstore0,
385            Opcode::Dstore1 => Self::Dstore1,
386            Opcode::Dstore2 => Self::Dstore2,
387            Opcode::Dstore3 => Self::Dstore3,
388            Opcode::Dsub => Self::Dsub,
389            Opcode::Dup => Self::Dup,
390            Opcode::Dup2 => Self::Dup2,
391            Opcode::Dup2X1 => Self::Dup2X1,
392            Opcode::Dup2X2 => Self::Dup2X2,
393            Opcode::DupX1 => Self::DupX1,
394            Opcode::DupX2 => Self::DupX2,
395            Opcode::F2d => Self::F2d,
396            Opcode::F2i => Self::F2i,
397            Opcode::F2l => Self::F2l,
398            Opcode::Fadd => Self::Fadd,
399            Opcode::Faload => Self::Faload,
400            Opcode::Fastore => Self::Fastore,
401            Opcode::Fcmpg => Self::Fcmpg,
402            Opcode::Fcmpl => Self::Fcmpl,
403            Opcode::Fconst0 => Self::Fconst0,
404            Opcode::Fconst1 => Self::Fconst1,
405            Opcode::Fconst2 => Self::Fconst2,
406            Opcode::Fdiv => Self::Fdiv,
407            Opcode::Fload => Self::Fload(cursor.u8()?),
408            Opcode::Fload0 => Self::Fload0,
409            Opcode::Fload1 => Self::Fload1,
410            Opcode::Fload2 => Self::Fload2,
411            Opcode::Fload3 => Self::Fload3,
412            Opcode::Fmul => Self::Fmul,
413            Opcode::Fneg => Self::Fneg,
414            Opcode::Frem => Self::Frem,
415            Opcode::Freturn => Self::Freturn,
416            Opcode::Fstore => Self::Fstore(cursor.u8()?),
417            Opcode::Fstore0 => Self::Fstore0,
418            Opcode::Fstore1 => Self::Fstore1,
419            Opcode::Fstore2 => Self::Fstore2,
420            Opcode::Fstore3 => Self::Fstore3,
421            Opcode::Fsub => Self::Fsub,
422            Opcode::Getfield => Self::Getfield(cursor.u16()?),
423            Opcode::Getstatic => Self::Getstatic(cursor.u16()?),
424            Opcode::Goto => Self::Goto(cursor.i16()?),
425            Opcode::GotoW => Self::GotoW(cursor.i32()?),
426            Opcode::I2b => Self::I2b,
427            Opcode::I2c => Self::I2c,
428            Opcode::I2d => Self::I2d,
429            Opcode::I2f => Self::I2f,
430            Opcode::I2l => Self::I2l,
431            Opcode::I2s => Self::I2s,
432            Opcode::Iadd => Self::Iadd,
433            Opcode::Iaload => Self::Iaload,
434            Opcode::Iand => Self::Iand,
435            Opcode::Iastore => Self::Iastore,
436            Opcode::IconstM1 => Self::IconstM1,
437            Opcode::Iconst0 => Self::Iconst0,
438            Opcode::Iconst1 => Self::Iconst1,
439            Opcode::Iconst2 => Self::Iconst2,
440            Opcode::Iconst3 => Self::Iconst3,
441            Opcode::Iconst4 => Self::Iconst4,
442            Opcode::Iconst5 => Self::Iconst5,
443            Opcode::Idiv => Self::Idiv,
444            Opcode::IfAcmpEq => Self::IfAcmpEq(cursor.i16()?),
445            Opcode::IfAcmpNe => Self::IfAcmpNe(cursor.i16()?),
446            Opcode::IfEq => Self::IfEq(cursor.i16()?),
447            Opcode::IfGe => Self::IfGe(cursor.i16()?),
448            Opcode::IfGt => Self::IfGt(cursor.i16()?),
449            Opcode::IfLe => Self::IfLe(cursor.i16()?),
450            Opcode::IfLt => Self::IfLt(cursor.i16()?),
451            Opcode::IfNe => Self::IfNe(cursor.i16()?),
452            Opcode::Ifnonnull => Self::Ifnonnull(cursor.i16()?),
453            Opcode::Ifnull => Self::Ifnull(cursor.i16()?),
454            Opcode::IfIcmpeq => Self::IfIcmpeq(cursor.i16()?),
455            Opcode::IfIcmpge => Self::IfIcmpge(cursor.i16()?),
456            Opcode::IfIcmpgt => Self::IfIcmpgt(cursor.i16()?),
457            Opcode::IfIcmple => Self::IfIcmple(cursor.i16()?),
458            Opcode::IfIcmplt => Self::IfIcmplt(cursor.i16()?),
459            Opcode::IfIcmpne => Self::IfIcmpne(cursor.i16()?),
460            Opcode::Iinc => Self::Iinc(cursor.u8()?, cursor.i8()?),
461            Opcode::Iload => Self::Iload(cursor.u8()?),
462            Opcode::Iload0 => Self::Iload0,
463            Opcode::Iload1 => Self::Iload1,
464            Opcode::Iload2 => Self::Iload2,
465            Opcode::Iload3 => Self::Iload3,
466            Opcode::Imul => Self::Imul,
467            Opcode::Ineg => Self::Ineg,
468            Opcode::Instanceof => Self::Instanceof(cursor.u16()?),
469            Opcode::InvokeDynamic => {
470                let index = cursor.u16()?;
471                let _zero = cursor.u16()?; //TODO assert?
472                Self::InvokeDynamic(index)
473            }
474            Opcode::InvokeInterface => {
475                let index = cursor.u16()?;
476                let count = cursor.u8()?;
477                let _zero = cursor.u8()?; //TODO assert?
478                Self::InvokeInterface(index, count)
479            }
480            Opcode::InvokeSpecial => Self::InvokeSpecial(cursor.u16()?),
481            Opcode::InvokeStatic => Self::InvokeStatic(cursor.u16()?),
482            Opcode::InvokeVirtual => Self::InvokeVirtual(cursor.u16()?),
483            Opcode::Ior => Self::Ior,
484            Opcode::Irem => Self::Irem,
485            Opcode::Ireturn => Self::Ireturn,
486            Opcode::Ishl => Self::Ishl,
487            Opcode::Ishr => Self::Ishr,
488            Opcode::Istore => Self::Istore(cursor.u8()?),
489            Opcode::Istore0 => Self::Istore0,
490            Opcode::Istore1 => Self::Istore1,
491            Opcode::Istore2 => Self::Istore2,
492            Opcode::Istore3 => Self::Istore3,
493            Opcode::Isub => Self::Isub,
494            Opcode::Iushr => Self::Iushr,
495            Opcode::Ixor => Self::Ixor,
496            Opcode::Jsr => Self::Jsr(cursor.i16()?),
497            Opcode::JsrW => Self::JsrW(cursor.i32()?),
498            Opcode::L2d => Self::L2d,
499            Opcode::L2f => Self::L2f,
500            Opcode::L2i => Self::L2i,
501            Opcode::Ladd => Self::Ladd,
502            Opcode::Laload => Self::Laload,
503            Opcode::Land => Self::Land,
504            Opcode::Lastore => Self::Lastore,
505            Opcode::Lcmp => Self::Lcmp,
506            Opcode::Lconst0 => Self::Lconst0,
507            Opcode::Lconst1 => Self::Lconst1,
508            Opcode::Ldc => Self::Ldc(cursor.u8()? as u16),
509            Opcode::Ldc2W => Self::Ldc2W(cursor.u16()?),
510            Opcode::LdcW => Self::LdcW(cursor.u16()?),
511            Opcode::Ldiv => Self::Ldiv,
512            Opcode::Lload => Self::Lload(cursor.u8()?),
513            Opcode::Lload0 => Self::Lload0,
514            Opcode::Lload1 => Self::Lload1,
515            Opcode::Lload2 => Self::Lload2,
516            Opcode::Lload3 => Self::Lload3,
517            Opcode::Lmul => Self::Lmul,
518            Opcode::Lneg => Self::Lneg,
519            Opcode::Lookupswitch => {
520                let padding = Self::switch_padding(pc);
521                for _ in 0..padding {
522                    cursor.u8()?;
523                }
524
525                let default_offset = cursor.i32()?;
526                let npairs = cursor.i32()?;
527                let mut pairs = Vec::with_capacity(npairs as usize);
528                for _ in 0..npairs {
529                    let match_value = cursor.i32()?;
530                    let offset = cursor.i32()?;
531                    pairs.push((match_value, offset));
532                }
533                Instruction::Lookupswitch(LookupSwitchData {
534                    padding,
535                    default_offset,
536                    pairs,
537                })
538            }
539            Opcode::Lor => Self::Lor,
540            Opcode::Lrem => Self::Lrem,
541            Opcode::Lreturn => Self::Lreturn,
542            Opcode::Lshl => Self::Lshl,
543            Opcode::Lshr => Self::Lshr,
544            Opcode::Lstore => Self::Lstore(cursor.u8()?),
545            Opcode::Lstore0 => Self::Lstore0,
546            Opcode::Lstore1 => Self::Lstore1,
547            Opcode::Lstore2 => Self::Lstore2,
548            Opcode::Lstore3 => Self::Lstore3,
549            Opcode::Lsub => Self::Lsub,
550            Opcode::Lushr => Self::Lushr,
551            Opcode::Lxor => Self::Lxor,
552            Opcode::Monitorenter => Self::Monitorenter,
553            Opcode::Monitorexit => Self::Monitorexit,
554            Opcode::Multianewarray => Self::Multianewarray(cursor.u16()?, cursor.u8()?),
555            Opcode::New => Self::New(cursor.u16()?),
556            Opcode::Newarray => {
557                let array_type_raw = cursor.u8()?;
558                let array_type = ArrayType::try_from_primitive(array_type_raw)
559                    .map_err(|_| InstructionErr::UnknownArrayType(array_type_raw))?;
560                Self::Newarray(array_type)
561            }
562            Opcode::Nop => Self::Nop,
563            Opcode::Pop => Self::Pop,
564            Opcode::Pop2 => Self::Pop2,
565            Opcode::Putfield => Self::Putfield(cursor.u16()?),
566            Opcode::Putstatic => Self::Putstatic(cursor.u16()?),
567            Opcode::Ret => Self::Ret(cursor.u8()?),
568            Opcode::Return => Self::Return,
569            Opcode::Saload => Self::Saload,
570            Opcode::Sastore => Self::Sastore,
571            Opcode::Sipush => Self::Sipush(cursor.i16()?),
572            Opcode::Swap => Self::Swap,
573            Opcode::TableSwitch => {
574                let padding = Self::switch_padding(pc);
575                for _ in 0..padding {
576                    cursor.u8()?;
577                }
578
579                let default_offset = cursor.i32()?;
580                let low = cursor.i32()?;
581                let high = cursor.i32()?;
582                let num_offsets = (high - low + 1) as usize;
583                let mut offsets = Vec::with_capacity(num_offsets);
584                for _ in 0..num_offsets {
585                    offsets.push(cursor.i32()?);
586                }
587                Instruction::TableSwitch(TableSwitchData {
588                    padding,
589                    default_offset,
590                    low,
591                    high,
592                    offsets,
593                })
594            }
595        };
596
597        Ok(instruction)
598    }
599
600    pub fn opcode(&self) -> Option<Opcode> {
601        let op = match self {
602            Self::Aaload => Opcode::Aaload,
603            Self::Aastore => Opcode::Aastore,
604            Self::AconstNull => Opcode::AconstNull,
605            Self::Aload(_) => Opcode::Aload,
606            Self::Aload0 => Opcode::Aload0,
607            Self::Aload1 => Opcode::Aload1,
608            Self::Aload2 => Opcode::Aload2,
609            Self::Aload3 => Opcode::Aload3,
610            Self::Anewarray(_) => Opcode::Anewarray,
611            Self::Areturn => Opcode::Areturn,
612            Self::ArrayLength => Opcode::ArrayLength,
613            Self::Astore(_) => Opcode::Astore,
614            Self::Astore0 => Opcode::Astore0,
615            Self::Astore1 => Opcode::Astore1,
616            Self::Astore2 => Opcode::Astore2,
617            Self::Astore3 => Opcode::Astore3,
618            Self::Athrow => Opcode::Athrow,
619            Self::Baload => Opcode::Baload,
620            Self::Bastore => Opcode::Bastore,
621            Self::Bipush(_) => Opcode::Bipush,
622            Self::Breakpoint => Opcode::Breakpoint,
623            Self::Caload => Opcode::Caload,
624            Self::Castore => Opcode::Castore,
625            Self::Checkcast(_) => Opcode::Checkcast,
626            Self::D2f => Opcode::D2f,
627            Self::D2i => Opcode::D2i,
628            Self::D2l => Opcode::D2l,
629            Self::Dadd => Opcode::Dadd,
630            Self::Daload => Opcode::Daload,
631            Self::Dastore => Opcode::Dastore,
632            Self::Dcmpg => Opcode::Dcmpg,
633            Self::Dcmpl => Opcode::Dcmpl,
634            Self::Dconst0 => Opcode::Dconst0,
635            Self::Dconst1 => Opcode::Dconst1,
636            Self::Ddiv => Opcode::Ddiv,
637            Self::Dload(_) => Opcode::Dload,
638            Self::Dload0 => Opcode::Dload0,
639            Self::Dload1 => Opcode::Dload1,
640            Self::Dload2 => Opcode::Dload2,
641            Self::Dload3 => Opcode::Dload3,
642            Self::Dmul => Opcode::Dmul,
643            Self::Dneg => Opcode::Dneg,
644            Self::Drem => Opcode::Drem,
645            Self::Dreturn => Opcode::Dreturn,
646            Self::Dstore(_) => Opcode::Dstore,
647            Self::Dstore0 => Opcode::Dstore0,
648            Self::Dstore1 => Opcode::Dstore1,
649            Self::Dstore2 => Opcode::Dstore2,
650            Self::Dstore3 => Opcode::Dstore3,
651            Self::Dsub => Opcode::Dsub,
652            Self::Dup => Opcode::Dup,
653            Self::Dup2 => Opcode::Dup2,
654            Self::Dup2X1 => Opcode::Dup2X1,
655            Self::Dup2X2 => Opcode::Dup2X2,
656            Self::DupX1 => Opcode::DupX1,
657            Self::DupX2 => Opcode::DupX2,
658            Self::F2d => Opcode::F2d,
659            Self::F2i => Opcode::F2i,
660            Self::F2l => Opcode::F2l,
661            Self::Fadd => Opcode::Fadd,
662            Self::Faload => Opcode::Faload,
663            Self::Fastore => Opcode::Fastore,
664            Self::Fcmpg => Opcode::Fcmpg,
665            Self::Fcmpl => Opcode::Fcmpl,
666            Self::Fconst0 => Opcode::Fconst0,
667            Self::Fconst1 => Opcode::Fconst1,
668            Self::Fconst2 => Opcode::Fconst2,
669            Self::Fdiv => Opcode::Fdiv,
670            Self::Fload(_) => Opcode::Fload,
671            Self::Fload0 => Opcode::Fload0,
672            Self::Fload1 => Opcode::Fload1,
673            Self::Fload2 => Opcode::Fload2,
674            Self::Fload3 => Opcode::Fload3,
675            Self::Fmul => Opcode::Fmul,
676            Self::Fneg => Opcode::Fneg,
677            Self::Frem => Opcode::Frem,
678            Self::Freturn => Opcode::Freturn,
679            Self::Fstore(_) => Opcode::Fstore,
680            Self::Fstore0 => Opcode::Fstore0,
681            Self::Fstore1 => Opcode::Fstore1,
682            Self::Fstore2 => Opcode::Fstore2,
683            Self::Fstore3 => Opcode::Fstore3,
684            Self::Fsub => Opcode::Fsub,
685            Self::Getfield(_) => Opcode::Getfield,
686            Self::Getstatic(_) => Opcode::Getstatic,
687            Self::Goto(_) => Opcode::Goto,
688            Self::GotoW(_) => Opcode::GotoW,
689            Self::I2b => Opcode::I2b,
690            Self::I2c => Opcode::I2c,
691            Self::I2d => Opcode::I2d,
692            Self::I2f => Opcode::I2f,
693            Self::I2l => Opcode::I2l,
694            Self::I2s => Opcode::I2s,
695            Self::Iadd => Opcode::Iadd,
696            Self::Iaload => Opcode::Iaload,
697            Self::Iand => Opcode::Iand,
698            Self::Iastore => Opcode::Iastore,
699            Self::IconstM1 => Opcode::IconstM1,
700            Self::Iconst0 => Opcode::Iconst0,
701            Self::Iconst1 => Opcode::Iconst1,
702            Self::Iconst2 => Opcode::Iconst2,
703            Self::Iconst3 => Opcode::Iconst3,
704            Self::Iconst4 => Opcode::Iconst4,
705            Self::Iconst5 => Opcode::Iconst5,
706            Self::Idiv => Opcode::Idiv,
707            Self::IfAcmpEq(_) => Opcode::IfAcmpEq,
708            Self::IfAcmpNe(_) => Opcode::IfAcmpNe,
709            Self::IfEq(_) => Opcode::IfEq,
710            Self::IfGe(_) => Opcode::IfGe,
711            Self::IfGt(_) => Opcode::IfGt,
712            Self::IfLe(_) => Opcode::IfLe,
713            Self::IfLt(_) => Opcode::IfLt,
714            Self::IfNe(_) => Opcode::IfNe,
715            Self::Ifnonnull(_) => Opcode::Ifnonnull,
716            Self::Ifnull(_) => Opcode::Ifnull,
717            Self::IfIcmpeq(_) => Opcode::IfIcmpeq,
718            Self::IfIcmpge(_) => Opcode::IfIcmpge,
719            Self::IfIcmpgt(_) => Opcode::IfIcmpgt,
720            Self::IfIcmple(_) => Opcode::IfIcmple,
721            Self::IfIcmplt(_) => Opcode::IfIcmplt,
722            Self::IfIcmpne(_) => Opcode::IfIcmpne,
723            Self::Iinc(_, _) => Opcode::Iinc,
724            Self::Iload(_) => Opcode::Iload,
725            Self::Iload0 => Opcode::Iload0,
726            Self::Iload1 => Opcode::Iload1,
727            Self::Iload2 => Opcode::Iload2,
728            Self::Iload3 => Opcode::Iload3,
729            Self::Imul => Opcode::Imul,
730            Self::Ineg => Opcode::Ineg,
731            Self::Instanceof(_) => Opcode::Instanceof,
732            Self::InvokeDynamic(_) => Opcode::InvokeDynamic,
733            Self::InvokeInterface(_, _) => Opcode::InvokeInterface,
734            Self::InvokeSpecial(_) => Opcode::InvokeSpecial,
735            Self::InvokeStatic(_) => Opcode::InvokeStatic,
736            Self::InvokeVirtual(_) => Opcode::InvokeVirtual,
737            Self::Ior => Opcode::Ior,
738            Self::Irem => Opcode::Irem,
739            Self::Ireturn => Opcode::Ireturn,
740            Self::Ishl => Opcode::Ishl,
741            Self::Ishr => Opcode::Ishr,
742            Self::Istore(_) => Opcode::Istore,
743            Self::Istore0 => Opcode::Istore0,
744            Self::Istore1 => Opcode::Istore1,
745            Self::Istore2 => Opcode::Istore2,
746            Self::Istore3 => Opcode::Istore3,
747            Self::Isub => Opcode::Isub,
748            Self::Iushr => Opcode::Iushr,
749            Self::Ixor => Opcode::Ixor,
750            Self::Jsr(_) => Opcode::Jsr,
751            Self::JsrW(_) => Opcode::JsrW,
752            Self::L2d => Opcode::L2d,
753            Self::L2f => Opcode::L2f,
754            Self::L2i => Opcode::L2i,
755            Self::Ladd => Opcode::Ladd,
756            Self::Laload => Opcode::Laload,
757            Self::Land => Opcode::Land,
758            Self::Lastore => Opcode::Lastore,
759            Self::Lcmp => Opcode::Lcmp,
760            Self::Lconst0 => Opcode::Lconst0,
761            Self::Lconst1 => Opcode::Lconst1,
762            Self::Ldc(_) => Opcode::Ldc,
763            Self::Ldc2W(_) => Opcode::Ldc2W,
764            Self::LdcW(_) => Opcode::LdcW,
765            Self::Ldiv => Opcode::Ldiv,
766            Self::Lload(_) => Opcode::Lload,
767            Self::Lload0 => Opcode::Lload0,
768            Self::Lload1 => Opcode::Lload1,
769            Self::Lload2 => Opcode::Lload2,
770            Self::Lload3 => Opcode::Lload3,
771            Self::Lmul => Opcode::Lmul,
772            Self::Lneg => Opcode::Lneg,
773            Self::Lookupswitch(_) => Opcode::Lookupswitch,
774            Self::Lor => Opcode::Lor,
775            Self::Lrem => Opcode::Lrem,
776            Self::Lreturn => Opcode::Lreturn,
777            Self::Lshl => Opcode::Lshl,
778            Self::Lshr => Opcode::Lshr,
779            Self::Lstore(_) => Opcode::Lstore,
780            Self::Lstore0 => Opcode::Lstore0,
781            Self::Lstore1 => Opcode::Lstore1,
782            Self::Lstore2 => Opcode::Lstore2,
783            Self::Lstore3 => Opcode::Lstore3,
784            Self::Lsub => Opcode::Lsub,
785            Self::Lushr => Opcode::Lushr,
786            Self::Lxor => Opcode::Lxor,
787            Self::Monitorenter => Opcode::Monitorenter,
788            Self::Monitorexit => Opcode::Monitorexit,
789            Self::Multianewarray(_, _) => Opcode::Multianewarray,
790            Self::New(_) => Opcode::New,
791            Self::Newarray(_) => Opcode::Newarray,
792            Self::Nop => Opcode::Nop,
793            Self::Pop => Opcode::Pop,
794            Self::Pop2 => Opcode::Pop2,
795            Self::Putfield(_) => Opcode::Putfield,
796            Self::Putstatic(_) => Opcode::Putstatic,
797            Self::Ret(_) => Opcode::Ret,
798            Self::Return => Opcode::Return,
799            Self::Saload => Opcode::Saload,
800            Self::Sastore => Opcode::Sastore,
801            Self::Sipush(_) => Opcode::Sipush,
802            Self::Swap => Opcode::Swap,
803            Self::TableSwitch(_) => Opcode::TableSwitch,
804            Self::Impdep1 | Self::Impdep2 => return None,
805        };
806        Some(op)
807    }
808
809    /// Returns the mnemonic name of this instruction (e.g. `"aload"`, `"invokespecial"`).
810    ///
811    /// Delegates to [`Opcode::as_str`] for standard instructions. Reserved
812    /// instructions (`impdep1`, `impdep2`) are handled as special cases since
813    /// they have no corresponding [`Opcode`] variant.
814    pub fn get_name(&self) -> &'static str {
815        match self {
816            Self::Impdep1 => "impdep1",
817            Self::Impdep2 => "impdep2",
818            // SAFETY: all other variants have a corresponding Opcode
819            _ => self.opcode().unwrap().as_str(),
820        }
821    }
822}
823
824impl std::fmt::Display for Instruction {
825    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
826        f.write_str(self.get_name())
827    }
828}