jvm_assembler/formats/class/writer/
mod.rs1#![doc = include_str!("readme.md")]
2
3mod attributes;
4mod cp;
5mod entities;
6mod instructions;
7mod pool;
8mod utils;
9
10use crate::program::*;
11use cp::CpEntry;
12use gaia_binary::{BigEndian, BinaryWriter, Fixed};
13use gaia_types::{GaiaDiagnostics, Result};
14use std::{collections::HashMap, io::Write};
15
16pub struct ClassWriter<W: Write> {
18 writer: BinaryWriter<W, Fixed<BigEndian>>,
20 cp_entries: Vec<CpEntry>,
22 cp_map: HashMap<CpEntry, u16>,
24}
25
26impl<W: Write> ClassWriter<W> {
27 pub fn new(writer: W) -> Self {
29 Self { writer: BinaryWriter::new(writer), cp_entries: Vec::new(), cp_map: HashMap::new() }
30 }
31
32 pub fn finish(self) -> W {
34 self.writer.into_inner()
35 }
36
37 pub fn write(mut self, program: &JvmProgram) -> GaiaDiagnostics<W> {
39 match self.write_class_file(program) {
40 Ok(_) => GaiaDiagnostics::success(self.finish()),
41 Err(error) => GaiaDiagnostics::failure(error),
42 }
43 }
44
45 fn write_class_file(&mut self, program: &JvmProgram) -> Result<()> {
47 let this_class_idx = self.add_class(program.name.clone());
49 let super_class_idx = if let Some(super_name) = &program.super_class {
50 self.add_class(super_name.clone())
51 }
52 else {
53 self.add_class("java/lang/Object".to_string())
54 };
55
56 for attr in &program.attributes {
58 self.collect_attribute_constants(attr);
59 }
60
61 for field in &program.fields {
63 self.add_utf8(field.name.clone());
64 self.add_utf8(field.descriptor.clone());
65 for attr in &field.attributes {
66 self.collect_attribute_constants(attr);
67 }
68 if field.constant_value.is_some() {
69 self.add_utf8("ConstantValue".to_string());
70 }
71 }
72
73 let code_utf8_idx = self.add_utf8("Code".to_string());
75 for method in &program.methods {
76 self.add_utf8(method.name.clone());
77 self.add_utf8(method.descriptor.clone());
78
79 for handler in &method.exception_handlers {
80 if let Some(catch_type) = &handler.catch_type {
81 self.add_class(catch_type.clone());
82 }
83 }
84
85 for attr in &method.attributes {
86 self.collect_attribute_constants(attr);
87 }
88 if !method.exceptions.is_empty() {
89 self.add_utf8("Exceptions".to_string());
90 }
91
92 let (_, label_positions) = self.generate_method_bytecode(method);
94
95 if program.version.major >= 50 {
96 self.add_utf8("StackMapTable".to_string());
97 let has_stack_map = method.attributes.iter().any(|a| matches!(a, JvmAttribute::StackMapTable { .. }));
99 if !has_stack_map {
100 let analyzer = crate::analyzer::StackMapAnalyzer::new(program.name.clone(), method, &label_positions);
101 let frames = analyzer.analyze();
102 for frame in &frames {
103 match frame {
104 JvmStackMapFrame::SameLocals1StackItem { stack, .. }
105 | JvmStackMapFrame::SameLocals1StackItemExtended { stack, .. } => {
106 self.collect_verification_type_constants(stack);
107 }
108 JvmStackMapFrame::Append { locals, .. } => {
109 for vt in locals {
110 self.collect_verification_type_constants(vt);
111 }
112 }
113 JvmStackMapFrame::Full { locals, stack, .. } => {
114 for vt in locals {
115 self.collect_verification_type_constants(vt);
116 }
117 for vt in stack {
118 self.collect_verification_type_constants(vt);
119 }
120 }
121 _ => {}
122 }
123 }
124 }
125 }
126
127 for inst in &method.instructions {
129 match inst {
130 JvmInstruction::Ldc { symbol } | JvmInstruction::LdcW { symbol } | JvmInstruction::Ldc2W { symbol } => {
131 self.add_string(symbol.clone());
132 }
133 JvmInstruction::Getstatic { class_name, field_name, descriptor }
134 | JvmInstruction::Putstatic { class_name, field_name, descriptor }
135 | JvmInstruction::Getfield { class_name, field_name, descriptor }
136 | JvmInstruction::Putfield { class_name, field_name, descriptor } => {
137 self.add_field_ref(class_name.clone(), field_name.clone(), descriptor.clone());
138 }
139 JvmInstruction::Invokevirtual { class_name, method_name, descriptor }
140 | JvmInstruction::Invokespecial { class_name, method_name, descriptor }
141 | JvmInstruction::Invokestatic { class_name, method_name, descriptor }
142 | JvmInstruction::Invokedynamic { class_name, method_name, descriptor } => {
143 self.add_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
144 }
145 JvmInstruction::Invokeinterface { class_name, method_name, descriptor } => {
146 self.add_interface_method_ref(class_name.clone(), method_name.clone(), descriptor.clone());
147 }
148 JvmInstruction::New { class_name }
149 | JvmInstruction::Anewarray { class_name }
150 | JvmInstruction::Checkcast { class_name }
151 | JvmInstruction::Instanceof { class_name }
152 | JvmInstruction::Multianewarray { class_name, .. } => {
153 self.add_class(class_name.clone());
154 }
155 _ => {}
156 }
157 }
158 }
159
160 self.writer.write_u32(0xCAFEBABE)?;
163
164 self.writer.write_u16(program.version.minor)?;
166 self.writer.write_u16(program.version.major)?;
167
168 self.write_constant_pool()?;
170
171 self.writer.write_u16(program.access_flags.to_flags())?;
173
174 self.writer.write_u16(this_class_idx)?;
176
177 self.writer.write_u16(super_class_idx)?;
179
180 self.writer.write_u16(0)?;
182
183 self.write_fields(program)?;
185
186 self.write_methods(program, code_utf8_idx)?;
188
189 self.writer.write_u16(program.attributes.len() as u16)?;
191 for attr in &program.attributes {
192 self.write_attribute(attr)?;
193 }
194
195 Ok(())
196 }
197}