Skip to main content

rusty_javac/bytecode/
codegen.rs

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}