Skip to main content

mimium_lang/runtime/vm/
primitives.rs

1use crate::runtime::primitives::{RuntimePrimitives, Word, WordSize};
2
3use super::{Machine, StateOffset, heap};
4
5impl RuntimePrimitives for Machine {
6    type HeapRef = heap::HeapIdx;
7    type ArrayRef = Word; // VM uses RawVal (u64) for array references
8    type StateOffset = StateOffset;
9    type TypeId = u8;
10
11    fn heap_alloc(&mut self, size_words: WordSize) -> Self::HeapRef {
12        self.heap.insert(heap::HeapObject::new(size_words as usize))
13    }
14
15    fn heap_retain(&mut self, obj: Self::HeapRef) {
16        heap::heap_retain(&mut self.heap, obj);
17    }
18
19    fn heap_release(&mut self, obj: Self::HeapRef) {
20        heap::heap_release(&mut self.heap, obj);
21    }
22
23    fn heap_load(&mut self, dst: &mut [Word], obj: Self::HeapRef, size_words: WordSize) {
24        let size = size_words as usize;
25        debug_assert!(dst.len() >= size);
26        let data = self
27            .heap
28            .get(obj)
29            .map(|heap_obj| &heap_obj.data[..size])
30            .expect("heap_load: invalid heap index");
31        dst[..size].copy_from_slice(data);
32    }
33
34    fn heap_store(&mut self, obj: Self::HeapRef, src: &[Word], size_words: WordSize) {
35        let size = size_words as usize;
36        debug_assert!(src.len() >= size);
37        let data = self
38            .heap
39            .get_mut(obj)
40            .map(|heap_obj| &mut heap_obj.data[..size])
41            .expect("heap_store: invalid heap index");
42        data.copy_from_slice(&src[..size]);
43    }
44
45    fn box_alloc(&mut self, src: &[Word], size_words: WordSize) -> Self::HeapRef {
46        let size = size_words as usize;
47        debug_assert!(src.len() >= size);
48        let data = src[..size].to_vec();
49        self.heap.insert(heap::HeapObject::with_data(data))
50    }
51
52    fn box_load(&mut self, dst: &mut [Word], obj: Self::HeapRef, size_words: WordSize) {
53        self.heap_load(dst, obj, size_words);
54    }
55
56    fn box_clone(&mut self, obj: Self::HeapRef) {
57        self.heap_retain(obj);
58    }
59
60    fn box_release(&mut self, obj: Self::HeapRef) {
61        self.heap_release(obj);
62    }
63
64    fn box_store(&mut self, obj: Self::HeapRef, src: &[Word], size_words: WordSize) {
65        self.heap_store(obj, src, size_words);
66    }
67
68    fn usersum_clone(&mut self, value: &mut [Word], size_words: WordSize, type_id: Self::TypeId) {
69        let size = size_words as usize;
70        let ty = self
71            .prog
72            .get_type_from_table(type_id)
73            .expect("usersum_clone: invalid type id");
74        let data = &value[..size];
75        Self::clone_usersum_recursive(data, &ty, &mut self.heap);
76    }
77
78    fn usersum_release(&mut self, value: &mut [Word], size_words: WordSize, type_id: Self::TypeId) {
79        let size = size_words as usize;
80        let ty = self
81            .prog
82            .get_type_from_table(type_id)
83            .expect("usersum_release: invalid type id");
84        let data = &value[..size];
85        let type_table = &self.prog.type_table;
86        Self::release_usersum_recursive(data, &ty, &mut self.heap, type_table);
87    }
88
89    fn closure_make(
90        &mut self,
91        _fn_index: Word,
92        _upvalue_count: WordSize,
93        _state_size: WordSize,
94    ) -> Self::HeapRef {
95        // VM backend uses MakeHeapClosure instruction directly, which requires upvalue_map
96        // from the execution context. This primitive is intended for WASM backend where
97        // closures are allocated differently.
98        unimplemented!("closure_make is not used in VM backend (see MakeHeapClosure instruction)")
99    }
100
101    fn closure_close(&mut self, obj: Self::HeapRef) {
102        self.close_heap_upvalues(obj);
103    }
104
105    fn closure_call(
106        &mut self,
107        _obj: Self::HeapRef,
108        _args: &[Word],
109        _nargs_words: WordSize,
110        _ret: &mut [Word],
111        _nret_words: WordSize,
112    ) {
113        // VM backend uses CallIndirect instruction directly, which integrates with
114        // the execution loop and call stack. This primitive is intended for WASM backend
115        // where function calls are handled differently.
116        unimplemented!("closure_call is not used in VM backend (see CallIndirect instruction)")
117    }
118
119    fn state_push(&mut self, offset: Self::StateOffset) {
120        self.get_current_state().push_pos(offset);
121    }
122
123    fn state_pop(&mut self, offset: Self::StateOffset) {
124        self.get_current_state().pop_pos(offset);
125    }
126
127    fn state_get(&mut self, dst: &mut [Word], size_words: WordSize) {
128        let size = size_words as usize;
129        debug_assert!(dst.len() >= size);
130        let data = self.get_current_state().get_state(size_words);
131        dst[..size].copy_from_slice(&data[..size]);
132    }
133
134    fn state_set(&mut self, src: &[Word], size_words: WordSize) {
135        let size = size_words as usize;
136        debug_assert!(src.len() >= size);
137        let dst = self.get_current_state().get_state_mut(size);
138        dst.copy_from_slice(&src[..size]);
139    }
140
141    fn state_delay(&mut self, dst: &mut [Word], src: &[Word], time: &[Word], max_len: Word) {
142        let input = src.first().copied().unwrap_or_default();
143        let t = time.first().copied().unwrap_or_default();
144        let size_in_samples = max_len;
145        let mut ringbuf = self.get_current_state().get_as_ringbuffer(size_in_samples);
146        let res = ringbuf.process(input, t);
147        if let Some(dst_first) = dst.first_mut() {
148            *dst_first = Self::to_value(res);
149        }
150    }
151
152    fn state_mem(&mut self, dst: &mut [Word], src: &[Word]) {
153        let prev = self.get_current_state().get_state_mut(1)[0];
154        let next = src.first().copied().unwrap_or_default();
155        if let Some(dst_first) = dst.first_mut() {
156            *dst_first = prev;
157        }
158        self.get_current_state().get_state_mut(1)[0] = next;
159    }
160
161    fn array_alloc(&mut self, len: Word, elem_size_words: WordSize) -> Self::ArrayRef {
162        self.arrays.alloc_array(len, elem_size_words)
163    }
164
165    fn array_get_elem(
166        &mut self,
167        dst: &mut [Word],
168        arr: Self::ArrayRef,
169        index: Word,
170        elem_size_words: WordSize,
171    ) {
172        let elem_size = elem_size_words as usize;
173        debug_assert!(dst.len() >= elem_size);
174        let index_val = Self::get_as::<f64>(index) as usize;
175        let array = self.arrays.get_array(arr);
176        let start = index_val * elem_size;
177        debug_assert!(start + elem_size <= array.data.len());
178        let data = &array.data[start..start + elem_size];
179        dst[..elem_size].copy_from_slice(data);
180    }
181
182    fn array_set_elem(
183        &mut self,
184        arr: Self::ArrayRef,
185        index: Word,
186        src: &[Word],
187        elem_size_words: WordSize,
188    ) {
189        let elem_size = elem_size_words as usize;
190        debug_assert!(src.len() >= elem_size);
191        let index_val = Self::get_as::<f64>(index) as usize;
192        let array = self.arrays.get_array_mut(arr);
193        let start = index_val * elem_size;
194        debug_assert!(start + elem_size <= array.data.len());
195        array.data[start..start + elem_size].copy_from_slice(&src[..elem_size]);
196    }
197
198    fn runtime_get_now(&mut self) -> Word {
199        // Runtime globals are provided through external functions in VM backend.
200        // For now, return 0. This will be properly wired when plugin infrastructure
201        // provides these runtime values.
202        Self::to_value(0.0)
203    }
204
205    fn runtime_get_samplerate(&mut self) -> Word {
206        // Default sample rate. In practice this should be provided by audio driver plugin.
207        // The VM backend typically accesses this through external function table.
208        Self::to_value(48000.0)
209    }
210}