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