jvm_assembler/analyzer/
mod.rs1use crate::program::*;
2use std::collections::{BTreeSet, HashMap};
3
4pub struct StackMapAnalyzer<'a> {
6 pub _class_name: String,
8 pub method: &'a JvmMethod,
10 pub label_positions: &'a HashMap<String, i32>,
12}
13
14impl<'a> StackMapAnalyzer<'a> {
15 pub fn new(_class_name: String, method: &'a JvmMethod, label_positions: &'a HashMap<String, i32>) -> Self {
17 Self { _class_name, method, label_positions }
18 }
19
20 pub fn analyze(&self) -> Vec<JvmStackMapFrame> {
22 let jump_targets = self.get_jump_targets();
23 if jump_targets.is_empty() {
24 return Vec::new();
25 }
26
27 let mut frames = Vec::new();
28 let mut last_offset = 0;
29 let mut first = true;
30
31 for target_offset in jump_targets {
32 let offset_delta = if first { target_offset as u16 } else { (target_offset - last_offset - 1) as u16 };
33
34 frames.push(self.generate_full_frame(offset_delta));
37
38 last_offset = target_offset;
39 first = false;
40 }
41
42 frames
43 }
44
45 fn get_jump_targets(&self) -> BTreeSet<i32> {
47 let mut targets = BTreeSet::new();
48 for inst in &self.method.instructions {
49 match inst {
50 JvmInstruction::Ifeq { target }
51 | JvmInstruction::Ifne { target }
52 | JvmInstruction::Iflt { target }
53 | JvmInstruction::Ifge { target }
54 | JvmInstruction::Ifgt { target }
55 | JvmInstruction::Ifle { target }
56 | JvmInstruction::IfIcmpeq { target }
57 | JvmInstruction::IfIcmpne { target }
58 | JvmInstruction::IfIcmplt { target }
59 | JvmInstruction::IfIcmpge { target }
60 | JvmInstruction::IfIcmpgt { target }
61 | JvmInstruction::IfIcmple { target }
62 | JvmInstruction::IfAcmpeq { target }
63 | JvmInstruction::IfAcmpne { target }
64 | JvmInstruction::Ifnull { target }
65 | JvmInstruction::Ifnonnull { target }
66 | JvmInstruction::Goto { target }
67 | JvmInstruction::GotoW { target } => {
68 if let Some(&pos) = self.label_positions.get(target) {
69 targets.insert(pos);
70 }
71 }
72 JvmInstruction::Tableswitch { default, offsets: switch_targets, .. } => {
73 if let Some(&pos) = self.label_positions.get(default) {
74 targets.insert(pos);
75 }
76 for target in switch_targets {
77 if let Some(&pos) = self.label_positions.get(target) {
78 targets.insert(pos);
79 }
80 }
81 }
82 JvmInstruction::Lookupswitch { default, match_offsets, .. } => {
83 if let Some(&pos) = self.label_positions.get(default) {
84 targets.insert(pos);
85 }
86 for (_, target) in match_offsets {
87 if let Some(&pos) = self.label_positions.get(target) {
88 targets.insert(pos);
89 }
90 }
91 }
92 _ => {}
93 }
94 }
95
96 for handler in &self.method.exception_handlers {
98 if let Some(&pos) = self.label_positions.get(&handler.handler_label) {
99 targets.insert(pos);
100 }
101 }
102
103 targets
104 }
105
106 fn generate_full_frame(&self, offset_delta: u16) -> JvmStackMapFrame {
108 JvmStackMapFrame::Full { offset_delta, locals: Vec::new(), stack: Vec::new() }
111 }
112}