1use std::collections::HashSet;
12
13use crate::ir::expr::TypeRef;
14use crate::types::{GenericType, JavaType};
15
16#[derive(Debug, Clone)]
17pub struct VarInfo {
18 pub id: u32,
19 pub slot: u16,
20 pub name: String,
21 pub ty: TypeRef,
22 pub is_param: bool,
23 pub range_start: u16,
25 pub range_end: u16,
26 pub synthetic_name: bool,
28}
29
30#[derive(Debug, Clone, Default)]
31pub struct VarTable {
32 pub vars: Vec<VarInfo>,
33 pub by_slot: Vec<Vec<(u16, u16, u32)>>,
35 pub has_lvt: bool,
36 pub stack_vars: Vec<u32>,
38 pub wide_stack_vars: HashSet<u32>,
42 pub handler_starts: Vec<u16>,
51}
52
53impl VarTable {
56 pub fn add_stack_var(&mut self, slot: u16, name: String, ty: TypeRef) -> u32 {
57 let id = self.add(slot, name, ty, false, 0, u16::MAX, true);
58 self.stack_vars.push(id);
59 id
60 }
61
62 pub fn add_split(&mut self, slot: u16, name: String, ty: TypeRef) -> u32 {
67 let id = self.vars.len() as u32;
68 self.vars.push(VarInfo {
69 id,
70 slot,
71 name,
72 ty,
73 is_param: false,
74 range_start: 0,
75 range_end: u16::MAX,
76 synthetic_name: true,
77 });
78 id
79 }
80
81 pub fn add_catch_var(&mut self, slot: u16, name: String, ty: TypeRef) -> u32 {
82 self.add(slot, name, ty, false, 0, u16::MAX, true)
83 }
84
85 fn add(&mut self, slot: u16, name: String, ty: TypeRef, is_param: bool, rs: u16, re: u16, synth: bool) -> u32 {
86 let id = self.vars.len() as u32;
87 self.vars.push(VarInfo { id, slot, name, ty, is_param, range_start: rs, range_end: re, synthetic_name: synth });
88 while self.by_slot.len() <= slot as usize {
89 self.by_slot.push(Vec::new());
90 }
91 self.by_slot[slot as usize].push((rs, re, id));
92 id
93 }
94
95 pub fn at(&self, slot: u16, pc: u16) -> Option<u32> {
98 let segs = self.by_slot.get(slot as usize)?;
99 for (rs, re, id) in segs {
100 if pc >= *rs && pc < *re {
101 return Some(*id);
102 }
103 }
104 for (rs, _, id) in segs {
113 if *rs > pc
114 && *rs - pc <= 8
115 && !self.handler_starts.iter().any(|h| {
116 *rs == *h || *rs == h + 1 || *rs == h + 2
117 })
118 {
119 return Some(*id);
120 }
121 }
122 let mut best: Option<u32> = None;
123 for (rs, _, id) in segs {
124 if *rs <= pc {
125 best = Some(*id);
126 }
127 }
128 best.or_else(|| segs.first().map(|(_, _, id)| *id))
129 }
130
131 pub fn sole_on_slot(&self, slot: u16) -> Option<u32> {
133 let segs = self.by_slot.get(slot as usize)?;
134 if segs.len() == 1 {
135 Some(segs[0].2)
136 } else {
137 None
138 }
139 }
140
141 pub fn vars_on_slot(&self, slot: u16) -> &[(u16, u16, u32)] {
142 self.by_slot.get(slot as usize).map(|v| v.as_slice()).unwrap_or(&[])
143 }
144
145 pub fn var(&self, id: u32) -> &VarInfo {
146 static DUMMY: std::sync::OnceLock<VarInfo> = std::sync::OnceLock::new();
147 self.vars.get(id as usize).unwrap_or_else(|| {
148 DUMMY.get_or_init(|| VarInfo {
149 id,
150 slot: u16::MAX,
151 name: format!("var{}", id),
152 ty: TypeRef::J(crate::types::JavaType::Int),
153 is_param: false,
154 range_start: 0,
155 range_end: 0,
156 synthetic_name: true,
157 })
158 })
159 }
160
161 pub fn var_mut(&mut self, id: u32) -> &mut VarInfo {
162 &mut self.vars[id as usize]
163 }
164}
165
166pub fn sig_type_at(
167 lvtt: &[(u16, u16, String, u16)],
168 start: u16,
169 slot: u16,
170 base: &JavaType,
171) -> Option<TypeRef> {
172 lvtt
173 .iter()
174 .find(|(s, _, _, sl)| *s == start && *sl == slot)
175 .and_then(|(_, _, sig, _)| crate::types::parse_field_signature(sig).map(TypeRef::G))
176 .filter(|tr| sig_matches_base(tr, base))
180}
181
182pub fn sig_matches_base(tr: &TypeRef, base: &JavaType) -> bool {
183 let g = match tr {
184 TypeRef::G(g) => g,
185 TypeRef::J(_) => return true,
186 };
187 match g {
188 crate::types::GenericType::TypeVar(_) => matches!(base, JavaType::Object(_)),
191 crate::types::GenericType::Class(cs) => {
192 matches!(base, JavaType::Object(n) if *n == cs.internal_name())
193 }
194 crate::types::GenericType::Primitive(c) => base.primitive_char() == Some(*c),
195 crate::types::GenericType::Array(_) => matches!(base, JavaType::Array(_)),
196 crate::types::GenericType::Wildcard(_) => false,
197 }
198}
199
200pub fn unknown_ref_type() -> TypeRef {
202 TypeRef::G(GenericType::Class(crate::types::ClassSig {
203 package: "java/lang".into(),
204 parts: vec![crate::types::ClassSigPart { name: "Object".into(), args: vec![] }],
205 }))
206}