1use crate::lcnf::*;
6use std::collections::HashSet;
7
8use super::functions::JAVA_KEYWORDS;
9
10use super::functions::*;
11use std::collections::{HashMap, VecDeque};
12
13#[allow(dead_code)]
14#[derive(Debug, Clone)]
15pub struct JavaWorklist {
16 pub(super) items: std::collections::VecDeque<u32>,
17 pub(super) in_worklist: std::collections::HashSet<u32>,
18}
19impl JavaWorklist {
20 #[allow(dead_code)]
21 pub fn new() -> Self {
22 JavaWorklist {
23 items: std::collections::VecDeque::new(),
24 in_worklist: std::collections::HashSet::new(),
25 }
26 }
27 #[allow(dead_code)]
28 pub fn push(&mut self, item: u32) -> bool {
29 if self.in_worklist.insert(item) {
30 self.items.push_back(item);
31 true
32 } else {
33 false
34 }
35 }
36 #[allow(dead_code)]
37 pub fn pop(&mut self) -> Option<u32> {
38 let item = self.items.pop_front()?;
39 self.in_worklist.remove(&item);
40 Some(item)
41 }
42 #[allow(dead_code)]
43 pub fn is_empty(&self) -> bool {
44 self.items.is_empty()
45 }
46 #[allow(dead_code)]
47 pub fn len(&self) -> usize {
48 self.items.len()
49 }
50 #[allow(dead_code)]
51 pub fn contains(&self, item: u32) -> bool {
52 self.in_worklist.contains(&item)
53 }
54}
55#[allow(dead_code)]
56#[derive(Debug, Clone, Default)]
57pub struct JavaPassStats {
58 pub total_runs: u32,
59 pub successful_runs: u32,
60 pub total_changes: u64,
61 pub time_ms: u64,
62 pub iterations_used: u32,
63}
64impl JavaPassStats {
65 #[allow(dead_code)]
66 pub fn new() -> Self {
67 Self::default()
68 }
69 #[allow(dead_code)]
70 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
71 self.total_runs += 1;
72 self.successful_runs += 1;
73 self.total_changes += changes;
74 self.time_ms += time_ms;
75 self.iterations_used = iterations;
76 }
77 #[allow(dead_code)]
78 pub fn average_changes_per_run(&self) -> f64 {
79 if self.total_runs == 0 {
80 return 0.0;
81 }
82 self.total_changes as f64 / self.total_runs as f64
83 }
84 #[allow(dead_code)]
85 pub fn success_rate(&self) -> f64 {
86 if self.total_runs == 0 {
87 return 0.0;
88 }
89 self.successful_runs as f64 / self.total_runs as f64
90 }
91 #[allow(dead_code)]
92 pub fn format_summary(&self) -> String {
93 format!(
94 "Runs: {}/{}, Changes: {}, Time: {}ms",
95 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
96 )
97 }
98}
99#[derive(Debug, Clone)]
101pub struct JavaMethod {
102 pub name: std::string::String,
103 pub return_type: JavaType,
104 pub params: Vec<(std::string::String, JavaType)>,
105 pub body: Vec<JavaStmt>,
106 pub visibility: Visibility,
107 pub is_static: bool,
108 pub is_final: bool,
109 pub is_abstract: bool,
110 pub annotations: Vec<std::string::String>,
111 pub throws: Vec<std::string::String>,
113}
114impl JavaMethod {
115 pub fn new(
117 name: &str,
118 return_type: JavaType,
119 params: Vec<(&str, JavaType)>,
120 body: Vec<JavaStmt>,
121 ) -> Self {
122 JavaMethod {
123 name: name.to_string(),
124 return_type,
125 params: params
126 .into_iter()
127 .map(|(n, t)| (n.to_string(), t))
128 .collect(),
129 body,
130 visibility: Visibility::Public,
131 is_static: false,
132 is_final: false,
133 is_abstract: false,
134 annotations: Vec::new(),
135 throws: Vec::new(),
136 }
137 }
138}
139#[derive(Debug, Clone)]
141pub struct JavaModule {
142 pub package: std::string::String,
143 pub imports: Vec<std::string::String>,
144 pub classes: Vec<JavaClass>,
145 pub interfaces: Vec<SealedInterface>,
146 pub records: Vec<JavaRecord>,
147 pub enums: Vec<JavaEnum>,
148}
149impl JavaModule {
150 pub fn new(package: &str) -> Self {
152 JavaModule {
153 package: package.to_string(),
154 imports: Vec::new(),
155 classes: Vec::new(),
156 interfaces: Vec::new(),
157 records: Vec::new(),
158 enums: Vec::new(),
159 }
160 }
161 pub fn emit(&self) -> std::string::String {
163 let mut out = std::string::String::new();
164 if !self.package.is_empty() {
165 out.push_str(&format!("package {};\n\n", self.package));
166 }
167 for imp in &self.imports {
168 out.push_str(&format!("import {};\n", imp));
169 }
170 if !self.imports.is_empty() {
171 out.push('\n');
172 }
173 for iface in &self.interfaces {
174 emit_sealed_interface(&mut out, iface, 0);
175 out.push('\n');
176 }
177 for rec in &self.records {
178 emit_record(&mut out, rec, 0);
179 out.push('\n');
180 }
181 for en in &self.enums {
182 emit_enum(&mut out, en, 0);
183 out.push('\n');
184 }
185 for cls in &self.classes {
186 emit_class(&mut out, cls, 0);
187 out.push('\n');
188 }
189 out
190 }
191}
192pub struct JavaBackend {
194 pub(super) var_counter: u64,
195}
196impl JavaBackend {
197 pub fn new() -> Self {
199 JavaBackend { var_counter: 0 }
200 }
201 pub fn mangle_name(&self, name: &str) -> std::string::String {
203 let sanitized: std::string::String = name
204 .chars()
205 .map(|c| match c {
206 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => c,
207 '.' | ':' | '\'' | '!' | '?' | '@' => '_',
208 _ => '_',
209 })
210 .collect();
211 let sanitized = if sanitized.starts_with(|c: char| c.is_ascii_digit()) {
212 format!("_{}", sanitized)
213 } else {
214 sanitized
215 };
216 if JAVA_KEYWORDS.contains(&sanitized.as_str()) {
217 format!("{}_", sanitized)
218 } else if sanitized.is_empty() {
219 "_anon".to_string()
220 } else {
221 sanitized
222 }
223 }
224 pub fn fresh_var(&mut self) -> std::string::String {
226 let v = self.var_counter;
227 self.var_counter += 1;
228 format!("_t{}", v)
229 }
230 pub fn emit_module(decls: &[LcnfFunDecl]) -> Result<std::string::String, std::string::String> {
232 let mut backend = JavaBackend::new();
233 let mut methods = Vec::new();
234 let mut ctor_names: HashSet<std::string::String> = HashSet::new();
235 for decl in decls {
236 collect_ctor_names_from_expr(&decl.body, &mut ctor_names);
237 }
238 let mut fun_class = JavaClass::new("OxiLeanGenerated");
239 fun_class
240 .annotations
241 .push("@SuppressWarnings(\"all\")".to_string());
242 for decl in decls {
243 let m = backend.compile_decl(decl)?;
244 methods.push(m);
245 }
246 fun_class.methods = methods;
247 let mut records: Vec<JavaRecord> = ctor_names
248 .into_iter()
249 .collect::<Vec<_>>()
250 .into_iter()
251 .map(|name| {
252 let mangled = backend.mangle_name(&name);
253 JavaRecord {
254 name: mangled,
255 components: vec![("tag".to_string(), JavaType::Int)],
256 methods: Vec::new(),
257 is_sealed: false,
258 implements: Vec::new(),
259 annotations: Vec::new(),
260 }
261 })
262 .collect();
263 records.sort_by(|a, b| a.name.cmp(&b.name));
264 let mut module = JavaModule::new("oxilean.generated");
265 module.imports = vec![
266 "java.util.List".to_string(),
267 "java.util.Map".to_string(),
268 "java.util.Optional".to_string(),
269 "java.util.function.Function".to_string(),
270 "java.util.function.Supplier".to_string(),
271 "java.util.stream.Collectors".to_string(),
272 ];
273 module.records = records;
274 module.classes = vec![fun_class];
275 Ok(module.emit())
276 }
277 pub fn compile_decl(&mut self, decl: &LcnfFunDecl) -> Result<JavaMethod, std::string::String> {
279 let name = self.mangle_name(&decl.name.to_string());
280 let params: Vec<(std::string::String, JavaType)> = decl
281 .params
282 .iter()
283 .map(|p| (self.mangle_name(&p.name), lcnf_type_to_java(&p.ty)))
284 .collect();
285 let return_type = lcnf_type_to_java(&decl.ret_type);
286 let mut body: Vec<JavaStmt> = Vec::new();
287 let result_expr = self.compile_expr(&decl.body, &mut body)?;
288 match &return_type {
289 JavaType::Void => {
290 body.push(JavaStmt::Expr(result_expr));
291 }
292 _ => {
293 body.push(JavaStmt::Return(Some(result_expr)));
294 }
295 }
296 let mut method = JavaMethod {
297 name,
298 return_type,
299 params: params.into_iter().collect(),
300 body,
301 visibility: Visibility::Public,
302 is_static: true,
303 is_final: false,
304 is_abstract: false,
305 annotations: Vec::new(),
306 throws: Vec::new(),
307 };
308 method
309 .annotations
310 .push("@SuppressWarnings(\"unchecked\")".to_string());
311 Ok(method)
312 }
313 pub fn compile_expr(
315 &mut self,
316 expr: &LcnfExpr,
317 stmts: &mut Vec<JavaStmt>,
318 ) -> Result<JavaExpr, std::string::String> {
319 match expr {
320 LcnfExpr::Return(arg) => Ok(self.compile_arg(arg)),
321 LcnfExpr::Unreachable => Ok(JavaExpr::MethodCall(
322 Box::new(JavaExpr::Var("OxiLeanRuntime".to_string())),
323 "unreachable".to_string(),
324 vec![],
325 )),
326 LcnfExpr::TailCall(func, args) => {
327 let callee = self.compile_arg(func);
328 let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
329 Ok(JavaExpr::Call(Box::new(callee), java_args))
330 }
331 LcnfExpr::Let {
332 id: _,
333 name,
334 ty,
335 value,
336 body,
337 } => {
338 let java_val = self.compile_let_value(value)?;
339 let var_name = self.mangle_name(name);
340 let java_ty = lcnf_type_to_java(ty);
341 stmts.push(JavaStmt::LocalVar {
342 ty: Some(java_ty),
343 name: var_name.clone(),
344 init: Some(java_val),
345 is_final: true,
346 });
347 self.compile_expr(body, stmts)
348 }
349 LcnfExpr::Case {
350 scrutinee,
351 scrutinee_ty: _,
352 alts,
353 default,
354 } => {
355 let result_var = self.fresh_var();
356 let scrutinee_expr = JavaExpr::Var(format!("_x{}", scrutinee.0));
357 stmts.push(JavaStmt::LocalVar {
358 ty: Some(JavaType::Object),
359 name: result_var.clone(),
360 init: Some(JavaExpr::Null),
361 is_final: false,
362 });
363 let mut cases: Vec<(JavaExpr, Vec<JavaStmt>)> = Vec::new();
364 for alt in alts {
365 let mut branch_stmts: Vec<JavaStmt> = Vec::new();
366 for (idx, param) in alt.params.iter().enumerate() {
367 let param_name = self.mangle_name(¶m.name);
368 let field_access = JavaExpr::FieldAccess(
369 Box::new(JavaExpr::Var(format!("_x{}", scrutinee.0))),
370 format!("field{}", idx),
371 );
372 branch_stmts.push(JavaStmt::LocalVar {
373 ty: Some(lcnf_type_to_java(¶m.ty)),
374 name: param_name,
375 init: Some(field_access),
376 is_final: true,
377 });
378 }
379 let branch_result = self.compile_expr(&alt.body, &mut branch_stmts)?;
380 branch_stmts.push(JavaStmt::Expr(JavaExpr::BinOp(
381 "=".to_string(),
382 Box::new(JavaExpr::Var(result_var.clone())),
383 Box::new(branch_result),
384 )));
385 branch_stmts.push(JavaStmt::Break(None));
386 let tag_label = JavaExpr::Lit(JavaLit::Int(alt.ctor_tag as i64));
387 cases.push((tag_label, branch_stmts));
388 }
389 let mut default_stmts: Vec<JavaStmt> = Vec::new();
390 if let Some(def) = default {
391 let def_result = self.compile_expr(def, &mut default_stmts)?;
392 default_stmts.push(JavaStmt::Expr(JavaExpr::BinOp(
393 "=".to_string(),
394 Box::new(JavaExpr::Var(result_var.clone())),
395 Box::new(def_result),
396 )));
397 } else {
398 default_stmts.push(JavaStmt::Throw(JavaExpr::New(
399 "IllegalStateException".to_string(),
400 vec![JavaExpr::Lit(JavaLit::Str(
401 "OxiLean: unreachable".to_string(),
402 ))],
403 )));
404 }
405 let discriminant =
406 JavaExpr::FieldAccess(Box::new(scrutinee_expr), "tag".to_string());
407 stmts.push(JavaStmt::Switch {
408 scrutinee: discriminant,
409 cases,
410 default: default_stmts,
411 });
412 Ok(JavaExpr::Var(result_var))
413 }
414 }
415 }
416 pub(super) fn compile_let_value(
418 &mut self,
419 value: &LcnfLetValue,
420 ) -> Result<JavaExpr, std::string::String> {
421 match value {
422 LcnfLetValue::Lit(lit) => Ok(self.compile_lit(lit)),
423 LcnfLetValue::Erased => Ok(JavaExpr::Null),
424 LcnfLetValue::FVar(id) => Ok(JavaExpr::Var(format!("_x{}", id.0))),
425 LcnfLetValue::App(func, args) => {
426 let callee = self.compile_arg(func);
427 let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
428 Ok(JavaExpr::Call(Box::new(callee), java_args))
429 }
430 LcnfLetValue::Proj(_name, idx, var) => {
431 let base = JavaExpr::Var(format!("_x{}", var.0));
432 Ok(JavaExpr::FieldAccess(
433 Box::new(base),
434 format!("field{}", idx),
435 ))
436 }
437 LcnfLetValue::Ctor(name, _tag, args) => {
438 let ctor_name = self.mangle_name(name);
439 let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
440 Ok(JavaExpr::New(ctor_name, java_args))
441 }
442 LcnfLetValue::Reset(_var) => Ok(JavaExpr::Null),
443 LcnfLetValue::Reuse(_slot, name, _tag, args) => {
444 let ctor_name = self.mangle_name(name);
445 let java_args: Vec<JavaExpr> = args.iter().map(|a| self.compile_arg(a)).collect();
446 Ok(JavaExpr::New(ctor_name, java_args))
447 }
448 }
449 }
450 pub(super) fn compile_arg(&self, arg: &LcnfArg) -> JavaExpr {
452 match arg {
453 LcnfArg::Var(id) => JavaExpr::Var(format!("_x{}", id.0)),
454 LcnfArg::Lit(lit) => self.compile_lit(lit),
455 LcnfArg::Erased => JavaExpr::Null,
456 LcnfArg::Type(_) => JavaExpr::Null,
457 }
458 }
459 pub(super) fn compile_lit(&self, lit: &LcnfLit) -> JavaExpr {
461 match lit {
462 LcnfLit::Nat(n) => JavaExpr::Lit(JavaLit::Long(*n as i64)),
463 LcnfLit::Str(s) => JavaExpr::Lit(JavaLit::Str(s.clone())),
464 }
465 }
466}
467#[derive(Debug, Clone, PartialEq)]
469pub enum JavaStmt {
470 Expr(JavaExpr),
472 LocalVar {
474 ty: Option<JavaType>,
475 name: std::string::String,
476 init: Option<JavaExpr>,
477 is_final: bool,
478 },
479 If(JavaExpr, Vec<JavaStmt>, Vec<JavaStmt>),
481 Switch {
483 scrutinee: JavaExpr,
484 cases: Vec<(JavaExpr, Vec<JavaStmt>)>,
485 default: Vec<JavaStmt>,
486 },
487 For {
489 init: Option<Box<JavaStmt>>,
490 cond: Option<JavaExpr>,
491 update: Option<JavaExpr>,
492 body: Vec<JavaStmt>,
493 },
494 ForEach {
496 ty: JavaType,
497 elem: std::string::String,
498 iterable: JavaExpr,
499 body: Vec<JavaStmt>,
500 },
501 While(JavaExpr, Vec<JavaStmt>),
503 DoWhile(Vec<JavaStmt>, JavaExpr),
505 Return(Option<JavaExpr>),
507 Throw(JavaExpr),
509 TryCatch {
511 body: Vec<JavaStmt>,
512 catches: Vec<JavaCatchClause>,
513 finally: Vec<JavaStmt>,
514 },
515 TryWithResources {
517 resources: Vec<(std::string::String, JavaExpr)>,
518 body: Vec<JavaStmt>,
519 catches: Vec<JavaCatchClause>,
520 finally: Vec<JavaStmt>,
521 },
522 Synchronized(JavaExpr, Vec<JavaStmt>),
524 Break(Option<std::string::String>),
526 Continue(Option<std::string::String>),
528 Assert(JavaExpr, Option<JavaExpr>),
530}
531#[derive(Debug, Clone, PartialEq, Eq)]
533pub enum ClassModifier {
534 Sealed,
535 Abstract,
536 Final,
537 Static,
538 NonSealed,
539}
540#[allow(dead_code)]
541#[derive(Debug, Clone, PartialEq)]
542pub enum JavaPassPhase {
543 Analysis,
544 Transformation,
545 Verification,
546 Cleanup,
547}
548impl JavaPassPhase {
549 #[allow(dead_code)]
550 pub fn name(&self) -> &str {
551 match self {
552 JavaPassPhase::Analysis => "analysis",
553 JavaPassPhase::Transformation => "transformation",
554 JavaPassPhase::Verification => "verification",
555 JavaPassPhase::Cleanup => "cleanup",
556 }
557 }
558 #[allow(dead_code)]
559 pub fn is_modifying(&self) -> bool {
560 matches!(self, JavaPassPhase::Transformation | JavaPassPhase::Cleanup)
561 }
562}
563#[allow(dead_code)]
564#[derive(Debug, Clone)]
565pub struct JavaPassConfig {
566 pub phase: JavaPassPhase,
567 pub enabled: bool,
568 pub max_iterations: u32,
569 pub debug_output: bool,
570 pub pass_name: String,
571}
572impl JavaPassConfig {
573 #[allow(dead_code)]
574 pub fn new(name: impl Into<String>, phase: JavaPassPhase) -> Self {
575 JavaPassConfig {
576 phase,
577 enabled: true,
578 max_iterations: 10,
579 debug_output: false,
580 pass_name: name.into(),
581 }
582 }
583 #[allow(dead_code)]
584 pub fn disabled(mut self) -> Self {
585 self.enabled = false;
586 self
587 }
588 #[allow(dead_code)]
589 pub fn with_debug(mut self) -> Self {
590 self.debug_output = true;
591 self
592 }
593 #[allow(dead_code)]
594 pub fn max_iter(mut self, n: u32) -> Self {
595 self.max_iterations = n;
596 self
597 }
598}
599#[derive(Debug, Clone, PartialEq, Eq)]
601pub enum Visibility {
602 Public,
603 Protected,
604 Private,
605 Package,
607}
608#[derive(Debug, Clone)]
610pub struct JavaEnumConstant {
611 pub name: std::string::String,
612 pub args: Vec<JavaExpr>,
613 pub annotations: Vec<std::string::String>,
614}
615#[allow(dead_code)]
616#[derive(Debug, Clone)]
617pub struct JavaDepGraph {
618 pub(super) nodes: Vec<u32>,
619 pub(super) edges: Vec<(u32, u32)>,
620}
621impl JavaDepGraph {
622 #[allow(dead_code)]
623 pub fn new() -> Self {
624 JavaDepGraph {
625 nodes: Vec::new(),
626 edges: Vec::new(),
627 }
628 }
629 #[allow(dead_code)]
630 pub fn add_node(&mut self, id: u32) {
631 if !self.nodes.contains(&id) {
632 self.nodes.push(id);
633 }
634 }
635 #[allow(dead_code)]
636 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
637 self.add_node(dep);
638 self.add_node(dependent);
639 self.edges.push((dep, dependent));
640 }
641 #[allow(dead_code)]
642 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
643 self.edges
644 .iter()
645 .filter(|(d, _)| *d == node)
646 .map(|(_, dep)| *dep)
647 .collect()
648 }
649 #[allow(dead_code)]
650 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
651 self.edges
652 .iter()
653 .filter(|(_, dep)| *dep == node)
654 .map(|(d, _)| *d)
655 .collect()
656 }
657 #[allow(dead_code)]
658 pub fn topological_sort(&self) -> Vec<u32> {
659 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
660 for &n in &self.nodes {
661 in_degree.insert(n, 0);
662 }
663 for (_, dep) in &self.edges {
664 *in_degree.entry(*dep).or_insert(0) += 1;
665 }
666 let mut queue: std::collections::VecDeque<u32> = self
667 .nodes
668 .iter()
669 .filter(|&&n| in_degree[&n] == 0)
670 .copied()
671 .collect();
672 let mut result = Vec::new();
673 while let Some(node) = queue.pop_front() {
674 result.push(node);
675 for dep in self.dependents_of(node) {
676 let cnt = in_degree.entry(dep).or_insert(0);
677 *cnt = cnt.saturating_sub(1);
678 if *cnt == 0 {
679 queue.push_back(dep);
680 }
681 }
682 }
683 result
684 }
685 #[allow(dead_code)]
686 pub fn has_cycle(&self) -> bool {
687 self.topological_sort().len() < self.nodes.len()
688 }
689}
690#[allow(dead_code)]
691#[derive(Debug, Clone)]
692pub struct JavaCacheEntry {
693 pub key: String,
694 pub data: Vec<u8>,
695 pub timestamp: u64,
696 pub valid: bool,
697}
698#[derive(Debug, Clone, PartialEq)]
700pub struct JavaCatchClause {
701 pub exception_types: Vec<std::string::String>,
703 pub var_name: std::string::String,
705 pub body: Vec<JavaStmt>,
707}
708#[derive(Debug, Clone, PartialEq)]
710pub enum JavaExpr {
711 Lit(JavaLit),
713 Var(std::string::String),
715 BinOp(std::string::String, Box<JavaExpr>, Box<JavaExpr>),
717 UnaryOp(std::string::String, Box<JavaExpr>),
719 Call(Box<JavaExpr>, Vec<JavaExpr>),
721 MethodCall(Box<JavaExpr>, std::string::String, Vec<JavaExpr>),
723 New(std::string::String, Vec<JavaExpr>),
725 Cast(JavaType, Box<JavaExpr>),
727 Instanceof(Box<JavaExpr>, std::string::String),
729 Ternary(Box<JavaExpr>, Box<JavaExpr>, Box<JavaExpr>),
731 Null,
733 Lambda(Vec<std::string::String>, Box<JavaExpr>),
735 MethodRef(std::string::String, std::string::String),
737 ArrayAccess(Box<JavaExpr>, Box<JavaExpr>),
739 FieldAccess(Box<JavaExpr>, std::string::String),
741}
742#[derive(Debug, Clone)]
744pub struct JavaField {
745 pub name: std::string::String,
746 pub ty: JavaType,
747 pub init: Option<JavaExpr>,
748 pub visibility: Visibility,
749 pub is_static: bool,
750 pub is_final: bool,
751 pub annotations: Vec<std::string::String>,
752}
753#[derive(Debug, Clone)]
755pub struct JavaClass {
756 pub name: std::string::String,
757 pub superclass: Option<std::string::String>,
758 pub interfaces: Vec<std::string::String>,
759 pub fields: Vec<JavaField>,
760 pub methods: Vec<JavaMethod>,
761 pub inner_classes: Vec<JavaClass>,
762 pub modifiers: Vec<ClassModifier>,
763 pub annotations: Vec<std::string::String>,
764 pub type_params: Vec<std::string::String>,
765 pub visibility: Visibility,
766 pub permits: Vec<std::string::String>,
768}
769impl JavaClass {
770 pub fn new(name: &str) -> Self {
772 JavaClass {
773 name: name.to_string(),
774 superclass: None,
775 interfaces: Vec::new(),
776 fields: Vec::new(),
777 methods: Vec::new(),
778 inner_classes: Vec::new(),
779 modifiers: Vec::new(),
780 annotations: Vec::new(),
781 type_params: Vec::new(),
782 visibility: Visibility::Public,
783 permits: Vec::new(),
784 }
785 }
786}
787#[derive(Debug, Clone)]
789pub struct JavaEnum {
790 pub name: std::string::String,
791 pub constants: Vec<JavaEnumConstant>,
792 pub fields: Vec<JavaField>,
793 pub methods: Vec<JavaMethod>,
794 pub interfaces: Vec<std::string::String>,
795 pub visibility: Visibility,
796 pub annotations: Vec<std::string::String>,
797}
798impl JavaEnum {
799 pub fn new(name: &str, constants: Vec<&str>) -> Self {
801 JavaEnum {
802 name: name.to_string(),
803 constants: constants
804 .into_iter()
805 .map(|c| JavaEnumConstant {
806 name: c.to_string(),
807 args: Vec::new(),
808 annotations: Vec::new(),
809 })
810 .collect(),
811 fields: Vec::new(),
812 methods: Vec::new(),
813 interfaces: Vec::new(),
814 visibility: Visibility::Public,
815 annotations: Vec::new(),
816 }
817 }
818}
819#[allow(dead_code)]
820#[derive(Debug, Clone)]
821pub struct JavaDominatorTree {
822 pub idom: Vec<Option<u32>>,
823 pub dom_children: Vec<Vec<u32>>,
824 pub dom_depth: Vec<u32>,
825}
826impl JavaDominatorTree {
827 #[allow(dead_code)]
828 pub fn new(size: usize) -> Self {
829 JavaDominatorTree {
830 idom: vec![None; size],
831 dom_children: vec![Vec::new(); size],
832 dom_depth: vec![0; size],
833 }
834 }
835 #[allow(dead_code)]
836 pub fn set_idom(&mut self, node: usize, idom: u32) {
837 self.idom[node] = Some(idom);
838 }
839 #[allow(dead_code)]
840 pub fn dominates(&self, a: usize, b: usize) -> bool {
841 if a == b {
842 return true;
843 }
844 let mut cur = b;
845 loop {
846 match self.idom[cur] {
847 Some(parent) if parent as usize == a => return true,
848 Some(parent) if parent as usize == cur => return false,
849 Some(parent) => cur = parent as usize,
850 None => return false,
851 }
852 }
853 }
854 #[allow(dead_code)]
855 pub fn depth(&self, node: usize) -> u32 {
856 self.dom_depth.get(node).copied().unwrap_or(0)
857 }
858}
859#[allow(dead_code)]
860pub struct JavaPassRegistry {
861 pub(super) configs: Vec<JavaPassConfig>,
862 pub(super) stats: std::collections::HashMap<String, JavaPassStats>,
863}
864impl JavaPassRegistry {
865 #[allow(dead_code)]
866 pub fn new() -> Self {
867 JavaPassRegistry {
868 configs: Vec::new(),
869 stats: std::collections::HashMap::new(),
870 }
871 }
872 #[allow(dead_code)]
873 pub fn register(&mut self, config: JavaPassConfig) {
874 self.stats
875 .insert(config.pass_name.clone(), JavaPassStats::new());
876 self.configs.push(config);
877 }
878 #[allow(dead_code)]
879 pub fn enabled_passes(&self) -> Vec<&JavaPassConfig> {
880 self.configs.iter().filter(|c| c.enabled).collect()
881 }
882 #[allow(dead_code)]
883 pub fn get_stats(&self, name: &str) -> Option<&JavaPassStats> {
884 self.stats.get(name)
885 }
886 #[allow(dead_code)]
887 pub fn total_passes(&self) -> usize {
888 self.configs.len()
889 }
890 #[allow(dead_code)]
891 pub fn enabled_count(&self) -> usize {
892 self.enabled_passes().len()
893 }
894 #[allow(dead_code)]
895 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
896 if let Some(stats) = self.stats.get_mut(name) {
897 stats.record_run(changes, time_ms, iter);
898 }
899 }
900}
901#[allow(dead_code)]
902pub struct JavaConstantFoldingHelper;
903impl JavaConstantFoldingHelper {
904 #[allow(dead_code)]
905 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
906 a.checked_add(b)
907 }
908 #[allow(dead_code)]
909 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
910 a.checked_sub(b)
911 }
912 #[allow(dead_code)]
913 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
914 a.checked_mul(b)
915 }
916 #[allow(dead_code)]
917 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
918 if b == 0 {
919 None
920 } else {
921 a.checked_div(b)
922 }
923 }
924 #[allow(dead_code)]
925 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
926 a + b
927 }
928 #[allow(dead_code)]
929 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
930 a * b
931 }
932 #[allow(dead_code)]
933 pub fn fold_neg_i64(a: i64) -> Option<i64> {
934 a.checked_neg()
935 }
936 #[allow(dead_code)]
937 pub fn fold_not_bool(a: bool) -> bool {
938 !a
939 }
940 #[allow(dead_code)]
941 pub fn fold_and_bool(a: bool, b: bool) -> bool {
942 a && b
943 }
944 #[allow(dead_code)]
945 pub fn fold_or_bool(a: bool, b: bool) -> bool {
946 a || b
947 }
948 #[allow(dead_code)]
949 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
950 a.checked_shl(b)
951 }
952 #[allow(dead_code)]
953 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
954 a.checked_shr(b)
955 }
956 #[allow(dead_code)]
957 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
958 if b == 0 {
959 None
960 } else {
961 Some(a % b)
962 }
963 }
964 #[allow(dead_code)]
965 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
966 a & b
967 }
968 #[allow(dead_code)]
969 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
970 a | b
971 }
972 #[allow(dead_code)]
973 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
974 a ^ b
975 }
976 #[allow(dead_code)]
977 pub fn fold_bitnot_i64(a: i64) -> i64 {
978 !a
979 }
980}
981#[derive(Debug, Clone)]
987pub struct SealedInterface {
988 pub name: std::string::String,
989 pub permits: Vec<std::string::String>,
991 pub methods: Vec<JavaMethod>,
993 pub annotations: Vec<std::string::String>,
995 pub extends: Vec<std::string::String>,
997}
998impl SealedInterface {
999 pub fn new(name: &str, permits: Vec<&str>) -> Self {
1001 SealedInterface {
1002 name: name.to_string(),
1003 permits: permits.into_iter().map(|s| s.to_string()).collect(),
1004 methods: Vec::new(),
1005 annotations: Vec::new(),
1006 extends: Vec::new(),
1007 }
1008 }
1009}
1010#[derive(Debug, Clone)]
1016pub struct JavaRecord {
1017 pub name: std::string::String,
1018 pub components: Vec<(std::string::String, JavaType)>,
1020 pub methods: Vec<JavaMethod>,
1022 pub is_sealed: bool,
1024 pub implements: Vec<std::string::String>,
1026 pub annotations: Vec<std::string::String>,
1028}
1029impl JavaRecord {
1030 pub fn new(name: &str, components: Vec<(&str, JavaType)>) -> Self {
1032 JavaRecord {
1033 name: name.to_string(),
1034 components: components
1035 .into_iter()
1036 .map(|(n, t)| (n.to_string(), t))
1037 .collect(),
1038 methods: Vec::new(),
1039 is_sealed: false,
1040 implements: Vec::new(),
1041 annotations: Vec::new(),
1042 }
1043 }
1044}
1045#[allow(dead_code)]
1046#[derive(Debug, Clone)]
1047pub struct JavaAnalysisCache {
1048 pub(super) entries: std::collections::HashMap<String, JavaCacheEntry>,
1049 pub(super) max_size: usize,
1050 pub(super) hits: u64,
1051 pub(super) misses: u64,
1052}
1053impl JavaAnalysisCache {
1054 #[allow(dead_code)]
1055 pub fn new(max_size: usize) -> Self {
1056 JavaAnalysisCache {
1057 entries: std::collections::HashMap::new(),
1058 max_size,
1059 hits: 0,
1060 misses: 0,
1061 }
1062 }
1063 #[allow(dead_code)]
1064 pub fn get(&mut self, key: &str) -> Option<&JavaCacheEntry> {
1065 if self.entries.contains_key(key) {
1066 self.hits += 1;
1067 self.entries.get(key)
1068 } else {
1069 self.misses += 1;
1070 None
1071 }
1072 }
1073 #[allow(dead_code)]
1074 pub fn insert(&mut self, key: String, data: Vec<u8>) {
1075 if self.entries.len() >= self.max_size {
1076 if let Some(oldest) = self.entries.keys().next().cloned() {
1077 self.entries.remove(&oldest);
1078 }
1079 }
1080 self.entries.insert(
1081 key.clone(),
1082 JavaCacheEntry {
1083 key,
1084 data,
1085 timestamp: 0,
1086 valid: true,
1087 },
1088 );
1089 }
1090 #[allow(dead_code)]
1091 pub fn invalidate(&mut self, key: &str) {
1092 if let Some(entry) = self.entries.get_mut(key) {
1093 entry.valid = false;
1094 }
1095 }
1096 #[allow(dead_code)]
1097 pub fn clear(&mut self) {
1098 self.entries.clear();
1099 }
1100 #[allow(dead_code)]
1101 pub fn hit_rate(&self) -> f64 {
1102 let total = self.hits + self.misses;
1103 if total == 0 {
1104 return 0.0;
1105 }
1106 self.hits as f64 / total as f64
1107 }
1108 #[allow(dead_code)]
1109 pub fn size(&self) -> usize {
1110 self.entries.len()
1111 }
1112}
1113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1115pub enum JavaType {
1116 Int,
1118 Long,
1120 Double,
1122 Float,
1124 Boolean,
1126 Char,
1128 Byte,
1130 Short,
1132 Void,
1134 String,
1136 Object,
1138 Array(Box<JavaType>),
1140 List(Box<JavaType>),
1142 Map(Box<JavaType>, Box<JavaType>),
1144 Optional(Box<JavaType>),
1146 Custom(std::string::String),
1148 Generic(std::string::String, Vec<JavaType>),
1150}
1151#[derive(Debug, Clone, PartialEq)]
1153pub enum JavaLit {
1154 Int(i64),
1156 Long(i64),
1158 Double(f64),
1160 Float(f64),
1162 Bool(bool),
1164 Char(char),
1166 Str(std::string::String),
1168 Null,
1170}
1171#[allow(dead_code)]
1172#[derive(Debug, Clone)]
1173pub struct JavaLivenessInfo {
1174 pub live_in: Vec<std::collections::HashSet<u32>>,
1175 pub live_out: Vec<std::collections::HashSet<u32>>,
1176 pub defs: Vec<std::collections::HashSet<u32>>,
1177 pub uses: Vec<std::collections::HashSet<u32>>,
1178}
1179impl JavaLivenessInfo {
1180 #[allow(dead_code)]
1181 pub fn new(block_count: usize) -> Self {
1182 JavaLivenessInfo {
1183 live_in: vec![std::collections::HashSet::new(); block_count],
1184 live_out: vec![std::collections::HashSet::new(); block_count],
1185 defs: vec![std::collections::HashSet::new(); block_count],
1186 uses: vec![std::collections::HashSet::new(); block_count],
1187 }
1188 }
1189 #[allow(dead_code)]
1190 pub fn add_def(&mut self, block: usize, var: u32) {
1191 if block < self.defs.len() {
1192 self.defs[block].insert(var);
1193 }
1194 }
1195 #[allow(dead_code)]
1196 pub fn add_use(&mut self, block: usize, var: u32) {
1197 if block < self.uses.len() {
1198 self.uses[block].insert(var);
1199 }
1200 }
1201 #[allow(dead_code)]
1202 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1203 self.live_in
1204 .get(block)
1205 .map(|s| s.contains(&var))
1206 .unwrap_or(false)
1207 }
1208 #[allow(dead_code)]
1209 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1210 self.live_out
1211 .get(block)
1212 .map(|s| s.contains(&var))
1213 .unwrap_or(false)
1214 }
1215}