jvm_assembler/formats/class/writer/
mod.rs1use crate::program::*;
6use byteorder::BigEndian;
7use gaia_types::{BinaryWriter, GaiaDiagnostics, Result};
8use std::io::Write;
9
10pub struct ClassWriter<W> {
12 writer: BinaryWriter<W, BigEndian>,
14}
15
16impl<W> ClassWriter<W> {
17 pub fn new(writer: W) -> Self {
19 Self { writer: BinaryWriter::new(writer) }
20 }
21
22 pub fn finish(self) -> W {
24 self.writer.finish()
25 }
26}
27
28impl<W: Write> ClassWriter<W> {
29 pub fn write(mut self, program: &JvmProgram) -> GaiaDiagnostics<W> {
31 match self.write_class_file(program) {
32 Ok(_) => GaiaDiagnostics::success(self.finish()),
33 Err(error) => GaiaDiagnostics::failure(error),
34 }
35 }
36
37 fn write_class_file(&mut self, program: &JvmProgram) -> Result<()> {
39 self.writer.write_u32(0xCAFEBABE)?;
41
42 self.writer.write_u16(program.version.minor)?;
44 self.writer.write_u16(program.version.major)?;
45
46 self.write_constant_pool(program)?;
48
49 self.writer.write_u16(program.access_flags.to_flags())?;
51
52 self.writer.write_u16(2)?; if program.super_class.is_some() {
57 self.writer.write_u16(4)?; } else {
59 self.writer.write_u16(0)?;
60 }
61
62 self.writer.write_u16(0)?;
64
65 self.write_fields(program)?;
67
68 self.write_methods(program)?;
70
71 self.writer.write_u16(0)?;
73
74 Ok(())
75 }
76
77 fn write_constant_pool(&mut self, program: &JvmProgram) -> Result<()> {
79 let mut pool_entries = Vec::new();
81
82 pool_entries.push(format!("UTF8:{}", program.name));
84
85 pool_entries.push("CLASS:1".to_string());
87
88 if let Some(super_class) = &program.super_class {
90 pool_entries.push(format!("UTF8:{}", super_class));
91 } else {
92 pool_entries.push("UTF8:java/lang/Object".to_string());
93 }
94
95 pool_entries.push("CLASS:3".to_string());
97
98 pool_entries.push("UTF8:Hello, World!".to_string());
100
101 pool_entries.push("STRING:5".to_string());
103
104 pool_entries.push("UTF8:java/lang/System".to_string());
106
107 pool_entries.push("CLASS:7".to_string());
109
110 pool_entries.push("UTF8:out".to_string());
112
113 pool_entries.push("UTF8:Ljava/io/PrintStream;".to_string());
115
116 pool_entries.push("NAMEANDTYPE:9:10".to_string());
118
119 pool_entries.push("FIELDREF:8:11".to_string());
121
122 pool_entries.push("UTF8:java/io/PrintStream".to_string());
124
125 pool_entries.push("CLASS:13".to_string());
127
128 pool_entries.push("UTF8:println".to_string());
130
131 pool_entries.push("UTF8:(Ljava/lang/String;)V".to_string());
133
134 pool_entries.push("NAMEANDTYPE:15:16".to_string());
136
137 pool_entries.push("METHODREF:14:17".to_string());
139
140 for method in &program.methods {
142 pool_entries.push(format!("UTF8:{}", method.name));
143 pool_entries.push(format!("UTF8:{}", method.descriptor));
144 }
145
146 for field in &program.fields {
147 pool_entries.push(format!("UTF8:{}", field.name));
148 pool_entries.push(format!("UTF8:{}", field.descriptor));
149 }
150
151 pool_entries.push("UTF8:Code".to_string());
153
154 self.writer.write_u16((pool_entries.len() + 1) as u16)?;
156
157 for entry in &pool_entries {
159 if entry.starts_with("UTF8:") {
160 let utf8_str = &entry[5..];
161 self.writer.write_u8(1)?; self.writer.write_u16(utf8_str.len() as u16)?;
163 self.writer.write_all(utf8_str.as_bytes())?;
164 } else if entry.starts_with("CLASS:") {
165 let class_index: u16 = entry[6..].parse().unwrap();
166 self.writer.write_u8(7)?; self.writer.write_u16(class_index)?;
168 } else if entry.starts_with("STRING:") {
169 let string_index: u16 = entry[7..].parse().unwrap();
170 self.writer.write_u8(8)?; self.writer.write_u16(string_index)?;
172 } else if entry.starts_with("NAMEANDTYPE:") {
173 let parts: Vec<&str> = entry[12..].split(':').collect();
174 let name_index: u16 = parts[0].parse().unwrap();
175 let descriptor_index: u16 = parts[1].parse().unwrap();
176 self.writer.write_u8(12)?; self.writer.write_u16(name_index)?;
178 self.writer.write_u16(descriptor_index)?;
179 } else if entry.starts_with("FIELDREF:") {
180 let parts: Vec<&str> = entry[9..].split(':').collect();
181 let class_index: u16 = parts[0].parse().unwrap();
182 let name_and_type_index: u16 = parts[1].parse().unwrap();
183 self.writer.write_u8(9)?; self.writer.write_u16(class_index)?;
185 self.writer.write_u16(name_and_type_index)?;
186 } else if entry.starts_with("METHODREF:") {
187 let parts: Vec<&str> = entry[10..].split(':').collect();
188 let class_index: u16 = parts[0].parse().unwrap();
189 let name_and_type_index: u16 = parts[1].parse().unwrap();
190 self.writer.write_u8(10)?; self.writer.write_u16(class_index)?;
192 self.writer.write_u16(name_and_type_index)?;
193 }
194 }
195
196 Ok(())
197 }
198
199 fn write_fields(&mut self, program: &JvmProgram) -> Result<()> {
201 self.writer.write_u16(program.fields.len() as u16)?;
202
203 for field in &program.fields {
204 self.writer.write_u16(field.access_flags.to_flags())?;
205 self.writer.write_u16(3)?; self.writer.write_u16(4)?; self.writer.write_u16(0)?; }
209
210 Ok(())
211 }
212
213 fn write_methods(&mut self, program: &JvmProgram) -> Result<()> {
215 self.writer.write_u16(program.methods.len() as u16)?;
216
217 for method in &program.methods {
218 self.writer.write_u16(method.access_flags.to_flags())?;
219 self.writer.write_u16(19)?; self.writer.write_u16(20)?; self.writer.write_u16(1)?; self.write_code_attribute(method)?;
227 }
228
229 Ok(())
230 }
231
232 fn write_code_attribute(&mut self, method: &JvmMethod) -> Result<()> {
234 self.writer.write_u16(21)?;
236
237 let bytecode = self.generate_method_bytecode(method);
238
239 let attribute_length = 2 + 2 + 4 + bytecode.len() + 2 + 2;
241 self.writer.write_u32(attribute_length as u32)?;
242
243 self.writer.write_u16(2)?; self.writer.write_u16(1)?; self.writer.write_u32(bytecode.len() as u32)?;
249 self.writer.write_all(&bytecode)?;
250
251 self.writer.write_u16(0)?;
253
254 self.writer.write_u16(0)?;
256
257 Ok(())
258 }
259
260 fn generate_method_bytecode(&self, method: &JvmMethod) -> Vec<u8> {
262 let mut bytecode = Vec::new();
263
264 for instruction in &method.instructions {
265 match instruction {
266 JvmInstruction::Nop => bytecode.push(0x00),
267 JvmInstruction::IconstM1 => bytecode.push(0x02),
268 JvmInstruction::Iconst0 => bytecode.push(0x03),
269 JvmInstruction::Iconst1 => bytecode.push(0x04),
270 JvmInstruction::Iconst2 => bytecode.push(0x05),
271 JvmInstruction::Iconst3 => bytecode.push(0x06),
272 JvmInstruction::Iconst4 => bytecode.push(0x07),
273 JvmInstruction::Iconst5 => bytecode.push(0x08),
274 JvmInstruction::Lconst0 => bytecode.push(0x09),
275 JvmInstruction::Lconst1 => bytecode.push(0x0A),
276 JvmInstruction::Fconst0 => bytecode.push(0x0B),
277 JvmInstruction::Fconst1 => bytecode.push(0x0C),
278 JvmInstruction::Fconst2 => bytecode.push(0x0D),
279 JvmInstruction::Dconst0 => bytecode.push(0x0E),
280 JvmInstruction::Dconst1 => bytecode.push(0x0F),
281 JvmInstruction::Ldc { symbol: _ } => {
282 bytecode.push(0x12); bytecode.push(6); }
285 JvmInstruction::Iload0 => bytecode.push(0x1A),
286 JvmInstruction::Iload1 => bytecode.push(0x1B),
287 JvmInstruction::Iload2 => bytecode.push(0x1C),
288 JvmInstruction::Iload3 => bytecode.push(0x1D),
289 JvmInstruction::Aload0 => bytecode.push(0x2A),
290 JvmInstruction::Aload1 => bytecode.push(0x2B),
291 JvmInstruction::Aload2 => bytecode.push(0x2C),
292 JvmInstruction::Aload3 => bytecode.push(0x2D),
293 JvmInstruction::Istore0 => bytecode.push(0x3B),
294 JvmInstruction::Istore1 => bytecode.push(0x3C),
295 JvmInstruction::Istore2 => bytecode.push(0x3D),
296 JvmInstruction::Istore3 => bytecode.push(0x3E),
297 JvmInstruction::Astore0 => bytecode.push(0x4B),
298 JvmInstruction::Astore1 => bytecode.push(0x4C),
299 JvmInstruction::Astore2 => bytecode.push(0x4D),
300 JvmInstruction::Astore3 => bytecode.push(0x4E),
301 JvmInstruction::Iadd => bytecode.push(0x60),
302 JvmInstruction::Pop => bytecode.push(0x57),
303 JvmInstruction::Return => bytecode.push(0xB1),
304 JvmInstruction::Ireturn => bytecode.push(0xAC),
305 JvmInstruction::New { class_name: _ } => {
306 bytecode.push(0xBB); bytecode.push(0x00); bytecode.push(0x02); }
310
311 JvmInstruction::Getstatic { class_name: _, field_name: _, descriptor: _ } => {
312 bytecode.push(0xB2); bytecode.push(0x00); bytecode.push(0x0C); }
316 JvmInstruction::Invokevirtual { class_name: _, method_name: _, descriptor: _ } => {
317 bytecode.push(0xB6); bytecode.push(0x00); bytecode.push(0x12); }
321 _ => {
322 bytecode.push(0x00);
324 }
325 }
326 }
327
328 if bytecode.is_empty() {
330 bytecode.push(0xB1); }
332
333 bytecode
334 }
335}