1#![doc = include_str!("readme.md")]
2use crate::program::*;
7use byteorder::BigEndian;
8use gaia_types::{BinaryWriter, GaiaDiagnostics, Result};
9use std::{collections::HashMap, io::Write};
10
11pub struct ClassWriter<W> {
13 writer: BinaryWriter<W, BigEndian>,
15 cp_entries: Vec<CpEntry>,
17 cp_map: HashMap<CpEntry, u16>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22enum CpEntry {
23 Utf8(String),
24 Class(u16),
25 String(u16),
26 Fieldref(u16, u16),
27 Methodref(u16, u16),
28 InterfaceMethodref(u16, u16),
29 NameAndType(u16, u16),
30 Integer(i32),
31 Float(u32),
32 Long(i64),
33 Double(u64),
34}
35
36impl<W> ClassWriter<W> {
37 pub fn new(writer: W) -> Self {
39 Self { writer: BinaryWriter::new(writer), cp_entries: Vec::new(), cp_map: HashMap::new() }
40 }
41
42 fn add_utf8(&mut self, s: String) -> u16 {
44 self.add_cp_entry(CpEntry::Utf8(s))
45 }
46
47 fn add_class(&mut self, name: String) -> u16 {
49 let name_index = self.add_utf8(name);
50 self.add_cp_entry(CpEntry::Class(name_index))
51 }
52
53 fn add_string(&mut self, value: String) -> u16 {
55 let utf8_index = self.add_utf8(value);
56 self.add_cp_entry(CpEntry::String(utf8_index))
57 }
58
59 fn add_name_and_type(&mut self, name: String, descriptor: String) -> u16 {
61 let name_index = self.add_utf8(name);
62 let descriptor_index = self.add_utf8(descriptor);
63 self.add_cp_entry(CpEntry::NameAndType(name_index, descriptor_index))
64 }
65
66 fn add_field_ref(&mut self, class_name: String, name: String, descriptor: String) -> u16 {
68 let class_index = self.add_class(class_name);
69 let name_and_type_index = self.add_name_and_type(name, descriptor);
70 self.add_cp_entry(CpEntry::Fieldref(class_index, name_and_type_index))
71 }
72
73 fn add_method_ref(&mut self, class_name: String, name: String, descriptor: String) -> u16 {
75 let class_index = self.add_class(class_name);
76 let name_and_type_index = self.add_name_and_type(name, descriptor);
77 self.add_cp_entry(CpEntry::Methodref(class_index, name_and_type_index))
78 }
79
80 fn add_interface_method_ref(&mut self, class_name: String, name: String, descriptor: String) -> u16 {
82 let class_index = self.add_class(class_name);
83 let name_and_type_index = self.add_name_and_type(name, descriptor);
84 self.add_cp_entry(CpEntry::InterfaceMethodref(class_index, name_and_type_index))
85 }
86
87 fn add_int(&mut self, val: i32) -> u16 {
89 self.add_cp_entry(CpEntry::Integer(val))
90 }
91
92 fn add_float(&mut self, val: f32) -> u16 {
94 self.add_cp_entry(CpEntry::Float(val.to_bits()))
95 }
96
97 fn add_long(&mut self, val: i64) -> u16 {
99 self.add_cp_entry(CpEntry::Long(val))
100 }
101
102 fn add_double(&mut self, val: f64) -> u16 {
104 self.add_cp_entry(CpEntry::Double(val.to_bits()))
105 }
106
107 fn add_cp_entry(&mut self, entry: CpEntry) -> u16 {
108 if let Some(&index) = self.cp_map.get(&entry) {
109 return index;
110 }
111
112 let index = (self.cp_entries.len() + 1) as u16;
113 self.cp_entries.push(entry.clone());
114 self.cp_map.insert(entry, index);
115
116 match self.cp_entries.last().unwrap() {
118 CpEntry::Long(_) | CpEntry::Double(_) => {
119 self.cp_entries.push(CpEntry::Utf8("Padding".to_string()));
121 }
122 _ => {}
123 }
124
125 index
126 }
127
128 pub fn finish(self) -> W {
130 self.writer.finish()
131 }
132}
133
134fn calculate_parameter_count(descriptor: &str) -> usize {
136 if !descriptor.starts_with('(') {
137 return 0;
138 }
139
140 let mut count = 0;
141 let mut chars = descriptor.chars().skip(1); while let Some(c) = chars.next() {
144 if c == ')' {
145 break;
146 }
147
148 match c {
149 'L' => {
150 while let Some(c) = chars.next() {
152 if c == ';' {
153 break;
154 }
155 }
156 count += 1;
157 }
158 '[' => {
159 while let Some(c) = chars.next() {
161 if c == '[' {
162 continue;
163 }
164 if c == 'L' {
165 while let Some(c) = chars.next() {
166 if c == ';' {
167 break;
168 }
169 }
170 }
171 break;
172 }
173 count += 1;
174 }
175 'J' | 'D' => {
176 count += 2;
178 }
179 _ => {
180 count += 1;
182 }
183 }
184 }
185
186 count
187}
188
189impl<W: Write> ClassWriter<W> {
190 pub fn write(mut self, program: &JvmProgram) -> GaiaDiagnostics<W> {
192 match self.write_class_file(program) {
193 Ok(_) => GaiaDiagnostics::success(self.finish()),
194 Err(error) => GaiaDiagnostics::failure(error),
195 }
196 }
197
198 fn collect_attribute_constants(&mut self, attribute: &JvmAttribute) {
199 match attribute {
200 JvmAttribute::SourceFile { filename } => {
201 self.add_utf8("SourceFile".to_string());
202 self.add_utf8(filename.clone());
203 }
204 JvmAttribute::ConstantValue { value } => {
205 self.add_utf8("ConstantValue".to_string());
206 match value {
207 JvmConstantPoolEntry::Integer { .. } => {}
208 JvmConstantPoolEntry::Float { .. } => {}
209 JvmConstantPoolEntry::Long { .. } => {}
210 JvmConstantPoolEntry::Double { .. } => {}
211 JvmConstantPoolEntry::String { value } => {
212 self.add_string(value.clone());
213 }
214 _ => {}
215 }
216 }
217 JvmAttribute::Exceptions { exceptions } => {
218 self.add_utf8("Exceptions".to_string());
219 for exc in exceptions {
220 self.add_class(exc.clone());
221 }
222 }
223 JvmAttribute::Signature { signature } => {
224 self.add_utf8("Signature".to_string());
225 self.add_utf8(signature.clone());
226 }
227 JvmAttribute::StackMapTable { frames } => {
228 self.add_utf8("StackMapTable".to_string());
229 for frame in frames {
230 match frame {
231 JvmStackMapFrame::SameLocals1StackItem { stack, .. }
232 | JvmStackMapFrame::SameLocals1StackItemExtended { stack, .. } => {
233 self.collect_verification_type_constants(stack);
234 }
235 JvmStackMapFrame::Append { locals, .. } => {
236 for vt in locals {
237 self.collect_verification_type_constants(vt);
238 }
239 }
240 JvmStackMapFrame::Full { locals, stack, .. } => {
241 for vt in locals {
242 self.collect_verification_type_constants(vt);
243 }
244 for vt in stack {
245 self.collect_verification_type_constants(vt);
246 }
247 }
248 _ => {}
249 }
250 }
251 }
252 JvmAttribute::InnerClasses { classes } => {
253 self.add_utf8("InnerClasses".to_string());
254 for inner in classes {
255 self.add_class(inner.inner_class.clone());
256 if let Some(outer) = &inner.outer_class {
257 self.add_class(outer.clone());
258 }
259 if let Some(name) = &inner.inner_name {
260 self.add_utf8(name.clone());
261 }
262 }
263 }
264 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
265 self.add_utf8("EnclosingMethod".to_string());
266 self.add_class(class_name.clone());
267 if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
268 self.add_name_and_type(name.clone(), desc.clone());
269 }
270 }
271 JvmAttribute::Code { attributes, exception_table, .. } => {
272 self.add_utf8("Code".to_string());
273 for attr in attributes {
274 self.collect_attribute_constants(attr);
275 }
276 for handler in exception_table {
277 if handler.catch_type_index > 0 {
278 }
281 }
282 }
283 JvmAttribute::LineNumberTable { .. } => {
284 self.add_utf8("LineNumberTable".to_string());
285 }
286 JvmAttribute::LocalVariableTable { entries } => {
287 self.add_utf8("LocalVariableTable".to_string());
288 for entry in entries {
289 self.add_utf8(entry.name.clone());
290 self.add_utf8(entry.descriptor.clone());
291 }
292 }
293 JvmAttribute::Unknown { name, .. } => {
294 self.add_utf8(name.clone());
295 }
296 }
297 }
298
299 fn collect_verification_type_constants(&mut self, vt: &JvmVerificationType) {
300 if let JvmVerificationType::Object { class_name } = vt {
301 self.add_class(class_name.clone());
302 }
303 }
304
305 fn write_class_file(&mut self, program: &JvmProgram) -> Result<()> {
307 let this_class_idx = self.add_class(program.name.clone());
309 let super_class_idx = if let Some(super_name) = &program.super_class {
310 self.add_class(super_name.clone())
311 }
312 else {
313 self.add_class("java/lang/Object".to_string())
314 };
315
316 for attr in &program.attributes {
318 self.collect_attribute_constants(attr);
319 }
320
321 for field in &program.fields {
323 self.add_utf8(field.name.clone());
324 self.add_utf8(field.descriptor.clone());
325 for attr in &field.attributes {
326 self.collect_attribute_constants(attr);
327 }
328 if field.constant_value.is_some() {
329 self.add_utf8("ConstantValue".to_string());
330 }
331 }
332
333 let code_utf8_idx = self.add_utf8("Code".to_string());
335 for method in &program.methods {
336 self.add_utf8(method.name.clone());
337 self.add_utf8(method.descriptor.clone());
338
339 for handler in &method.exception_handlers {
340 if let Some(catch_type) = &handler.catch_type {
341 self.add_class(catch_type.clone());
342 }
343 }
344
345 for attr in &method.attributes {
346 self.collect_attribute_constants(attr);
347 }
348 if !method.exceptions.is_empty() {
349 self.add_utf8("Exceptions".to_string());
350 }
351
352 let (_, label_positions) = self.generate_method_bytecode(method);
354
355 if program.version.major >= 50 {
356 self.add_utf8("StackMapTable".to_string());
357 let has_stack_map = method.attributes.iter().any(|a| matches!(a, JvmAttribute::StackMapTable { .. }));
359 if !has_stack_map {
360 let analyzer = crate::analyzer::StackMapAnalyzer::new(program.name.clone(), method, &label_positions);
361 let frames = analyzer.analyze();
362 for frame in &frames {
363 match frame {
364 JvmStackMapFrame::SameLocals1StackItem { stack, .. }
365 | JvmStackMapFrame::SameLocals1StackItemExtended { stack, .. } => {
366 self.collect_verification_type_constants(stack);
367 }
368 JvmStackMapFrame::Append { locals, .. } => {
369 for vt in locals {
370 self.collect_verification_type_constants(vt);
371 }
372 }
373 JvmStackMapFrame::Full { locals, stack, .. } => {
374 for vt in locals {
375 self.collect_verification_type_constants(vt);
376 }
377 for vt in stack {
378 self.collect_verification_type_constants(vt);
379 }
380 }
381 _ => {}
382 }
383 }
384 }
385 }
386
387 for inst in &method.instructions {
389 match inst {
390 JvmInstruction::Ldc { symbol } | JvmInstruction::LdcW { symbol } | JvmInstruction::Ldc2W { symbol } => {
391 self.add_string(symbol.clone());
392 }
393 JvmInstruction::Getstatic { class_name, field_name, descriptor }
394 | JvmInstruction::Putstatic { class_name, field_name, descriptor }
395 | JvmInstruction::Getfield { class_name, field_name, descriptor }
396 | JvmInstruction::Putfield { class_name, field_name, descriptor } => {
397 self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
398 }
399 JvmInstruction::Invokevirtual { class_name, method_name, descriptor }
400 | JvmInstruction::Invokespecial { class_name, method_name, descriptor }
401 | JvmInstruction::Invokestatic { class_name, method_name, descriptor }
402 | JvmInstruction::Invokedynamic { class_name, method_name, descriptor } => {
403 self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
404 }
405 JvmInstruction::Invokeinterface { class_name, method_name, descriptor } => {
406 self.add_interface_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
407 }
408 JvmInstruction::New { class_name }
409 | JvmInstruction::Anewarray { class_name }
410 | JvmInstruction::Checkcast { class_name }
411 | JvmInstruction::Instanceof { class_name }
412 | JvmInstruction::Multianewarray { class_name, .. } => {
413 self.add_class(class_name.clone());
414 }
415 _ => {}
416 }
417 }
418 }
419
420 self.writer.write_u32(0xCAFEBABE)?;
423
424 self.writer.write_u16(program.version.minor)?;
426 self.writer.write_u16(program.version.major)?;
427
428 self.write_constant_pool()?;
430
431 self.writer.write_u16(program.access_flags.to_flags())?;
433
434 self.writer.write_u16(this_class_idx)?;
436
437 self.writer.write_u16(super_class_idx)?;
439
440 self.writer.write_u16(0)?;
442
443 self.write_fields(program)?;
445
446 self.write_methods(program, code_utf8_idx)?;
448
449 self.writer.write_u16(program.attributes.len() as u16)?;
451 for attr in &program.attributes {
452 self.write_attribute(attr)?;
453 }
454
455 Ok(())
456 }
457
458 fn write_constant_pool(&mut self) -> Result<()> {
460 self.writer.write_u16((self.cp_entries.len() + 1) as u16)?;
462
463 let mut i = 0;
465 while i < self.cp_entries.len() {
466 let entry = &self.cp_entries[i];
467 match entry {
468 CpEntry::Utf8(s) => {
469 self.writer.write_u8(1)?; self.writer.write_u16(s.len() as u16)?;
471 self.writer.write_all(s.as_bytes())?;
472 }
473 CpEntry::Class(name_idx) => {
474 self.writer.write_u8(7)?; self.writer.write_u16(*name_idx)?;
476 }
477 CpEntry::String(utf8_idx) => {
478 self.writer.write_u8(8)?; self.writer.write_u16(*utf8_idx)?;
480 }
481 CpEntry::NameAndType(name_idx, desc_idx) => {
482 self.writer.write_u8(12)?; self.writer.write_u16(*name_idx)?;
484 self.writer.write_u16(*desc_idx)?;
485 }
486 CpEntry::Fieldref(class_idx, nt_idx) => {
487 self.writer.write_u8(9)?; self.writer.write_u16(*class_idx)?;
489 self.writer.write_u16(*nt_idx)?;
490 }
491 CpEntry::Methodref(class_idx, nt_idx) => {
492 self.writer.write_u8(10)?; self.writer.write_u16(*class_idx)?;
494 self.writer.write_u16(*nt_idx)?;
495 }
496 CpEntry::InterfaceMethodref(class_idx, nt_idx) => {
497 self.writer.write_u8(11)?; self.writer.write_u16(*class_idx)?;
499 self.writer.write_u16(*nt_idx)?;
500 }
501 CpEntry::Integer(val) => {
502 self.writer.write_u8(3)?; self.writer.write_i32(*val)?;
504 }
505 CpEntry::Float(bits) => {
506 self.writer.write_u8(4)?; self.writer.write_u32(*bits)?;
508 }
509 CpEntry::Long(val) => {
510 self.writer.write_u8(5)?; self.writer.write_i64(*val)?;
512 i += 1; }
514 CpEntry::Double(bits) => {
515 self.writer.write_u8(6)?; self.writer.write_u64(*bits)?;
517 i += 1; }
519 }
520 i += 1;
521 }
522
523 Ok(())
524 }
525
526 fn write_fields(&mut self, program: &JvmProgram) -> Result<()> {
528 self.writer.write_u16(program.fields.len() as u16)?;
529
530 for field in &program.fields {
531 self.writer.write_u16(field.access_flags.to_flags())?;
532 let name_idx = self.add_utf8(field.name.clone());
533 let desc_idx = self.add_utf8(field.descriptor.clone());
534 self.writer.write_u16(name_idx)?;
535 self.writer.write_u16(desc_idx)?;
536
537 let mut attr_count = field.attributes.len() as u16;
539 if field.constant_value.is_some() {
540 attr_count += 1;
541 }
542 self.writer.write_u16(attr_count)?;
543
544 if let Some(val) = &field.constant_value {
546 self.write_attribute(&JvmAttribute::ConstantValue { value: val.clone() })?;
547 }
548
549 for attr in &field.attributes {
551 self.write_attribute(attr)?;
552 }
553 }
554
555 Ok(())
556 }
557
558 fn write_methods(&mut self, program: &JvmProgram, code_utf8_idx: u16) -> Result<()> {
560 self.writer.write_u16(program.methods.len() as u16)?;
561
562 let exceptions_utf8_idx = self.add_utf8("Exceptions".to_string());
563
564 for method in &program.methods {
565 self.writer.write_u16(method.access_flags.to_flags())?;
566 let name_idx = self.add_utf8(method.name.clone());
567 let desc_idx = self.add_utf8(method.descriptor.clone());
568 self.writer.write_u16(name_idx)?;
569 self.writer.write_u16(desc_idx)?;
570
571 let mut attribute_count = 1; if !method.exceptions.is_empty() {
574 attribute_count += 1;
575 }
576 attribute_count += method.attributes.len() as u16;
577
578 self.writer.write_u16(attribute_count)?;
580
581 self.write_code_attribute(program, method, code_utf8_idx)?;
583
584 if !method.exceptions.is_empty() {
586 self.writer.write_u16(exceptions_utf8_idx)?;
587 let attr_len = 2 + method.exceptions.len() * 2;
588 self.writer.write_u32(attr_len as u32)?;
589 self.writer.write_u16(method.exceptions.len() as u16)?;
590 for exc in &method.exceptions {
591 let exc_idx = self.add_class(exc.clone());
592 self.writer.write_u16(exc_idx)?;
593 }
594 }
595
596 for attr in &method.attributes {
598 self.write_attribute(attr)?;
599 }
600 }
601
602 Ok(())
603 }
604
605 fn write_code_attribute(&mut self, program: &JvmProgram, method: &JvmMethod, code_utf8_idx: u16) -> Result<()> {
607 self.writer.write_u16(code_utf8_idx)?;
609
610 let (bytecode, label_positions) = self.generate_method_bytecode(method);
611
612 let mut raw_exception_table = Vec::new();
614 for handler in &method.exception_handlers {
615 let start_pc = *label_positions.get(&handler.start_label).unwrap_or(&0) as u16;
616 let end_pc = *label_positions.get(&handler.end_label).unwrap_or(&0) as u16;
617 let handler_pc = *label_positions.get(&handler.handler_label).unwrap_or(&0) as u16;
618 let catch_type_index =
619 if let Some(catch_type) = &handler.catch_type { self.add_class(catch_type.clone()) } else { 0 };
620 raw_exception_table.push(RawExceptionHandler { start_pc, end_pc, handler_pc, catch_type_index });
621 }
622
623 let mut code_attributes = Vec::new();
625
626 if program.version.major >= 50 {
628 let has_stack_map = method.attributes.iter().any(|a| matches!(a, JvmAttribute::StackMapTable { .. }));
629 if !has_stack_map {
630 let analyzer = crate::analyzer::StackMapAnalyzer::new(program.name.clone(), method, &label_positions);
631 let frames = analyzer.analyze();
632 if !frames.is_empty() {
633 code_attributes.push(JvmAttribute::StackMapTable { frames });
634 }
635 }
636 }
637
638 let mut sub_attr_buf = Vec::new();
640 let mut temp_writer = ClassWriter {
642 writer: BinaryWriter::new(&mut sub_attr_buf),
643 cp_entries: self.cp_entries.clone(),
644 cp_map: self.cp_map.clone(),
645 };
646
647 for attr in &code_attributes {
649 temp_writer.write_attribute(attr)?;
650 }
651 self.cp_entries = temp_writer.cp_entries;
659 self.cp_map = temp_writer.cp_map;
660
661 let exception_table_len = raw_exception_table.len() * 8;
663 let attribute_length = 2 + 2 + 4 + bytecode.len() + 2 + exception_table_len + 2 + sub_attr_buf.len();
664 self.writer.write_u32(attribute_length as u32)?;
665
666 self.writer.write_u16(method.max_stack)?;
668 self.writer.write_u16(method.max_locals)?;
669
670 self.writer.write_u32(bytecode.len() as u32)?;
672 self.writer.write_all(&bytecode)?;
673
674 self.writer.write_u16(raw_exception_table.len() as u16)?;
676 for handler in raw_exception_table {
677 self.writer.write_u16(handler.start_pc)?;
678 self.writer.write_u16(handler.end_pc)?;
679 self.writer.write_u16(handler.handler_pc)?;
680 self.writer.write_u16(handler.catch_type_index)?;
681 }
682
683 self.writer.write_u16(code_attributes.len() as u16)?;
685 self.writer.write_all(&sub_attr_buf)?;
686
687 Ok(())
688 }
689
690 fn generate_method_bytecode(&mut self, method: &JvmMethod) -> (Vec<u8>, HashMap<String, i32>) {
692 let mut bytecode = Vec::new();
693 let mut label_positions = HashMap::new();
694 let mut jump_patches = Vec::new(); for instruction in &method.instructions {
698 match instruction {
699 JvmInstruction::Label { name } => {
700 label_positions.insert(name.clone(), bytecode.len() as i32);
701 }
702 _ => {
703 let pos = bytecode.len();
704 self.emit_instruction(instruction, &mut bytecode, &mut jump_patches, pos);
705 }
706 }
707 }
708
709 for (instr_pos, patch_pos, target_name, is_wide) in jump_patches {
711 if let Some(&target_pos) = label_positions.get(&target_name) {
712 let offset = target_pos - instr_pos as i32;
713 if is_wide {
714 bytecode[patch_pos] = ((offset >> 24) & 0xFF) as u8;
716 bytecode[patch_pos + 1] = ((offset >> 16) & 0xFF) as u8;
717 bytecode[patch_pos + 2] = ((offset >> 8) & 0xFF) as u8;
718 bytecode[patch_pos + 3] = (offset & 0xFF) as u8;
719 }
720 else {
721 bytecode[patch_pos] = ((offset >> 8) & 0xFF) as u8;
723 bytecode[patch_pos + 1] = (offset & 0xFF) as u8;
724 }
725 }
726 }
727
728 if bytecode.is_empty() {
730 bytecode.push(0xB1); }
732
733 (bytecode, label_positions)
734 }
735
736 fn write_attribute(&mut self, attribute: &JvmAttribute) -> Result<()> {
738 match attribute {
739 JvmAttribute::SourceFile { filename } => {
740 let name_idx = self.add_utf8("SourceFile".to_string());
741 let file_idx = self.add_utf8(filename.clone());
742 self.writer.write_u16(name_idx)?;
743 self.writer.write_u32(2)?;
744 self.writer.write_u16(file_idx)?;
745 }
746 JvmAttribute::ConstantValue { value } => {
747 let name_idx = self.add_utf8("ConstantValue".to_string());
748 let val_idx = match value {
749 JvmConstantPoolEntry::Integer { value } => self.add_int(*value),
750 JvmConstantPoolEntry::Float { value } => self.add_float(*value),
751 JvmConstantPoolEntry::Long { value } => self.add_long(*value),
752 JvmConstantPoolEntry::Double { value } => self.add_double(*value),
753 JvmConstantPoolEntry::String { value } => self.add_string(value.clone()),
754 _ => 0,
755 };
756 self.writer.write_u16(name_idx)?;
757 self.writer.write_u32(2)?;
758 self.writer.write_u16(val_idx)?;
759 }
760 JvmAttribute::Exceptions { exceptions } => {
761 let name_idx = self.add_utf8("Exceptions".to_string());
762 let attr_len = 2 + exceptions.len() * 2;
763 self.writer.write_u16(name_idx)?;
764 self.writer.write_u32(attr_len as u32)?;
765 self.writer.write_u16(exceptions.len() as u16)?;
766 for exc in exceptions {
767 let exc_idx = self.add_class(exc.clone());
768 self.writer.write_u16(exc_idx)?;
769 }
770 }
771 JvmAttribute::Signature { signature } => {
772 let name_idx = self.add_utf8("Signature".to_string());
773 let sig_idx = self.add_utf8(signature.clone());
774 self.writer.write_u16(name_idx)?;
775 self.writer.write_u32(2)?;
776 self.writer.write_u16(sig_idx)?;
777 }
778 JvmAttribute::StackMapTable { frames } => {
779 let name_idx = self.add_utf8("StackMapTable".to_string());
780 let mut buf = Vec::new();
781 buf.extend_from_slice(&(frames.len() as u16).to_be_bytes());
782 for frame in frames {
783 self.write_stack_map_frame_to_buf(frame, &mut buf)?;
784 }
785 self.writer.write_u16(name_idx)?;
786 self.writer.write_u32(buf.len() as u32)?;
787 self.writer.write_all(&buf)?;
788 }
789 JvmAttribute::InnerClasses { classes } => {
790 let name_idx = self.add_utf8("InnerClasses".to_string());
791 let attr_len = 2 + classes.len() * 8;
792 self.writer.write_u16(name_idx)?;
793 self.writer.write_u32(attr_len as u32)?;
794 self.writer.write_u16(classes.len() as u16)?;
795 for inner in classes {
796 let inner_idx = self.add_class(inner.inner_class.clone());
797 let outer_idx = if let Some(outer) = &inner.outer_class { self.add_class(outer.clone()) } else { 0 };
798 let name_idx = if let Some(name) = &inner.inner_name { self.add_utf8(name.clone()) } else { 0 };
799 self.writer.write_u16(inner_idx)?;
800 self.writer.write_u16(outer_idx)?;
801 self.writer.write_u16(name_idx)?;
802 self.writer.write_u16(inner.access_flags.to_flags())?;
803 }
804 }
805 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
806 let name_idx = self.add_utf8("EnclosingMethod".to_string());
807 let class_idx = self.add_class(class_name.clone());
808 let nt_idx = if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
809 self.add_name_and_type(name.clone(), desc.clone())
810 }
811 else {
812 0
813 };
814 self.writer.write_u16(name_idx)?;
815 self.writer.write_u32(4)?;
816 self.writer.write_u16(class_idx)?;
817 self.writer.write_u16(nt_idx)?;
818 }
819 JvmAttribute::Unknown { name, data } => {
820 let name_idx = self.add_utf8(name.clone());
821 self.writer.write_u16(name_idx)?;
822 self.writer.write_u32(data.len() as u32)?;
823 self.writer.write_all(data)?;
824 }
825 _ => {
826 }
828 }
829 Ok(())
830 }
831
832 fn write_verification_type_to_buf(&mut self, vt: &JvmVerificationType, buf: &mut Vec<u8>) -> Result<()> {
833 match vt {
834 JvmVerificationType::Top => buf.push(0),
835 JvmVerificationType::Integer => buf.push(1),
836 JvmVerificationType::Float => buf.push(2),
837 JvmVerificationType::Double => buf.push(3),
838 JvmVerificationType::Long => buf.push(4),
839 JvmVerificationType::Null => buf.push(5),
840 JvmVerificationType::UninitializedThis => buf.push(6),
841 JvmVerificationType::Object { class_name } => {
842 buf.push(7);
843 let class_idx = self.add_class(class_name.clone());
844 buf.extend_from_slice(&class_idx.to_be_bytes());
845 }
846 JvmVerificationType::Uninitialized { offset } => {
847 buf.push(8);
848 buf.extend_from_slice(&offset.to_be_bytes());
849 }
850 }
851 Ok(())
852 }
853
854 fn write_stack_map_frame_to_buf(&mut self, frame: &JvmStackMapFrame, buf: &mut Vec<u8>) -> Result<()> {
855 match frame {
856 JvmStackMapFrame::Same { offset_delta } => {
857 if *offset_delta <= 63 {
858 buf.push(*offset_delta as u8);
859 }
860 else {
861 buf.push(251);
862 buf.extend_from_slice(&offset_delta.to_be_bytes());
863 }
864 }
865 JvmStackMapFrame::SameLocals1StackItem { offset_delta, stack } => {
866 if *offset_delta <= 63 {
867 buf.push((*offset_delta + 64) as u8);
868 self.write_verification_type_to_buf(stack, buf)?;
869 }
870 else {
871 buf.push(247);
872 buf.extend_from_slice(&offset_delta.to_be_bytes());
873 self.write_verification_type_to_buf(stack, buf)?;
874 }
875 }
876 JvmStackMapFrame::SameLocals1StackItemExtended { offset_delta, stack } => {
877 buf.push(247);
878 buf.extend_from_slice(&offset_delta.to_be_bytes());
879 self.write_verification_type_to_buf(stack, buf)?;
880 }
881 JvmStackMapFrame::Chop { offset_delta, k } => {
882 buf.push(251 - k);
883 buf.extend_from_slice(&offset_delta.to_be_bytes());
884 }
885 JvmStackMapFrame::SameExtended { offset_delta } => {
886 buf.push(251);
887 buf.extend_from_slice(&offset_delta.to_be_bytes());
888 }
889 JvmStackMapFrame::Append { offset_delta, locals } => {
890 buf.push((251 + locals.len()) as u8);
891 buf.extend_from_slice(&offset_delta.to_be_bytes());
892 for vt in locals {
893 self.write_verification_type_to_buf(vt, buf)?;
894 }
895 }
896 JvmStackMapFrame::Full { offset_delta, locals, stack } => {
897 buf.push(255);
898 buf.extend_from_slice(&offset_delta.to_be_bytes());
899 buf.extend_from_slice(&(locals.len() as u16).to_be_bytes());
900 for vt in locals {
901 self.write_verification_type_to_buf(vt, buf)?;
902 }
903 buf.extend_from_slice(&(stack.len() as u16).to_be_bytes());
904 for vt in stack {
905 self.write_verification_type_to_buf(vt, buf)?;
906 }
907 }
908 }
909 Ok(())
910 }
911
912 fn emit_instruction(
914 &mut self,
915 instruction: &JvmInstruction,
916 bytecode: &mut Vec<u8>,
917 jump_patches: &mut Vec<(usize, usize, String, bool)>,
918 pos: usize,
919 ) {
920 match instruction {
921 JvmInstruction::Nop => bytecode.push(0x00),
922 JvmInstruction::AconstNull => bytecode.push(0x01),
923 JvmInstruction::IconstM1 => bytecode.push(0x02),
924 JvmInstruction::Iconst0 => bytecode.push(0x03),
925 JvmInstruction::Iconst1 => bytecode.push(0x04),
926 JvmInstruction::Iconst2 => bytecode.push(0x05),
927 JvmInstruction::Iconst3 => bytecode.push(0x06),
928 JvmInstruction::Iconst4 => bytecode.push(0x07),
929 JvmInstruction::Iconst5 => bytecode.push(0x08),
930 JvmInstruction::Lconst0 => bytecode.push(0x09),
931 JvmInstruction::Lconst1 => bytecode.push(0x0A),
932 JvmInstruction::Fconst0 => bytecode.push(0x0B),
933 JvmInstruction::Fconst1 => bytecode.push(0x0C),
934 JvmInstruction::Fconst2 => bytecode.push(0x0D),
935 JvmInstruction::Dconst0 => bytecode.push(0x0E),
936 JvmInstruction::Dconst1 => bytecode.push(0x0F),
937
938 JvmInstruction::Bipush { value } => {
939 bytecode.push(0x10);
940 bytecode.push(*value as u8);
941 }
942 JvmInstruction::Sipush { value } => {
943 bytecode.push(0x11);
944 bytecode.push((*value >> 8) as u8);
945 bytecode.push((*value & 0xFF) as u8);
946 }
947
948 JvmInstruction::Ldc { symbol } => {
949 let index = self.add_string(symbol.clone());
950 if index < 256 {
951 bytecode.push(0x12); bytecode.push(index as u8);
953 }
954 else {
955 bytecode.push(0x13); bytecode.push((index >> 8) as u8);
957 bytecode.push((index & 0xFF) as u8);
958 }
959 }
960 JvmInstruction::LdcW { symbol } => {
961 let index = self.add_string(symbol.clone());
962 bytecode.push(0x13); bytecode.push((index >> 8) as u8);
964 bytecode.push((index & 0xFF) as u8);
965 }
966 JvmInstruction::Ldc2W { symbol } => {
967 let index = self.add_string(symbol.clone());
968 bytecode.push(0x14); bytecode.push((index >> 8) as u8);
970 bytecode.push((index & 0xFF) as u8);
971 }
972
973 JvmInstruction::Iload { index } => {
974 if *index <= 3 {
975 bytecode.push(0x1A + *index as u8);
976 }
977 else if *index <= 255 {
978 bytecode.push(0x15);
979 bytecode.push(*index as u8);
980 }
981 else {
982 bytecode.push(0xC4); bytecode.push(0x15);
984 bytecode.push((*index >> 8) as u8);
985 bytecode.push((*index & 0xFF) as u8);
986 }
987 }
988 JvmInstruction::Iload0 => bytecode.push(0x1A),
989 JvmInstruction::Iload1 => bytecode.push(0x1B),
990 JvmInstruction::Iload2 => bytecode.push(0x1C),
991 JvmInstruction::Iload3 => bytecode.push(0x1D),
992
993 JvmInstruction::Lload { index } => {
994 if *index <= 3 {
995 bytecode.push(0x1E + *index as u8);
996 }
997 else if *index <= 255 {
998 bytecode.push(0x16);
999 bytecode.push(*index as u8);
1000 }
1001 else {
1002 bytecode.push(0xC4); bytecode.push(0x16);
1004 bytecode.push((*index >> 8) as u8);
1005 bytecode.push((*index & 0xFF) as u8);
1006 }
1007 }
1008 JvmInstruction::Lload0 => bytecode.push(0x1E),
1009 JvmInstruction::Lload1 => bytecode.push(0x1F),
1010 JvmInstruction::Lload2 => bytecode.push(0x20),
1011 JvmInstruction::Lload3 => bytecode.push(0x21),
1012
1013 JvmInstruction::Fload { index } => {
1014 if *index <= 3 {
1015 bytecode.push(0x22 + *index as u8);
1016 }
1017 else if *index <= 255 {
1018 bytecode.push(0x17);
1019 bytecode.push(*index as u8);
1020 }
1021 else {
1022 bytecode.push(0xC4); bytecode.push(0x17);
1024 bytecode.push((*index >> 8) as u8);
1025 bytecode.push((*index & 0xFF) as u8);
1026 }
1027 }
1028 JvmInstruction::Fload0 => bytecode.push(0x22),
1029 JvmInstruction::Fload1 => bytecode.push(0x23),
1030 JvmInstruction::Fload2 => bytecode.push(0x24),
1031 JvmInstruction::Fload3 => bytecode.push(0x25),
1032
1033 JvmInstruction::Dload { index } => {
1034 if *index <= 3 {
1035 bytecode.push(0x26 + *index as u8);
1036 }
1037 else if *index <= 255 {
1038 bytecode.push(0x18);
1039 bytecode.push(*index as u8);
1040 }
1041 else {
1042 bytecode.push(0xC4); bytecode.push(0x18);
1044 bytecode.push((*index >> 8) as u8);
1045 bytecode.push((*index & 0xFF) as u8);
1046 }
1047 }
1048 JvmInstruction::Dload0 => bytecode.push(0x26),
1049 JvmInstruction::Dload1 => bytecode.push(0x27),
1050 JvmInstruction::Dload2 => bytecode.push(0x28),
1051 JvmInstruction::Dload3 => bytecode.push(0x29),
1052
1053 JvmInstruction::Aload { index } => {
1054 if *index <= 3 {
1055 bytecode.push(0x2A + *index as u8);
1056 }
1057 else if *index <= 255 {
1058 bytecode.push(0x19);
1059 bytecode.push(*index as u8);
1060 }
1061 else {
1062 bytecode.push(0xC4); bytecode.push(0x19);
1064 bytecode.push((*index >> 8) as u8);
1065 bytecode.push((*index & 0xFF) as u8);
1066 }
1067 }
1068 JvmInstruction::Aload0 => bytecode.push(0x2A),
1069 JvmInstruction::Aload1 => bytecode.push(0x2B),
1070 JvmInstruction::Aload2 => bytecode.push(0x2C),
1071 JvmInstruction::Aload3 => bytecode.push(0x2D),
1072
1073 JvmInstruction::Istore { index } => {
1074 if *index <= 3 {
1075 bytecode.push(0x3B + *index as u8);
1076 }
1077 else if *index <= 255 {
1078 bytecode.push(0x36);
1079 bytecode.push(*index as u8);
1080 }
1081 else {
1082 bytecode.push(0xC4); bytecode.push(0x36);
1084 bytecode.push((*index >> 8) as u8);
1085 bytecode.push((*index & 0xFF) as u8);
1086 }
1087 }
1088 JvmInstruction::Istore0 => bytecode.push(0x3B),
1089 JvmInstruction::Istore1 => bytecode.push(0x3C),
1090 JvmInstruction::Istore2 => bytecode.push(0x3D),
1091 JvmInstruction::Istore3 => bytecode.push(0x3E),
1092
1093 JvmInstruction::Lstore { index } => {
1094 if *index <= 3 {
1095 bytecode.push(0x3F + *index as u8);
1096 }
1097 else if *index <= 255 {
1098 bytecode.push(0x37);
1099 bytecode.push(*index as u8);
1100 }
1101 else {
1102 bytecode.push(0xC4); bytecode.push(0x37);
1104 bytecode.push((*index >> 8) as u8);
1105 bytecode.push((*index & 0xFF) as u8);
1106 }
1107 }
1108 JvmInstruction::Lstore0 => bytecode.push(0x3F),
1109 JvmInstruction::Lstore1 => bytecode.push(0x40),
1110 JvmInstruction::Lstore2 => bytecode.push(0x41),
1111 JvmInstruction::Lstore3 => bytecode.push(0x42),
1112
1113 JvmInstruction::Fstore { index } => {
1114 if *index <= 3 {
1115 bytecode.push(0x43 + *index as u8);
1116 }
1117 else if *index <= 255 {
1118 bytecode.push(0x38);
1119 bytecode.push(*index as u8);
1120 }
1121 else {
1122 bytecode.push(0xC4); bytecode.push(0x38);
1124 bytecode.push((*index >> 8) as u8);
1125 bytecode.push((*index & 0xFF) as u8);
1126 }
1127 }
1128 JvmInstruction::Fstore0 => bytecode.push(0x43),
1129 JvmInstruction::Fstore1 => bytecode.push(0x44),
1130 JvmInstruction::Fstore2 => bytecode.push(0x45),
1131 JvmInstruction::Fstore3 => bytecode.push(0x46),
1132
1133 JvmInstruction::Dstore { index } => {
1134 if *index <= 3 {
1135 bytecode.push(0x47 + *index as u8);
1136 }
1137 else if *index <= 255 {
1138 bytecode.push(0x39);
1139 bytecode.push(*index as u8);
1140 }
1141 else {
1142 bytecode.push(0xC4); bytecode.push(0x39);
1144 bytecode.push((*index >> 8) as u8);
1145 bytecode.push((*index & 0xFF) as u8);
1146 }
1147 }
1148 JvmInstruction::Dstore0 => bytecode.push(0x47),
1149 JvmInstruction::Dstore1 => bytecode.push(0x48),
1150 JvmInstruction::Dstore2 => bytecode.push(0x49),
1151 JvmInstruction::Dstore3 => bytecode.push(0x4A),
1152
1153 JvmInstruction::Astore { index } => {
1154 if *index <= 3 {
1155 bytecode.push(0x4B + *index as u8);
1156 }
1157 else if *index <= 255 {
1158 bytecode.push(0x3A);
1159 bytecode.push(*index as u8);
1160 }
1161 else {
1162 bytecode.push(0xC4); bytecode.push(0x3A);
1164 bytecode.push((*index >> 8) as u8);
1165 bytecode.push((*index & 0xFF) as u8);
1166 }
1167 }
1168 JvmInstruction::Astore0 => bytecode.push(0x4B),
1169 JvmInstruction::Astore1 => bytecode.push(0x4C),
1170 JvmInstruction::Astore2 => bytecode.push(0x4D),
1171 JvmInstruction::Astore3 => bytecode.push(0x4E),
1172
1173 JvmInstruction::Pop => bytecode.push(0x57),
1174 JvmInstruction::Pop2 => bytecode.push(0x58),
1175 JvmInstruction::Dup => bytecode.push(0x59),
1176 JvmInstruction::DupX1 => bytecode.push(0x5A),
1177 JvmInstruction::DupX2 => bytecode.push(0x5B),
1178 JvmInstruction::Dup2 => bytecode.push(0x5C),
1179 JvmInstruction::Dup2X1 => bytecode.push(0x5D),
1180 JvmInstruction::Dup2X2 => bytecode.push(0x5E),
1181 JvmInstruction::Swap => bytecode.push(0x5F),
1182
1183 JvmInstruction::Iadd => bytecode.push(0x60),
1184 JvmInstruction::Ladd => bytecode.push(0x61),
1185 JvmInstruction::Fadd => bytecode.push(0x62),
1186 JvmInstruction::Dadd => bytecode.push(0x63),
1187 JvmInstruction::Isub => bytecode.push(0x64),
1188 JvmInstruction::Lsub => bytecode.push(0x65),
1189 JvmInstruction::Fsub => bytecode.push(0x66),
1190 JvmInstruction::Dsub => bytecode.push(0x67),
1191 JvmInstruction::Imul => bytecode.push(0x68),
1192 JvmInstruction::Lmul => bytecode.push(0x69),
1193 JvmInstruction::Fmul => bytecode.push(0x6A),
1194 JvmInstruction::Dmul => bytecode.push(0x6B),
1195 JvmInstruction::Idiv => bytecode.push(0x6C),
1196 JvmInstruction::Ldiv => bytecode.push(0x6D),
1197 JvmInstruction::Fdiv => bytecode.push(0x6E),
1198 JvmInstruction::Ddiv => bytecode.push(0x6F),
1199 JvmInstruction::Irem => bytecode.push(0x70),
1200 JvmInstruction::Lrem => bytecode.push(0x71),
1201 JvmInstruction::Frem => bytecode.push(0x72),
1202 JvmInstruction::Drem => bytecode.push(0x73),
1203 JvmInstruction::Ineg => bytecode.push(0x74),
1204 JvmInstruction::Lneg => bytecode.push(0x75),
1205 JvmInstruction::Fneg => bytecode.push(0x76),
1206 JvmInstruction::Dneg => bytecode.push(0x77),
1207
1208 JvmInstruction::Ishl => bytecode.push(0x78),
1209 JvmInstruction::Lshl => bytecode.push(0x79),
1210 JvmInstruction::Ishr => bytecode.push(0x7A),
1211 JvmInstruction::Lshr => bytecode.push(0x7B),
1212 JvmInstruction::Iushr => bytecode.push(0x7C),
1213 JvmInstruction::Lushr => bytecode.push(0x7D),
1214 JvmInstruction::Iand => bytecode.push(0x7E),
1215 JvmInstruction::Land => bytecode.push(0x7F),
1216 JvmInstruction::Ior => bytecode.push(0x80),
1217 JvmInstruction::Lor => bytecode.push(0x81),
1218 JvmInstruction::Ixor => bytecode.push(0x82),
1219 JvmInstruction::Lxor => bytecode.push(0x83),
1220
1221 JvmInstruction::Lcmp => bytecode.push(0x94),
1222 JvmInstruction::Fcmpl => bytecode.push(0x95),
1223 JvmInstruction::Fcmpg => bytecode.push(0x96),
1224 JvmInstruction::Dcmpl => bytecode.push(0x97),
1225 JvmInstruction::Dcmpg => bytecode.push(0x98),
1226
1227 JvmInstruction::Ifeq { target } => {
1228 jump_patches.push((pos, pos + 1, target.clone(), false));
1229 bytecode.push(0x99);
1230 bytecode.push(0);
1231 bytecode.push(0);
1232 }
1233 JvmInstruction::Ifne { target } => {
1234 jump_patches.push((pos, pos + 1, target.clone(), false));
1235 bytecode.push(0x9A);
1236 bytecode.push(0);
1237 bytecode.push(0);
1238 }
1239 JvmInstruction::Iflt { target } => {
1240 jump_patches.push((pos, pos + 1, target.clone(), false));
1241 bytecode.push(0x9B);
1242 bytecode.push(0);
1243 bytecode.push(0);
1244 }
1245 JvmInstruction::Ifge { target } => {
1246 jump_patches.push((pos, pos + 1, target.clone(), false));
1247 bytecode.push(0x9C);
1248 bytecode.push(0);
1249 bytecode.push(0);
1250 }
1251 JvmInstruction::Ifgt { target } => {
1252 jump_patches.push((pos, pos + 1, target.clone(), false));
1253 bytecode.push(0x9D);
1254 bytecode.push(0);
1255 bytecode.push(0);
1256 }
1257 JvmInstruction::Ifle { target } => {
1258 jump_patches.push((pos, pos + 1, target.clone(), false));
1259 bytecode.push(0x9E);
1260 bytecode.push(0);
1261 bytecode.push(0);
1262 }
1263 JvmInstruction::IfIcmpeq { target } => {
1264 jump_patches.push((pos, pos + 1, target.clone(), false));
1265 bytecode.push(0x9F);
1266 bytecode.push(0);
1267 bytecode.push(0);
1268 }
1269 JvmInstruction::IfIcmpne { target } => {
1270 jump_patches.push((pos, pos + 1, target.clone(), false));
1271 bytecode.push(0xA0);
1272 bytecode.push(0);
1273 bytecode.push(0);
1274 }
1275 JvmInstruction::IfIcmplt { target } => {
1276 jump_patches.push((pos, pos + 1, target.clone(), false));
1277 bytecode.push(0xA1);
1278 bytecode.push(0);
1279 bytecode.push(0);
1280 }
1281 JvmInstruction::IfIcmpge { target } => {
1282 jump_patches.push((pos, pos + 1, target.clone(), false));
1283 bytecode.push(0xA2);
1284 bytecode.push(0);
1285 bytecode.push(0);
1286 }
1287 JvmInstruction::IfIcmpgt { target } => {
1288 jump_patches.push((pos, pos + 1, target.clone(), false));
1289 bytecode.push(0xA3);
1290 bytecode.push(0);
1291 bytecode.push(0);
1292 }
1293 JvmInstruction::IfIcmple { target } => {
1294 jump_patches.push((pos, pos + 1, target.clone(), false));
1295 bytecode.push(0xA4);
1296 bytecode.push(0);
1297 bytecode.push(0);
1298 }
1299 JvmInstruction::IfAcmpeq { target } => {
1300 jump_patches.push((pos, pos + 1, target.clone(), false));
1301 bytecode.push(0xA5);
1302 bytecode.push(0);
1303 bytecode.push(0);
1304 }
1305 JvmInstruction::IfAcmpne { target } => {
1306 jump_patches.push((pos, pos + 1, target.clone(), false));
1307 bytecode.push(0xA6);
1308 bytecode.push(0);
1309 bytecode.push(0);
1310 }
1311 JvmInstruction::Ifnull { target } => {
1312 jump_patches.push((pos, pos + 1, target.clone(), false));
1313 bytecode.push(0xC6);
1314 bytecode.push(0);
1315 bytecode.push(0);
1316 }
1317 JvmInstruction::Ifnonnull { target } => {
1318 jump_patches.push((pos, pos + 1, target.clone(), false));
1319 bytecode.push(0xC7);
1320 bytecode.push(0);
1321 bytecode.push(0);
1322 }
1323 JvmInstruction::Goto { target } => {
1324 jump_patches.push((pos, pos + 1, target.clone(), false));
1325 bytecode.push(0xA7);
1326 bytecode.push(0);
1327 bytecode.push(0);
1328 }
1329 JvmInstruction::GotoW { target } => {
1330 jump_patches.push((pos, pos + 1, target.clone(), true));
1331 bytecode.push(0xC8);
1332 bytecode.push(0);
1333 bytecode.push(0);
1334 bytecode.push(0);
1335 bytecode.push(0);
1336 }
1337
1338 JvmInstruction::Return => bytecode.push(0xB1),
1339 JvmInstruction::Ireturn => bytecode.push(0xAC),
1340 JvmInstruction::Lreturn => bytecode.push(0xAD),
1341 JvmInstruction::Freturn => bytecode.push(0xAE),
1342 JvmInstruction::Dreturn => bytecode.push(0xAF),
1343 JvmInstruction::Areturn => bytecode.push(0xB0),
1344
1345 JvmInstruction::Arraylength => bytecode.push(0xBE),
1346 JvmInstruction::Athrow => bytecode.push(0xBF),
1347 JvmInstruction::Monitorenter => bytecode.push(0xC2),
1348 JvmInstruction::Monitorexit => bytecode.push(0xC3),
1349
1350 JvmInstruction::Iaload => bytecode.push(0x2E),
1351 JvmInstruction::Laload => bytecode.push(0x2F),
1352 JvmInstruction::Faload => bytecode.push(0x30),
1353 JvmInstruction::Daload => bytecode.push(0x31),
1354 JvmInstruction::Aaload => bytecode.push(0x32),
1355 JvmInstruction::Baload => bytecode.push(0x33),
1356 JvmInstruction::Saload => bytecode.push(0x34),
1357
1358 JvmInstruction::Iastore => bytecode.push(0x4F),
1359 JvmInstruction::Lastore => bytecode.push(0x50),
1360 JvmInstruction::Fastore => bytecode.push(0x51),
1361 JvmInstruction::Dastore => bytecode.push(0x52),
1362 JvmInstruction::Aastore => bytecode.push(0x53),
1363 JvmInstruction::Bastore => bytecode.push(0x54),
1364 JvmInstruction::Sastore => bytecode.push(0x55),
1365
1366 JvmInstruction::Getstatic { class_name, field_name, descriptor } => {
1367 let index = self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
1368 bytecode.push(0xB2); bytecode.push((index >> 8) as u8);
1370 bytecode.push((index & 0xFF) as u8);
1371 }
1372 JvmInstruction::Putstatic { class_name, field_name, descriptor } => {
1373 let index = self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
1374 bytecode.push(0xB3); bytecode.push((index >> 8) as u8);
1376 bytecode.push((index & 0xFF) as u8);
1377 }
1378 JvmInstruction::Getfield { class_name, field_name, descriptor } => {
1379 let index = self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
1380 bytecode.push(0xB4); bytecode.push((index >> 8) as u8);
1382 bytecode.push((index & 0xFF) as u8);
1383 }
1384 JvmInstruction::Putfield { class_name, field_name, descriptor } => {
1385 let index = self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
1386 bytecode.push(0xB5); bytecode.push((index >> 8) as u8);
1388 bytecode.push((index & 0xFF) as u8);
1389 }
1390 JvmInstruction::Invokevirtual { class_name, method_name, descriptor } => {
1391 let index = self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
1392 bytecode.push(0xB6); bytecode.push((index >> 8) as u8);
1394 bytecode.push((index & 0xFF) as u8);
1395 }
1396 JvmInstruction::Invokespecial { class_name, method_name, descriptor } => {
1397 let index = self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
1398 bytecode.push(0xB7); bytecode.push((index >> 8) as u8);
1400 bytecode.push((index & 0xFF) as u8);
1401 }
1402 JvmInstruction::Invokestatic { class_name, method_name, descriptor } => {
1403 let index = self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
1404 bytecode.push(0xB8); bytecode.push((index >> 8) as u8);
1406 bytecode.push((index & 0xFF) as u8);
1407 }
1408 JvmInstruction::Invokeinterface { class_name, method_name, descriptor } => {
1409 let index = self.add_interface_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
1410 bytecode.push(0xB9); bytecode.push((index >> 8) as u8);
1412 bytecode.push((index & 0xFF) as u8);
1413
1414 let count = calculate_parameter_count(descriptor) + 1;
1416 bytecode.push(count as u8);
1417 bytecode.push(0);
1418 }
1419 JvmInstruction::Invokedynamic { class_name, method_name, descriptor } => {
1420 let index = self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
1421 bytecode.push(0xBA); bytecode.push((index >> 8) as u8);
1423 bytecode.push((index & 0xFF) as u8);
1424 bytecode.push(0);
1425 bytecode.push(0);
1426 }
1427 JvmInstruction::New { class_name } => {
1428 let index = self.add_class(class_name.clone());
1429 bytecode.push(0xBB); bytecode.push((index >> 8) as u8);
1431 bytecode.push((index & 0xFF) as u8);
1432 }
1433 JvmInstruction::Newarray { atype } => {
1434 bytecode.push(0xBC); bytecode.push(*atype);
1436 }
1437 JvmInstruction::Anewarray { class_name } => {
1438 let index = self.add_class(class_name.clone());
1439 bytecode.push(0xBD); bytecode.push((index >> 8) as u8);
1441 bytecode.push((index & 0xFF) as u8);
1442 }
1443 JvmInstruction::Multianewarray { class_name, dimensions } => {
1444 let index = self.add_class(class_name.clone());
1445 bytecode.push(0xC5); bytecode.push((index >> 8) as u8);
1447 bytecode.push((index & 0xFF) as u8);
1448 bytecode.push(*dimensions);
1449 }
1450 JvmInstruction::Checkcast { class_name } => {
1451 let index = self.add_class(class_name.clone());
1452 bytecode.push(0xC0); bytecode.push((index >> 8) as u8);
1454 bytecode.push((index & 0xFF) as u8);
1455 }
1456 JvmInstruction::Instanceof { class_name } => {
1457 let index = self.add_class(class_name.clone());
1458 bytecode.push(0xC1); bytecode.push((index >> 8) as u8);
1460 bytecode.push((index & 0xFF) as u8);
1461 }
1462 JvmInstruction::Jsr { target } => {
1463 jump_patches.push((pos, pos + 1, target.clone(), false));
1464 bytecode.push(0xA8); bytecode.push(0);
1466 bytecode.push(0);
1467 }
1468 JvmInstruction::Ret { index } => {
1469 if *index <= 255 {
1470 bytecode.push(0xA9); bytecode.push(*index as u8);
1472 }
1473 else {
1474 bytecode.push(0xC4); bytecode.push(0xA9);
1476 bytecode.push((*index >> 8) as u8);
1477 bytecode.push((*index & 0xFF) as u8);
1478 }
1479 }
1480 JvmInstruction::Iinc { index, increment } => {
1481 if *index <= 255 && *increment >= -128 && *increment <= 127 {
1482 bytecode.push(0x84); bytecode.push(*index as u8);
1484 bytecode.push(*increment as u8);
1485 }
1486 else {
1487 bytecode.push(0xC4); bytecode.push(0x84);
1489 bytecode.push((*index >> 8) as u8);
1490 bytecode.push((*index & 0xFF) as u8);
1491 bytecode.push((*increment >> 8) as u8);
1492 bytecode.push((*increment & 0xFF) as u8);
1493 }
1494 }
1495 JvmInstruction::JsrW { target } => {
1496 jump_patches.push((pos, pos + 1, target.clone(), true));
1497 bytecode.push(0xC9); bytecode.push(0);
1499 bytecode.push(0);
1500 bytecode.push(0);
1501 bytecode.push(0);
1502 }
1503
1504 JvmInstruction::Lookupswitch { default, pairs } => {
1505 bytecode.push(0xAB); let padding = (4 - (bytecode.len() % 4)) % 4;
1509 for _ in 0..padding {
1510 bytecode.push(0);
1511 }
1512
1513 let default_patch_pos = bytecode.len();
1515 jump_patches.push((pos, default_patch_pos, default.clone(), true));
1516 bytecode.push(0);
1517 bytecode.push(0);
1518 bytecode.push(0);
1519 bytecode.push(0);
1520
1521 let npairs = pairs.len() as i32;
1523 bytecode.push((npairs >> 24) as u8);
1524 bytecode.push((npairs >> 16) as u8);
1525 bytecode.push((npairs >> 8) as u8);
1526 bytecode.push(npairs as u8);
1527
1528 for (val, target) in pairs {
1530 bytecode.push((val >> 24) as u8);
1532 bytecode.push((val >> 16) as u8);
1533 bytecode.push((val >> 8) as u8);
1534 bytecode.push(*val as u8);
1535
1536 let patch_pos = bytecode.len();
1538 jump_patches.push((pos, patch_pos, target.clone(), true));
1539 bytecode.push(0);
1540 bytecode.push(0);
1541 bytecode.push(0);
1542 bytecode.push(0);
1543 }
1544 }
1545 JvmInstruction::Tableswitch { low, high, default, targets } => {
1546 bytecode.push(0xAA); let padding = (4 - (bytecode.len() % 4)) % 4;
1550 for _ in 0..padding {
1551 bytecode.push(0);
1552 }
1553
1554 let default_patch_pos = bytecode.len();
1556 jump_patches.push((pos, default_patch_pos, default.clone(), true));
1557 bytecode.push(0);
1558 bytecode.push(0);
1559 bytecode.push(0);
1560 bytecode.push(0);
1561
1562 bytecode.push((low >> 24) as u8);
1564 bytecode.push((low >> 16) as u8);
1565 bytecode.push((low >> 8) as u8);
1566 bytecode.push(*low as u8);
1567
1568 bytecode.push((high >> 24) as u8);
1570 bytecode.push((high >> 16) as u8);
1571 bytecode.push((high >> 8) as u8);
1572 bytecode.push(*high as u8);
1573
1574 for target in targets {
1576 let patch_pos = bytecode.len();
1577 jump_patches.push((pos, patch_pos, target.clone(), true));
1578 bytecode.push(0);
1579 bytecode.push(0);
1580 bytecode.push(0);
1581 bytecode.push(0);
1582 }
1583 }
1584 JvmInstruction::Label { .. } => {} JvmInstruction::Wide => bytecode.push(0xC4), }
1587 }
1588}