stak_vm/
memory.rs

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