1use oxilean_kernel::Name;
6use std::collections::HashMap;
7use std::hash::{Hash, Hasher};
8
9use super::functions::BoxInto;
10use super::rtobject_type::RtObject;
11
12#[derive(Clone, Debug)]
14pub struct BigIntData {
15 pub header: ObjectHeader,
17 pub negative: bool,
19 pub digits: Vec<u64>,
21}
22#[derive(Clone, Debug)]
24pub struct StringData {
25 pub header: ObjectHeader,
27 pub value: String,
29 pub cached_hash: Option<u64>,
31}
32#[derive(Clone, Debug)]
34pub struct BigNatData {
35 pub header: ObjectHeader,
37 pub digits: Vec<u64>,
39}
40#[derive(Clone, Debug)]
42pub enum ThunkState {
43 Unevaluated {
45 closure: RtObject,
47 },
48 Evaluating,
50 Evaluated {
52 value: RtObject,
54 },
55 Excepted {
57 exception: RtObject,
59 },
60}
61#[derive(Clone, Debug)]
63pub struct BoxedFloatData {
64 pub header: ObjectHeader,
66 pub value: f64,
68}
69#[derive(Clone, Debug)]
71pub struct MutRecData {
72 pub header: ObjectHeader,
74 pub closures: Vec<RtObject>,
76 pub index: u32,
78}
79pub struct FieldAccess;
81impl FieldAccess {
82 pub fn get_field(obj: &RtObject, field_index: usize) -> Option<RtObject> {
84 obj.with_heap(|heap| {
85 if let HeapObject::Constructor(data) = heap {
86 data.object_fields.get(field_index).cloned()
87 } else {
88 None
89 }
90 })
91 .flatten()
92 }
93 pub fn set_field(obj: &RtObject, field_index: usize, value: RtObject) -> bool {
95 obj.with_heap_mut(|heap| {
96 if let HeapObject::Constructor(data) = heap {
97 if field_index < data.object_fields.len() {
98 data.object_fields[field_index] = value;
99 return true;
100 }
101 }
102 false
103 })
104 .unwrap_or(false)
105 }
106 pub fn get_ctor_index(obj: &RtObject) -> Option<u32> {
108 if let Some(idx) = obj.as_small_ctor() {
109 return Some(idx);
110 }
111 obj.with_heap(|heap| {
112 if let HeapObject::Constructor(data) = heap {
113 Some(data.ctor_index)
114 } else {
115 None
116 }
117 })
118 .flatten()
119 }
120 pub fn num_fields(obj: &RtObject) -> Option<usize> {
122 if obj.is_small_ctor() {
123 return Some(0);
124 }
125 obj.with_heap(|heap| {
126 if let HeapObject::Constructor(data) = heap {
127 Some(data.object_fields.len())
128 } else {
129 None
130 }
131 })
132 .flatten()
133 }
134 pub fn get_scalar_field(obj: &RtObject, field_index: usize) -> Option<u64> {
136 obj.with_heap(|heap| {
137 if let HeapObject::Constructor(data) = heap {
138 data.scalar_fields.get(field_index).copied()
139 } else {
140 None
141 }
142 })
143 .flatten()
144 }
145 pub fn proj_fst(obj: &RtObject) -> Option<RtObject> {
147 Self::get_field(obj, 0)
148 }
149 pub fn proj_snd(obj: &RtObject) -> Option<RtObject> {
151 Self::get_field(obj, 1)
152 }
153}
154#[derive(Clone, Debug)]
156pub enum HeapObject {
157 Closure(ClosureData),
159 Constructor(ConstructorData),
161 Array(ArrayData),
163 StringObj(StringData),
165 BigNat(BigNatData),
167 BigInt(BigIntData),
169 Thunk(ThunkData),
171 IoAction(IoActionData),
173 Task(TaskData),
175 External(ExternalData),
177 Pap(PapData),
179 MutRec(MutRecData),
181 BoxedFloat(BoxedFloatData),
183 ByteArray(ByteArrayData),
185}
186impl HeapObject {
187 pub fn type_tag(&self) -> TypeTag {
189 match self {
190 HeapObject::Closure(_) => TypeTag::Closure,
191 HeapObject::Constructor(_) => TypeTag::Constructor,
192 HeapObject::Array(_) => TypeTag::Array,
193 HeapObject::StringObj(_) => TypeTag::StringObj,
194 HeapObject::BigNat(_) => TypeTag::BigNat,
195 HeapObject::BigInt(_) => TypeTag::BigInt,
196 HeapObject::Thunk(_) => TypeTag::Thunk,
197 HeapObject::IoAction(_) => TypeTag::IoAction,
198 HeapObject::Task(_) => TypeTag::Task,
199 HeapObject::External(_) => TypeTag::External,
200 HeapObject::Pap(_) => TypeTag::Pap,
201 HeapObject::MutRec(_) => TypeTag::MutRec,
202 HeapObject::BoxedFloat(_) => TypeTag::BoxedFloat,
203 HeapObject::ByteArray(_) => TypeTag::ByteArray,
204 }
205 }
206 pub fn header(&self) -> &ObjectHeader {
208 match self {
209 HeapObject::Closure(d) => &d.header,
210 HeapObject::Constructor(d) => &d.header,
211 HeapObject::Array(d) => &d.header,
212 HeapObject::StringObj(d) => &d.header,
213 HeapObject::BigNat(d) => &d.header,
214 HeapObject::BigInt(d) => &d.header,
215 HeapObject::Thunk(d) => &d.header,
216 HeapObject::IoAction(d) => &d.header,
217 HeapObject::Task(d) => &d.header,
218 HeapObject::External(d) => &d.header,
219 HeapObject::Pap(d) => &d.header,
220 HeapObject::MutRec(d) => &d.header,
221 HeapObject::BoxedFloat(d) => &d.header,
222 HeapObject::ByteArray(d) => &d.header,
223 }
224 }
225 pub fn header_mut(&mut self) -> &mut ObjectHeader {
227 match self {
228 HeapObject::Closure(d) => &mut d.header,
229 HeapObject::Constructor(d) => &mut d.header,
230 HeapObject::Array(d) => &mut d.header,
231 HeapObject::StringObj(d) => &mut d.header,
232 HeapObject::BigNat(d) => &mut d.header,
233 HeapObject::BigInt(d) => &mut d.header,
234 HeapObject::Thunk(d) => &mut d.header,
235 HeapObject::IoAction(d) => &mut d.header,
236 HeapObject::Task(d) => &mut d.header,
237 HeapObject::External(d) => &mut d.header,
238 HeapObject::Pap(d) => &mut d.header,
239 HeapObject::MutRec(d) => &mut d.header,
240 HeapObject::BoxedFloat(d) => &mut d.header,
241 HeapObject::ByteArray(d) => &mut d.header,
242 }
243 }
244}
245#[derive(Clone, Debug)]
247pub enum IoActionKind {
248 Pure(RtObject),
250 Bind {
252 action: Box<IoActionKind>,
254 continuation: RtObject,
256 },
257 PrintLn(String),
259 ReadLn,
261 ReadFile(String),
263 WriteFile {
265 path: String,
267 contents: String,
269 },
270 GetTime,
272 Exit(i32),
274 Throw(RtObject),
276 Catch {
278 action: Box<IoActionKind>,
280 handler: RtObject,
282 },
283 NewRef(RtObject),
285 ReadRef(u64),
287 WriteRef(u64, RtObject),
289 Spawn(RtObject),
291 Wait(u64),
293}
294pub struct ArrayOps;
296impl ArrayOps {
297 pub fn len(obj: &RtObject) -> Option<usize> {
299 obj.with_heap(|heap| {
300 if let HeapObject::Array(data) = heap {
301 Some(data.elements.len())
302 } else {
303 None
304 }
305 })
306 .flatten()
307 }
308 pub fn is_empty(obj: &RtObject) -> Option<bool> {
310 Self::len(obj).map(|l| l == 0)
311 }
312 pub fn get(obj: &RtObject, index: usize) -> Option<RtObject> {
314 obj.with_heap(|heap| {
315 if let HeapObject::Array(data) = heap {
316 data.elements.get(index).cloned()
317 } else {
318 None
319 }
320 })
321 .flatten()
322 }
323 pub fn set(obj: &RtObject, index: usize, value: RtObject) -> Option<RtObject> {
325 let mutated = obj.with_heap_mut(|heap| {
326 if let HeapObject::Array(data) = heap {
327 if data.header.is_unique() && index < data.elements.len() {
328 data.elements[index] = value.clone();
329 return true;
330 }
331 }
332 false
333 });
334 if mutated == Some(true) {
335 return Some(obj.clone());
336 }
337 obj.with_heap(|heap| {
338 if let HeapObject::Array(data) = heap {
339 if index < data.elements.len() {
340 let mut new_elements = data.elements.clone();
341 new_elements[index] = value;
342 Some(RtObject::array(new_elements))
343 } else {
344 None
345 }
346 } else {
347 None
348 }
349 })
350 .flatten()
351 }
352 pub fn push(obj: &RtObject, value: RtObject) -> Option<RtObject> {
354 let pushed = obj.with_heap_mut(|heap| {
355 if let HeapObject::Array(data) = heap {
356 if data.header.is_unique() {
357 data.elements.push(value.clone());
358 return true;
359 }
360 }
361 false
362 });
363 if pushed == Some(true) {
364 return Some(obj.clone());
365 }
366 obj.with_heap(|heap| {
367 if let HeapObject::Array(data) = heap {
368 let mut new_elements = data.elements.clone();
369 new_elements.push(value);
370 Some(RtObject::array(new_elements))
371 } else {
372 None
373 }
374 })
375 .flatten()
376 }
377 pub fn pop(obj: &RtObject) -> Option<(RtObject, RtObject)> {
379 obj.with_heap(|heap| {
380 if let HeapObject::Array(data) = heap {
381 if data.elements.is_empty() {
382 return None;
383 }
384 let mut new_elements = data.elements.clone();
385 let last = new_elements
386 .pop()
387 .expect("elements is non-empty as verified by the is_empty check above");
388 Some((RtObject::array(new_elements), last))
389 } else {
390 None
391 }
392 })
393 .flatten()
394 }
395 pub fn mk_array(size: usize, default: RtObject) -> RtObject {
397 let elements = vec![default; size];
398 RtObject::array(elements)
399 }
400 pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
402 let elems_a = a
403 .with_heap(|heap| {
404 if let HeapObject::Array(data) = heap {
405 Some(data.elements.clone())
406 } else {
407 None
408 }
409 })
410 .flatten()?;
411 let elems_b = b
412 .with_heap(|heap| {
413 if let HeapObject::Array(data) = heap {
414 Some(data.elements.clone())
415 } else {
416 None
417 }
418 })
419 .flatten()?;
420 let mut combined = elems_a;
421 combined.extend(elems_b);
422 Some(RtObject::array(combined))
423 }
424 pub fn slice(obj: &RtObject, start: usize, end: usize) -> Option<RtObject> {
426 obj.with_heap(|heap| {
427 if let HeapObject::Array(data) = heap {
428 let end = end.min(data.elements.len());
429 if start > end {
430 return Some(RtObject::array(Vec::new()));
431 }
432 Some(RtObject::array(data.elements[start..end].to_vec()))
433 } else {
434 None
435 }
436 })
437 .flatten()
438 }
439 pub fn reverse(obj: &RtObject) -> Option<RtObject> {
441 obj.with_heap(|heap| {
442 if let HeapObject::Array(data) = heap {
443 let mut rev = data.elements.clone();
444 rev.reverse();
445 Some(RtObject::array(rev))
446 } else {
447 None
448 }
449 })
450 .flatten()
451 }
452}
453pub struct StringOps;
455impl StringOps {
456 pub fn byte_len(obj: &RtObject) -> Option<usize> {
458 obj.with_heap(|heap| {
459 if let HeapObject::StringObj(data) = heap {
460 Some(data.value.len())
461 } else {
462 None
463 }
464 })
465 .flatten()
466 }
467 pub fn char_len(obj: &RtObject) -> Option<usize> {
469 obj.with_heap(|heap| {
470 if let HeapObject::StringObj(data) = heap {
471 Some(data.value.chars().count())
472 } else {
473 None
474 }
475 })
476 .flatten()
477 }
478 pub fn as_str(obj: &RtObject) -> Option<String> {
480 obj.with_heap(|heap| {
481 if let HeapObject::StringObj(data) = heap {
482 Some(data.value.clone())
483 } else {
484 None
485 }
486 })
487 .flatten()
488 }
489 pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
491 let sa = Self::as_str(a)?;
492 let sb = Self::as_str(b)?;
493 Some(RtObject::string(format!("{}{}", sa, sb)))
494 }
495 pub fn char_at(obj: &RtObject, index: usize) -> Option<RtObject> {
497 obj.with_heap(|heap| {
498 if let HeapObject::StringObj(data) = heap {
499 data.value.chars().nth(index).map(RtObject::char_val)
500 } else {
501 None
502 }
503 })
504 .flatten()
505 }
506 pub fn substring(obj: &RtObject, start: usize, len: usize) -> Option<RtObject> {
508 obj.with_heap(|heap| {
509 if let HeapObject::StringObj(data) = heap {
510 let s: String = data.value.chars().skip(start).take(len).collect();
511 Some(RtObject::string(s))
512 } else {
513 None
514 }
515 })
516 .flatten()
517 }
518 pub fn to_char_list(obj: &RtObject) -> Option<Vec<RtObject>> {
520 obj.with_heap(|heap| {
521 if let HeapObject::StringObj(data) = heap {
522 Some(data.value.chars().map(RtObject::char_val).collect())
523 } else {
524 None
525 }
526 })
527 .flatten()
528 }
529 pub fn nat_to_string(n: &RtObject) -> Option<RtObject> {
531 let v = n.as_small_nat()?;
532 Some(RtObject::string(format!("{}", v)))
533 }
534 pub fn push_char(s: &RtObject, c: &RtObject) -> Option<RtObject> {
536 let sv = Self::as_str(s)?;
537 let cv = c.as_char()?;
538 let mut result = sv;
539 result.push(cv);
540 Some(RtObject::string(result))
541 }
542}
543#[allow(dead_code)]
545pub struct RtObjectCmp;
546#[allow(dead_code)]
547impl RtObjectCmp {
548 pub fn numeric_eq(a: &RtObject, b: &RtObject) -> bool {
550 match (a.as_small_int(), b.as_small_int()) {
551 (Some(x), Some(y)) => return x == y,
552 _ => {}
553 }
554 match (a.as_float_bits(), b.as_float_bits()) {
555 (Some(x), Some(y)) => return x == y,
556 _ => {}
557 }
558 false
559 }
560 pub fn int_lt(a: &RtObject, b: &RtObject) -> Option<bool> {
562 match (a.as_small_int(), b.as_small_int()) {
563 (Some(x), Some(y)) => Some(x < y),
564 _ => None,
565 }
566 }
567}
568#[derive(Clone, Debug)]
570pub struct TypeInfo {
571 pub name: Name,
573 pub num_params: u32,
575 pub is_prop: bool,
577 pub constructors: Vec<CtorInfo>,
579 pub special_repr: Option<SpecialRepr>,
581}
582pub struct TypeRegistry {
584 types: HashMap<String, TypeInfo>,
586}
587impl TypeRegistry {
588 pub fn new() -> Self {
590 TypeRegistry {
591 types: HashMap::new(),
592 }
593 }
594 pub fn register(&mut self, info: TypeInfo) {
596 let key = format!("{}", info.name);
597 self.types.insert(key, info);
598 }
599 pub fn lookup(&self, name: &str) -> Option<&TypeInfo> {
601 self.types.get(name)
602 }
603 pub fn all_types(&self) -> impl Iterator<Item = &TypeInfo> {
605 self.types.values()
606 }
607 pub fn len(&self) -> usize {
609 self.types.len()
610 }
611 pub fn is_empty(&self) -> bool {
613 self.types.is_empty()
614 }
615 pub fn register_builtins(&mut self) {
617 self.register(TypeInfo {
618 name: Name::str("Nat"),
619 num_params: 0,
620 is_prop: false,
621 constructors: vec![
622 CtorInfo {
623 name: Name::str("Nat").append_str("zero"),
624 index: 0,
625 num_scalar_fields: 0,
626 num_object_fields: 0,
627 field_names: Vec::new(),
628 },
629 CtorInfo {
630 name: Name::str("Nat").append_str("succ"),
631 index: 1,
632 num_scalar_fields: 0,
633 num_object_fields: 1,
634 field_names: vec!["n".to_string()],
635 },
636 ],
637 special_repr: Some(SpecialRepr::InlineNat),
638 });
639 self.register(TypeInfo {
640 name: Name::str("Bool"),
641 num_params: 0,
642 is_prop: false,
643 constructors: vec![
644 CtorInfo {
645 name: Name::str("Bool").append_str("false"),
646 index: 0,
647 num_scalar_fields: 0,
648 num_object_fields: 0,
649 field_names: Vec::new(),
650 },
651 CtorInfo {
652 name: Name::str("Bool").append_str("true"),
653 index: 1,
654 num_scalar_fields: 0,
655 num_object_fields: 0,
656 field_names: Vec::new(),
657 },
658 ],
659 special_repr: Some(SpecialRepr::InlineBool),
660 });
661 self.register(TypeInfo {
662 name: Name::str("Unit"),
663 num_params: 0,
664 is_prop: false,
665 constructors: vec![CtorInfo {
666 name: Name::str("Unit").append_str("unit"),
667 index: 0,
668 num_scalar_fields: 0,
669 num_object_fields: 0,
670 field_names: Vec::new(),
671 }],
672 special_repr: Some(SpecialRepr::InlineUnit),
673 });
674 self.register(TypeInfo {
675 name: Name::str("Option"),
676 num_params: 1,
677 is_prop: false,
678 constructors: vec![
679 CtorInfo {
680 name: Name::str("Option").append_str("none"),
681 index: 0,
682 num_scalar_fields: 0,
683 num_object_fields: 0,
684 field_names: Vec::new(),
685 },
686 CtorInfo {
687 name: Name::str("Option").append_str("some"),
688 index: 1,
689 num_scalar_fields: 0,
690 num_object_fields: 1,
691 field_names: vec!["val".to_string()],
692 },
693 ],
694 special_repr: None,
695 });
696 self.register(TypeInfo {
697 name: Name::str("List"),
698 num_params: 1,
699 is_prop: false,
700 constructors: vec![
701 CtorInfo {
702 name: Name::str("List").append_str("nil"),
703 index: 0,
704 num_scalar_fields: 0,
705 num_object_fields: 0,
706 field_names: Vec::new(),
707 },
708 CtorInfo {
709 name: Name::str("List").append_str("cons"),
710 index: 1,
711 num_scalar_fields: 0,
712 num_object_fields: 2,
713 field_names: vec!["head".to_string(), "tail".to_string()],
714 },
715 ],
716 special_repr: None,
717 });
718 self.register(TypeInfo {
719 name: Name::str("Prod"),
720 num_params: 2,
721 is_prop: false,
722 constructors: vec![CtorInfo {
723 name: Name::str("Prod").append_str("mk"),
724 index: 0,
725 num_scalar_fields: 0,
726 num_object_fields: 2,
727 field_names: vec!["fst".to_string(), "snd".to_string()],
728 }],
729 special_repr: None,
730 });
731 }
732}
733#[derive(Clone, Copy, Debug, PartialEq, Eq)]
735pub struct ObjectFlags(u8);
736impl ObjectFlags {
737 pub fn empty() -> Self {
739 ObjectFlags(0)
740 }
741 pub fn moved() -> Self {
743 ObjectFlags(0x01)
744 }
745 pub fn pinned() -> Self {
747 ObjectFlags(0x02)
748 }
749 pub fn shared() -> Self {
751 ObjectFlags(0x04)
752 }
753 pub fn finalized() -> Self {
755 ObjectFlags(0x08)
756 }
757 pub fn immutable() -> Self {
759 ObjectFlags(0x10)
760 }
761 pub fn has(&self, flag: ObjectFlags) -> bool {
763 (self.0 & flag.0) != 0
764 }
765 pub fn set(&mut self, flag: ObjectFlags) {
767 self.0 |= flag.0;
768 }
769 pub fn clear(&mut self, flag: ObjectFlags) {
771 self.0 &= !flag.0;
772 }
773 pub fn bits(&self) -> u8 {
775 self.0
776 }
777}
778#[allow(dead_code)]
780#[derive(Debug, Default)]
781pub struct RtObjectPool {
782 free: Vec<RtObject>,
783}
784#[allow(dead_code)]
785impl RtObjectPool {
786 pub fn new() -> Self {
787 Self::default()
788 }
789 pub fn acquire_unit(&mut self) -> RtObject {
790 self.free.pop().unwrap_or_else(RtObject::unit)
791 }
792 pub fn release(&mut self, obj: RtObject) {
793 if self.free.len() < 64 {
794 self.free.push(obj);
795 }
796 }
797 pub fn free_count(&self) -> usize {
798 self.free.len()
799 }
800}
801#[derive(Clone, Debug)]
803pub struct ByteArrayData {
804 pub header: ObjectHeader,
806 pub bytes: Vec<u8>,
808}
809#[derive(Clone, Debug)]
811pub struct CtorInfo {
812 pub name: Name,
814 pub index: u32,
816 pub num_scalar_fields: u16,
818 pub num_object_fields: u16,
820 pub field_names: Vec<String>,
822}
823#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
825#[repr(u8)]
826pub enum TypeTag {
827 Closure = 0,
829 Constructor = 1,
831 Array = 2,
833 StringObj = 3,
835 BigNat = 4,
837 BigInt = 5,
839 Thunk = 6,
841 IoAction = 7,
843 Task = 8,
845 External = 9,
847 Pap = 10,
849 MutRec = 11,
851 ClosureEnv = 12,
853 BoxedFloat = 13,
855 ByteArray = 14,
857 Module = 15,
859}
860impl TypeTag {
861 pub fn from_u8(v: u8) -> Option<TypeTag> {
863 match v {
864 0 => Some(TypeTag::Closure),
865 1 => Some(TypeTag::Constructor),
866 2 => Some(TypeTag::Array),
867 3 => Some(TypeTag::StringObj),
868 4 => Some(TypeTag::BigNat),
869 5 => Some(TypeTag::BigInt),
870 6 => Some(TypeTag::Thunk),
871 7 => Some(TypeTag::IoAction),
872 8 => Some(TypeTag::Task),
873 9 => Some(TypeTag::External),
874 10 => Some(TypeTag::Pap),
875 11 => Some(TypeTag::MutRec),
876 12 => Some(TypeTag::ClosureEnv),
877 13 => Some(TypeTag::BoxedFloat),
878 14 => Some(TypeTag::ByteArray),
879 15 => Some(TypeTag::Module),
880 _ => None,
881 }
882 }
883 pub fn as_u8(self) -> u8 {
885 self as u8
886 }
887}
888#[derive(Clone, Debug)]
896pub struct ObjectHeader {
897 pub rc_count: u32,
899 pub type_tag: TypeTag,
901 pub flags: ObjectFlags,
903 pub size_words: u16,
905}
906impl ObjectHeader {
907 pub fn new(type_tag: TypeTag, size_words: u16) -> Self {
909 ObjectHeader {
910 rc_count: 1,
911 type_tag,
912 flags: ObjectFlags::empty(),
913 size_words,
914 }
915 }
916 pub fn inc_ref(&mut self) {
918 self.rc_count = self.rc_count.saturating_add(1);
919 }
920 pub fn dec_ref(&mut self) -> bool {
922 if self.rc_count == 0 {
923 return true;
924 }
925 self.rc_count -= 1;
926 self.rc_count == 0
927 }
928 pub fn is_unique(&self) -> bool {
930 self.rc_count == 1
931 }
932 pub fn is_shared(&self) -> bool {
934 self.rc_count > 1 || self.flags.has(ObjectFlags::shared())
935 }
936 pub fn size_bytes(&self) -> usize {
938 self.size_words as usize * 8
939 }
940 pub fn encode(&self) -> u64 {
942 let rc = self.rc_count as u64;
943 let tag = self.type_tag.as_u8() as u64;
944 let flags = self.flags.bits() as u64;
945 let size = self.size_words as u64;
946 (rc << 32) | (tag << 24) | (flags << 16) | size
947 }
948 pub fn decode(bits: u64) -> Option<Self> {
950 let rc = (bits >> 32) as u32;
951 let tag_byte = ((bits >> 24) & 0xFF) as u8;
952 let flags_byte = ((bits >> 16) & 0xFF) as u8;
953 let size = (bits & 0xFFFF) as u16;
954 let type_tag = TypeTag::from_u8(tag_byte)?;
955 Some(ObjectHeader {
956 rc_count: rc,
957 type_tag,
958 flags: ObjectFlags(flags_byte),
959 size_words: size,
960 })
961 }
962}
963#[derive(Clone, Debug)]
965pub struct PapData {
966 pub header: ObjectHeader,
968 pub closure: RtObject,
970 pub arity: u16,
972 pub args: Vec<RtObject>,
974}
975#[derive(Clone, Debug)]
977pub struct TaskData {
978 pub header: ObjectHeader,
980 pub state: TaskState,
982 pub task_id: u64,
984}
985pub struct ThunkOps;
987impl ThunkOps {
988 pub fn is_evaluated(obj: &RtObject) -> Option<bool> {
990 obj.with_heap(|heap| {
991 if let HeapObject::Thunk(data) = heap {
992 Some(matches!(data.state, ThunkState::Evaluated { .. }))
993 } else {
994 None
995 }
996 })
997 .flatten()
998 }
999 pub fn get_value(obj: &RtObject) -> Option<RtObject> {
1001 obj.with_heap(|heap| {
1002 if let HeapObject::Thunk(data) = heap {
1003 if let ThunkState::Evaluated { ref value } = data.state {
1004 Some(value.clone())
1005 } else {
1006 None
1007 }
1008 } else {
1009 None
1010 }
1011 })
1012 .flatten()
1013 }
1014 pub fn set_value(obj: &RtObject, value: RtObject) -> bool {
1016 obj.with_heap_mut(|heap| {
1017 if let HeapObject::Thunk(data) = heap {
1018 data.state = ThunkState::Evaluated { value };
1019 true
1020 } else {
1021 false
1022 }
1023 })
1024 .unwrap_or(false)
1025 }
1026 pub fn mark_evaluating(obj: &RtObject) -> bool {
1028 obj.with_heap_mut(|heap| {
1029 if let HeapObject::Thunk(data) = heap {
1030 data.state = ThunkState::Evaluating;
1031 true
1032 } else {
1033 false
1034 }
1035 })
1036 .unwrap_or(false)
1037 }
1038 pub fn is_evaluating(obj: &RtObject) -> Option<bool> {
1040 obj.with_heap(|heap| {
1041 if let HeapObject::Thunk(data) = heap {
1042 Some(matches!(data.state, ThunkState::Evaluating))
1043 } else {
1044 None
1045 }
1046 })
1047 .flatten()
1048 }
1049}
1050#[derive(Clone, Debug, Default)]
1052pub struct AllocationStats {
1053 pub total_allocations: u64,
1055 pub total_deallocations: u64,
1057 pub live_objects: u64,
1059 pub peak_objects: u64,
1061 pub total_bytes_allocated: u64,
1063}
1064#[derive(Clone, Debug)]
1066pub struct ConstructorData {
1067 pub header: ObjectHeader,
1069 pub ctor_index: u32,
1071 pub num_fields: u16,
1073 pub scalar_fields: Vec<u64>,
1075 pub object_fields: Vec<RtObject>,
1077 pub name: Option<Name>,
1079}
1080#[derive(Clone, Debug)]
1082pub struct ThunkData {
1083 pub header: ObjectHeader,
1085 pub state: ThunkState,
1087}
1088#[derive(Clone, Debug)]
1090pub struct ClosureData {
1091 pub header: ObjectHeader,
1093 pub fn_index: u32,
1095 pub arity: u16,
1097 pub env_size: u16,
1099 pub env: Vec<RtObject>,
1101}
1102#[derive(Clone, Debug)]
1104pub enum SpecialRepr {
1105 InlineNat,
1107 InlineBool,
1109 InlineUnit,
1111 InlineChar,
1113 EnumTag {
1115 num_ctors: u32,
1117 },
1118 PackedStruct {
1120 size_bytes: u32,
1122 },
1123 BoxedArray,
1125 BoxedString,
1127}
1128pub struct ObjectStore {
1134 objects: Vec<Option<HeapObject>>,
1136 free_list: Vec<usize>,
1138 stats: AllocationStats,
1140}
1141impl ObjectStore {
1142 pub fn new() -> Self {
1144 ObjectStore {
1145 objects: Vec::new(),
1146 free_list: Vec::new(),
1147 stats: AllocationStats::default(),
1148 }
1149 }
1150 pub fn with_capacity(cap: usize) -> Self {
1152 ObjectStore {
1153 objects: Vec::with_capacity(cap),
1154 free_list: Vec::new(),
1155 stats: AllocationStats::default(),
1156 }
1157 }
1158 pub fn allocate(&mut self, obj: HeapObject) -> usize {
1160 self.stats.total_allocations += 1;
1161 self.stats.live_objects += 1;
1162 if self.stats.live_objects > self.stats.peak_objects {
1163 self.stats.peak_objects = self.stats.live_objects;
1164 }
1165 self.stats.total_bytes_allocated += obj.header().size_bytes() as u64;
1166 if let Some(id) = self.free_list.pop() {
1167 self.objects[id] = Some(obj);
1168 id
1169 } else {
1170 let id = self.objects.len();
1171 self.objects.push(Some(obj));
1172 id
1173 }
1174 }
1175 pub fn deallocate(&mut self, id: usize) -> Option<HeapObject> {
1177 if id >= self.objects.len() {
1178 return None;
1179 }
1180 let obj = self.objects[id].take();
1181 if obj.is_some() {
1182 self.free_list.push(id);
1183 self.stats.total_deallocations += 1;
1184 self.stats.live_objects = self.stats.live_objects.saturating_sub(1);
1185 }
1186 obj
1187 }
1188 pub fn get(&self, id: usize) -> Option<&HeapObject> {
1190 self.objects.get(id).and_then(|o| o.as_ref())
1191 }
1192 pub fn get_mut(&mut self, id: usize) -> Option<&mut HeapObject> {
1194 self.objects.get_mut(id).and_then(|o| o.as_mut())
1195 }
1196 pub fn stats(&self) -> &AllocationStats {
1198 &self.stats
1199 }
1200 pub fn live_count(&self) -> usize {
1202 self.stats.live_objects as usize
1203 }
1204 pub fn capacity(&self) -> usize {
1206 self.objects.capacity()
1207 }
1208 pub(super) fn global_store<R>(f: impl FnOnce(&mut ObjectStore) -> R) -> R {
1210 thread_local! {
1211 static STORE : std::cell::RefCell < ObjectStore > =
1212 std::cell::RefCell::new(ObjectStore::new());
1213 }
1214 STORE.with(|store| f(&mut store.borrow_mut()))
1215 }
1216}
1217#[derive(Clone, Debug)]
1219pub struct ArrayData {
1220 pub header: ObjectHeader,
1222 pub elements: Vec<RtObject>,
1224 pub capacity: usize,
1226}
1227#[derive(Clone, Debug)]
1229pub struct IoActionData {
1230 pub header: ObjectHeader,
1232 pub kind: IoActionKind,
1234}
1235#[derive(Clone, Debug)]
1237pub enum TaskState {
1238 Pending,
1240 Running,
1242 Completed(RtObject),
1244 Failed(RtObject),
1246 Cancelled,
1248}
1249#[derive(Clone, Debug)]
1251pub struct ExternalData {
1252 pub header: ObjectHeader,
1254 pub type_name: String,
1256 pub payload: Vec<u8>,
1258}
1259pub struct ObjectTable {
1263 entries: HashMap<String, RtObject>,
1265 order: Vec<String>,
1267}
1268impl ObjectTable {
1269 pub fn new() -> Self {
1271 ObjectTable {
1272 entries: HashMap::new(),
1273 order: Vec::new(),
1274 }
1275 }
1276 pub fn insert(&mut self, name: String, obj: RtObject) {
1278 if !self.entries.contains_key(&name) {
1279 self.order.push(name.clone());
1280 }
1281 self.entries.insert(name, obj);
1282 }
1283 pub fn get(&self, name: &str) -> Option<&RtObject> {
1285 self.entries.get(name)
1286 }
1287 pub fn contains(&self, name: &str) -> bool {
1289 self.entries.contains_key(name)
1290 }
1291 pub fn len(&self) -> usize {
1293 self.entries.len()
1294 }
1295 pub fn is_empty(&self) -> bool {
1297 self.entries.is_empty()
1298 }
1299 pub fn iter(&self) -> impl Iterator<Item = (&str, &RtObject)> {
1301 self.order
1302 .iter()
1303 .filter_map(move |name| self.entries.get(name).map(|obj| (name.as_str(), obj)))
1304 }
1305 pub fn remove(&mut self, name: &str) -> Option<RtObject> {
1307 if let Some(obj) = self.entries.remove(name) {
1308 self.order.retain(|n| n != name);
1309 Some(obj)
1310 } else {
1311 None
1312 }
1313 }
1314 pub fn clear(&mut self) {
1316 self.entries.clear();
1317 self.order.clear();
1318 }
1319}
1320pub struct RtArith;
1322impl RtArith {
1323 pub fn nat_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1325 let av = a.as_small_nat()?;
1326 let bv = b.as_small_nat()?;
1327 Some(RtObject::nat(av.wrapping_add(bv)))
1328 }
1329 pub fn nat_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1331 let av = a.as_small_nat()?;
1332 let bv = b.as_small_nat()?;
1333 Some(RtObject::nat(av.saturating_sub(bv)))
1334 }
1335 pub fn nat_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1337 let av = a.as_small_nat()?;
1338 let bv = b.as_small_nat()?;
1339 Some(RtObject::nat(av.wrapping_mul(bv)))
1340 }
1341 pub fn nat_div(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1343 let av = a.as_small_nat()?;
1344 let bv = b.as_small_nat()?;
1345 if bv == 0 {
1346 return Some(RtObject::nat(0));
1347 }
1348 Some(RtObject::nat(av / bv))
1349 }
1350 pub fn nat_mod(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1352 let av = a.as_small_nat()?;
1353 let bv = b.as_small_nat()?;
1354 if bv == 0 {
1355 return Some(RtObject::nat(av));
1356 }
1357 Some(RtObject::nat(av % bv))
1358 }
1359 pub fn nat_le(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1361 let av = a.as_small_nat()?;
1362 let bv = b.as_small_nat()?;
1363 Some(RtObject::bool_val(av <= bv))
1364 }
1365 pub fn nat_lt(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1367 let av = a.as_small_nat()?;
1368 let bv = b.as_small_nat()?;
1369 Some(RtObject::bool_val(av < bv))
1370 }
1371 pub fn nat_eq(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1373 let av = a.as_small_nat()?;
1374 let bv = b.as_small_nat()?;
1375 Some(RtObject::bool_val(av == bv))
1376 }
1377 pub fn bool_and(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1379 let av = a.as_bool()?;
1380 let bv = b.as_bool()?;
1381 Some(RtObject::bool_val(av && bv))
1382 }
1383 pub fn bool_or(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1385 let av = a.as_bool()?;
1386 let bv = b.as_bool()?;
1387 Some(RtObject::bool_val(av || bv))
1388 }
1389 pub fn bool_not(a: &RtObject) -> Option<RtObject> {
1391 let av = a.as_bool()?;
1392 Some(RtObject::bool_val(!av))
1393 }
1394 pub fn int_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1396 let av = a.as_small_int()?;
1397 let bv = b.as_small_int()?;
1398 Some(av.wrapping_add(bv).box_into())
1399 }
1400 pub fn int_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1402 let av = a.as_small_int()?;
1403 let bv = b.as_small_int()?;
1404 Some(av.wrapping_sub(bv).box_into())
1405 }
1406 pub fn int_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
1408 let av = a.as_small_int()?;
1409 let bv = b.as_small_int()?;
1410 Some(av.wrapping_mul(bv).box_into())
1411 }
1412 pub fn int_neg(a: &RtObject) -> Option<RtObject> {
1414 let av = a.as_small_int()?;
1415 Some(av.wrapping_neg().box_into())
1416 }
1417}