Skip to main content

jvm_assembler/analyzer/
mod.rs

1use crate::program::*;
2use std::collections::{BTreeSet, HashMap};
3
4/// StackMapTable analyzer framework
5pub struct StackMapAnalyzer<'a> {
6    /// Class name being analyzed
7    pub _class_name: String,
8    /// Method being analyzed
9    pub method: &'a JvmMethod,
10    /// Mapping from label names to bytecode positions
11    pub label_positions: &'a HashMap<String, i32>,
12}
13
14impl<'a> StackMapAnalyzer<'a> {
15    /// Creates a new StackMapAnalyzer
16    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    /// Analyzes the method and generates StackMapTable frames
21    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            // Basic implementation: temporarily assume Full frame for maximum compatibility
35            // This can be optimized to Same, Append, Chop, etc. based on state differences
36            frames.push(self.generate_full_frame(offset_delta));
37
38            last_offset = target_offset;
39            first = false;
40        }
41
42        frames
43    }
44
45    /// Gets all jump target offsets
46    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        // Exception handlers are also jump targets
97        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    /// Generates a Full frame (currently as a universal solution)
107    fn generate_full_frame(&self, offset_delta: u16) -> JvmStackMapFrame {
108        // TODO: Truly implement local variable and operand stack state tracking
109        // Currently returns empty locals and stack, which is usually incorrect but demonstrates the framework structure
110        JvmStackMapFrame::Full { offset_delta, locals: Vec::new(), stack: Vec::new() }
111    }
112}