jvm_assembler/formats/class/writer/
attributes.rs1use super::ClassWriter;
2use crate::program::*;
3use gaia_types::{BinaryWriter, Result};
4use std::io::Write;
5
6struct RawExceptionHandler {
8 start_pc: u16,
9 end_pc: u16,
10 handler_pc: u16,
11 catch_type_index: u16,
12}
13
14impl<W: Write> ClassWriter<W> {
15 pub fn collect_attribute_constants(&mut self, attribute: &JvmAttribute) {
17 match attribute {
18 JvmAttribute::SourceFile { filename } => {
19 self.add_utf8("SourceFile".to_string());
20 self.add_utf8(filename.clone());
21 }
22 JvmAttribute::ConstantValue { value } => {
23 self.add_utf8("ConstantValue".to_string());
24 match value {
25 JvmConstantPoolEntry::Integer { .. } => {}
26 JvmConstantPoolEntry::Float { .. } => {}
27 JvmConstantPoolEntry::Long { .. } => {}
28 JvmConstantPoolEntry::Double { .. } => {}
29 JvmConstantPoolEntry::String { value } => {
30 self.add_string(value.clone());
31 }
32 _ => {}
33 }
34 }
35 JvmAttribute::Exceptions { exceptions } => {
36 self.add_utf8("Exceptions".to_string());
37 for exc in exceptions {
38 self.add_class(exc.clone());
39 }
40 }
41 JvmAttribute::Signature { signature } => {
42 self.add_utf8("Signature".to_string());
43 self.add_utf8(signature.clone());
44 }
45 JvmAttribute::StackMapTable { frames } => {
46 self.add_utf8("StackMapTable".to_string());
47 for frame in frames {
48 match frame {
49 JvmStackMapFrame::SameLocals1StackItem { stack, .. }
50 | JvmStackMapFrame::SameLocals1StackItemExtended { stack, .. } => {
51 self.collect_verification_type_constants(stack);
52 }
53 JvmStackMapFrame::Append { locals, .. } => {
54 for vt in locals {
55 self.collect_verification_type_constants(vt);
56 }
57 }
58 JvmStackMapFrame::Full { locals, stack, .. } => {
59 for vt in locals {
60 self.collect_verification_type_constants(vt);
61 }
62 for vt in stack {
63 self.collect_verification_type_constants(vt);
64 }
65 }
66 _ => {}
67 }
68 }
69 }
70 JvmAttribute::InnerClasses { classes } => {
71 self.add_utf8("InnerClasses".to_string());
72 for inner in classes {
73 self.add_class(inner.inner_class.clone());
74 if let Some(outer) = &inner.outer_class {
75 self.add_class(outer.clone());
76 }
77 if let Some(name) = &inner.inner_name {
78 self.add_utf8(name.clone());
79 }
80 }
81 }
82 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
83 self.add_utf8("EnclosingMethod".to_string());
84 self.add_class(class_name.clone());
85 if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
86 self.add_name_and_type(name.clone(), desc.clone());
87 }
88 }
89 JvmAttribute::Code { attributes, exception_table, .. } => {
90 self.add_utf8("Code".to_string());
91 for attr in attributes {
92 self.collect_attribute_constants(attr);
93 }
94 for handler in exception_table {
95 if let Some(catch_type) = &handler.catch_type {
96 self.add_class(catch_type.clone());
97 }
98 }
99 }
100 JvmAttribute::LineNumberTable { .. } => {
101 self.add_utf8("LineNumberTable".to_string());
102 }
103 JvmAttribute::LocalVariableTable { entries } => {
104 self.add_utf8("LocalVariableTable".to_string());
105 for entry in entries {
106 self.add_utf8(entry.name.clone());
107 self.add_utf8(entry.descriptor.clone());
108 }
109 }
110 JvmAttribute::Unknown { name, .. } => {
111 self.add_utf8(name.clone());
112 }
113 }
114 }
115
116 pub fn collect_verification_type_constants(&mut self, vt: &JvmVerificationType) {
118 if let JvmVerificationType::Object { class_name } = vt {
119 self.add_class(class_name.clone());
120 }
121 }
122
123 pub fn write_attribute(&mut self, attribute: &JvmAttribute) -> Result<()> {
125 match attribute {
126 JvmAttribute::SourceFile { filename } => {
127 let name_idx = self.add_utf8("SourceFile".to_string());
128 let file_idx = self.add_utf8(filename.clone());
129 self.writer.write_u16(name_idx)?;
130 self.writer.write_u32(2)?;
131 self.writer.write_u16(file_idx)?;
132 }
133 JvmAttribute::ConstantValue { value } => {
134 let name_idx = self.add_utf8("ConstantValue".to_string());
135 let val_idx = match value {
136 JvmConstantPoolEntry::Integer { value } => self.add_int(*value),
137 JvmConstantPoolEntry::Float { value } => self.add_float(*value),
138 JvmConstantPoolEntry::Long { value } => self.add_long(*value),
139 JvmConstantPoolEntry::Double { value } => self.add_double(*value),
140 JvmConstantPoolEntry::String { value } => self.add_string(value.clone()),
141 _ => 0,
142 };
143 self.writer.write_u16(name_idx)?;
144 self.writer.write_u32(2)?;
145 self.writer.write_u16(val_idx)?;
146 }
147 JvmAttribute::Exceptions { exceptions } => {
148 let name_idx = self.add_utf8("Exceptions".to_string());
149 let attr_len = 2 + exceptions.len() * 2;
150 self.writer.write_u16(name_idx)?;
151 self.writer.write_u32(attr_len as u32)?;
152 self.writer.write_u16(exceptions.len() as u16)?;
153 for exc in exceptions {
154 let exc_idx = self.add_class(exc.clone());
155 self.writer.write_u16(exc_idx)?;
156 }
157 }
158 JvmAttribute::Signature { signature } => {
159 let name_idx = self.add_utf8("Signature".to_string());
160 let sig_idx = self.add_utf8(signature.clone());
161 self.writer.write_u16(name_idx)?;
162 self.writer.write_u32(2)?;
163 self.writer.write_u16(sig_idx)?;
164 }
165 JvmAttribute::StackMapTable { frames } => {
166 let name_idx = self.add_utf8("StackMapTable".to_string());
167 let mut buf = Vec::new();
168 buf.extend_from_slice(&(frames.len() as u16).to_be_bytes());
169 for frame in frames {
170 self.write_stack_map_frame_to_buf(frame, &mut buf)?;
171 }
172 self.writer.write_u16(name_idx)?;
173 self.writer.write_u32(buf.len() as u32)?;
174 self.writer.write_all(&buf)?;
175 }
176 JvmAttribute::InnerClasses { classes } => {
177 let name_idx = self.add_utf8("InnerClasses".to_string());
178 let attr_len = 2 + classes.len() * 8;
179 self.writer.write_u16(name_idx)?;
180 self.writer.write_u32(attr_len as u32)?;
181 self.writer.write_u16(classes.len() as u16)?;
182 for inner in classes {
183 let inner_idx = self.add_class(inner.inner_class.clone());
184 let outer_idx = if let Some(outer) = &inner.outer_class { self.add_class(outer.clone()) } else { 0 };
185 let name_idx = if let Some(name) = &inner.inner_name { self.add_utf8(name.clone()) } else { 0 };
186 self.writer.write_u16(inner_idx)?;
187 self.writer.write_u16(outer_idx)?;
188 self.writer.write_u16(name_idx)?;
189 self.writer.write_u16(inner.access_flags.to_flags())?;
190 }
191 }
192 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
193 let name_idx = self.add_utf8("EnclosingMethod".to_string());
194 let class_idx = self.add_class(class_name.clone());
195 let nt_idx = if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
196 self.add_name_and_type(name.clone(), desc.clone())
197 }
198 else {
199 0
200 };
201 self.writer.write_u16(name_idx)?;
202 self.writer.write_u32(4)?;
203 self.writer.write_u16(class_idx)?;
204 self.writer.write_u16(nt_idx)?;
205 }
206 JvmAttribute::Unknown { name, data } => {
207 let name_idx = self.add_utf8(name.clone());
208 self.writer.write_u16(name_idx)?;
209 self.writer.write_u32(data.len() as u32)?;
210 self.writer.write_all(data)?;
211 }
212 _ => {
213 }
215 }
216 Ok(())
217 }
218
219 pub fn write_verification_type_to_buf(&mut self, vt: &JvmVerificationType, buf: &mut Vec<u8>) -> Result<()> {
221 match vt {
222 JvmVerificationType::Top => buf.push(0),
223 JvmVerificationType::Integer => buf.push(1),
224 JvmVerificationType::Float => buf.push(2),
225 JvmVerificationType::Double => buf.push(3),
226 JvmVerificationType::Long => buf.push(4),
227 JvmVerificationType::Null => buf.push(5),
228 JvmVerificationType::UninitializedThis => buf.push(6),
229 JvmVerificationType::Object { class_name } => {
230 buf.push(7);
231 let class_idx = self.add_class(class_name.clone());
232 buf.extend_from_slice(&class_idx.to_be_bytes());
233 }
234 JvmVerificationType::Uninitialized { offset } => {
235 buf.push(8);
236 buf.extend_from_slice(&offset.to_be_bytes());
237 }
238 }
239 Ok(())
240 }
241
242 pub fn write_stack_map_frame_to_buf(&mut self, frame: &JvmStackMapFrame, buf: &mut Vec<u8>) -> Result<()> {
244 match frame {
245 JvmStackMapFrame::Same { offset_delta } => {
246 if *offset_delta <= 63 {
247 buf.push(*offset_delta as u8);
248 }
249 else {
250 buf.push(251);
251 buf.extend_from_slice(&offset_delta.to_be_bytes());
252 }
253 }
254 JvmStackMapFrame::SameLocals1StackItem { offset_delta, stack } => {
255 if *offset_delta <= 63 {
256 buf.push((*offset_delta + 64) as u8);
257 self.write_verification_type_to_buf(stack, buf)?;
258 }
259 else {
260 buf.push(247);
261 buf.extend_from_slice(&offset_delta.to_be_bytes());
262 self.write_verification_type_to_buf(stack, buf)?;
263 }
264 }
265 JvmStackMapFrame::SameLocals1StackItemExtended { offset_delta, stack } => {
266 buf.push(247);
267 buf.extend_from_slice(&offset_delta.to_be_bytes());
268 self.write_verification_type_to_buf(stack, buf)?;
269 }
270 JvmStackMapFrame::Chop { offset_delta, k } => {
271 buf.push(251 - k);
272 buf.extend_from_slice(&offset_delta.to_be_bytes());
273 }
274 JvmStackMapFrame::SameExtended { offset_delta } => {
275 buf.push(251);
276 buf.extend_from_slice(&offset_delta.to_be_bytes());
277 }
278 JvmStackMapFrame::Append { offset_delta, locals } => {
279 buf.push((251 + locals.len()) as u8);
280 buf.extend_from_slice(&offset_delta.to_be_bytes());
281 for vt in locals {
282 self.write_verification_type_to_buf(vt, buf)?;
283 }
284 }
285 JvmStackMapFrame::Full { offset_delta, locals, stack } => {
286 buf.push(255);
287 buf.extend_from_slice(&offset_delta.to_be_bytes());
288 buf.extend_from_slice(&(locals.len() as u16).to_be_bytes());
289 for vt in locals {
290 self.write_verification_type_to_buf(vt, buf)?;
291 }
292 buf.extend_from_slice(&(stack.len() as u16).to_be_bytes());
293 for vt in stack {
294 self.write_verification_type_to_buf(vt, buf)?;
295 }
296 }
297 }
298 Ok(())
299 }
300
301 pub fn write_code_attribute(&mut self, program: &JvmProgram, method: &JvmMethod, code_utf8_idx: u16) -> Result<()> {
303 self.writer.write_u16(code_utf8_idx)?;
305
306 let (bytecode, label_positions) = self.generate_method_bytecode(method);
307
308 let mut raw_exception_table = Vec::new();
310 for handler in &method.exception_handlers {
311 let start_pc = *label_positions.get(&handler.start_label).unwrap_or(&0) as u16;
312 let end_pc = *label_positions.get(&handler.end_label).unwrap_or(&0) as u16;
313 let handler_pc = *label_positions.get(&handler.handler_label).unwrap_or(&0) as u16;
314 let catch_type_index =
315 if let Some(catch_type) = &handler.catch_type { self.add_class(catch_type.clone()) } else { 0 };
316 raw_exception_table.push(RawExceptionHandler { start_pc, end_pc, handler_pc, catch_type_index });
317 }
318
319 let mut code_attributes = Vec::new();
321
322 if program.version.major >= 50 {
324 let has_stack_map = method.attributes.iter().any(|a| matches!(a, JvmAttribute::StackMapTable { .. }));
325 if !has_stack_map {
326 let analyzer = crate::analyzer::StackMapAnalyzer::new(program.name.clone(), method, &label_positions);
327 let frames = analyzer.analyze();
328 if !frames.is_empty() {
329 code_attributes.push(JvmAttribute::StackMapTable { frames });
330 }
331 }
332 }
333
334 let mut sub_attr_buf = Vec::new();
336 let mut temp_writer = ClassWriter {
338 writer: BinaryWriter::new(&mut sub_attr_buf),
339 cp_entries: self.cp_entries.clone(),
340 cp_map: self.cp_map.clone(),
341 };
342
343 for attr in &code_attributes {
345 temp_writer.write_attribute(attr)?;
346 }
347
348 self.cp_entries = temp_writer.cp_entries;
350 self.cp_map = temp_writer.cp_map;
351
352 let exception_table_len = raw_exception_table.len() * 8;
354 let attribute_length = 2 + 2 + 4 + bytecode.len() + 2 + exception_table_len + 2 + sub_attr_buf.len();
355 self.writer.write_u32(attribute_length as u32)?;
356
357 self.writer.write_u16(method.max_stack)?;
359 self.writer.write_u16(method.max_locals)?;
360
361 self.writer.write_u32(bytecode.len() as u32)?;
363 self.writer.write_all(&bytecode)?;
364
365 self.writer.write_u16(raw_exception_table.len() as u16)?;
367 for handler in raw_exception_table {
368 self.writer.write_u16(handler.start_pc)?;
369 self.writer.write_u16(handler.end_pc)?;
370 self.writer.write_u16(handler.handler_pc)?;
371 self.writer.write_u16(handler.catch_type_index)?;
372 }
373
374 self.writer.write_u16(code_attributes.len() as u16)?;
376 self.writer.write_all(&sub_attr_buf)?;
377
378 Ok(())
379 }
380}