1use crate::object::RtObject;
6use std::collections::{BTreeSet, HashMap, VecDeque};
7
8#[allow(dead_code)]
10pub struct LambdaLifter {
11 next_id: u32,
12 lifted: Vec<LiftedLambda>,
13}
14#[allow(dead_code)]
15impl LambdaLifter {
16 pub fn new() -> Self {
18 Self {
19 next_id: 0,
20 lifted: Vec::new(),
21 }
22 }
23 pub fn lift(&mut self, free_vars: Vec<String>, arity: u32) -> LiftedLambda {
25 let id = self.next_id;
26 self.next_id += 1;
27 let lifted = LiftedLambda {
28 id,
29 free_vars,
30 arity,
31 };
32 self.lifted.push(lifted.clone());
33 lifted
34 }
35 pub fn len(&self) -> usize {
37 self.lifted.len()
38 }
39 pub fn is_empty(&self) -> bool {
41 self.lifted.is_empty()
42 }
43 pub fn all(&self) -> &[LiftedLambda] {
45 &self.lifted
46 }
47 pub fn total_free_vars(&self) -> usize {
49 self.lifted.iter().map(|l| l.free_vars.len()).sum()
50 }
51}
52#[derive(Clone, Debug)]
54pub enum PapResult {
55 UnderApplied(Pap),
57 Saturated {
59 closure: Closure,
61 args: Vec<RtObject>,
63 },
64 OverApplied {
66 closure: Closure,
68 args: Vec<RtObject>,
70 remaining_args: Vec<RtObject>,
72 },
73}
74#[allow(dead_code)]
76#[derive(Clone, Debug)]
77pub struct BatchForceResult {
78 pub forced: usize,
79 pub failed: usize,
80 pub already_evaluated: usize,
81}
82#[allow(dead_code)]
84pub struct ClosureArena {
85 closures: Vec<Option<Closure>>,
86 free: Vec<usize>,
87 alloc_count: u64,
88 free_count: u64,
89}
90#[allow(dead_code)]
91impl ClosureArena {
92 pub fn new() -> Self {
94 Self {
95 closures: Vec::new(),
96 free: Vec::new(),
97 alloc_count: 0,
98 free_count: 0,
99 }
100 }
101 pub fn alloc(&mut self, c: Closure) -> ClosureHandle {
103 self.alloc_count += 1;
104 if let Some(idx) = self.free.pop() {
105 self.closures[idx] = Some(c);
106 ClosureHandle(idx)
107 } else {
108 let idx = self.closures.len();
109 self.closures.push(Some(c));
110 ClosureHandle(idx)
111 }
112 }
113 pub fn free(&mut self, h: ClosureHandle) {
115 if let Some(slot) = self.closures.get_mut(h.0) {
116 if slot.take().is_some() {
117 self.free.push(h.0);
118 self.free_count += 1;
119 }
120 }
121 }
122 pub fn get(&self, h: ClosureHandle) -> Option<&Closure> {
124 self.closures.get(h.0)?.as_ref()
125 }
126 pub fn get_mut(&mut self, h: ClosureHandle) -> Option<&mut Closure> {
128 self.closures.get_mut(h.0)?.as_mut()
129 }
130 pub fn live_count(&self) -> usize {
132 self.closures.iter().filter(|s| s.is_some()).count()
133 }
134 pub fn capacity(&self) -> usize {
136 self.closures.len()
137 }
138 pub fn alloc_count(&self) -> u64 {
140 self.alloc_count
141 }
142 pub fn free_count(&self) -> u64 {
144 self.free_count
145 }
146 pub fn iter(&self) -> impl Iterator<Item = (ClosureHandle, &Closure)> {
148 self.closures
149 .iter()
150 .enumerate()
151 .filter_map(|(i, s)| s.as_ref().map(|c| (ClosureHandle(i), c)))
152 }
153}
154#[derive(Clone, Debug)]
156pub struct CallInfo {
157 pub convention: CallConvention,
159 pub fn_ptr: FnPtr,
161 pub num_args: u16,
163 pub is_recursive: bool,
165 pub caller_name: Option<String>,
167 pub callee_name: Option<String>,
169}
170impl CallInfo {
171 pub fn new(convention: CallConvention, fn_ptr: FnPtr, num_args: u16) -> Self {
173 CallInfo {
174 convention,
175 fn_ptr,
176 num_args,
177 is_recursive: false,
178 caller_name: None,
179 callee_name: None,
180 }
181 }
182}
183#[allow(dead_code)]
185#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
186pub struct ClosureHandle(pub usize);
187#[derive(Clone, Debug)]
189pub struct ClosureConversionResult {
190 pub closure: Closure,
192 pub captured_vars: Vec<String>,
194 pub eta_expanded: bool,
196 pub has_mutual_rec: bool,
198}
199impl ClosureConversionResult {
200 pub fn new(closure: Closure) -> Self {
202 ClosureConversionResult {
203 closure,
204 captured_vars: Vec::new(),
205 eta_expanded: false,
206 has_mutual_rec: false,
207 }
208 }
209 pub fn add_captured(&mut self, var: String) {
211 self.captured_vars.push(var);
212 }
213}
214#[allow(dead_code)]
217pub struct EnvGraph {
218 edges: HashMap<u32, Vec<u32>>,
219 node_count: u32,
220}
221#[allow(dead_code)]
222impl EnvGraph {
223 pub fn new() -> Self {
225 Self {
226 edges: HashMap::new(),
227 node_count: 0,
228 }
229 }
230 pub fn add_node(&mut self) -> u32 {
232 let id = self.node_count;
233 self.node_count += 1;
234 self.edges.insert(id, Vec::new());
235 id
236 }
237 pub fn add_edge(&mut self, from: u32, to: u32) {
239 self.edges.entry(from).or_default().push(to);
240 }
241 pub fn captures(&self, id: u32) -> &[u32] {
243 self.edges.get(&id).map(|v| v.as_slice()).unwrap_or(&[])
244 }
245 pub fn transitive_captures(&self, id: u32) -> Vec<u32> {
247 let mut visited = std::collections::HashSet::new();
248 let mut stack = vec![id];
249 let mut result = Vec::new();
250 while let Some(curr) = stack.pop() {
251 for &dep in self.captures(curr) {
252 if visited.insert(dep) {
253 result.push(dep);
254 stack.push(dep);
255 }
256 }
257 }
258 result
259 }
260 pub fn has_cycle(&self) -> bool {
262 for &start in self.edges.keys() {
263 if self.transitive_captures(start).contains(&start) {
264 return true;
265 }
266 }
267 false
268 }
269 pub fn node_count(&self) -> u32 {
271 self.node_count
272 }
273 pub fn edge_count(&self) -> usize {
275 self.edges.values().map(|v| v.len()).sum()
276 }
277}
278pub struct CallStack {
280 frames: Vec<StackFrame>,
282 max_depth: usize,
284}
285impl CallStack {
286 pub fn new() -> Self {
288 CallStack {
289 frames: Vec::new(),
290 max_depth: 10_000,
291 }
292 }
293 pub fn with_max_depth(max_depth: usize) -> Self {
295 CallStack {
296 frames: Vec::new(),
297 max_depth,
298 }
299 }
300 pub fn push(&mut self, frame: StackFrame) -> Result<(), StackOverflow> {
302 if self.frames.len() >= self.max_depth {
303 return Err(StackOverflow {
304 depth: self.frames.len(),
305 max_depth: self.max_depth,
306 });
307 }
308 self.frames.push(frame);
309 Ok(())
310 }
311 pub fn pop(&mut self) -> Option<StackFrame> {
313 self.frames.pop()
314 }
315 pub fn current(&self) -> Option<&StackFrame> {
317 self.frames.last()
318 }
319 pub fn current_mut(&mut self) -> Option<&mut StackFrame> {
321 self.frames.last_mut()
322 }
323 pub fn depth(&self) -> usize {
325 self.frames.len()
326 }
327 pub fn is_empty(&self) -> bool {
329 self.frames.is_empty()
330 }
331 pub fn trace(&self) -> Vec<String> {
333 self.frames
334 .iter()
335 .rev()
336 .map(|f| f.name.clone().unwrap_or_else(|| format!("{}", f.fn_ptr)))
337 .collect()
338 }
339 pub fn set_max_depth(&mut self, depth: usize) {
341 self.max_depth = depth;
342 }
343}
344pub struct ClosureBuilder {
346 fn_ptr: FnPtr,
348 arity: u16,
350 env: Vec<RtObject>,
352 name: Option<String>,
354 is_recursive: bool,
356 is_known: bool,
358}
359impl ClosureBuilder {
360 pub fn new(fn_ptr: FnPtr, arity: u16) -> Self {
362 ClosureBuilder {
363 fn_ptr,
364 arity,
365 env: Vec::new(),
366 name: None,
367 is_recursive: false,
368 is_known: false,
369 }
370 }
371 pub fn name(mut self, name: String) -> Self {
373 self.name = Some(name);
374 self
375 }
376 pub fn capture(mut self, value: RtObject) -> Self {
378 self.env.push(value);
379 self
380 }
381 pub fn capture_many(mut self, values: Vec<RtObject>) -> Self {
383 self.env.extend(values);
384 self
385 }
386 pub fn recursive(mut self) -> Self {
388 self.is_recursive = true;
389 self
390 }
391 pub fn known(mut self) -> Self {
393 self.is_known = true;
394 self
395 }
396 pub fn build(self) -> Closure {
398 Closure {
399 fn_ptr: self.fn_ptr,
400 arity: self.arity,
401 env: self.env,
402 name: self.name,
403 is_recursive: self.is_recursive,
404 is_known: self.is_known,
405 }
406 }
407}
408#[allow(dead_code)]
410pub struct PapQueue {
411 queue: std::collections::VecDeque<Pap>,
412 max_size: usize,
413 enqueue_count: u64,
414 saturated_count: u64,
415}
416#[allow(dead_code)]
417impl PapQueue {
418 pub fn new(max_size: usize) -> Self {
420 Self {
421 queue: std::collections::VecDeque::new(),
422 max_size,
423 enqueue_count: 0,
424 saturated_count: 0,
425 }
426 }
427 pub fn enqueue(&mut self, pap: Pap) -> bool {
429 if self.queue.len() >= self.max_size {
430 return false;
431 }
432 self.queue.push_back(pap);
433 self.enqueue_count += 1;
434 true
435 }
436 pub fn dequeue(&mut self) -> Option<Pap> {
438 self.queue.pop_front()
439 }
440 pub fn apply_front(&mut self, args: Vec<RtObject>) -> Option<PapResult> {
442 let pap = self.dequeue()?;
443 let result = pap.apply(&args);
444 if matches!(result, PapResult::Saturated { .. }) {
445 self.saturated_count += 1;
446 }
447 Some(result)
448 }
449 pub fn len(&self) -> usize {
451 self.queue.len()
452 }
453 pub fn is_empty(&self) -> bool {
455 self.queue.is_empty()
456 }
457 pub fn enqueue_count(&self) -> u64 {
459 self.enqueue_count
460 }
461 pub fn saturated_count(&self) -> u64 {
463 self.saturated_count
464 }
465}
466#[derive(Clone, Debug)]
471pub struct Pap {
472 pub closure: Closure,
474 pub args: Vec<RtObject>,
476}
477impl Pap {
478 pub fn new(closure: Closure, args: Vec<RtObject>) -> Self {
480 Pap { closure, args }
481 }
482 pub fn remaining_arity(&self) -> u16 {
484 self.closure.arity.saturating_sub(self.args.len() as u16)
485 }
486 pub fn total_arity(&self) -> u16 {
488 self.closure.arity
489 }
490 pub fn num_applied(&self) -> usize {
492 self.args.len()
493 }
494 pub fn is_saturated(&self) -> bool {
496 self.args.len() >= self.closure.arity as usize
497 }
498 pub fn apply(&self, new_args: &[RtObject]) -> PapResult {
500 let total_args = self.args.len() + new_args.len();
501 let arity = self.closure.arity as usize;
502 if total_args < arity {
503 let mut all_args = self.args.clone();
504 all_args.extend_from_slice(new_args);
505 PapResult::UnderApplied(Pap::new(self.closure.clone(), all_args))
506 } else if total_args == arity {
507 let mut all_args = self.args.clone();
508 all_args.extend_from_slice(new_args);
509 PapResult::Saturated {
510 closure: self.closure.clone(),
511 args: all_args,
512 }
513 } else {
514 let mut exact_args = self.args.clone();
515 let needed = arity - self.args.len();
516 exact_args.extend_from_slice(&new_args[..needed]);
517 let remaining = new_args[needed..].to_vec();
518 PapResult::OverApplied {
519 closure: self.closure.clone(),
520 args: exact_args,
521 remaining_args: remaining,
522 }
523 }
524 }
525 pub fn all_args(&self) -> Vec<RtObject> {
527 let mut args = self.closure.env.clone();
528 args.extend(self.args.iter().cloned());
529 args
530 }
531}
532#[allow(dead_code)]
534#[derive(Clone, Debug, Default)]
535pub struct ClosureOptReport {
536 pub inlined_paps: usize,
537 pub specialized_arities: usize,
538 pub env_reduced_vars: usize,
539 pub removed_dead_closures: usize,
540}
541#[allow(dead_code)]
542impl ClosureOptReport {
543 pub fn has_changes(&self) -> bool {
545 self.inlined_paps > 0
546 || self.specialized_arities > 0
547 || self.env_reduced_vars > 0
548 || self.removed_dead_closures > 0
549 }
550 pub fn total(&self) -> usize {
552 self.inlined_paps
553 + self.specialized_arities
554 + self.env_reduced_vars
555 + self.removed_dead_closures
556 }
557}
558#[allow(dead_code)]
560#[derive(Clone, Debug)]
561pub struct InlineCandidate {
562 pub fn_id: u32,
563 pub call_site_count: u32,
564 pub env_size: usize,
565 pub arity: u32,
566}
567#[allow(dead_code)]
568impl InlineCandidate {
569 pub fn inline_score(&self) -> f64 {
571 self.env_size as f64 / (self.call_site_count as f64 + 1.0)
572 }
573 pub fn is_leaf_candidate(&self) -> bool {
575 self.env_size <= 4 && self.arity <= 3
576 }
577}
578#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
583pub struct FnPtr {
584 pub index: u32,
586 pub module_id: u16,
588}
589impl FnPtr {
590 pub fn new(index: u32) -> Self {
592 FnPtr {
593 index,
594 module_id: 0,
595 }
596 }
597 pub fn with_module(index: u32, module_id: u16) -> Self {
599 FnPtr { index, module_id }
600 }
601 pub fn null() -> Self {
603 FnPtr {
604 index: u32::MAX,
605 module_id: 0,
606 }
607 }
608 pub fn is_null(&self) -> bool {
610 self.index == u32::MAX
611 }
612}
613#[derive(Clone, Debug)]
615pub struct StackFrame {
616 pub fn_ptr: FnPtr,
618 pub locals: Vec<RtObject>,
620 pub args: Vec<RtObject>,
622 pub env: Vec<RtObject>,
624 pub return_ip: u32,
626 pub name: Option<String>,
628}
629impl StackFrame {
630 pub fn new(fn_ptr: FnPtr, args: Vec<RtObject>, env: Vec<RtObject>, frame_size: usize) -> Self {
632 StackFrame {
633 fn_ptr,
634 locals: vec![RtObject::unit(); frame_size],
635 args,
636 env,
637 return_ip: 0,
638 name: None,
639 }
640 }
641 pub fn get_local(&self, index: usize) -> Option<&RtObject> {
643 self.locals.get(index)
644 }
645 pub fn set_local(&mut self, index: usize, value: RtObject) -> bool {
647 if index < self.locals.len() {
648 self.locals[index] = value;
649 true
650 } else {
651 false
652 }
653 }
654 pub fn get_arg(&self, index: usize) -> Option<&RtObject> {
656 self.args.get(index)
657 }
658 pub fn get_env(&self, index: usize) -> Option<&RtObject> {
660 self.env.get(index)
661 }
662}
663#[allow(dead_code)]
665#[derive(Clone, Debug)]
666pub struct LiftedLambda {
667 pub id: u32,
669 pub free_vars: Vec<String>,
671 pub arity: u32,
673}
674#[allow(dead_code)]
676pub struct CallInliner {
677 candidates: Vec<InlineCandidate>,
678 inlined_count: u64,
679}
680#[allow(dead_code)]
681impl CallInliner {
682 pub fn new() -> Self {
684 Self {
685 candidates: Vec::new(),
686 inlined_count: 0,
687 }
688 }
689 pub fn register(&mut self, candidate: InlineCandidate) {
691 self.candidates.push(candidate);
692 }
693 pub fn top_candidates(&self, n: usize) -> Vec<&InlineCandidate> {
695 let mut sorted: Vec<&InlineCandidate> = self.candidates.iter().collect();
696 sorted.sort_by(|a, b| {
697 a.inline_score()
698 .partial_cmp(&b.inline_score())
699 .unwrap_or(std::cmp::Ordering::Equal)
700 });
701 sorted.truncate(n);
702 sorted
703 }
704 pub fn record_inline(&mut self, fn_id: u32) {
706 self.candidates.retain(|c| c.fn_id != fn_id);
707 self.inlined_count += 1;
708 }
709 pub fn inlined_count(&self) -> u64 {
711 self.inlined_count
712 }
713 pub fn candidate_count(&self) -> usize {
715 self.candidates.len()
716 }
717}
718#[derive(Clone, Debug)]
722pub struct FunctionEntry {
723 pub name: String,
725 pub arity: u16,
727 pub env_size: u16,
729 pub convention: CallConvention,
731 pub is_recursive: bool,
733 pub is_builtin: bool,
735 pub is_inlined: bool,
737 pub frame_size: u16,
739 pub param_names: Vec<String>,
741}
742impl FunctionEntry {
743 pub fn new(name: String, arity: u16) -> Self {
745 FunctionEntry {
746 name,
747 arity,
748 env_size: 0,
749 convention: CallConvention::ClosureCall,
750 is_recursive: false,
751 is_builtin: false,
752 is_inlined: false,
753 frame_size: 0,
754 param_names: Vec::new(),
755 }
756 }
757 pub fn builtin(name: String, arity: u16) -> Self {
759 FunctionEntry {
760 name,
761 arity,
762 env_size: 0,
763 convention: CallConvention::BuiltinCall,
764 is_recursive: false,
765 is_builtin: true,
766 is_inlined: false,
767 frame_size: 0,
768 param_names: Vec::new(),
769 }
770 }
771}
772#[derive(Clone, Debug)]
774pub struct StackOverflow {
775 pub depth: usize,
777 pub max_depth: usize,
779}
780pub struct FunctionTable {
785 pub(super) entries: Vec<FunctionEntry>,
787 name_index: HashMap<String, u32>,
789}
790impl FunctionTable {
791 pub fn new() -> Self {
793 FunctionTable {
794 entries: Vec::new(),
795 name_index: HashMap::new(),
796 }
797 }
798 pub fn with_capacity(cap: usize) -> Self {
800 FunctionTable {
801 entries: Vec::with_capacity(cap),
802 name_index: HashMap::with_capacity(cap),
803 }
804 }
805 pub fn register(&mut self, entry: FunctionEntry) -> FnPtr {
807 let index = self.entries.len() as u32;
808 self.name_index.insert(entry.name.clone(), index);
809 self.entries.push(entry);
810 FnPtr::new(index)
811 }
812 pub fn get(&self, ptr: FnPtr) -> Option<&FunctionEntry> {
814 self.entries.get(ptr.index as usize)
815 }
816 pub fn get_by_name(&self, name: &str) -> Option<(FnPtr, &FunctionEntry)> {
818 self.name_index
819 .get(name)
820 .and_then(|&idx| self.entries.get(idx as usize).map(|e| (FnPtr::new(idx), e)))
821 }
822 pub fn len(&self) -> usize {
824 self.entries.len()
825 }
826 pub fn is_empty(&self) -> bool {
828 self.entries.is_empty()
829 }
830 pub fn iter(&self) -> impl Iterator<Item = (FnPtr, &FunctionEntry)> {
832 self.entries
833 .iter()
834 .enumerate()
835 .map(|(i, e)| (FnPtr::new(i as u32), e))
836 }
837 pub fn register_builtins(&mut self) {
839 self.register(FunctionEntry::builtin("Nat.add".to_string(), 2));
840 self.register(FunctionEntry::builtin("Nat.sub".to_string(), 2));
841 self.register(FunctionEntry::builtin("Nat.mul".to_string(), 2));
842 self.register(FunctionEntry::builtin("Nat.div".to_string(), 2));
843 self.register(FunctionEntry::builtin("Nat.mod".to_string(), 2));
844 self.register(FunctionEntry::builtin("Nat.beq".to_string(), 2));
845 self.register(FunctionEntry::builtin("Nat.ble".to_string(), 2));
846 self.register(FunctionEntry::builtin("Bool.and".to_string(), 2));
847 self.register(FunctionEntry::builtin("Bool.or".to_string(), 2));
848 self.register(FunctionEntry::builtin("Bool.not".to_string(), 1));
849 self.register(FunctionEntry::builtin("String.append".to_string(), 2));
850 self.register(FunctionEntry::builtin("String.length".to_string(), 1));
851 self.register(FunctionEntry::builtin("String.mk".to_string(), 1));
852 self.register(FunctionEntry::builtin("IO.println".to_string(), 2));
853 self.register(FunctionEntry::builtin("IO.getLine".to_string(), 1));
854 self.register(FunctionEntry::builtin("IO.pure".to_string(), 2));
855 self.register(FunctionEntry::builtin("IO.bind".to_string(), 4));
856 self.register(FunctionEntry::builtin("Array.mk".to_string(), 1));
857 self.register(FunctionEntry::builtin("Array.push".to_string(), 2));
858 self.register(FunctionEntry::builtin("Array.get!".to_string(), 2));
859 self.register(FunctionEntry::builtin("Array.set!".to_string(), 3));
860 self.register(FunctionEntry::builtin("Array.size".to_string(), 1));
861 }
862}
863#[allow(dead_code)]
865pub struct ClosureSerializer;
866#[allow(dead_code)]
867impl ClosureSerializer {
868 pub fn serialize_env(env: &HashMap<String, u64>) -> Vec<u8> {
870 let mut out = Vec::new();
871 let count = env.len() as u32;
872 out.extend_from_slice(&count.to_le_bytes());
873 let mut pairs: Vec<(&String, &u64)> = env.iter().collect();
874 pairs.sort_by_key(|(k, _)| k.as_str());
875 for (key, val) in pairs {
876 let key_bytes = key.as_bytes();
877 out.extend_from_slice(&(key_bytes.len() as u32).to_le_bytes());
878 out.extend_from_slice(key_bytes);
879 out.extend_from_slice(&val.to_le_bytes());
880 }
881 out
882 }
883 pub fn deserialize_env(data: &[u8]) -> Option<HashMap<String, u64>> {
885 if data.len() < 4 {
886 return None;
887 }
888 let count = u32::from_le_bytes(data[0..4].try_into().ok()?) as usize;
889 let mut pos = 4;
890 let mut env = HashMap::new();
891 for _ in 0..count {
892 if pos + 4 > data.len() {
893 return None;
894 }
895 let key_len = u32::from_le_bytes(data[pos..pos + 4].try_into().ok()?) as usize;
896 pos += 4;
897 if pos + key_len > data.len() {
898 return None;
899 }
900 let key = std::str::from_utf8(&data[pos..pos + key_len])
901 .ok()?
902 .to_string();
903 pos += key_len;
904 if pos + 8 > data.len() {
905 return None;
906 }
907 let val = u64::from_le_bytes(data[pos..pos + 8].try_into().ok()?);
908 pos += 8;
909 env.insert(key, val);
910 }
911 Some(env)
912 }
913}
914#[allow(dead_code)]
916pub struct ClosureOptimizer {
917 inline_threshold: usize,
918}
919#[allow(dead_code)]
920impl ClosureOptimizer {
921 pub fn new(inline_threshold: usize) -> Self {
923 Self { inline_threshold }
924 }
925 pub fn reduce_env(
927 &self,
928 closure: &mut Closure,
929 used_names: &std::collections::HashSet<String>,
930 ) -> usize {
931 let before = closure.env.len();
932 closure.env.retain(|obj| {
933 let _ = obj;
934 let _ = used_names;
935 true
936 });
937 before - closure.env.len()
938 }
939 pub fn optimize_pap(&self, pap: &Pap) -> Option<Closure> {
941 if pap.args.len() == pap.closure.arity as usize {
942 Some(Closure {
943 fn_ptr: pap.closure.fn_ptr,
944 arity: 0,
945 env: pap
946 .closure
947 .env
948 .iter()
949 .chain(pap.args.iter())
950 .cloned()
951 .collect(),
952 name: pap.closure.name.clone(),
953 is_recursive: pap.closure.is_recursive,
954 is_known: pap.closure.is_known,
955 })
956 } else {
957 None
958 }
959 }
960 pub fn inline_paps(&self, table: &mut FunctionTable) -> usize {
962 let _ = table;
963 0
964 }
965}
966#[allow(dead_code)]
968#[derive(Clone, Debug)]
969pub struct FlatClosure {
970 pub fn_index: u32,
972 pub arity: u32,
974 pub env: Vec<u64>,
976}
977#[allow(dead_code)]
978impl FlatClosure {
979 pub fn new(fn_index: u32, arity: u32, env: Vec<u64>) -> Self {
981 Self {
982 fn_index,
983 arity,
984 env,
985 }
986 }
987 pub fn serialize(&self) -> Vec<u8> {
989 let mut out = Vec::new();
990 out.extend_from_slice(&self.fn_index.to_le_bytes());
991 out.extend_from_slice(&self.arity.to_le_bytes());
992 let env_len = self.env.len() as u32;
993 out.extend_from_slice(&env_len.to_le_bytes());
994 for v in &self.env {
995 out.extend_from_slice(&v.to_le_bytes());
996 }
997 out
998 }
999 pub fn deserialize(data: &[u8]) -> Option<Self> {
1001 if data.len() < 12 {
1002 return None;
1003 }
1004 let fn_index = u32::from_le_bytes(data[0..4].try_into().ok()?);
1005 let arity = u32::from_le_bytes(data[4..8].try_into().ok()?);
1006 let env_len = u32::from_le_bytes(data[8..12].try_into().ok()?) as usize;
1007 if data.len() < 12 + env_len * 8 {
1008 return None;
1009 }
1010 let mut env = Vec::with_capacity(env_len);
1011 for i in 0..env_len {
1012 let off = 12 + i * 8;
1013 let v = u64::from_le_bytes(data[off..off + 8].try_into().ok()?);
1014 env.push(v);
1015 }
1016 Some(Self {
1017 fn_index,
1018 arity,
1019 env,
1020 })
1021 }
1022 pub fn is_thunk(&self) -> bool {
1024 self.arity == 0
1025 }
1026 pub fn env_size(&self) -> usize {
1028 self.env.len()
1029 }
1030}
1031#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1033pub enum CallConvention {
1034 ClosureCall,
1036 DirectCall,
1038 TailCall,
1040 IndirectCall,
1042 BuiltinCall,
1044}
1045impl CallConvention {
1046 pub fn supports_tco(&self) -> bool {
1048 matches!(self, CallConvention::TailCall | CallConvention::DirectCall)
1049 }
1050 pub fn is_direct(&self) -> bool {
1052 matches!(self, CallConvention::DirectCall | CallConvention::TailCall)
1053 }
1054}
1055#[derive(Clone, Debug, Default)]
1057pub struct ClosureStats {
1058 pub closures_created: u64,
1060 pub paps_created: u64,
1062 pub exact_calls: u64,
1064 pub under_applications: u64,
1066 pub over_applications: u64,
1068 pub tail_calls: u64,
1070 pub direct_calls: u64,
1072 pub builtin_calls: u64,
1074 pub peak_stack_depth: usize,
1076}
1077impl ClosureStats {
1078 pub fn new() -> Self {
1080 Self::default()
1081 }
1082 pub fn record_closure_created(&mut self) {
1084 self.closures_created += 1;
1085 }
1086 pub fn record_pap_created(&mut self) {
1088 self.paps_created += 1;
1089 }
1090 pub fn record_exact_call(&mut self) {
1092 self.exact_calls += 1;
1093 }
1094 pub fn record_under_application(&mut self) {
1096 self.under_applications += 1;
1097 }
1098 pub fn record_over_application(&mut self) {
1100 self.over_applications += 1;
1101 }
1102 pub fn record_tail_call(&mut self) {
1104 self.tail_calls += 1;
1105 }
1106 pub fn record_direct_call(&mut self) {
1108 self.direct_calls += 1;
1109 }
1110 pub fn record_builtin_call(&mut self) {
1112 self.builtin_calls += 1;
1113 }
1114 pub fn update_peak_depth(&mut self, depth: usize) {
1116 if depth > self.peak_stack_depth {
1117 self.peak_stack_depth = depth;
1118 }
1119 }
1120 pub fn total_calls(&self) -> u64 {
1122 self.exact_calls
1123 + self.under_applications
1124 + self.over_applications
1125 + self.tail_calls
1126 + self.direct_calls
1127 + self.builtin_calls
1128 }
1129 pub fn reset(&mut self) {
1131 *self = Self::default();
1132 }
1133}
1134#[allow(dead_code)]
1136pub struct ClosureRegistry {
1137 map: HashMap<String, Closure>,
1138 access_counts: HashMap<String, u64>,
1139}
1140#[allow(dead_code)]
1141impl ClosureRegistry {
1142 pub fn new() -> Self {
1144 Self {
1145 map: HashMap::new(),
1146 access_counts: HashMap::new(),
1147 }
1148 }
1149 pub fn register(&mut self, name: &str, c: Closure) {
1151 self.map.insert(name.to_string(), c);
1152 self.access_counts.insert(name.to_string(), 0);
1153 }
1154 pub fn lookup(&mut self, name: &str) -> Option<&Closure> {
1156 if let Some(count) = self.access_counts.get_mut(name) {
1157 *count += 1;
1158 }
1159 self.map.get(name)
1160 }
1161 pub fn unregister(&mut self, name: &str) -> Option<Closure> {
1163 self.access_counts.remove(name);
1164 self.map.remove(name)
1165 }
1166 pub fn len(&self) -> usize {
1168 self.map.len()
1169 }
1170 pub fn is_empty(&self) -> bool {
1172 self.map.is_empty()
1173 }
1174 pub fn access_count(&self, name: &str) -> u64 {
1176 self.access_counts.get(name).copied().unwrap_or(0)
1177 }
1178 pub fn most_accessed(&self) -> Option<&str> {
1180 self.access_counts
1181 .iter()
1182 .max_by_key(|(_, &c)| c)
1183 .map(|(name, _)| name.as_str())
1184 }
1185 pub fn names(&self) -> impl Iterator<Item = &str> {
1187 self.map.keys().map(|s| s.as_str())
1188 }
1189}
1190#[allow(dead_code)]
1192pub struct ClosureSizeEstimator {
1193 pub(super) ptr_size: usize,
1194 pub(super) object_overhead: usize,
1195}
1196#[allow(dead_code)]
1197impl ClosureSizeEstimator {
1198 pub fn new(ptr_size: usize) -> Self {
1200 Self {
1201 ptr_size,
1202 object_overhead: 16,
1203 }
1204 }
1205 pub fn estimate_closure(&self, c: &Closure) -> usize {
1207 self.object_overhead + self.ptr_size + 4 + 4 + c.env.len() * self.ptr_size
1208 }
1209 pub fn estimate_pap(&self, pap: &Pap) -> usize {
1211 self.object_overhead + self.estimate_closure(&pap.closure) + pap.args.len() * self.ptr_size
1212 }
1213 pub fn estimate_flat(&self, fc: &FlatClosure) -> usize {
1215 self.object_overhead + 4 + 4 + fc.env.len() * 8
1216 }
1217}
1218#[allow(dead_code)]
1220#[derive(Clone, Debug, Default)]
1221pub struct CaptureSet {
1222 pub(super) vars: std::collections::BTreeSet<String>,
1223}
1224#[allow(dead_code)]
1225impl CaptureSet {
1226 pub fn new() -> Self {
1228 Self {
1229 vars: std::collections::BTreeSet::new(),
1230 }
1231 }
1232 pub fn capture(&mut self, name: &str) {
1234 self.vars.insert(name.to_string());
1235 }
1236 pub fn bind(&mut self, name: &str) {
1238 self.vars.remove(name);
1239 }
1240 pub fn is_captured(&self, name: &str) -> bool {
1242 self.vars.contains(name)
1243 }
1244 pub fn len(&self) -> usize {
1246 self.vars.len()
1247 }
1248 pub fn is_empty(&self) -> bool {
1250 self.vars.is_empty()
1251 }
1252 pub fn iter(&self) -> impl Iterator<Item = &str> {
1254 self.vars.iter().map(|s| s.as_str())
1255 }
1256 pub fn union(&mut self, other: &CaptureSet) {
1258 for name in &other.vars {
1259 self.vars.insert(name.clone());
1260 }
1261 }
1262 pub fn difference(&mut self, other: &CaptureSet) {
1264 for name in &other.vars {
1265 self.vars.remove(name);
1266 }
1267 }
1268}
1269#[derive(Clone, Debug)]
1274pub struct Closure {
1275 pub fn_ptr: FnPtr,
1277 pub arity: u16,
1279 pub env: Vec<RtObject>,
1281 pub name: Option<String>,
1283 pub is_recursive: bool,
1285 pub is_known: bool,
1288}
1289impl Closure {
1290 pub fn new(fn_ptr: FnPtr, arity: u16, env: Vec<RtObject>) -> Self {
1292 Closure {
1293 fn_ptr,
1294 arity,
1295 env,
1296 name: None,
1297 is_recursive: false,
1298 is_known: false,
1299 }
1300 }
1301 pub fn named(name: String, fn_ptr: FnPtr, arity: u16, env: Vec<RtObject>) -> Self {
1303 Closure {
1304 fn_ptr,
1305 arity,
1306 env,
1307 name: Some(name),
1308 is_recursive: false,
1309 is_known: false,
1310 }
1311 }
1312 pub fn simple(fn_ptr: FnPtr, arity: u16) -> Self {
1314 Closure::new(fn_ptr, arity, Vec::new())
1315 }
1316 pub fn env_size(&self) -> usize {
1318 self.env.len()
1319 }
1320 pub fn get_env(&self, index: usize) -> Option<&RtObject> {
1322 self.env.get(index)
1323 }
1324 pub fn set_env(&mut self, index: usize, value: RtObject) -> bool {
1326 if index < self.env.len() {
1327 self.env[index] = value;
1328 true
1329 } else {
1330 false
1331 }
1332 }
1333 pub fn extend_env(&mut self, values: &[RtObject]) {
1335 self.env.extend_from_slice(values);
1336 }
1337 pub fn set_recursive(&mut self) {
1339 self.is_recursive = true;
1340 }
1341 pub fn set_known(&mut self) {
1343 self.is_known = true;
1344 }
1345}
1346#[derive(Clone, Debug)]
1351pub struct MutualRecGroup {
1352 pub closures: Vec<Closure>,
1354 pub shared_env: Vec<RtObject>,
1356}
1357impl MutualRecGroup {
1358 pub fn new(closures: Vec<Closure>, shared_env: Vec<RtObject>) -> Self {
1360 MutualRecGroup {
1361 closures,
1362 shared_env,
1363 }
1364 }
1365 pub fn get_closure(&self, index: usize) -> Option<&Closure> {
1367 self.closures.get(index)
1368 }
1369 pub fn size(&self) -> usize {
1371 self.closures.len()
1372 }
1373}