jvm_assembler/formats/class/writer/
attributes.rs1use super::ClassWriter;
2use crate::program::*;
3use gaia_binary::BinaryWriter;
4use gaia_types::Result;
5use std::io::Write;
6
7struct RawExceptionHandler {
9 start_pc: u16,
10 end_pc: u16,
11 handler_pc: u16,
12 catch_type_index: u16,
13}
14
15impl<W: Write> ClassWriter<W> {
16 pub fn collect_attribute_constants(&mut self, attribute: &JvmAttribute) {
18 match attribute {
19 JvmAttribute::SourceFile { filename } => {
20 self.add_utf8("SourceFile".to_string());
21 self.add_utf8(filename.clone());
22 }
23 JvmAttribute::ConstantValue { value } => {
24 self.add_utf8("ConstantValue".to_string());
25 match value {
26 JvmConstantPoolEntry::Integer { .. } => {}
27 JvmConstantPoolEntry::Float { .. } => {}
28 JvmConstantPoolEntry::Long { .. } => {}
29 JvmConstantPoolEntry::Double { .. } => {}
30 JvmConstantPoolEntry::String { value } => {
31 self.add_string(value.clone());
32 }
33 _ => {}
34 }
35 }
36 JvmAttribute::Exceptions { exceptions } => {
37 self.add_utf8("Exceptions".to_string());
38 for exc in exceptions {
39 self.add_class(exc.clone());
40 }
41 }
42 JvmAttribute::Signature { signature } => {
43 self.add_utf8("Signature".to_string());
44 self.add_utf8(signature.clone());
45 }
46 JvmAttribute::StackMapTable { frames } => {
47 self.add_utf8("StackMapTable".to_string());
48 for frame in frames {
49 match frame {
50 JvmStackMapFrame::SameLocals1StackItem { stack, .. }
51 | JvmStackMapFrame::SameLocals1StackItemExtended { stack, .. } => {
52 self.collect_verification_type_constants(stack);
53 }
54 JvmStackMapFrame::Append { locals, .. } => {
55 for vt in locals {
56 self.collect_verification_type_constants(vt);
57 }
58 }
59 JvmStackMapFrame::Full { locals, stack, .. } => {
60 for vt in locals {
61 self.collect_verification_type_constants(vt);
62 }
63 for vt in stack {
64 self.collect_verification_type_constants(vt);
65 }
66 }
67 _ => {}
68 }
69 }
70 }
71 JvmAttribute::InnerClasses { classes } => {
72 self.add_utf8("InnerClasses".to_string());
73 for inner in classes {
74 self.add_class(inner.inner_class.clone());
75 if let Some(outer) = &inner.outer_class {
76 self.add_class(outer.clone());
77 }
78 if let Some(name) = &inner.inner_name {
79 self.add_utf8(name.clone());
80 }
81 }
82 }
83 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
84 self.add_utf8("EnclosingMethod".to_string());
85 self.add_class(class_name.clone());
86 if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
87 self.add_name_and_type(name.clone(), desc.clone());
88 }
89 }
90 JvmAttribute::Code { attributes, exception_table, .. } => {
91 self.add_utf8("Code".to_string());
92 for attr in attributes {
93 self.collect_attribute_constants(attr);
94 }
95 for handler in exception_table {
96 if let Some(catch_type) = &handler.catch_type {
97 self.add_class(catch_type.clone());
98 }
99 }
100 }
101 JvmAttribute::LineNumberTable { .. } => {
102 self.add_utf8("LineNumberTable".to_string());
103 }
104 JvmAttribute::LocalVariableTable { entries } => {
105 self.add_utf8("LocalVariableTable".to_string());
106 for entry in entries {
107 self.add_utf8(entry.name.clone());
108 self.add_utf8(entry.descriptor.clone());
109 }
110 }
111 JvmAttribute::BootstrapMethods { methods: _ } => {
112 self.add_utf8("BootstrapMethods".to_string());
113 }
115 JvmAttribute::RuntimeVisibleAnnotations { annotations } => {
116 self.add_utf8("RuntimeVisibleAnnotations".to_string());
117 self.collect_annotation_constants(annotations);
118 }
119 JvmAttribute::RuntimeInvisibleAnnotations { annotations } => {
120 self.add_utf8("RuntimeInvisibleAnnotations".to_string());
121 self.collect_annotation_constants(annotations);
122 }
123 JvmAttribute::MethodParameters { parameters } => {
124 self.add_utf8("MethodParameters".to_string());
125 for param in parameters {
126 if let Some(name) = ¶m.name {
127 self.add_utf8(name.clone());
128 }
129 }
130 }
131 JvmAttribute::Unknown { name, .. } => {
132 self.add_utf8(name.clone());
133 }
134 }
135 }
136
137 pub fn collect_annotation_constants(&mut self, annotations: &[JvmAnnotation]) {
139 for annotation in annotations {
140 self.add_class(annotation.type_name.clone());
141 for element in &annotation.elements {
142 self.add_utf8(element.name.clone());
143 self.collect_annotation_value_constants(&element.value);
144 }
145 }
146 }
147
148 pub fn collect_annotation_value_constants(&mut self, value: &JvmAnnotationValue) {
150 match value {
151 JvmAnnotationValue::String(s) => {
152 self.add_string(s.clone());
153 }
154 JvmAnnotationValue::Enum { class_name, enum_name } => {
155 self.add_class(class_name.clone());
156 self.add_utf8(enum_name.clone());
157 }
158 JvmAnnotationValue::Class(class_name) => {
159 self.add_string(class_name.clone());
160 }
161 JvmAnnotationValue::Annotation(annotation) => {
162 self.add_class(annotation.type_name.clone());
163 for element in &annotation.elements {
164 self.add_utf8(element.name.clone());
165 self.collect_annotation_value_constants(&element.value);
166 }
167 }
168 JvmAnnotationValue::Array(values) => {
169 for v in values {
170 self.collect_annotation_value_constants(v);
171 }
172 }
173 _ => {}
174 }
175 }
176
177 pub fn collect_verification_type_constants(&mut self, vt: &JvmVerificationType) {
179 if let JvmVerificationType::Object { class_name } = vt {
180 self.add_class(class_name.clone());
181 }
182 }
183
184 pub fn write_attribute(&mut self, attribute: &JvmAttribute) -> Result<()> {
186 match attribute {
187 JvmAttribute::SourceFile { filename } => {
188 let name_idx = self.add_utf8("SourceFile".to_string());
189 let file_idx = self.add_utf8(filename.clone());
190 self.writer.write_u16(name_idx)?;
191 self.writer.write_u32(2)?;
192 self.writer.write_u16(file_idx)?;
193 }
194 JvmAttribute::ConstantValue { value } => {
195 let name_idx = self.add_utf8("ConstantValue".to_string());
196 let val_idx = match value {
197 JvmConstantPoolEntry::Integer { value } => self.add_int(*value),
198 JvmConstantPoolEntry::Float { value } => self.add_float(*value),
199 JvmConstantPoolEntry::Long { value } => self.add_long(*value),
200 JvmConstantPoolEntry::Double { value } => self.add_double(*value),
201 JvmConstantPoolEntry::String { value } => self.add_string(value.clone()),
202 _ => 0,
203 };
204 self.writer.write_u16(name_idx)?;
205 self.writer.write_u32(2)?;
206 self.writer.write_u16(val_idx)?;
207 }
208 JvmAttribute::Exceptions { exceptions } => {
209 let name_idx = self.add_utf8("Exceptions".to_string());
210 let attr_len = 2 + exceptions.len() * 2;
211 self.writer.write_u16(name_idx)?;
212 self.writer.write_u32(attr_len as u32)?;
213 self.writer.write_u16(exceptions.len() as u16)?;
214 for exc in exceptions {
215 let exc_idx = self.add_class(exc.clone());
216 self.writer.write_u16(exc_idx)?;
217 }
218 }
219 JvmAttribute::Signature { signature } => {
220 let name_idx = self.add_utf8("Signature".to_string());
221 let sig_idx = self.add_utf8(signature.clone());
222 self.writer.write_u16(name_idx)?;
223 self.writer.write_u32(2)?;
224 self.writer.write_u16(sig_idx)?;
225 }
226 JvmAttribute::StackMapTable { frames } => {
227 let name_idx = self.add_utf8("StackMapTable".to_string());
228 let mut buf = Vec::new();
229 buf.extend_from_slice(&(frames.len() as u16).to_be_bytes());
230 for frame in frames {
231 self.write_stack_map_frame_to_buf(frame, &mut buf)?;
232 }
233 self.writer.write_u16(name_idx)?;
234 self.writer.write_u32(buf.len() as u32)?;
235 self.writer.write_all(&buf)?;
236 }
237 JvmAttribute::InnerClasses { classes } => {
238 let name_idx = self.add_utf8("InnerClasses".to_string());
239 let attr_len = 2 + classes.len() * 8;
240 self.writer.write_u16(name_idx)?;
241 self.writer.write_u32(attr_len as u32)?;
242 self.writer.write_u16(classes.len() as u16)?;
243 for inner in classes {
244 let inner_idx = self.add_class(inner.inner_class.clone());
245 let outer_idx = if let Some(outer) = &inner.outer_class { self.add_class(outer.clone()) } else { 0 };
246 let name_idx = if let Some(name) = &inner.inner_name { self.add_utf8(name.clone()) } else { 0 };
247 self.writer.write_u16(inner_idx)?;
248 self.writer.write_u16(outer_idx)?;
249 self.writer.write_u16(name_idx)?;
250 self.writer.write_u16(inner.access_flags.to_flags())?;
251 }
252 }
253 JvmAttribute::EnclosingMethod { class_name, method_name, method_descriptor } => {
254 let name_idx = self.add_utf8("EnclosingMethod".to_string());
255 let class_idx = self.add_class(class_name.clone());
256 let nt_idx = if let (Some(name), Some(desc)) = (method_name, method_descriptor) {
257 self.add_name_and_type(name.clone(), desc.clone())
258 }
259 else {
260 0
261 };
262 self.writer.write_u16(name_idx)?;
263 self.writer.write_u32(4)?;
264 self.writer.write_u16(class_idx)?;
265 self.writer.write_u16(nt_idx)?;
266 }
267 JvmAttribute::BootstrapMethods { methods } => {
268 let name_idx = self.add_utf8("BootstrapMethods".to_string());
269
270 let mut attr_len = 2; for method in methods {
273 attr_len += 2; attr_len += 2; attr_len += method.arguments.len() * 2; }
277
278 self.writer.write_u16(name_idx)?;
279 self.writer.write_u32(attr_len as u32)?;
280 self.writer.write_u16(methods.len() as u16)?;
281
282 for method in methods {
283 self.writer.write_u16(method.method_ref)?;
284 self.writer.write_u16(method.arguments.len() as u16)?;
285 for arg in &method.arguments {
286 self.writer.write_u16(*arg)?;
287 }
288 }
289 }
290 JvmAttribute::RuntimeVisibleAnnotations { annotations } => {
291 let name_idx = self.add_utf8("RuntimeVisibleAnnotations".to_string());
292 let mut buf = Vec::new();
293 buf.extend_from_slice(&annotations.len().to_be_bytes());
294 for annotation in annotations {
295 self.write_annotation_to_buf(annotation, &mut buf)?;
296 }
297 self.writer.write_u16(name_idx)?;
298 self.writer.write_u32(buf.len() as u32)?;
299 self.writer.write_all(&buf)?;
300 }
301 JvmAttribute::RuntimeInvisibleAnnotations { annotations } => {
302 let name_idx = self.add_utf8("RuntimeInvisibleAnnotations".to_string());
303 let mut buf = Vec::new();
304 buf.extend_from_slice(&annotations.len().to_be_bytes());
305 for annotation in annotations {
306 self.write_annotation_to_buf(annotation, &mut buf)?;
307 }
308 self.writer.write_u16(name_idx)?;
309 self.writer.write_u32(buf.len() as u32)?;
310 self.writer.write_all(&buf)?;
311 }
312 JvmAttribute::MethodParameters { parameters } => {
313 let name_idx = self.add_utf8("MethodParameters".to_string());
314 let mut buf = Vec::new();
315 buf.extend_from_slice(¶meters.len().to_be_bytes());
316 for param in parameters {
317 let name_idx = if let Some(name) = ¶m.name {
318 self.add_utf8(name.clone())
319 } else {
320 0
321 };
322 buf.extend_from_slice(&name_idx.to_be_bytes());
323 buf.extend_from_slice(¶m.access_flags.to_be_bytes());
324 }
325 self.writer.write_u16(name_idx)?;
326 self.writer.write_u32(buf.len() as u32)?;
327 self.writer.write_all(&buf)?;
328 }
329 JvmAttribute::Unknown { name, data } => {
330 let name_idx = self.add_utf8(name.clone());
331 self.writer.write_u16(name_idx)?;
332 self.writer.write_u32(data.len() as u32)?;
333 self.writer.write_all(data)?;
334 }
335 _ => {
336 }
338 }
339 Ok(())
340 }
341
342 pub fn write_verification_type_to_buf(&mut self, vt: &JvmVerificationType, buf: &mut Vec<u8>) -> Result<()> {
344 match vt {
345 JvmVerificationType::Top => buf.push(0),
346 JvmVerificationType::Integer => buf.push(1),
347 JvmVerificationType::Float => buf.push(2),
348 JvmVerificationType::Double => buf.push(3),
349 JvmVerificationType::Long => buf.push(4),
350 JvmVerificationType::Null => buf.push(5),
351 JvmVerificationType::UninitializedThis => buf.push(6),
352 JvmVerificationType::Object { class_name } => {
353 buf.push(7);
354 let class_idx = self.add_class(class_name.clone());
355 buf.extend_from_slice(&class_idx.to_be_bytes());
356 }
357 JvmVerificationType::Uninitialized { offset } => {
358 buf.push(8);
359 buf.extend_from_slice(&offset.to_be_bytes());
360 }
361 }
362 Ok(())
363 }
364
365 pub fn write_stack_map_frame_to_buf(&mut self, frame: &JvmStackMapFrame, buf: &mut Vec<u8>) -> Result<()> {
367 match frame {
368 JvmStackMapFrame::Same { offset_delta } => {
369 if *offset_delta <= 63 {
370 buf.push(*offset_delta as u8);
371 }
372 else {
373 buf.push(251);
374 buf.extend_from_slice(&offset_delta.to_be_bytes());
375 }
376 }
377 JvmStackMapFrame::SameLocals1StackItem { offset_delta, stack } => {
378 if *offset_delta <= 63 {
379 buf.push((*offset_delta + 64) as u8);
380 self.write_verification_type_to_buf(stack, buf)?;
381 }
382 else {
383 buf.push(247);
384 buf.extend_from_slice(&offset_delta.to_be_bytes());
385 self.write_verification_type_to_buf(stack, buf)?;
386 }
387 }
388 JvmStackMapFrame::SameLocals1StackItemExtended { offset_delta, stack } => {
389 buf.push(247);
390 buf.extend_from_slice(&offset_delta.to_be_bytes());
391 self.write_verification_type_to_buf(stack, buf)?;
392 }
393 JvmStackMapFrame::Chop { offset_delta, k } => {
394 buf.push(251 - k);
395 buf.extend_from_slice(&offset_delta.to_be_bytes());
396 }
397 JvmStackMapFrame::SameExtended { offset_delta } => {
398 buf.push(251);
399 buf.extend_from_slice(&offset_delta.to_be_bytes());
400 }
401 JvmStackMapFrame::Append { offset_delta, locals } => {
402 buf.push((251 + locals.len()) as u8);
403 buf.extend_from_slice(&offset_delta.to_be_bytes());
404 for vt in locals {
405 self.write_verification_type_to_buf(vt, buf)?;
406 }
407 }
408 JvmStackMapFrame::Full { offset_delta, locals, stack } => {
409 buf.push(255);
410 buf.extend_from_slice(&offset_delta.to_be_bytes());
411 buf.extend_from_slice(&(locals.len() as u16).to_be_bytes());
412 for vt in locals {
413 self.write_verification_type_to_buf(vt, buf)?;
414 }
415 buf.extend_from_slice(&(stack.len() as u16).to_be_bytes());
416 for vt in stack {
417 self.write_verification_type_to_buf(vt, buf)?;
418 }
419 }
420 }
421 Ok(())
422 }
423
424 pub fn write_annotation_to_buf(&mut self, annotation: &JvmAnnotation, buf: &mut Vec<u8>) -> Result<()> {
426 let type_idx = self.add_class(annotation.type_name.clone());
427 buf.extend_from_slice(&type_idx.to_be_bytes());
428 buf.extend_from_slice(&annotation.elements.len().to_be_bytes());
429 for element in &annotation.elements {
430 self.write_annotation_element_to_buf(element, buf)?;
431 }
432 Ok(())
433 }
434
435 pub fn write_annotation_element_to_buf(&mut self, element: &JvmAnnotationElement, buf: &mut Vec<u8>) -> Result<()> {
437 let name_idx = self.add_utf8(element.name.clone());
438 buf.extend_from_slice(&name_idx.to_be_bytes());
439 self.write_annotation_value_to_buf(&element.value, buf)?;
440 Ok(())
441 }
442
443 pub fn write_annotation_value_to_buf(&mut self, value: &JvmAnnotationValue, buf: &mut Vec<u8>) -> Result<()> {
445 match value {
446 JvmAnnotationValue::Byte(b) => {
447 buf.push(6); let idx = self.add_int(*b as i32);
449 buf.extend_from_slice(&idx.to_be_bytes());
450 }
451 JvmAnnotationValue::Char(c) => {
452 buf.push(6); let idx = self.add_int(*c as i32);
454 buf.extend_from_slice(&idx.to_be_bytes());
455 }
456 JvmAnnotationValue::Double(d) => {
457 buf.push(5); let idx = self.add_double(*d);
459 buf.extend_from_slice(&idx.to_be_bytes());
460 }
461 JvmAnnotationValue::Float(f) => {
462 buf.push(4); let idx = self.add_float(*f);
464 buf.extend_from_slice(&idx.to_be_bytes());
465 }
466 JvmAnnotationValue::Int(i) => {
467 buf.push(6); let idx = self.add_int(*i);
469 buf.extend_from_slice(&idx.to_be_bytes());
470 }
471 JvmAnnotationValue::Long(l) => {
472 buf.push(5); let idx = self.add_long(*l);
474 buf.extend_from_slice(&idx.to_be_bytes());
475 }
476 JvmAnnotationValue::Short(s) => {
477 buf.push(6); let idx = self.add_int(*s as i32);
479 buf.extend_from_slice(&idx.to_be_bytes());
480 }
481 JvmAnnotationValue::Boolean(b) => {
482 buf.push(6); let idx = self.add_int(if *b { 1 } else { 0 });
484 buf.extend_from_slice(&idx.to_be_bytes());
485 }
486 JvmAnnotationValue::String(s) => {
487 buf.push(8); let idx = self.add_string(s.clone());
489 buf.extend_from_slice(&idx.to_be_bytes());
490 }
491 JvmAnnotationValue::Enum { class_name, enum_name } => {
492 buf.push(10); let class_idx = self.add_class(class_name.clone());
494 let nt_idx = self.add_name_and_type(enum_name.clone(), "".to_string());
495 buf.extend_from_slice(&class_idx.to_be_bytes());
496 buf.extend_from_slice(&nt_idx.to_be_bytes());
497 }
498 JvmAnnotationValue::Class(class_name) => {
499 buf.push(9); let idx = self.add_string(class_name.clone());
501 buf.extend_from_slice(&idx.to_be_bytes());
502 }
503 JvmAnnotationValue::Annotation(annotation) => {
504 buf.push(0x00); self.write_annotation_to_buf(annotation, buf)?;
506 }
507 JvmAnnotationValue::Array(values) => {
508 buf.push(0x01); buf.extend_from_slice(&values.len().to_be_bytes());
510 for v in values {
511 self.write_annotation_value_to_buf(v, buf)?;
512 }
513 }
514 }
515 Ok(())
516 }
517
518 pub fn write_code_attribute(&mut self, program: &JvmProgram, method: &JvmMethod, code_utf8_idx: u16) -> Result<()> {
520 self.writer.write_u16(code_utf8_idx)?;
522
523 let (bytecode, label_positions) = self.generate_method_bytecode(method);
524
525 let mut raw_exception_table = Vec::new();
527 for handler in &method.exception_handlers {
528 let start_pc = *label_positions.get(&handler.start_label).unwrap_or(&0) as u16;
529 let end_pc = *label_positions.get(&handler.end_label).unwrap_or(&0) as u16;
530 let handler_pc = *label_positions.get(&handler.handler_label).unwrap_or(&0) as u16;
531 let catch_type_index =
532 if let Some(catch_type) = &handler.catch_type { self.add_class(catch_type.clone()) } else { 0 };
533 raw_exception_table.push(RawExceptionHandler { start_pc, end_pc, handler_pc, catch_type_index });
534 }
535
536 let mut code_attributes = Vec::new();
538
539 if program.version.major >= 50 {
541 let has_stack_map = method.attributes.iter().any(|a| matches!(a, JvmAttribute::StackMapTable { .. }));
542 if !has_stack_map {
543 let analyzer = crate::analyzer::StackMapAnalyzer::new(program.name.clone(), method, &label_positions);
544 let frames = analyzer.analyze();
545 if !frames.is_empty() {
546 code_attributes.push(JvmAttribute::StackMapTable { frames });
547 }
548 }
549 }
550
551 let mut sub_attr_buf = Vec::new();
553 let mut temp_writer = ClassWriter {
555 writer: BinaryWriter::new(&mut sub_attr_buf),
556 cp_entries: self.cp_entries.clone(),
557 cp_map: self.cp_map.clone(),
558 };
559
560 for attr in &code_attributes {
562 temp_writer.write_attribute(attr)?;
563 }
564
565 self.cp_entries = temp_writer.cp_entries;
567 self.cp_map = temp_writer.cp_map;
568
569 let exception_table_len = raw_exception_table.len() * 8;
571 let attribute_length = 2 + 2 + 4 + bytecode.len() + 2 + exception_table_len + 2 + sub_attr_buf.len();
572 self.writer.write_u32(attribute_length as u32)?;
573
574 self.writer.write_u16(method.max_stack)?;
576 self.writer.write_u16(method.max_locals)?;
577
578 self.writer.write_u32(bytecode.len() as u32)?;
580 self.writer.write_all(&bytecode)?;
581
582 self.writer.write_u16(raw_exception_table.len() as u16)?;
584 for handler in raw_exception_table {
585 self.writer.write_u16(handler.start_pc)?;
586 self.writer.write_u16(handler.end_pc)?;
587 self.writer.write_u16(handler.handler_pc)?;
588 self.writer.write_u16(handler.catch_type_index)?;
589 }
590
591 self.writer.write_u16(code_attributes.len() as u16)?;
593 self.writer.write_all(&sub_attr_buf)?;
594
595 Ok(())
596 }
597}