Skip to main content

lvm_class/bytecode/
opcode.rs

1use num_enum::TryFromPrimitive;
2
3/// JVM bytecode opcode.
4///
5/// https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-6.html
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
7#[repr(u8)]
8pub enum Opcode {
9    Aaload = 0x32,
10    Aastore = 0x53,
11    AconstNull = 0x01,
12    Aload = 0x19,
13    Aload0 = 0x2A,
14    Aload1 = 0x2B,
15    Aload2 = 0x2C,
16    Aload3 = 0x2D,
17    Anewarray = 0xBD,
18    Areturn = 0xB0,
19    ArrayLength = 0xBE,
20    Astore = 0x3A,
21    Astore0 = 0x4B,
22    Astore1 = 0x4C,
23    Astore2 = 0x4D,
24    Astore3 = 0x4E,
25    Athrow = 0xBF,
26    Baload = 0x33,
27    Bastore = 0x54,
28    Bipush = 0x10,
29    Breakpoint = 0xCA,
30    Caload = 0x34,
31    Castore = 0x55,
32    Checkcast = 0xC0,
33    D2f = 0x90,
34    D2i = 0x8E,
35    D2l = 0x8F,
36    Dadd = 0x63,
37    Daload = 0x31,
38    Dastore = 0x52,
39    Dcmpg = 0x98,
40    Dcmpl = 0x97,
41    Dconst0 = 0x0E,
42    Dconst1 = 0x0F,
43    Ddiv = 0x6F,
44    Dload = 0x18,
45    Dload0 = 0x26,
46    Dload1 = 0x27,
47    Dload2 = 0x28,
48    Dload3 = 0x29,
49    Dmul = 0x6B,
50    Dneg = 0x77,
51    Drem = 0x73,
52    Dreturn = 0xAF,
53    Dstore = 0x39,
54    Dstore0 = 0x47,
55    Dstore1 = 0x48,
56    Dstore2 = 0x49,
57    Dstore3 = 0x4A,
58    Dsub = 0x67,
59    Dup = 0x59,
60    DupX1 = 0x5A,
61    DupX2 = 0x5B,
62    Dup2 = 0x5C,
63    Dup2X1 = 0x5D,
64    Dup2X2 = 0x5E,
65    F2d = 0x8D,
66    F2i = 0x8B,
67    F2l = 0x8C,
68    Fadd = 0x62,
69    Faload = 0x30,
70    Fastore = 0x51,
71    Fcmpg = 0x96,
72    Fcmpl = 0x95,
73    Fconst0 = 0x0B,
74    Fconst1 = 0x0C,
75    Fconst2 = 0x0D,
76    Fdiv = 0x6E,
77    Fload = 0x17,
78    Fload0 = 0x22,
79    Fload1 = 0x23,
80    Fload2 = 0x24,
81    Fload3 = 0x25,
82    Fmul = 0x6A,
83    Fneg = 0x76,
84    Frem = 0x72,
85    Freturn = 0xAE,
86    Fstore = 0x38,
87    Fstore0 = 0x43,
88    Fstore1 = 0x44,
89    Fstore2 = 0x45,
90    Fstore3 = 0x46,
91    Fsub = 0x66,
92    Getfield = 0xB4,
93    Getstatic = 0xB2,
94    Goto = 0xA7,
95    GotoW = 0xC8,
96    I2b = 0x91,
97    I2c = 0x92,
98    I2d = 0x87,
99    I2f = 0x86,
100    I2l = 0x85,
101    I2s = 0x93,
102    Iadd = 0x60,
103    Iaload = 0x2E,
104    Iand = 0x7E,
105    Iastore = 0x4F,
106    IconstM1 = 0x02,
107    Iconst0 = 0x03,
108    Iconst1 = 0x04,
109    Iconst2 = 0x05,
110    Iconst3 = 0x06,
111    Iconst4 = 0x07,
112    Iconst5 = 0x08,
113    Idiv = 0x6C,
114    IfAcmpEq = 0xA5,
115    IfAcmpNe = 0xA6,
116    IfIcmpeq = 0x9F,
117    IfIcmpge = 0xA2,
118    IfIcmpgt = 0xA3,
119    IfIcmple = 0xA4,
120    IfIcmplt = 0xA1,
121    IfIcmpne = 0xA0,
122    IfEq = 0x99,
123    IfGe = 0x9C,
124    IfGt = 0x9D,
125    IfLe = 0x9E,
126    IfLt = 0x9B,
127    IfNe = 0x9A,
128    Ifnonnull = 0xC7,
129    Ifnull = 0xC6,
130    Iinc = 0x84,
131    Iload = 0x15,
132    Iload0 = 0x1A,
133    Iload1 = 0x1B,
134    Iload2 = 0x1C,
135    Iload3 = 0x1D,
136    Imul = 0x68,
137    Ineg = 0x74,
138    Instanceof = 0xC1,
139    InvokeDynamic = 0xBA,
140    InvokeInterface = 0xB9,
141    InvokeSpecial = 0xB7,
142    InvokeStatic = 0xB8,
143    InvokeVirtual = 0xB6,
144    Ior = 0x80,
145    Irem = 0x70,
146    Ireturn = 0xAC,
147    Ishl = 0x78,
148    Ishr = 0x7A,
149    Istore = 0x36,
150    Istore0 = 0x3B,
151    Istore1 = 0x3C,
152    Istore2 = 0x3D,
153    Istore3 = 0x3E,
154    Isub = 0x64,
155    Iushr = 0x7C,
156    Ixor = 0x82,
157    Jsr = 0xA8,
158    JsrW = 0xC9,
159    L2d = 0x8A,
160    L2f = 0x89,
161    L2i = 0x88,
162    Ladd = 0x61,
163    Laload = 0x2F,
164    Land = 0x7F,
165    Lastore = 0x50,
166    Lcmp = 0x94,
167    Lconst0 = 0x09,
168    Lconst1 = 0x0A,
169    Ldc = 0x12,
170    LdcW = 0x13,
171    Ldc2W = 0x14,
172    Ldiv = 0x6D,
173    Lload = 0x16,
174    Lload0 = 0x1E,
175    Lload1 = 0x1F,
176    Lload2 = 0x20,
177    Lload3 = 0x21,
178    Lmul = 0x69,
179    Lneg = 0x75,
180    Lookupswitch = 0xAB,
181    Lor = 0x81,
182    Lrem = 0x71,
183    Lreturn = 0xAD,
184    Lshl = 0x79,
185    Lshr = 0x7B,
186    Lstore = 0x37,
187    Lstore0 = 0x3F,
188    Lstore1 = 0x40,
189    Lstore2 = 0x41,
190    Lstore3 = 0x42,
191    Lsub = 0x65,
192    Lushr = 0x7D,
193    Lxor = 0x83,
194    Monitorenter = 0xC2,
195    Monitorexit = 0xC3,
196    Multianewarray = 0xC5,
197    New = 0xBB,
198    Newarray = 0xBC,
199    Nop = 0x00,
200    Pop = 0x57,
201    Pop2 = 0x58,
202    Putfield = 0xB5,
203    Putstatic = 0xB3,
204    Ret = 0xA9,
205    Return = 0xB1,
206    Saload = 0x35,
207    Sastore = 0x56,
208    Sipush = 0x11,
209    Swap = 0x5F,
210    TableSwitch = 0xAA,
211}
212
213impl Opcode {
214    pub const fn as_str(self) -> &'static str {
215        match self {
216            Self::Aaload => "aaload",
217            Self::Aastore => "aastore",
218            Self::AconstNull => "aconst_null",
219            Self::Aload => "aload",
220            Self::Aload0 => "aload_0",
221            Self::Aload1 => "aload_1",
222            Self::Aload2 => "aload_2",
223            Self::Aload3 => "aload_3",
224            Self::Anewarray => "anewarray",
225            Self::Areturn => "areturn",
226            Self::ArrayLength => "arraylength",
227            Self::Astore => "astore",
228            Self::Astore0 => "astore_0",
229            Self::Astore1 => "astore_1",
230            Self::Astore2 => "astore_2",
231            Self::Astore3 => "astore_3",
232            Self::Athrow => "athrow",
233            Self::Baload => "baload",
234            Self::Bastore => "bastore",
235            Self::Bipush => "bipush",
236            Self::Breakpoint => "breakpoint",
237            Self::Caload => "caload",
238            Self::Castore => "castore",
239            Self::Checkcast => "checkcast",
240            Self::D2f => "d2f",
241            Self::D2i => "d2i",
242            Self::D2l => "d2l",
243            Self::Dadd => "dadd",
244            Self::Daload => "daload",
245            Self::Dastore => "dastore",
246            Self::Dcmpg => "dcmpg",
247            Self::Dcmpl => "dcmpl",
248            Self::Dconst0 => "dconst_0",
249            Self::Dconst1 => "dconst_1",
250            Self::Ddiv => "ddiv",
251            Self::Dload => "dload",
252            Self::Dload0 => "dload_0",
253            Self::Dload1 => "dload_1",
254            Self::Dload2 => "dload_2",
255            Self::Dload3 => "dload_3",
256            Self::Dmul => "dmul",
257            Self::Dneg => "dneg",
258            Self::Drem => "drem",
259            Self::Dreturn => "dreturn",
260            Self::Dstore => "dstore",
261            Self::Dstore0 => "dstore_0",
262            Self::Dstore1 => "dstore_1",
263            Self::Dstore2 => "dstore_2",
264            Self::Dstore3 => "dstore_3",
265            Self::Dsub => "dsub",
266            Self::Dup => "dup",
267            Self::DupX1 => "dup_x1",
268            Self::DupX2 => "dup_x2",
269            Self::Dup2 => "dup2",
270            Self::Dup2X1 => "dup2_x1",
271            Self::Dup2X2 => "dup2_x2",
272            Self::F2d => "f2d",
273            Self::F2i => "f2i",
274            Self::F2l => "f2l",
275            Self::Fadd => "fadd",
276            Self::Faload => "faload",
277            Self::Fastore => "fastore",
278            Self::Fcmpg => "fcmpg",
279            Self::Fcmpl => "fcmpl",
280            Self::Fconst0 => "fconst_0",
281            Self::Fconst1 => "fconst_1",
282            Self::Fconst2 => "fconst_2",
283            Self::Fdiv => "fdiv",
284            Self::Fload => "fload",
285            Self::Fload0 => "fload_0",
286            Self::Fload1 => "fload_1",
287            Self::Fload2 => "fload_2",
288            Self::Fload3 => "fload_3",
289            Self::Fmul => "fmul",
290            Self::Fneg => "fneg",
291            Self::Frem => "frem",
292            Self::Freturn => "freturn",
293            Self::Fstore => "fstore",
294            Self::Fstore0 => "fstore_0",
295            Self::Fstore1 => "fstore_1",
296            Self::Fstore2 => "fstore_2",
297            Self::Fstore3 => "fstore_3",
298            Self::Fsub => "fsub",
299            Self::Getfield => "getfield",
300            Self::Getstatic => "getstatic",
301            Self::Goto => "goto",
302            Self::GotoW => "goto_w",
303            Self::I2b => "i2b",
304            Self::I2c => "i2c",
305            Self::I2d => "i2d",
306            Self::I2f => "i2f",
307            Self::I2l => "i2l",
308            Self::I2s => "i2s",
309            Self::Iadd => "iadd",
310            Self::Iaload => "iaload",
311            Self::Iand => "iand",
312            Self::Iastore => "iastore",
313            Self::IconstM1 => "iconst_m1",
314            Self::Iconst0 => "iconst_0",
315            Self::Iconst1 => "iconst_1",
316            Self::Iconst2 => "iconst_2",
317            Self::Iconst3 => "iconst_3",
318            Self::Iconst4 => "iconst_4",
319            Self::Iconst5 => "iconst_5",
320            Self::Idiv => "idiv",
321            Self::IfAcmpEq => "if_acmpeq",
322            Self::IfAcmpNe => "if_acmpne",
323            Self::IfIcmpeq => "if_icmpeq",
324            Self::IfIcmpge => "if_icmpge",
325            Self::IfIcmpgt => "if_icmpgt",
326            Self::IfIcmple => "if_icmple",
327            Self::IfIcmplt => "if_icmplt",
328            Self::IfIcmpne => "if_icmpne",
329            Self::IfEq => "ifeq",
330            Self::IfGe => "ifge",
331            Self::IfGt => "ifgt",
332            Self::IfLe => "ifle",
333            Self::IfLt => "iflt",
334            Self::IfNe => "ifne",
335            Self::Ifnonnull => "ifnonnull",
336            Self::Ifnull => "ifnull",
337            Self::Iinc => "iinc",
338            Self::Iload => "iload",
339            Self::Iload0 => "iload_0",
340            Self::Iload1 => "iload_1",
341            Self::Iload2 => "iload_2",
342            Self::Iload3 => "iload_3",
343            Self::Imul => "imul",
344            Self::Ineg => "ineg",
345            Self::Instanceof => "instanceof",
346            Self::InvokeDynamic => "invokedynamic",
347            Self::InvokeInterface => "invokeinterface",
348            Self::InvokeSpecial => "invokespecial",
349            Self::InvokeStatic => "invokestatic",
350            Self::InvokeVirtual => "invokevirtual",
351            Self::Ior => "ior",
352            Self::Irem => "irem",
353            Self::Ireturn => "ireturn",
354            Self::Ishl => "ishl",
355            Self::Ishr => "ishr",
356            Self::Istore => "istore",
357            Self::Istore0 => "istore_0",
358            Self::Istore1 => "istore_1",
359            Self::Istore2 => "istore_2",
360            Self::Istore3 => "istore_3",
361            Self::Isub => "isub",
362            Self::Iushr => "iushr",
363            Self::Ixor => "ixor",
364            Self::Jsr => "jsr",
365            Self::JsrW => "jsr_w",
366            Self::L2d => "l2d",
367            Self::L2f => "l2f",
368            Self::L2i => "l2i",
369            Self::Ladd => "ladd",
370            Self::Laload => "laload",
371            Self::Land => "land",
372            Self::Lastore => "lastore",
373            Self::Lcmp => "lcmp",
374            Self::Lconst0 => "lconst_0",
375            Self::Lconst1 => "lconst_1",
376            Self::Ldc => "ldc",
377            Self::LdcW => "ldc_w",
378            Self::Ldc2W => "ldc2_w",
379            Self::Ldiv => "ldiv",
380            Self::Lload => "lload",
381            Self::Lload0 => "lload_0",
382            Self::Lload1 => "lload_1",
383            Self::Lload2 => "lload_2",
384            Self::Lload3 => "lload_3",
385            Self::Lmul => "lmul",
386            Self::Lneg => "lneg",
387            Self::Lookupswitch => "lookupswitch",
388            Self::Lor => "lor",
389            Self::Lrem => "lrem",
390            Self::Lreturn => "lreturn",
391            Self::Lshl => "lshl",
392            Self::Lshr => "lshr",
393            Self::Lstore => "lstore",
394            Self::Lstore0 => "lstore_0",
395            Self::Lstore1 => "lstore_1",
396            Self::Lstore2 => "lstore_2",
397            Self::Lstore3 => "lstore_3",
398            Self::Lsub => "lsub",
399            Self::Lushr => "lushr",
400            Self::Lxor => "lxor",
401            Self::Monitorenter => "monitorenter",
402            Self::Monitorexit => "monitorexit",
403            Self::Multianewarray => "multianewarray",
404            Self::New => "new",
405            Self::Newarray => "newarray",
406            Self::Nop => "nop",
407            Self::Pop => "pop",
408            Self::Pop2 => "pop2",
409            Self::Putfield => "putfield",
410            Self::Putstatic => "putstatic",
411            Self::Ret => "ret",
412            Self::Return => "return",
413            Self::Saload => "saload",
414            Self::Sastore => "sastore",
415            Self::Sipush => "sipush",
416            Self::Swap => "swap",
417            Self::TableSwitch => "tableswitch",
418        }
419    }
420}
421
422impl Opcode {
423    pub const fn operand_size(self) -> u8 {
424        match self {
425            // 4-byte operand
426            Self::GotoW | Self::JsrW | Self::InvokeDynamic | Self::InvokeInterface => 4,
427
428            // 3-byte operand
429            Self::Multianewarray => 3,
430
431            // 2-byte operand
432            Self::Anewarray
433            | Self::Checkcast
434            | Self::Getfield
435            | Self::Getstatic
436            | Self::Goto
437            | Self::IfAcmpEq
438            | Self::IfAcmpNe
439            | Self::IfEq
440            | Self::IfGe
441            | Self::IfGt
442            | Self::IfLe
443            | Self::IfLt
444            | Self::IfNe
445            | Self::Ifnonnull
446            | Self::Ifnull
447            | Self::IfIcmpeq
448            | Self::IfIcmpge
449            | Self::IfIcmpgt
450            | Self::IfIcmple
451            | Self::IfIcmplt
452            | Self::IfIcmpne
453            | Self::Iinc
454            | Self::Instanceof
455            | Self::InvokeSpecial
456            | Self::InvokeStatic
457            | Self::InvokeVirtual
458            | Self::Ldc2W
459            | Self::LdcW
460            | Self::New
461            | Self::Putfield
462            | Self::Putstatic
463            | Self::Sipush
464            | Self::Jsr => 2,
465
466            // 1-byte operand
467            Self::Aload
468            | Self::Astore
469            | Self::Bipush
470            | Self::Dload
471            | Self::Dstore
472            | Self::Fload
473            | Self::Fstore
474            | Self::Iload
475            | Self::Istore
476            | Self::Ldc
477            | Self::Lload
478            | Self::Lstore
479            | Self::Newarray
480            | Self::Ret => 1,
481
482            // No operand (everything else, including variable-size lookupswitch/tableswitch)
483            _ => 0,
484        }
485    }
486
487    pub const fn pc_size(self) -> Option<u8> {
488        match self {
489            Self::Lookupswitch | Self::TableSwitch => None,
490            _ => Some(1 + self.operand_size()),
491        }
492    }
493}
494
495impl std::fmt::Display for Opcode {
496    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
497        f.write_str(self.as_str())
498    }
499}