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(
86 &mut self,
87 slot: u16,
88 name: String,
89 ty: TypeRef,
90 is_param: bool,
91 rs: u16,
92 re: u16,
93 synth: bool,
94 ) -> u32 {
95 let id = self.vars.len() as u32;
96 self.vars.push(VarInfo {
97 id,
98 slot,
99 name,
100 ty,
101 is_param,
102 range_start: rs,
103 range_end: re,
104 synthetic_name: synth,
105 });
106 while self.by_slot.len() <= slot as usize {
107 self.by_slot.push(Vec::new());
108 }
109 self.by_slot[slot as usize].push((rs, re, id));
110 id
111 }
112
113 pub fn at(&self, slot: u16, pc: u16) -> Option<u32> {
116 let segs = self.by_slot.get(slot as usize)?;
117 for (rs, re, id) in segs {
118 if pc >= *rs && pc < *re {
119 return Some(*id);
120 }
121 }
122 for (rs, _, id) in segs {
131 if *rs > pc
132 && *rs - pc <= 8
133 && !self
134 .handler_starts
135 .iter()
136 .any(|h| *rs == *h || *rs == h + 1 || *rs == h + 2)
137 {
138 return Some(*id);
139 }
140 }
141 let mut best: Option<u32> = None;
142 for (rs, _, id) in segs {
143 if *rs <= pc {
144 best = Some(*id);
145 }
146 }
147 best.or_else(|| segs.first().map(|(_, _, id)| *id))
148 }
149
150 pub fn sole_on_slot(&self, slot: u16) -> Option<u32> {
152 let segs = self.by_slot.get(slot as usize)?;
153 if segs.len() == 1 {
154 Some(segs[0].2)
155 } else {
156 None
157 }
158 }
159
160 pub fn vars_on_slot(&self, slot: u16) -> &[(u16, u16, u32)] {
161 self.by_slot
162 .get(slot as usize)
163 .map(|v| v.as_slice())
164 .unwrap_or(&[])
165 }
166
167 pub fn var(&self, id: u32) -> &VarInfo {
168 static DUMMY: std::sync::OnceLock<VarInfo> = std::sync::OnceLock::new();
169 self.vars.get(id as usize).unwrap_or_else(|| {
170 DUMMY.get_or_init(|| VarInfo {
171 id,
172 slot: u16::MAX,
173 name: format!("var{}", id),
174 ty: TypeRef::J(crate::types::JavaType::Int),
175 is_param: false,
176 range_start: 0,
177 range_end: 0,
178 synthetic_name: true,
179 })
180 })
181 }
182
183 pub fn var_mut(&mut self, id: u32) -> &mut VarInfo {
184 &mut self.vars[id as usize]
185 }
186}
187
188pub fn sig_type_at(
189 lvtt: &[(u16, u16, String, u16)],
190 start: u16,
191 slot: u16,
192 base: &JavaType,
193) -> Option<TypeRef> {
194 lvtt.iter()
195 .find(|(s, _, _, sl)| *s == start && *sl == slot)
196 .and_then(|(_, _, sig, _)| crate::types::parse_field_signature(sig).map(TypeRef::G))
197 .filter(|tr| sig_matches_base(tr, base))
201}
202
203pub fn sig_matches_base(tr: &TypeRef, base: &JavaType) -> bool {
204 let g = match tr {
205 TypeRef::G(g) => g,
206 TypeRef::J(_) => return true,
207 };
208 match g {
209 crate::types::GenericType::TypeVar(_) => matches!(base, JavaType::Object(_)),
212 crate::types::GenericType::Class(cs) => {
213 matches!(base, JavaType::Object(n) if n.as_ref() == cs.internal_name())
214 }
215 crate::types::GenericType::Primitive(c) => base.primitive_char() == Some(*c),
216 crate::types::GenericType::Array(_) => matches!(base, JavaType::Array(_)),
217 crate::types::GenericType::Wildcard(_) => false,
218 }
219}
220
221pub fn unknown_ref_type() -> TypeRef {
223 TypeRef::G(GenericType::Class(crate::types::ClassSig {
224 package: "java/lang".into(),
225 parts: vec![crate::types::ClassSigPart {
226 name: "Object".into(),
227 args: vec![],
228 }],
229 }))
230}