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::Int(i) => JavaExpr::Lit(JavaLit::Long(*i)),
464 LcnfLit::Str(s) => JavaExpr::Lit(JavaLit::Str(s.clone())),
465 }
466 }
467}
468#[derive(Debug, Clone, PartialEq)]
470pub enum JavaStmt {
471 Expr(JavaExpr),
473 LocalVar {
475 ty: Option<JavaType>,
476 name: std::string::String,
477 init: Option<JavaExpr>,
478 is_final: bool,
479 },
480 If(JavaExpr, Vec<JavaStmt>, Vec<JavaStmt>),
482 Switch {
484 scrutinee: JavaExpr,
485 cases: Vec<(JavaExpr, Vec<JavaStmt>)>,
486 default: Vec<JavaStmt>,
487 },
488 For {
490 init: Option<Box<JavaStmt>>,
491 cond: Option<JavaExpr>,
492 update: Option<JavaExpr>,
493 body: Vec<JavaStmt>,
494 },
495 ForEach {
497 ty: JavaType,
498 elem: std::string::String,
499 iterable: JavaExpr,
500 body: Vec<JavaStmt>,
501 },
502 While(JavaExpr, Vec<JavaStmt>),
504 DoWhile(Vec<JavaStmt>, JavaExpr),
506 Return(Option<JavaExpr>),
508 Throw(JavaExpr),
510 TryCatch {
512 body: Vec<JavaStmt>,
513 catches: Vec<JavaCatchClause>,
514 finally: Vec<JavaStmt>,
515 },
516 TryWithResources {
518 resources: Vec<(std::string::String, JavaExpr)>,
519 body: Vec<JavaStmt>,
520 catches: Vec<JavaCatchClause>,
521 finally: Vec<JavaStmt>,
522 },
523 Synchronized(JavaExpr, Vec<JavaStmt>),
525 Break(Option<std::string::String>),
527 Continue(Option<std::string::String>),
529 Assert(JavaExpr, Option<JavaExpr>),
531}
532#[derive(Debug, Clone, PartialEq, Eq)]
534pub enum ClassModifier {
535 Sealed,
536 Abstract,
537 Final,
538 Static,
539 NonSealed,
540}
541#[allow(dead_code)]
542#[derive(Debug, Clone, PartialEq)]
543pub enum JavaPassPhase {
544 Analysis,
545 Transformation,
546 Verification,
547 Cleanup,
548}
549impl JavaPassPhase {
550 #[allow(dead_code)]
551 pub fn name(&self) -> &str {
552 match self {
553 JavaPassPhase::Analysis => "analysis",
554 JavaPassPhase::Transformation => "transformation",
555 JavaPassPhase::Verification => "verification",
556 JavaPassPhase::Cleanup => "cleanup",
557 }
558 }
559 #[allow(dead_code)]
560 pub fn is_modifying(&self) -> bool {
561 matches!(self, JavaPassPhase::Transformation | JavaPassPhase::Cleanup)
562 }
563}
564#[allow(dead_code)]
565#[derive(Debug, Clone)]
566pub struct JavaPassConfig {
567 pub phase: JavaPassPhase,
568 pub enabled: bool,
569 pub max_iterations: u32,
570 pub debug_output: bool,
571 pub pass_name: String,
572}
573impl JavaPassConfig {
574 #[allow(dead_code)]
575 pub fn new(name: impl Into<String>, phase: JavaPassPhase) -> Self {
576 JavaPassConfig {
577 phase,
578 enabled: true,
579 max_iterations: 10,
580 debug_output: false,
581 pass_name: name.into(),
582 }
583 }
584 #[allow(dead_code)]
585 pub fn disabled(mut self) -> Self {
586 self.enabled = false;
587 self
588 }
589 #[allow(dead_code)]
590 pub fn with_debug(mut self) -> Self {
591 self.debug_output = true;
592 self
593 }
594 #[allow(dead_code)]
595 pub fn max_iter(mut self, n: u32) -> Self {
596 self.max_iterations = n;
597 self
598 }
599}
600#[derive(Debug, Clone, PartialEq, Eq)]
602pub enum Visibility {
603 Public,
604 Protected,
605 Private,
606 Package,
608}
609#[derive(Debug, Clone)]
611pub struct JavaEnumConstant {
612 pub name: std::string::String,
613 pub args: Vec<JavaExpr>,
614 pub annotations: Vec<std::string::String>,
615}
616#[allow(dead_code)]
617#[derive(Debug, Clone)]
618pub struct JavaDepGraph {
619 pub(super) nodes: Vec<u32>,
620 pub(super) edges: Vec<(u32, u32)>,
621}
622impl JavaDepGraph {
623 #[allow(dead_code)]
624 pub fn new() -> Self {
625 JavaDepGraph {
626 nodes: Vec::new(),
627 edges: Vec::new(),
628 }
629 }
630 #[allow(dead_code)]
631 pub fn add_node(&mut self, id: u32) {
632 if !self.nodes.contains(&id) {
633 self.nodes.push(id);
634 }
635 }
636 #[allow(dead_code)]
637 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
638 self.add_node(dep);
639 self.add_node(dependent);
640 self.edges.push((dep, dependent));
641 }
642 #[allow(dead_code)]
643 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
644 self.edges
645 .iter()
646 .filter(|(d, _)| *d == node)
647 .map(|(_, dep)| *dep)
648 .collect()
649 }
650 #[allow(dead_code)]
651 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
652 self.edges
653 .iter()
654 .filter(|(_, dep)| *dep == node)
655 .map(|(d, _)| *d)
656 .collect()
657 }
658 #[allow(dead_code)]
659 pub fn topological_sort(&self) -> Vec<u32> {
660 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
661 for &n in &self.nodes {
662 in_degree.insert(n, 0);
663 }
664 for (_, dep) in &self.edges {
665 *in_degree.entry(*dep).or_insert(0) += 1;
666 }
667 let mut queue: std::collections::VecDeque<u32> = self
668 .nodes
669 .iter()
670 .filter(|&&n| in_degree[&n] == 0)
671 .copied()
672 .collect();
673 let mut result = Vec::new();
674 while let Some(node) = queue.pop_front() {
675 result.push(node);
676 for dep in self.dependents_of(node) {
677 let cnt = in_degree.entry(dep).or_insert(0);
678 *cnt = cnt.saturating_sub(1);
679 if *cnt == 0 {
680 queue.push_back(dep);
681 }
682 }
683 }
684 result
685 }
686 #[allow(dead_code)]
687 pub fn has_cycle(&self) -> bool {
688 self.topological_sort().len() < self.nodes.len()
689 }
690}
691#[allow(dead_code)]
692#[derive(Debug, Clone)]
693pub struct JavaCacheEntry {
694 pub key: String,
695 pub data: Vec<u8>,
696 pub timestamp: u64,
697 pub valid: bool,
698}
699#[derive(Debug, Clone, PartialEq)]
701pub struct JavaCatchClause {
702 pub exception_types: Vec<std::string::String>,
704 pub var_name: std::string::String,
706 pub body: Vec<JavaStmt>,
708}
709#[derive(Debug, Clone, PartialEq)]
711pub enum JavaExpr {
712 Lit(JavaLit),
714 Var(std::string::String),
716 BinOp(std::string::String, Box<JavaExpr>, Box<JavaExpr>),
718 UnaryOp(std::string::String, Box<JavaExpr>),
720 Call(Box<JavaExpr>, Vec<JavaExpr>),
722 MethodCall(Box<JavaExpr>, std::string::String, Vec<JavaExpr>),
724 New(std::string::String, Vec<JavaExpr>),
726 Cast(JavaType, Box<JavaExpr>),
728 Instanceof(Box<JavaExpr>, std::string::String),
730 Ternary(Box<JavaExpr>, Box<JavaExpr>, Box<JavaExpr>),
732 Null,
734 Lambda(Vec<std::string::String>, Box<JavaExpr>),
736 MethodRef(std::string::String, std::string::String),
738 ArrayAccess(Box<JavaExpr>, Box<JavaExpr>),
740 FieldAccess(Box<JavaExpr>, std::string::String),
742}
743#[derive(Debug, Clone)]
745pub struct JavaField {
746 pub name: std::string::String,
747 pub ty: JavaType,
748 pub init: Option<JavaExpr>,
749 pub visibility: Visibility,
750 pub is_static: bool,
751 pub is_final: bool,
752 pub annotations: Vec<std::string::String>,
753}
754#[derive(Debug, Clone)]
756pub struct JavaClass {
757 pub name: std::string::String,
758 pub superclass: Option<std::string::String>,
759 pub interfaces: Vec<std::string::String>,
760 pub fields: Vec<JavaField>,
761 pub methods: Vec<JavaMethod>,
762 pub inner_classes: Vec<JavaClass>,
763 pub modifiers: Vec<ClassModifier>,
764 pub annotations: Vec<std::string::String>,
765 pub type_params: Vec<std::string::String>,
766 pub visibility: Visibility,
767 pub permits: Vec<std::string::String>,
769}
770impl JavaClass {
771 pub fn new(name: &str) -> Self {
773 JavaClass {
774 name: name.to_string(),
775 superclass: None,
776 interfaces: Vec::new(),
777 fields: Vec::new(),
778 methods: Vec::new(),
779 inner_classes: Vec::new(),
780 modifiers: Vec::new(),
781 annotations: Vec::new(),
782 type_params: Vec::new(),
783 visibility: Visibility::Public,
784 permits: Vec::new(),
785 }
786 }
787}
788#[derive(Debug, Clone)]
790pub struct JavaEnum {
791 pub name: std::string::String,
792 pub constants: Vec<JavaEnumConstant>,
793 pub fields: Vec<JavaField>,
794 pub methods: Vec<JavaMethod>,
795 pub interfaces: Vec<std::string::String>,
796 pub visibility: Visibility,
797 pub annotations: Vec<std::string::String>,
798}
799impl JavaEnum {
800 pub fn new(name: &str, constants: Vec<&str>) -> Self {
802 JavaEnum {
803 name: name.to_string(),
804 constants: constants
805 .into_iter()
806 .map(|c| JavaEnumConstant {
807 name: c.to_string(),
808 args: Vec::new(),
809 annotations: Vec::new(),
810 })
811 .collect(),
812 fields: Vec::new(),
813 methods: Vec::new(),
814 interfaces: Vec::new(),
815 visibility: Visibility::Public,
816 annotations: Vec::new(),
817 }
818 }
819}
820#[allow(dead_code)]
821#[derive(Debug, Clone)]
822pub struct JavaDominatorTree {
823 pub idom: Vec<Option<u32>>,
824 pub dom_children: Vec<Vec<u32>>,
825 pub dom_depth: Vec<u32>,
826}
827impl JavaDominatorTree {
828 #[allow(dead_code)]
829 pub fn new(size: usize) -> Self {
830 JavaDominatorTree {
831 idom: vec![None; size],
832 dom_children: vec![Vec::new(); size],
833 dom_depth: vec![0; size],
834 }
835 }
836 #[allow(dead_code)]
837 pub fn set_idom(&mut self, node: usize, idom: u32) {
838 self.idom[node] = Some(idom);
839 }
840 #[allow(dead_code)]
841 pub fn dominates(&self, a: usize, b: usize) -> bool {
842 if a == b {
843 return true;
844 }
845 let mut cur = b;
846 loop {
847 match self.idom[cur] {
848 Some(parent) if parent as usize == a => return true,
849 Some(parent) if parent as usize == cur => return false,
850 Some(parent) => cur = parent as usize,
851 None => return false,
852 }
853 }
854 }
855 #[allow(dead_code)]
856 pub fn depth(&self, node: usize) -> u32 {
857 self.dom_depth.get(node).copied().unwrap_or(0)
858 }
859}
860#[allow(dead_code)]
861pub struct JavaPassRegistry {
862 pub(super) configs: Vec<JavaPassConfig>,
863 pub(super) stats: std::collections::HashMap<String, JavaPassStats>,
864}
865impl JavaPassRegistry {
866 #[allow(dead_code)]
867 pub fn new() -> Self {
868 JavaPassRegistry {
869 configs: Vec::new(),
870 stats: std::collections::HashMap::new(),
871 }
872 }
873 #[allow(dead_code)]
874 pub fn register(&mut self, config: JavaPassConfig) {
875 self.stats
876 .insert(config.pass_name.clone(), JavaPassStats::new());
877 self.configs.push(config);
878 }
879 #[allow(dead_code)]
880 pub fn enabled_passes(&self) -> Vec<&JavaPassConfig> {
881 self.configs.iter().filter(|c| c.enabled).collect()
882 }
883 #[allow(dead_code)]
884 pub fn get_stats(&self, name: &str) -> Option<&JavaPassStats> {
885 self.stats.get(name)
886 }
887 #[allow(dead_code)]
888 pub fn total_passes(&self) -> usize {
889 self.configs.len()
890 }
891 #[allow(dead_code)]
892 pub fn enabled_count(&self) -> usize {
893 self.enabled_passes().len()
894 }
895 #[allow(dead_code)]
896 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
897 if let Some(stats) = self.stats.get_mut(name) {
898 stats.record_run(changes, time_ms, iter);
899 }
900 }
901}
902#[allow(dead_code)]
903pub struct JavaConstantFoldingHelper;
904impl JavaConstantFoldingHelper {
905 #[allow(dead_code)]
906 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
907 a.checked_add(b)
908 }
909 #[allow(dead_code)]
910 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
911 a.checked_sub(b)
912 }
913 #[allow(dead_code)]
914 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
915 a.checked_mul(b)
916 }
917 #[allow(dead_code)]
918 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
919 if b == 0 {
920 None
921 } else {
922 a.checked_div(b)
923 }
924 }
925 #[allow(dead_code)]
926 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
927 a + b
928 }
929 #[allow(dead_code)]
930 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
931 a * b
932 }
933 #[allow(dead_code)]
934 pub fn fold_neg_i64(a: i64) -> Option<i64> {
935 a.checked_neg()
936 }
937 #[allow(dead_code)]
938 pub fn fold_not_bool(a: bool) -> bool {
939 !a
940 }
941 #[allow(dead_code)]
942 pub fn fold_and_bool(a: bool, b: bool) -> bool {
943 a && b
944 }
945 #[allow(dead_code)]
946 pub fn fold_or_bool(a: bool, b: bool) -> bool {
947 a || b
948 }
949 #[allow(dead_code)]
950 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
951 a.checked_shl(b)
952 }
953 #[allow(dead_code)]
954 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
955 a.checked_shr(b)
956 }
957 #[allow(dead_code)]
958 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
959 if b == 0 {
960 None
961 } else {
962 Some(a % b)
963 }
964 }
965 #[allow(dead_code)]
966 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
967 a & b
968 }
969 #[allow(dead_code)]
970 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
971 a | b
972 }
973 #[allow(dead_code)]
974 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
975 a ^ b
976 }
977 #[allow(dead_code)]
978 pub fn fold_bitnot_i64(a: i64) -> i64 {
979 !a
980 }
981}
982#[derive(Debug, Clone)]
988pub struct SealedInterface {
989 pub name: std::string::String,
990 pub permits: Vec<std::string::String>,
992 pub methods: Vec<JavaMethod>,
994 pub annotations: Vec<std::string::String>,
996 pub extends: Vec<std::string::String>,
998}
999impl SealedInterface {
1000 pub fn new(name: &str, permits: Vec<&str>) -> Self {
1002 SealedInterface {
1003 name: name.to_string(),
1004 permits: permits.into_iter().map(|s| s.to_string()).collect(),
1005 methods: Vec::new(),
1006 annotations: Vec::new(),
1007 extends: Vec::new(),
1008 }
1009 }
1010}
1011#[derive(Debug, Clone)]
1017pub struct JavaRecord {
1018 pub name: std::string::String,
1019 pub components: Vec<(std::string::String, JavaType)>,
1021 pub methods: Vec<JavaMethod>,
1023 pub is_sealed: bool,
1025 pub implements: Vec<std::string::String>,
1027 pub annotations: Vec<std::string::String>,
1029}
1030impl JavaRecord {
1031 pub fn new(name: &str, components: Vec<(&str, JavaType)>) -> Self {
1033 JavaRecord {
1034 name: name.to_string(),
1035 components: components
1036 .into_iter()
1037 .map(|(n, t)| (n.to_string(), t))
1038 .collect(),
1039 methods: Vec::new(),
1040 is_sealed: false,
1041 implements: Vec::new(),
1042 annotations: Vec::new(),
1043 }
1044 }
1045}
1046#[allow(dead_code)]
1047#[derive(Debug, Clone)]
1048pub struct JavaAnalysisCache {
1049 pub(super) entries: std::collections::HashMap<String, JavaCacheEntry>,
1050 pub(super) max_size: usize,
1051 pub(super) hits: u64,
1052 pub(super) misses: u64,
1053}
1054impl JavaAnalysisCache {
1055 #[allow(dead_code)]
1056 pub fn new(max_size: usize) -> Self {
1057 JavaAnalysisCache {
1058 entries: std::collections::HashMap::new(),
1059 max_size,
1060 hits: 0,
1061 misses: 0,
1062 }
1063 }
1064 #[allow(dead_code)]
1065 pub fn get(&mut self, key: &str) -> Option<&JavaCacheEntry> {
1066 if self.entries.contains_key(key) {
1067 self.hits += 1;
1068 self.entries.get(key)
1069 } else {
1070 self.misses += 1;
1071 None
1072 }
1073 }
1074 #[allow(dead_code)]
1075 pub fn insert(&mut self, key: String, data: Vec<u8>) {
1076 if self.entries.len() >= self.max_size {
1077 if let Some(oldest) = self.entries.keys().next().cloned() {
1078 self.entries.remove(&oldest);
1079 }
1080 }
1081 self.entries.insert(
1082 key.clone(),
1083 JavaCacheEntry {
1084 key,
1085 data,
1086 timestamp: 0,
1087 valid: true,
1088 },
1089 );
1090 }
1091 #[allow(dead_code)]
1092 pub fn invalidate(&mut self, key: &str) {
1093 if let Some(entry) = self.entries.get_mut(key) {
1094 entry.valid = false;
1095 }
1096 }
1097 #[allow(dead_code)]
1098 pub fn clear(&mut self) {
1099 self.entries.clear();
1100 }
1101 #[allow(dead_code)]
1102 pub fn hit_rate(&self) -> f64 {
1103 let total = self.hits + self.misses;
1104 if total == 0 {
1105 return 0.0;
1106 }
1107 self.hits as f64 / total as f64
1108 }
1109 #[allow(dead_code)]
1110 pub fn size(&self) -> usize {
1111 self.entries.len()
1112 }
1113}
1114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1116pub enum JavaType {
1117 Int,
1119 Long,
1121 Double,
1123 Float,
1125 Boolean,
1127 Char,
1129 Byte,
1131 Short,
1133 Void,
1135 String,
1137 Object,
1139 Array(Box<JavaType>),
1141 List(Box<JavaType>),
1143 Map(Box<JavaType>, Box<JavaType>),
1145 Optional(Box<JavaType>),
1147 Custom(std::string::String),
1149 Generic(std::string::String, Vec<JavaType>),
1151}
1152#[derive(Debug, Clone, PartialEq)]
1154pub enum JavaLit {
1155 Int(i64),
1157 Long(i64),
1159 Double(f64),
1161 Float(f64),
1163 Bool(bool),
1165 Char(char),
1167 Str(std::string::String),
1169 Null,
1171}
1172#[allow(dead_code)]
1173#[derive(Debug, Clone)]
1174pub struct JavaLivenessInfo {
1175 pub live_in: Vec<std::collections::HashSet<u32>>,
1176 pub live_out: Vec<std::collections::HashSet<u32>>,
1177 pub defs: Vec<std::collections::HashSet<u32>>,
1178 pub uses: Vec<std::collections::HashSet<u32>>,
1179}
1180impl JavaLivenessInfo {
1181 #[allow(dead_code)]
1182 pub fn new(block_count: usize) -> Self {
1183 JavaLivenessInfo {
1184 live_in: vec![std::collections::HashSet::new(); block_count],
1185 live_out: vec![std::collections::HashSet::new(); block_count],
1186 defs: vec![std::collections::HashSet::new(); block_count],
1187 uses: vec![std::collections::HashSet::new(); block_count],
1188 }
1189 }
1190 #[allow(dead_code)]
1191 pub fn add_def(&mut self, block: usize, var: u32) {
1192 if block < self.defs.len() {
1193 self.defs[block].insert(var);
1194 }
1195 }
1196 #[allow(dead_code)]
1197 pub fn add_use(&mut self, block: usize, var: u32) {
1198 if block < self.uses.len() {
1199 self.uses[block].insert(var);
1200 }
1201 }
1202 #[allow(dead_code)]
1203 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1204 self.live_in
1205 .get(block)
1206 .map(|s| s.contains(&var))
1207 .unwrap_or(false)
1208 }
1209 #[allow(dead_code)]
1210 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1211 self.live_out
1212 .get(block)
1213 .map(|s| s.contains(&var))
1214 .unwrap_or(false)
1215 }
1216}