stak_vm/
memory.rs

1use crate::{
2    Error,
3    cons::{Cons, NEVER, Tag},
4    heap::Heap,
5    number::Number,
6    r#type::Type,
7    value::Value,
8};
9use core::fmt::{self, Display, Formatter, Write};
10
11const CONS_FIELD_COUNT: usize = 2;
12
13macro_rules! assert_heap_index {
14    ($self:expr, $index:expr, $garbage:expr) => {
15        let (start, end) = if $garbage {
16            let start = if $self.space { 0 } else { $self.space_size() };
17
18            (start, start + $self.space_size())
19        } else {
20            ($self.allocation_start(), $self.allocation_end())
21        };
22
23        debug_assert!(start <= $index);
24        debug_assert!($index < end);
25    };
26}
27
28macro_rules! assert_heap_cons {
29    ($self:expr, $cons:expr) => {
30        if $cons != NEVER {
31            assert_heap_index!($self, $cons.index(), false);
32        }
33    };
34}
35
36macro_rules! assert_heap_value {
37    ($self:expr, $cons:expr) => {
38        if let Some(cons) = $cons.to_cons() {
39            assert_heap_cons!($self, cons);
40        }
41    };
42}
43
44/// A memory on a virtual machine.
45pub struct Memory<H> {
46    code: Cons,
47    stack: Cons,
48    r#false: Cons,
49    register: Cons,
50    allocation_index: usize,
51    space: bool,
52    heap: H,
53}
54
55impl<H: Heap> Memory<H> {
56    /// Creates a memory.
57    pub fn new(heap: H) -> Result<Self, Error> {
58        let mut memory = Self {
59            code: NEVER,
60            stack: NEVER,
61            r#false: NEVER,
62            register: NEVER,
63            allocation_index: 0,
64            space: false,
65            heap,
66        };
67
68        // Initialize a fake false value.
69        let cons = memory.allocate_unchecked(Default::default(), Default::default())?;
70        memory.r#false = memory.allocate_unchecked(cons.into(), cons.into())?;
71
72        Ok(memory)
73    }
74
75    fn heap(&self) -> &[Value] {
76        self.heap.as_ref()
77    }
78
79    fn heap_mut(&mut self) -> &mut [Value] {
80        self.heap.as_mut()
81    }
82
83    /// Returns a code.
84    pub const fn code(&self) -> Cons {
85        self.code
86    }
87
88    /// Sets a code.
89    pub const fn set_code(&mut self, value: Cons) {
90        self.code = value;
91    }
92
93    /// Returns a register.
94    pub const fn register(&self) -> Cons {
95        self.register
96    }
97
98    /// Sets a register.
99    pub const fn set_register(&mut self, value: Cons) {
100        self.register = value;
101    }
102
103    /// Returns a stack.
104    pub const fn stack(&self) -> Cons {
105        self.stack
106    }
107
108    /// Sets a stack.
109    pub const fn set_stack(&mut self, value: Cons) {
110        self.stack = value;
111    }
112
113    /// Returns a boolean value.
114    pub fn boolean(&self, value: bool) -> Result<Cons, Error> {
115        Ok(if value {
116            self.cdr(self.r#false)?.assume_cons()
117        } else {
118            self.r#false
119        })
120    }
121
122    /// Returns a null value.
123    pub fn null(&self) -> Result<Cons, Error> {
124        Ok(self.car(self.r#false)?.assume_cons())
125    }
126
127    /// Sets a false value.
128    pub(crate) const fn set_false(&mut self, cons: Cons) {
129        self.r#false = cons;
130    }
131
132    /// Pushes a value to a stack.
133    #[inline]
134    pub fn push(&mut self, value: Value) -> Result<(), Error> {
135        self.stack = self.cons(value, self.stack)?;
136
137        Ok(())
138    }
139
140    /// Pops a value from a stack.
141    pub fn pop(&mut self) -> Result<Value, Error> {
142        debug_assert_ne!(self.stack, self.null()?);
143
144        let value = self.car(self.stack)?;
145        self.stack = self.cdr(self.stack)?.assume_cons();
146        Ok(value)
147    }
148
149    /// Pops values from a stack.
150    pub fn pop_many<const M: usize>(&mut self) -> Result<[Value; M], Error> {
151        let mut values = [Default::default(); M];
152
153        for index in 0..=M - 1 {
154            values[M - 1 - index] = self.pop()?;
155        }
156
157        Ok(values)
158    }
159
160    /// Pops numbers from a stack.
161    pub fn pop_numbers<const M: usize>(&mut self) -> Result<[Number; M], Error> {
162        let mut numbers = [Default::default(); M];
163
164        for (index, value) in self.pop_many::<M>()?.into_iter().enumerate() {
165            numbers[index] = value.assume_number();
166        }
167
168        Ok(numbers)
169    }
170
171    /// Peeks a value at the top of a stack.
172    pub fn top(&self) -> Result<Value, Error> {
173        debug_assert_ne!(self.stack, self.null()?);
174
175        self.car(self.stack)
176    }
177
178    /// Sets a value at the top of a stack.
179    pub fn set_top(&mut self, value: Value) -> Result<(), Error> {
180        self.set_car(self.stack, value)
181    }
182
183    /// Allocates a cons with a default tag of [`Type::Pair`].
184    pub fn cons(&mut self, car: Value, cdr: Cons) -> Result<Cons, Error> {
185        self.allocate(car, cdr.set_tag(Type::Pair as Tag).into())
186    }
187
188    /// Allocates a cons.
189    #[inline(always)]
190    pub fn allocate(&mut self, car: Value, cdr: Value) -> Result<Cons, Error> {
191        let mut cons = self.allocate_unchecked(car, cdr)?;
192
193        debug_assert_eq!(cons.tag(), Type::default() as Tag);
194        assert_heap_cons!(self, cons);
195        assert_heap_value!(self, car);
196        assert_heap_value!(self, cdr);
197
198        if self.is_out_of_memory() || cfg!(feature = "gc_always") {
199            self.collect_garbages(Some(&mut cons))?;
200        }
201
202        Ok(cons)
203    }
204
205    #[inline(always)]
206    fn allocate_unchecked(&mut self, car: Value, cdr: Value) -> Result<Cons, Error> {
207        if self.is_out_of_memory() {
208            return Err(Error::OutOfMemory);
209        }
210
211        let cons = Cons::new(self.allocation_end() as u64);
212        self.allocation_index += CONS_FIELD_COUNT;
213
214        assert_heap_cons!(self, cons);
215
216        self.set_car(cons, car)?;
217        self.set_raw_cdr(cons, cdr)?;
218
219        debug_assert!(self.allocation_index <= self.space_size());
220
221        Ok(cons)
222    }
223
224    fn is_out_of_memory(&self) -> bool {
225        self.allocation_index >= self.space_size()
226    }
227
228    /// Returns a heap size.
229    pub fn size(&self) -> usize {
230        self.heap().len()
231    }
232
233    fn space_size(&self) -> usize {
234        self.size() / 2
235    }
236
237    /// Returns the current allocation index relative an allocation start index.
238    pub const fn allocation_index(&self) -> usize {
239        self.allocation_index
240    }
241
242    /// Returns an allocation start index.
243    pub fn allocation_start(&self) -> usize {
244        if self.space { self.space_size() } else { 0 }
245    }
246
247    /// Returns an allocation end index.
248    pub fn allocation_end(&self) -> usize {
249        self.allocation_start() + self.allocation_index
250    }
251
252    fn get<const G: bool>(&self, index: usize) -> Result<Value, Error> {
253        assert_heap_index!(self, index, G);
254
255        self.heap()
256            .get(index)
257            .copied()
258            .ok_or(Error::InvalidMemoryAccess)
259    }
260
261    fn set<const G: bool>(&mut self, index: usize, value: Value) -> Result<(), Error> {
262        assert_heap_index!(self, index, G);
263
264        *self
265            .heap_mut()
266            .get_mut(index)
267            .ok_or(Error::InvalidMemoryAccess)? = value;
268
269        Ok(())
270    }
271
272    /// Returns a value of a `car` field in a cons.
273    pub fn car(&self, cons: Cons) -> Result<Value, Error> {
274        self.get::<false>(cons.index())
275    }
276
277    /// Returns a value of a `cdr` field in a cons.
278    pub fn cdr(&self, cons: Cons) -> Result<Value, Error> {
279        self.get::<false>(cons.index() + 1)
280    }
281
282    fn garbage_car(&self, cons: Cons) -> Result<Value, Error> {
283        self.get::<true>(cons.index())
284    }
285
286    fn garbage_cdr(&self, cons: Cons) -> Result<Value, Error> {
287        self.get::<true>(cons.index() + 1)
288    }
289
290    /// Returns a value of a `car` field in a value assumed as a cons.
291    pub fn car_value(&self, cons: Value) -> Result<Value, Error> {
292        self.car(cons.assume_cons())
293    }
294
295    /// Returns a value of a `cdr` field in a value assumed as a cons.
296    pub fn cdr_value(&self, cons: Value) -> Result<Value, Error> {
297        self.cdr(cons.assume_cons())
298    }
299
300    fn set_field<const G: bool>(
301        &mut self,
302        cons: Cons,
303        index: usize,
304        value: Value,
305    ) -> Result<(), Error> {
306        self.set::<G>(cons.index() + index, value)
307    }
308
309    /// Sets a value to a `car` field in a cons.
310    pub fn set_car(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
311        self.set_field::<false>(cons, 0, value)
312    }
313
314    /// Sets a value to a `cdr` field in a cons.
315    pub fn set_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
316        // Keep an existing tag.
317        self.set_field::<false>(
318            cons,
319            1,
320            value.set_tag(self.get::<false>(cons.index() + 1)?.tag()),
321        )
322    }
323
324    /// Sets a raw value to a `cdr` field in a cons overwriting its tag.
325    pub fn set_raw_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
326        self.set_field::<false>(cons, 1, value)
327    }
328
329    fn set_garbage_car(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
330        self.set_field::<true>(cons, 0, value)
331    }
332
333    fn set_garbage_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
334        self.set_field::<true>(cons, 1, value)
335    }
336
337    /// Sets a value to a `car` field in a value assumed as a cons.
338    pub fn set_car_value(&mut self, cons: Value, value: Value) -> Result<(), Error> {
339        self.set_car(cons.assume_cons(), value)
340    }
341
342    /// Sets a value to a `cdr` field in a value assumed as a cons.
343    pub fn set_cdr_value(&mut self, cons: Value, value: Value) -> Result<(), Error> {
344        self.set_cdr(cons.assume_cons(), value)
345    }
346
347    /// Returns a tail of a list.
348    pub fn tail(&self, mut list: Cons, mut index: usize) -> Result<Cons, Error> {
349        while index > 0 {
350            list = self.cdr(list)?.assume_cons();
351            index -= 1;
352        }
353
354        Ok(list)
355    }
356
357    /// Builds a string.
358    pub fn build_string(&mut self, string: &str) -> Result<Cons, Error> {
359        let string = self.build_raw_string(string)?;
360        let length = Number::from_i64(self.list_length(string)? as _).into();
361        self.allocate(length, string.set_tag(Type::String as _).into())
362    }
363
364    /// Builds a raw string.
365    pub fn build_raw_string(&mut self, string: &str) -> Result<Cons, Error> {
366        let mut list = self.null()?;
367        self.build_intermediate_string(string, &mut list)?;
368        Ok(list)
369    }
370
371    fn build_intermediate_string(&mut self, string: &str, list: &mut Cons) -> Result<(), Error> {
372        for character in string.chars().rev() {
373            *list = self.cons(Number::from_i64(character as _).into(), *list)?;
374        }
375
376        Ok(())
377    }
378
379    /// Executes an operation against a value at the top of a stack.
380    pub fn operate_top(
381        &mut self,
382        operate: impl Fn(&Self, Value) -> Result<Value, Error>,
383    ) -> Result<(), Error> {
384        let value = self.pop()?;
385        self.push(operate(self, value)?)?;
386        Ok(())
387    }
388
389    /// Calculates a length of a list.
390    pub fn list_length(&self, mut list: Cons) -> Result<usize, Error> {
391        let mut length = 0;
392
393        while list != self.null()? {
394            length += 1;
395            list = self.cdr(list)?.assume_cons();
396        }
397
398        Ok(length)
399    }
400
401    /// Executes an unary number operation.
402    pub fn operate_unary(&mut self, operate: impl Fn(Number) -> Number) -> Result<(), Error> {
403        let [x] = self.pop_numbers()?;
404
405        self.push(operate(x).into())?;
406
407        Ok(())
408    }
409
410    /// Executes a binary number operation.
411    pub fn operate_binary(&mut self, operate: fn(Number, Number) -> Number) -> Result<(), Error> {
412        let [x, y] = self.pop_numbers()?;
413
414        self.push(operate(x, y).into())?;
415
416        Ok(())
417    }
418
419    // Garbage collection
420
421    /// Collects garbage memory blocks.
422    pub fn collect_garbages(&mut self, cons: Option<&mut Cons>) -> Result<(), Error> {
423        self.allocation_index = 0;
424        self.space = !self.space;
425
426        self.code = self.copy_cons(self.code)?;
427        self.stack = self.copy_cons(self.stack)?;
428        self.r#false = self.copy_cons(self.r#false)?;
429        self.register = self.copy_cons(self.register)?;
430
431        if let Some(cons) = cons {
432            *cons = self.copy_cons(*cons)?;
433        }
434
435        let mut index = self.allocation_start();
436
437        while index < self.allocation_end() {
438            let value = self.copy_value(self.get::<false>(index)?)?;
439            self.set::<false>(index, value)?;
440            index += 1;
441        }
442
443        Ok(())
444    }
445
446    fn copy_value(&mut self, value: Value) -> Result<Value, Error> {
447        Ok(if let Some(cons) = value.to_cons() {
448            self.copy_cons(cons)?.into()
449        } else {
450            value
451        })
452    }
453
454    fn copy_cons(&mut self, cons: Cons) -> Result<Cons, Error> {
455        Ok(if cons == NEVER {
456            NEVER
457        } else if self.garbage_car(cons)? == NEVER.into() {
458            // Get a forward pointer.
459            self.garbage_cdr(cons)?.assume_cons()
460        } else {
461            let copy = self.allocate_unchecked(self.garbage_car(cons)?, self.garbage_cdr(cons)?)?;
462
463            // Set a forward pointer.
464            self.set_garbage_car(cons, NEVER.into())?;
465            self.set_garbage_cdr(cons, copy.into())?;
466
467            copy
468        }
469        .set_tag(cons.tag()))
470    }
471}
472
473impl<H: Heap> Write for Memory<H> {
474    fn write_str(&mut self, string: &str) -> fmt::Result {
475        (|| -> Result<(), Error> {
476            let mut list = self.null()?;
477            self.build_intermediate_string(string, &mut list)?;
478
479            if self.register() == self.null()? {
480                self.set_register(list);
481            } else {
482                let mut head = self.register();
483
484                while self.cdr(head)? != self.null()?.into() {
485                    head = self.cdr(head)?.assume_cons();
486                }
487
488                self.set_cdr(head, list.into())?;
489            }
490
491            Ok(())
492        })()
493        .map_err(|_| fmt::Error)
494    }
495}
496
497impl<H: Heap> Display for Memory<H> {
498    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
499        writeln!(formatter, "code: {}", self.code)?;
500        writeln!(formatter, "stack: {}", self.stack)?;
501
502        for index in 0..self.allocation_index / 2 {
503            let index = self.allocation_start() + 2 * index;
504            let cons = Cons::new(index as u64);
505
506            write!(
507                formatter,
508                "{:02x}: {} {}",
509                index,
510                self.car(cons).map_err(|_| fmt::Error)?,
511                self.cdr(cons).map_err(|_| fmt::Error)?
512            )?;
513
514            for (cons, name) in [
515                (self.code, "code"),
516                (self.register, "register"),
517                (self.stack, "stack"),
518            ] {
519                if index == cons.index() && cons != NEVER {
520                    write!(formatter, " <- {name}")?;
521                }
522            }
523
524            writeln!(formatter)?;
525        }
526
527        Ok(())
528    }
529}
530
531#[cfg(test)]
532mod tests {
533    use super::*;
534
535    const HEAP_SIZE: usize = 1 << 9;
536
537    fn create_heap() -> [Value; HEAP_SIZE] {
538        [Default::default(); HEAP_SIZE]
539    }
540
541    macro_rules! assert_snapshot {
542        ($memory:expr) => {
543            #[cfg(not(feature = "gc_always"))]
544            insta::assert_snapshot!($memory);
545
546            let _ = $memory;
547        };
548    }
549
550    #[test]
551    fn create() {
552        let memory = Memory::new(create_heap()).unwrap();
553
554        assert_snapshot!(memory);
555    }
556
557    #[test]
558    fn create_list() {
559        let mut memory = Memory::new(create_heap()).unwrap();
560
561        let list = memory
562            .cons(Number::from_i64(1).into(), memory.null().unwrap())
563            .unwrap();
564
565        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
566        assert_snapshot!(memory);
567
568        let list = memory.cons(Number::from_i64(2).into(), list).unwrap();
569
570        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
571        assert_snapshot!(memory);
572
573        let list = memory.cons(Number::from_i64(3).into(), list).unwrap();
574
575        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
576        assert_snapshot!(memory);
577    }
578
579    #[test]
580    fn convert_false() {
581        let memory = Memory::new(create_heap()).unwrap();
582
583        assert_eq!(
584            Value::from(memory.boolean(false).unwrap())
585                .to_cons()
586                .unwrap(),
587            memory.boolean(false).unwrap()
588        );
589    }
590
591    #[test]
592    fn convert_true() {
593        let memory = Memory::new(create_heap()).unwrap();
594
595        assert_eq!(
596            Value::from(memory.boolean(true).unwrap())
597                .to_cons()
598                .unwrap(),
599            memory.boolean(true).unwrap()
600        );
601    }
602
603    #[test]
604    fn convert_null() {
605        let memory = Memory::new(create_heap()).unwrap();
606
607        assert_eq!(
608            Value::from(memory.null().unwrap()).to_cons().unwrap(),
609            memory.null().unwrap()
610        );
611    }
612
613    fn assert_raw_string<H: Heap>(memory: &Memory<H>, mut cons: Cons, string: &str) {
614        for character in string.chars() {
615            assert_eq!(
616                memory.car(cons).unwrap().assume_number().to_i64(),
617                character as _
618            );
619            cons = memory.cdr(cons).unwrap().assume_cons();
620        }
621
622        assert_eq!(cons, memory.null().unwrap());
623    }
624
625    #[test]
626    fn build_string() {
627        let mut memory = Memory::new(create_heap()).unwrap();
628
629        let string = memory.build_string("foo").unwrap();
630
631        assert_eq!(memory.car(string).unwrap(), Number::from_i64(3).into());
632        assert_eq!(memory.cdr(string).unwrap().tag(), Type::String as _);
633        assert_raw_string(&memory, memory.cdr(string).unwrap().assume_cons(), "foo");
634    }
635
636    #[test]
637    fn format_string() {
638        let mut memory = Memory::new(create_heap()).unwrap();
639
640        memory.set_register(memory.null().unwrap());
641
642        memory.write_str("foo").unwrap();
643
644        assert_raw_string(&memory, memory.register(), "foo");
645    }
646
647    #[test]
648    fn format_two_strings() {
649        let mut memory = Memory::new(create_heap()).unwrap();
650
651        memory.set_register(memory.null().unwrap());
652
653        memory.write_str("foo").unwrap();
654        memory.write_str("bar").unwrap();
655
656        assert_raw_string(&memory, memory.register(), "foobar");
657    }
658
659    #[test]
660    fn format_templated_string() {
661        const FOO: usize = 42;
662
663        let mut memory = Memory::new(create_heap()).unwrap();
664
665        memory.set_register(memory.null().unwrap());
666
667        write!(&mut memory, "foo{FOO}bar").unwrap();
668
669        assert_raw_string(&memory, memory.register(), "foo42bar");
670    }
671
672    mod stack {
673        use super::*;
674
675        #[test]
676        fn push_and_pop() {
677            let mut memory = Memory::new(create_heap()).unwrap();
678
679            memory.stack = memory.null().unwrap();
680            memory.push(Number::from_i64(42).into()).unwrap();
681
682            assert_eq!(memory.pop().unwrap(), Number::from_i64(42).into());
683        }
684
685        #[test]
686        fn push_and_pop_twice() {
687            let mut memory = Memory::new(create_heap()).unwrap();
688
689            memory.stack = memory.null().unwrap();
690            memory.push(Number::from_i64(1).into()).unwrap();
691            memory.push(Number::from_i64(2).into()).unwrap();
692
693            assert_eq!(memory.pop().unwrap(), Number::from_i64(2).into());
694            assert_eq!(memory.pop().unwrap(), Number::from_i64(1).into());
695        }
696    }
697
698    mod garbage_collection {
699        use super::*;
700
701        #[test]
702        fn collect_cons() {
703            let mut memory = Memory::new(create_heap()).unwrap();
704
705            memory
706                .allocate(Number::default().into(), Number::default().into())
707                .unwrap();
708            memory.collect_garbages(None).unwrap();
709
710            assert_snapshot!(memory);
711        }
712
713        #[test]
714        fn collect_stack() {
715            let mut memory = Memory::new(create_heap()).unwrap();
716
717            memory.stack = memory.null().unwrap();
718            memory.push(Number::from_i64(42).into()).unwrap();
719            memory.collect_garbages(None).unwrap();
720
721            assert_snapshot!(memory);
722        }
723
724        #[test]
725        fn collect_deep_stack() {
726            let mut memory = Memory::new(create_heap()).unwrap();
727
728            memory.stack = memory.null().unwrap();
729            memory.push(Number::from_i64(1).into()).unwrap();
730            memory.push(Number::from_i64(2).into()).unwrap();
731            memory.collect_garbages(None).unwrap();
732
733            assert_snapshot!(memory);
734        }
735
736        #[test]
737        fn collect_cycle() {
738            let mut memory = Memory::new(create_heap()).unwrap();
739
740            let cons = memory
741                .allocate(Number::default().into(), Number::default().into())
742                .unwrap();
743            memory.set_cdr(cons, cons.into()).unwrap();
744
745            memory.collect_garbages(None).unwrap();
746
747            assert_snapshot!(memory);
748        }
749    }
750}