Skip to main content

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