1use crate::bytecode::lambda::LambdaTable;
2use crate::call_resolver::ClassCatalog;
3use crate::classfile::{ClassFileWriter, Label};
4use crate::hir::{AnonymousClassInfo, Block, CapturedField, FieldDecl, MethodDecl, OuterThisInfo};
5use crate::ty::{MethodSig, Ty};
6use std::collections::HashMap;
7use ustr::Ustr;
8
9#[derive(Clone)]
10pub struct FieldInfo {
11 pub ty: Ty,
12 pub access_flags: u16,
13}
14
15#[derive(Clone)]
16pub struct CleanupResource {
17 pub ty: Ty,
18 pub slot: u16,
19}
20
21#[derive(Clone)]
22pub struct CleanupScope {
23 pub resources: Vec<CleanupResource>,
24 pub finally: Option<Block>,
25}
26
27#[derive(Clone, Copy)]
28pub struct ControlTarget {
29 pub label: Label,
30 pub cleanup_depth: usize,
31}
32
33pub struct CodegenCtx<'a> {
34 pub writer: &'a mut ClassFileWriter,
35 pub catalog: ClassCatalog,
36 pub class_name: Ustr,
37 pub super_name: Ustr,
38 pub return_ty: Ty,
39 pub next_local: u16,
40 pub locals: HashMap<Ustr, u16>,
41 pub local_types: HashMap<Ustr, Ty>,
42 pub fields: HashMap<Ustr, FieldInfo>,
43 pub methods: HashMap<Ustr, MethodSig>,
44 pub outer_this: Option<OuterThisInfo>,
45 pub outer_fields: HashMap<Ustr, CapturedField>,
46 pub enclosing_static_owner: Option<Ustr>,
47 pub break_labels: Vec<ControlTarget>,
48 pub continue_labels: Vec<ControlTarget>,
49 pub labeled_break_labels: Vec<(Ustr, ControlTarget)>,
50 pub labeled_continue_labels: Vec<(Ustr, ControlTarget)>,
51 pub cleanup_scopes: Vec<CleanupScope>,
52 pub(crate) lambdas: LambdaTable,
53}
54
55impl<'a> CodegenCtx<'a> {
56 pub fn new(writer: &'a mut ClassFileWriter, class_name: Ustr, catalog: &ClassCatalog) -> Self {
57 Self {
58 writer,
59 catalog: catalog.clone(),
60 class_name,
61 super_name: Ustr::from("java/lang/Object"),
62 return_ty: Ty::Void,
63 next_local: 0,
64 locals: HashMap::new(),
65 local_types: HashMap::new(),
66 fields: HashMap::new(),
67 methods: HashMap::new(),
68 outer_this: None,
69 outer_fields: HashMap::new(),
70 enclosing_static_owner: None,
71 break_labels: Vec::new(),
72 continue_labels: Vec::new(),
73 labeled_break_labels: Vec::new(),
74 labeled_continue_labels: Vec::new(),
75 cleanup_scopes: Vec::new(),
76 lambdas: HashMap::new(),
77 }
78 }
79
80 pub fn set_super_name(&mut self, super_name: Ustr) {
81 self.super_name = super_name;
82 }
83
84 pub fn set_fields(&mut self, fields: &[FieldDecl]) {
85 self.fields.clear();
86 for field in fields {
87 self.fields.insert(
88 field.name,
89 FieldInfo {
90 ty: field.ty.clone(),
91 access_flags: field.access_flags,
92 },
93 );
94 }
95 }
96
97 pub fn set_methods(&mut self, methods: &[MethodDecl]) {
98 self.methods.clear();
99 for method in methods {
100 let mut sig = method.signature.clone();
101 sig.access_flags = method.access_flags;
102 self.methods.insert(method.name, sig);
103 }
104 }
105
106 pub fn set_anonymous_info(&mut self, info: Option<&AnonymousClassInfo>) {
107 self.outer_this = info.and_then(|info| info.outer_this.clone());
108 self.enclosing_static_owner = info.and_then(|info| info.enclosing_static_owner);
109 self.outer_fields.clear();
110 if let Some(info) = info {
111 for field in &info.outer_fields {
112 self.outer_fields.insert(field.name, field.clone());
113 }
114 }
115 }
116
117 pub fn begin_method(&mut self, method: &MethodDecl) {
118 self.return_ty = method.signature.return_type.clone();
119 self.next_local = 0;
120 self.locals.clear();
121 self.local_types.clear();
122
123 if method.access_flags & crate::classfile::ACC_STATIC == 0 {
124 self.next_local = 1;
125 }
126
127 for param in &method.params {
128 let slot = self.next_local;
129 self.locals.insert(param.name, slot);
130 self.local_types.insert(param.name, param.ty.clone());
131 self.next_local += param.ty.size() as u16;
132 }
133 }
134
135 pub fn alloc_local(&mut self, name: Ustr, ty: Ty) -> u16 {
136 let slot = self.next_local;
137 self.locals.insert(name, slot);
138 self.local_types.insert(name, ty.clone());
139 self.next_local += ty.size() as u16;
140 slot
141 }
142
143 pub fn alloc_temp(&mut self, ty: &Ty) -> u16 {
144 let slot = self.next_local;
145 self.next_local += ty.size() as u16;
146 slot
147 }
148
149 pub fn get_local(&self, name: Ustr) -> Option<u16> {
150 self.locals.get(&name).copied()
151 }
152
153 pub fn local_ty(&self, name: Ustr) -> Option<Ty> {
154 self.local_types.get(&name).cloned()
155 }
156
157 pub fn field_ty(&self, name: Ustr) -> Option<Ty> {
158 self.fields
159 .get(&name)
160 .map(|field| field.ty.clone())
161 .or_else(|| self.outer_fields.get(&name).map(|field| field.ty.clone()))
162 .or_else(|| {
163 self.enclosing_static_owner.and_then(|owner| {
164 self.catalog
165 .resolve_static_field(owner.as_str(), name.as_str())
166 .map(|field| field.ty)
167 })
168 })
169 }
170
171 pub fn field_is_static(&self, name: Ustr) -> bool {
172 self.fields
173 .get(&name)
174 .is_some_and(|field| field.access_flags & crate::classfile::ACC_STATIC != 0)
175 }
176
177 pub fn field_is_instance(&self, name: Ustr) -> bool {
178 self.fields
179 .get(&name)
180 .is_some_and(|field| field.access_flags & crate::classfile::ACC_STATIC == 0)
181 }
182
183 pub fn method_sig(&self, name: Ustr) -> Option<MethodSig> {
184 self.methods.get(&name).cloned()
185 }
186
187 pub fn control_target(&self, label: Label) -> ControlTarget {
188 ControlTarget {
189 label,
190 cleanup_depth: self.cleanup_scopes.len(),
191 }
192 }
193
194 pub fn push_labeled_loop(
195 &mut self,
196 label: Ustr,
197 break_label: ControlTarget,
198 continue_label: ControlTarget,
199 ) {
200 self.labeled_break_labels.push((label, break_label));
201 self.labeled_continue_labels.push((label, continue_label));
202 }
203
204 pub fn pop_labeled_loop(&mut self) {
205 self.labeled_break_labels.pop();
206 self.labeled_continue_labels.pop();
207 }
208
209 pub fn find_break_target(&self, label: Option<Ustr>) -> Option<ControlTarget> {
210 match label {
211 Some(label) => self
212 .labeled_break_labels
213 .iter()
214 .rev()
215 .find_map(|(name, target)| (*name == label).then_some(*target)),
216 None => self.break_labels.last().copied(),
217 }
218 }
219
220 pub fn find_continue_target(&self, label: Option<Ustr>) -> Option<ControlTarget> {
221 match label {
222 Some(label) => self
223 .labeled_continue_labels
224 .iter()
225 .rev()
226 .find_map(|(name, target)| (*name == label).then_some(*target)),
227 None => self.continue_labels.last().copied(),
228 }
229 }
230}