itsy/bytecode/
builtins.rs

1//! Built-in functions. These will be implemented on the Builtin enum and exec'd via vm::builtincall()
2
3use crate::prelude::*;
4use crate::StackAddress;
5use crate::bytecode::{HeapRef, runtime::heap::{HeapOp, HeapRefOp}};
6
7impl_builtins! {
8
9    fn <
10        array_push8<T: u8>(this: HeapRef, value: u8),
11        array_push16<T: u16>(this: HeapRef, value: u16),
12        array_push32<T: u32>(this: HeapRef, value: u32),
13        array_push64<T: u64>(this: HeapRef, value: u64),
14    >(&mut vm) {
15        vm.heap.item_mut(this.index()).data.extend_from_slice(&value.to_ne_bytes());
16    }
17
18    fn array_pushx(&mut vm + constructor, this: HeapRef, value: HeapRef) {
19        vm.heap.item_mut(this.index()).data.extend_from_slice(&value.to_ne_bytes());
20        vm.refcount_value(value, constructor, HeapRefOp::Inc);
21    }
22
23    fn <
24        array_pop8<T: u8>(this: HeapRef) -> u8,
25        array_pop16<T: u16>(this: HeapRef) -> u16,
26        array_pop32<T: u32>(this: HeapRef) -> u32,
27        array_pop64<T: u64>(this: HeapRef) -> u64,
28    >(&mut vm) {
29        let index = this.index();
30        let offset = vm.heap.item(index).data.len() - size_of::<T>();
31        let result = vm.heap.read(HeapRef::new(index as StackAddress, offset as StackAddress));
32        vm.heap.item_mut(index).data.truncate(offset);
33        result
34    }
35
36    fn array_popx(&mut vm + constructor, this: HeapRef) -> HeapRef { // FIXME: once data enums are usable this needs to return an Option
37        let index = this.index();
38        let offset = vm.heap.item(index).data.len() - size_of::<HeapRef>();
39        let result = vm.heap.read(HeapRef::new(index as StackAddress, offset as StackAddress));
40        vm.heap.item_mut(index).data.truncate(offset);
41        vm.refcount_value(result, constructor, HeapRefOp::DecNoFree);
42        result
43    }
44
45    fn <
46        array_truncate8<T: u8>(this: HeapRef, size: StackAddress),
47        array_truncate16<T: u16>(this: HeapRef, size: StackAddress),
48        array_truncate32<T: u32>(this: HeapRef, size: StackAddress),
49        array_truncate64<T: u64>(this: HeapRef, size: StackAddress),
50    >(&mut vm) {
51        let index = this.index();
52        let current_size = vm.heap.item(index).data.len();
53        let new_size = size_of::<T>() * size as usize;
54        if new_size < current_size {
55            vm.heap.item_mut(index).data.truncate(new_size);
56        }
57    }
58
59    fn array_truncatex(&mut vm + constructor, this: HeapRef, size: StackAddress) {
60        let index = this.index();
61        let current_size = vm.heap.item(index).data.len();
62        let new_size = size_of::<HeapRef>() * size as usize;
63        if new_size < current_size {
64            let mut cursor = HeapRef::new(index, new_size as StackAddress);
65            let end = HeapRef::new(index, current_size as StackAddress);
66            while cursor < end {
67                let item: HeapRef = vm.heap.read_seq(&mut cursor);
68                vm.refcount_value(item, constructor, HeapRefOp::Dec);
69            }
70            vm.heap.item_mut(index).data.truncate(new_size);
71        }
72    }
73
74    fn <
75        array_remove8<T: u8>(this: HeapRef, element: StackAddress) -> u8,
76        array_remove16<T: u16>(this: HeapRef, element: StackAddress) -> u16,
77        array_remove32<T: u32>(this: HeapRef, element: StackAddress) -> u32,
78        array_remove64<T: u64>(this: HeapRef, element: StackAddress) -> u64,
79    >(&mut vm) {
80        const ELEMENT_SIZE: usize = size_of::<T>();
81        let offset = element as usize * ELEMENT_SIZE;
82        let index = this.index();
83        let result: T = vm.heap.read(HeapRef::new(index, offset as StackAddress));
84        let data = &mut vm.heap.item_mut(index).data;
85        data.copy_within(offset + ELEMENT_SIZE .., offset);
86        data.truncate(data.len() - ELEMENT_SIZE);
87        result
88    }
89
90    fn array_removex(&mut vm + constructor, this: HeapRef, element: StackAddress) -> HeapRef {
91        const ELEMENT_SIZE: usize = size_of::<HeapRef>();
92        let offset = element as usize * ELEMENT_SIZE;
93        let index = this.index();
94        let result: HeapRef = vm.heap.read(HeapRef::new(index, offset as StackAddress));
95        let data = &mut vm.heap.item_mut(index).data;
96        data.copy_within(offset + ELEMENT_SIZE .., offset);
97        data.truncate(data.len() - ELEMENT_SIZE);
98        vm.refcount_value(result, constructor, HeapRefOp::DecNoFree);
99        result
100    }
101}