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).rev() {
165            values[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 in (0..M).rev() {
176            numbers[index] = self.pop()?.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    #[inline(always)]
423    pub fn operate_binary(&mut self, operate: fn(Number, Number) -> Number) -> Result<(), Error> {
424        let [x, y] = self.pop_numbers()?;
425
426        self.push(operate(x, y).into())?;
427
428        Ok(())
429    }
430
431    /// Executes a fallible binary number operation.
432    #[inline(always)]
433    pub fn try_operate_binary(
434        &mut self,
435        operate: fn(Number, Number) -> Result<Number, Error>,
436    ) -> Result<(), Error> {
437        let [x, y] = self.pop_numbers()?;
438
439        self.push(operate(x, y)?.into())?;
440
441        Ok(())
442    }
443
444    // Garbage collection
445
446    /// Collects garbage memory blocks.
447    pub fn collect_garbages(&mut self, cons: Option<&mut Cons>) -> Result<(), Error> {
448        self.allocation_index = 0;
449        self.space = !self.space;
450
451        self.code = self.copy_cons(self.code)?;
452        self.stack = self.copy_cons(self.stack)?;
453        self.r#false = self.copy_cons(self.r#false)?;
454        self.register = self.copy_cons(self.register)?;
455
456        if let Some(cons) = cons {
457            *cons = self.copy_cons(*cons)?;
458        }
459
460        let mut index = self.allocation_start();
461
462        while index < self.allocation_end() {
463            let value = self.copy_value(self.get::<false>(index)?)?;
464            self.set::<false>(index, value)?;
465            index += 1;
466        }
467
468        self.refresh_singletons()?;
469
470        Ok(())
471    }
472
473    fn copy_value(&mut self, value: Value) -> Result<Value, Error> {
474        Ok(if let Some(cons) = value.to_cons() {
475            self.copy_cons(cons)?.into()
476        } else {
477            value
478        })
479    }
480
481    fn copy_cons(&mut self, cons: Cons) -> Result<Cons, Error> {
482        if cons == NEVER {
483            return Ok(NEVER);
484        }
485
486        let car = self.garbage_car(cons)?;
487
488        Ok(if car == NEVER.into() {
489            // Get a forward pointer.
490            self.garbage_cdr(cons)?.assume_cons()
491        } else {
492            let copy = self.allocate_unchecked(car, self.garbage_cdr(cons)?)?;
493
494            // Set a forward pointer.
495            self.set_garbage_car(cons, NEVER.into())?;
496            self.set_garbage_cdr(cons, copy.into())?;
497
498            copy
499        }
500        .set_tag(cons.tag()))
501    }
502}
503
504impl<H: Heap> Write for Memory<H> {
505    fn write_str(&mut self, string: &str) -> fmt::Result {
506        (|| -> Result<(), Error> {
507            let mut list = self.null()?;
508            self.build_intermediate_string(string, &mut list)?;
509
510            if self.register() == self.null()? {
511                self.set_register(list);
512            } else {
513                let mut head = self.register();
514
515                while self.cdr(head)? != self.null()?.into() {
516                    head = self.cdr(head)?.assume_cons();
517                }
518
519                self.set_cdr(head, list.into())?;
520            }
521
522            Ok(())
523        })()
524        .map_err(|_| fmt::Error)
525    }
526}
527
528impl<H: Heap> Display for Memory<H> {
529    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
530        writeln!(formatter, "code: {}", self.code)?;
531        writeln!(formatter, "stack: {}", self.stack)?;
532
533        for index in 0..self.allocation_index / 2 {
534            let index = self.allocation_start() + 2 * index;
535            let cons = Cons::new(index as u64);
536
537            write!(
538                formatter,
539                "{:02x}: {} {}",
540                index,
541                self.car(cons).map_err(|_| fmt::Error)?,
542                self.cdr(cons).map_err(|_| fmt::Error)?
543            )?;
544
545            for (cons, name) in [
546                (self.code, "code"),
547                (self.register, "register"),
548                (self.stack, "stack"),
549            ] {
550                if index == cons.index() && cons != NEVER {
551                    write!(formatter, " <- {name}")?;
552                }
553            }
554
555            writeln!(formatter)?;
556        }
557
558        Ok(())
559    }
560}
561
562#[cfg(test)]
563mod tests {
564    use super::*;
565
566    const HEAP_SIZE: usize = 1 << 9;
567
568    fn create_heap() -> [Value; HEAP_SIZE] {
569        [Default::default(); HEAP_SIZE]
570    }
571
572    macro_rules! assert_snapshot {
573        ($memory:expr) => {
574            #[cfg(not(feature = "gc_always"))]
575            insta::assert_snapshot!($memory);
576
577            let _ = $memory;
578        };
579    }
580
581    #[test]
582    fn create() {
583        let memory = Memory::new(create_heap()).unwrap();
584
585        assert_snapshot!(memory);
586    }
587
588    #[test]
589    fn create_list() {
590        let mut memory = Memory::new(create_heap()).unwrap();
591
592        let list = memory
593            .cons(Number::from_i64(1).into(), memory.null().unwrap())
594            .unwrap();
595
596        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
597        assert_snapshot!(memory);
598
599        let list = memory.cons(Number::from_i64(2).into(), list).unwrap();
600
601        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
602        assert_snapshot!(memory);
603
604        let list = memory.cons(Number::from_i64(3).into(), list).unwrap();
605
606        assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
607        assert_snapshot!(memory);
608    }
609
610    #[test]
611    fn convert_false() {
612        let memory = Memory::new(create_heap()).unwrap();
613
614        assert_eq!(
615            Value::from(memory.boolean(false).unwrap())
616                .to_cons()
617                .unwrap(),
618            memory.boolean(false).unwrap()
619        );
620    }
621
622    #[test]
623    fn convert_true() {
624        let memory = Memory::new(create_heap()).unwrap();
625
626        assert_eq!(
627            Value::from(memory.boolean(true).unwrap())
628                .to_cons()
629                .unwrap(),
630            memory.boolean(true).unwrap()
631        );
632    }
633
634    #[test]
635    fn convert_null() {
636        let memory = Memory::new(create_heap()).unwrap();
637
638        assert_eq!(
639            Value::from(memory.null().unwrap()).to_cons().unwrap(),
640            memory.null().unwrap()
641        );
642    }
643
644    fn assert_raw_string<H: Heap>(memory: &Memory<H>, mut cons: Cons, string: &str) {
645        for character in string.chars() {
646            assert_eq!(
647                memory.car(cons).unwrap().assume_number().to_i64(),
648                character as _
649            );
650            cons = memory.cdr(cons).unwrap().assume_cons();
651        }
652
653        assert_eq!(cons, memory.null().unwrap());
654    }
655
656    #[test]
657    fn build_string() {
658        let mut memory = Memory::new(create_heap()).unwrap();
659
660        let string = memory.build_string("foo").unwrap();
661
662        assert_eq!(memory.car(string).unwrap(), Number::from_i64(3).into());
663        assert_eq!(memory.cdr(string).unwrap().tag(), Type::String as _);
664        assert_raw_string(&memory, memory.cdr(string).unwrap().assume_cons(), "foo");
665    }
666
667    #[test]
668    fn format_string() {
669        let mut memory = Memory::new(create_heap()).unwrap();
670
671        memory.set_register(memory.null().unwrap());
672
673        memory.write_str("foo").unwrap();
674
675        assert_raw_string(&memory, memory.register(), "foo");
676    }
677
678    #[test]
679    fn format_two_strings() {
680        let mut memory = Memory::new(create_heap()).unwrap();
681
682        memory.set_register(memory.null().unwrap());
683
684        memory.write_str("foo").unwrap();
685        memory.write_str("bar").unwrap();
686
687        assert_raw_string(&memory, memory.register(), "foobar");
688    }
689
690    #[test]
691    fn format_templated_string() {
692        const FOO: usize = 42;
693
694        let mut memory = Memory::new(create_heap()).unwrap();
695
696        memory.set_register(memory.null().unwrap());
697
698        write!(&mut memory, "foo{FOO}bar").unwrap();
699
700        assert_raw_string(&memory, memory.register(), "foo42bar");
701    }
702
703    mod stack {
704        use super::*;
705
706        #[test]
707        fn push_and_pop() {
708            let mut memory = Memory::new(create_heap()).unwrap();
709
710            memory.stack = memory.null().unwrap();
711            memory.push(Number::from_i64(42).into()).unwrap();
712
713            assert_eq!(memory.pop().unwrap(), Number::from_i64(42).into());
714        }
715
716        #[test]
717        fn push_and_pop_twice() {
718            let mut memory = Memory::new(create_heap()).unwrap();
719
720            memory.stack = memory.null().unwrap();
721            memory.push(Number::from_i64(1).into()).unwrap();
722            memory.push(Number::from_i64(2).into()).unwrap();
723
724            assert_eq!(memory.pop().unwrap(), Number::from_i64(2).into());
725            assert_eq!(memory.pop().unwrap(), Number::from_i64(1).into());
726        }
727    }
728
729    mod garbage_collection {
730        use super::*;
731
732        #[test]
733        fn collect_cons() {
734            let mut memory = Memory::new(create_heap()).unwrap();
735
736            memory
737                .allocate(Number::default().into(), Number::default().into())
738                .unwrap();
739            memory.collect_garbages(None).unwrap();
740
741            assert_snapshot!(memory);
742        }
743
744        #[test]
745        fn collect_stack() {
746            let mut memory = Memory::new(create_heap()).unwrap();
747
748            memory.stack = memory.null().unwrap();
749            memory.push(Number::from_i64(42).into()).unwrap();
750            memory.collect_garbages(None).unwrap();
751
752            assert_snapshot!(memory);
753        }
754
755        #[test]
756        fn collect_deep_stack() {
757            let mut memory = Memory::new(create_heap()).unwrap();
758
759            memory.stack = memory.null().unwrap();
760            memory.push(Number::from_i64(1).into()).unwrap();
761            memory.push(Number::from_i64(2).into()).unwrap();
762            memory.collect_garbages(None).unwrap();
763
764            assert_snapshot!(memory);
765        }
766
767        #[test]
768        fn collect_cycle() {
769            let mut memory = Memory::new(create_heap()).unwrap();
770
771            let cons = memory
772                .allocate(Number::default().into(), Number::default().into())
773                .unwrap();
774            memory.set_cdr(cons, cons.into()).unwrap();
775
776            memory.collect_garbages(None).unwrap();
777
778            assert_snapshot!(memory);
779        }
780    }
781}