mimium_lang/runtime/
vm.rs

1use core::slice;
2use slotmap::{DefaultKey, SlotMap};
3use std::{cell::RefCell, cmp::Ordering, collections::HashMap, ops::Range, rc::Rc};
4pub mod bytecode;
5pub mod program;
6mod ringbuffer;
7pub use bytecode::*;
8use ringbuffer::Ringbuffer;
9
10use program::OpenUpValue;
11pub use program::{FuncProto, Program};
12
13use crate::{
14    compiler::bytecodegen::ByteCodeGenerator,
15    interner::Symbol,
16    plugin::{ExtClsInfo, ExtClsType, ExtFunInfo, ExtFunType, MachineFunction},
17    runtime::vm::program::WordSize,
18    types::{Type, TypeSize},
19};
20pub type RawVal = u64;
21pub type ReturnCode = i64;
22
23#[derive(Debug, Default, PartialEq)]
24struct StateStorage {
25    pos: usize,
26    rawdata: Vec<u64>,
27}
28impl StateStorage {
29    fn resize(&mut self, size: usize) {
30        self.rawdata.resize(size, 0)
31    }
32    fn get_state(&self, size: u64) -> &[RawVal] {
33        unsafe {
34            let head = self.rawdata.as_ptr().add(self.pos);
35            slice::from_raw_parts(head, size as _)
36        }
37    }
38    fn get_state_mut(&mut self, size: usize) -> &mut [RawVal] {
39        unsafe {
40            let head = self.rawdata.as_mut_ptr().add(self.pos);
41            slice::from_raw_parts_mut(head, size as _)
42        }
43    }
44    fn get_as_ringbuffer(&mut self, size_in_samples: u64) -> Ringbuffer<'_> {
45        let data_head = unsafe { self.rawdata.as_mut_ptr().add(self.pos) };
46        Ringbuffer::new(data_head, size_in_samples)
47    }
48    fn push_pos(&mut self, offset: StateOffset) {
49        self.pos = (self.pos as u64 + (std::convert::Into::<u64>::into(offset))) as usize;
50    }
51    fn pop_pos(&mut self, offset: StateOffset) {
52        self.pos = (self.pos as u64 - (std::convert::Into::<u64>::into(offset))) as usize;
53    }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub struct ClosureIdx(pub slotmap::DefaultKey);
58
59#[derive(Debug, Clone, Default)]
60struct StateStorageStack(Vec<ClosureIdx>);
61
62impl StateStorageStack {
63    pub fn push(&mut self, i: ClosureIdx) {
64        self.0.push(i)
65    }
66    pub fn pop(&mut self) {
67        let _ = self.0.pop();
68    }
69}
70
71#[derive(Debug, Clone, Default)]
72pub(crate) struct ArrayHeap {
73    elem_word_size: u64,
74    data: Vec<RawVal>,
75}
76impl ArrayHeap {
77    pub fn get_length_array(&self) -> u64 {
78        self.data.len() as u64 / self.elem_word_size
79    }
80    pub fn get_elem_word_size(&self) -> u64 {
81        self.elem_word_size
82    }
83    pub fn get_data(&self) -> &[RawVal] {
84        &self.data
85    }
86    pub fn get_data_mut(&mut self) -> &mut [RawVal] {
87        &mut self.data
88    }
89}
90#[derive(Debug, Clone, Default)]
91pub(crate) struct ArrayStorage {
92    data: SlotMap<DefaultKey, ArrayHeap>,
93}
94pub(crate) type ArrayIdx = slotmap::DefaultKey;
95impl ArrayStorage {
96    pub fn alloc_array(&mut self, len: u64, elem_size: u64) -> RawVal {
97        let array = ArrayHeap {
98            elem_word_size: elem_size,
99            data: vec![0u64; (len * elem_size) as usize],
100        };
101        let key = self.data.insert(array);
102        debug_assert!(
103            std::mem::size_of::<ArrayIdx>() == 8,
104            "ArrayIdx size must be 8 bytes"
105        );
106        unsafe { std::mem::transmute_copy::<ArrayIdx, RawVal>(&key) }
107    }
108    pub fn get_array(&self, id: RawVal) -> &ArrayHeap {
109        let key: ArrayIdx = unsafe { std::mem::transmute_copy::<RawVal, ArrayIdx>(&id) };
110        self.data.get(key).expect("Invalid ArrayIdx")
111    }
112    pub fn get_array_mut(&mut self, id: RawVal) -> &mut ArrayHeap {
113        let key: ArrayIdx = unsafe { std::mem::transmute_copy::<RawVal, ArrayIdx>(&id) };
114        self.data.get_mut(key).expect("Invalid ArrayIdx")
115    }
116}
117// Upvalues are used with Rc<RefCell<UpValue>> because it maybe shared between multiple closures
118// Maybe it will be managed with some GC mechanism in the future.
119#[derive(Debug, Clone, PartialEq)]
120enum UpValue {
121    Open(OpenUpValue),
122    Closed(Vec<RawVal>, bool),
123}
124type SharedUpValue = Rc<RefCell<UpValue>>;
125impl From<OpenUpValue> for UpValue {
126    fn from(value: OpenUpValue) -> Self {
127        Self::Open(value)
128    }
129}
130
131#[derive(Default)]
132struct LocalUpValueMap(Vec<(Reg, SharedUpValue)>);
133
134impl LocalUpValueMap {
135    pub fn get_or_insert(&mut self, ov: OpenUpValue) -> SharedUpValue {
136        let OpenUpValue { pos, .. } = ov;
137        self.0
138            .iter()
139            .find_map(|(i2, v)| (pos == *i2 as _).then_some(v.clone()))
140            .unwrap_or_else(|| {
141                let v = Rc::new(RefCell::new(UpValue::Open(ov)));
142                self.0.push((pos as Reg, v.clone()));
143                v
144            })
145    }
146}
147
148#[derive(Debug, Default, PartialEq)]
149//closure object dynamically allocated
150pub struct Closure {
151    pub fn_proto_pos: usize, //position of function prototype in global_ftable
152    pub base_ptr: u64,       //base pointer to current closure, to calculate open upvalue
153    pub is_closed: bool,
154    pub refcount: u64,
155    pub(self) upvalues: Vec<SharedUpValue>,
156    state_storage: StateStorage,
157}
158impl Closure {
159    pub(self) fn new(
160        program: &Program,
161        base_ptr: u64,
162        fn_i: usize,
163        upv_map: &mut LocalUpValueMap,
164    ) -> Self {
165        let fnproto = &program.global_fn_table[fn_i].1;
166        let upvalues = fnproto
167            .upindexes
168            .iter()
169            .map(|ov| upv_map.get_or_insert(*ov))
170            .collect::<Vec<_>>();
171        let mut state_storage = StateStorage::default();
172        state_storage.resize(fnproto.state_skeleton.total_size() as usize);
173        Self {
174            fn_proto_pos: fn_i,
175            upvalues,
176            is_closed: false,
177            refcount: 1,
178            base_ptr,
179            state_storage,
180        }
181    }
182}
183
184pub type ClosureStorage = SlotMap<DefaultKey, Closure>;
185pub fn drop_closure(storage: &mut ClosureStorage, id: ClosureIdx) {
186    let cls = storage.get_mut(id.0).unwrap();
187    cls.refcount -= 1;
188    if cls.refcount == 0 {
189        let c_cls = storage
190            .get_mut(id.0)
191            .unwrap()
192            .upvalues
193            .iter()
194            .map(|v| {
195                let v = v.borrow();
196                if let UpValue::Closed(v, _) = &v as &UpValue {
197                    let cls_i = Machine::get_as::<ClosureIdx>(v[0]);
198                    Some(cls_i)
199                } else {
200                    None
201                }
202            })
203            .collect::<Vec<_>>();
204        c_cls.iter().filter_map(|i| *i).for_each(|clsi| {
205            drop_closure(storage, clsi);
206        });
207        storage.remove(id.0);
208    }
209}
210
211#[derive(Clone, Copy, Default)]
212enum RawValType {
213    Float,
214    #[default]
215    Int,
216    // UInt,
217}
218
219#[derive(Clone, Copy)]
220enum ExtFnIdx {
221    Fun(usize),
222    Cls(usize),
223}
224/// The virtual machine that executes mimium bytecode programs.
225///
226/// A [`Machine`] holds the compiled [`Program`], value stack and all live
227/// closures. External functions and closures installed from plugins are also
228/// managed here.
229pub struct Machine {
230    // program will be modified while its execution, e.g., higher-order external closure creates its wrapper.
231    pub prog: Program,
232    stack: Vec<RawVal>,
233    base_pointer: u64,
234    pub closures: ClosureStorage,
235    pub ext_fun_table: Vec<(Symbol, ExtFunType)>,
236    pub ext_cls_table: Vec<(Symbol, ExtClsType)>,
237    pub arrays: ArrayStorage,
238    fn_map: HashMap<usize, ExtFnIdx>, //index from fntable index of program to it of machine.
239    // cls_map: HashMap<usize, usize>, //index from fntable index of program to it of machine.
240    global_states: StateStorage,
241    states_stack: StateStorageStack,
242    delaysizes_pos_stack: Vec<usize>,
243    global_vals: Vec<RawVal>,
244    debug_stacktype: Vec<RawValType>,
245}
246
247macro_rules! binop {
248    ($op:tt,$t:ty, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
249        {
250        $self.set_stacktype($dst as i64, RawValType::Float);
251        $self.set_stack($dst as i64, Self::to_value::<$t>(
252            Self::get_as::<$t>($self.get_stack($src1 as i64))
253        $op Self::get_as::<$t>($self.get_stack($src2 as i64))))
254    }
255    };
256}
257macro_rules! binop_bool {
258    ($op:tt, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
259        {
260        $self.set_stacktype($dst as i64, RawValType::Float);
261        let bres:bool =
262            Self::get_as::<f64>($self.get_stack($src1 as i64))
263        $op Self::get_as::<f64>($self.get_stack($src2 as i64));
264        let fres = if bres{
265            1.0f64
266        }else{
267            0.0f64
268        };
269        $self.set_stack($dst as i64,Self::to_value::<f64>(fres))
270    }
271    };
272}
273macro_rules! binop_bool_compose {//for and&or
274    ($op:tt, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
275        {
276        $self.set_stacktype($dst as i64, RawValType::Float);
277        let bres:bool =
278            Self::get_as::<f64>($self.get_stack($src1 as i64))>0.0
279        $op Self::get_as::<f64>($self.get_stack($src2 as i64))>0.0;
280        let fres = if bres{ 1.0f64 }else{ 0.0f64 };
281        $self.set_stack($dst as i64,Self::to_value::<f64>(fres))
282    }
283    };
284}
285macro_rules! binopmethod {
286    ($op:ident,$t:ty, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {{
287        $self.set_stacktype($dst as i64, RawValType::Float);
288        $self.set_stack(
289            $dst as i64,
290            Self::to_value::<$t>(
291                Self::get_as::<$t>($self.get_stack($src1 as i64))
292                    .$op(Self::get_as::<$t>($self.get_stack($src2 as i64))),
293            ),
294        )
295    }};
296}
297macro_rules! uniop {
298    ($op:tt,$t:ty, $dst:expr,$src:expr,$self:ident) => {
299        $self.set_stack($dst as i64,
300            Self::to_value::<$t>(
301            $op Self::get_as::<$t>($self.get_stack($src as i64))))
302    };
303}
304macro_rules! uniop_bool {
305    ($op:tt, $dst:expr,$src:expr,$self:ident) => {{
306        let bres: bool = $op(matches!(
307            Self::get_as::<f64>($self.get_stack($src as i64)).partial_cmp(&0.0),
308            Some(std::cmp::Ordering::Greater)
309        ));
310        let fres = if bres { 1.0f64 } else { 0.0f64 };
311        $self.set_stack($dst as i64, Self::to_value::<f64>(fres))
312    }};
313}
314macro_rules! uniopmethod {
315    ($op:tt,$t:ty, $dst:expr,$src:expr,$self:ident) => {{
316        $self.set_stack(
317            $dst as i64,
318            Self::to_value::<$t>(Self::get_as::<$t>($self.get_stack($src as i64)).$op()),
319        )
320    }};
321}
322
323fn set_vec<T>(vec: &mut Vec<T>, i: usize, value: T)
324where
325    T: Clone + std::default::Default,
326{
327    match i.cmp(&vec.len()) {
328        Ordering::Less => vec[i] = value,
329        Ordering::Equal => vec.push(value),
330        Ordering::Greater => {
331            vec.resize(i, T::default());
332            vec.push(value);
333        }
334    }
335}
336fn set_vec_range<T>(vec: &mut Vec<T>, i: usize, values: &[T])
337where
338    T: std::fmt::Debug + Copy + std::default::Default,
339{
340    //do not use copy_from_slice  or extend_from_slice because the ptr range may overwrap,
341    // and copy_from_slice use ptr::copy_nonoverwrapping internally.
342    // vec[range].copy_from_slice(values)
343    let start = i;
344    let end = i + values.len();
345    if end > vec.len() {
346        vec.resize(i, T::default());
347    }
348    match start.cmp(&vec.len()) {
349        Ordering::Less => {
350            let range = i..(i + values.len());
351            for (v, i) in values.iter().zip(range.into_iter()) {
352                vec[i] = *v;
353            }
354        }
355        Ordering::Equal => values.iter().for_each(|v| vec.push(*v)),
356        Ordering::Greater => values.iter().for_each(|v| vec.push(*v)),
357    }
358}
359
360impl Machine {
361    /// Create a new VM from a compiled [`Program`] and external functions.
362    pub fn new(
363        prog: Program,
364        extfns: impl Iterator<Item = ExtFunInfo>,
365        extcls: impl Iterator<Item = Box<dyn MachineFunction>>,
366    ) -> Self {
367        let mut res = Self {
368            prog,
369            stack: vec![],
370            base_pointer: 0,
371            closures: Default::default(),
372            ext_fun_table: vec![],
373            ext_cls_table: vec![],
374            fn_map: HashMap::new(),
375            // cls_map: HashMap::new(),
376            arrays: ArrayStorage::default(),
377            global_states: Default::default(),
378            states_stack: Default::default(),
379            delaysizes_pos_stack: vec![0],
380            global_vals: vec![],
381            debug_stacktype: vec![RawValType::Int; 255],
382        };
383        extfns.for_each(|ExtFunInfo { name, fun, .. }| {
384            let _ = res.install_extern_fn(name, fun);
385        });
386        extcls.for_each(|machine_function| {
387            let _ = res.install_extern_cls(machine_function.get_name(), machine_function.get_fn());
388        });
389        res.link_functions();
390        res
391    }
392    /// Create a new VM instance with the new program, preserving the current state as possible.
393    pub fn new_resume(&self, prog: Program) -> Self {
394        let mut new_vm = Self {
395            prog,
396            stack: vec![],
397            base_pointer: 0,
398            closures: Default::default(),
399            ext_fun_table: vec![],
400            ext_cls_table: vec![],
401            fn_map: HashMap::new(),
402            // cls_map: HashMap::new(),
403            arrays: ArrayStorage::default(),
404            global_states: Default::default(),
405            states_stack: Default::default(),
406            delaysizes_pos_stack: vec![0],
407            global_vals: vec![],
408            debug_stacktype: vec![RawValType::Int; 255],
409        };
410        //expect there are no change changes in external function use for now
411
412        new_vm.ext_fun_table = self.ext_fun_table.clone();
413        new_vm.ext_cls_table = self.ext_cls_table.clone();
414        new_vm.global_vals = self.global_vals.clone();
415        new_vm.arrays = self.arrays.clone();
416
417        let new_state = state_tree::update_state_storage(
418            &self.global_states.rawdata,
419            self.prog
420                .get_dsp_state_skeleton()
421                .cloned()
422                .expect("dsp function not found"),
423            new_vm
424                .prog
425                .get_dsp_state_skeleton()
426                .cloned()
427                .expect("dsp function not found"),
428        );
429        match new_state {
430            Ok(Some(s)) => {
431                new_vm.global_states.rawdata = s;
432            }
433            Ok(None) => {
434                log::info!("No state structure change detected. Just copies buffer");
435                new_vm.global_states.rawdata = self.global_states.rawdata.clone();
436            }
437            Err(e) => {
438                log::error!("Failed to migrate global state: {e}");
439            }
440        }
441        new_vm.link_functions();
442        new_vm.execute_main();
443        new_vm
444    }
445    pub fn clear_stack(&mut self) {
446        self.stack.fill(0);
447    }
448    pub fn get_stack(&self, offset: i64) -> RawVal {
449        // unsafe {
450        //     *self
451        //         .stack
452        //         .get_unchecked((self.base_pointer + offset as u64) as usize)
453        // }
454        self.get_stack_range(offset, 1).1[0]
455    }
456    pub fn get_stack_range(&self, offset: i64, word_size: TypeSize) -> (Range<usize>, &[RawVal]) {
457        let addr_start = self.base_pointer as usize + offset as usize;
458        let addr_end = addr_start + word_size as usize;
459        let start = self.stack.as_slice().as_ptr();
460        let slice = unsafe {
461            // w/ unstable feature
462            // let (_,snd) = self.stack.as_slice().split_at_unchecked(offset as usize);
463            // snd.split_at_unchecked(n as usize)
464            let vstart = start.add(addr_start);
465            slice::from_raw_parts(vstart, word_size as usize)
466        };
467        (addr_start..addr_end, slice)
468    }
469    pub fn get_stack_range_mut(
470        &mut self,
471        offset: i64,
472        word_size: TypeSize,
473    ) -> (Range<usize>, &mut [RawVal]) {
474        let addr_start = self.base_pointer as usize + offset as usize;
475        let addr_end = addr_start + word_size as usize;
476        let start = self.stack.as_mut_ptr();
477        let slice = unsafe {
478            // w/ unstable feature
479            // let (_,snd) = self.stack.as_slice().split_at_unchecked(offset as usize);
480            // snd.split_at_unchecked(n as usize)
481            let vstart = start.add(addr_start);
482            slice::from_raw_parts_mut(vstart, word_size as usize)
483        };
484        (addr_start..addr_end, slice)
485    }
486    pub fn set_stack(&mut self, offset: i64, v: RawVal) {
487        self.set_stack_range(offset, &[v])
488    }
489    pub fn set_stack_range(&mut self, offset: i64, vs: &[RawVal]) {
490        // debug_assert!(!v.is_null());
491        // debug_assert!(v.is_aligned());
492        // let vs = unsafe { slice::from_raw_parts(v, size) };
493        set_vec_range(
494            &mut self.stack,
495            (self.base_pointer as i64 + offset) as usize,
496            vs,
497        )
498    }
499    fn move_stack_range(&mut self, offset: i64, srcrange: Range<usize>) {
500        let dest = (self.base_pointer as i64 + offset) as usize;
501        if srcrange.end > self.stack.len() {
502            self.stack.resize(srcrange.end, 0);
503        }
504        let dest_end = dest + (srcrange.end - srcrange.start);
505        if dest_end > self.stack.len() {
506            self.stack.resize(dest_end, 0);
507        }
508        self.stack.copy_within(srcrange, dest)
509    }
510    fn set_stacktype(&mut self, offset: i64, t: RawValType) {
511        // set_vec(
512        //     &mut self.debug_stacktype,
513        //     (self.base_pointer as i64 + offset) as usize,
514        //     t,
515        // );
516    }
517    pub fn get_top_n(&self, n: usize) -> &[RawVal] {
518        let len = self.stack.len();
519        &self.stack[(len - n)..]
520    }
521    fn get_upvalue_offset(upper_base: usize, offset: OpenUpValue) -> usize {
522        upper_base + offset.pos
523    }
524    pub fn get_open_upvalue(
525        &self,
526        upper_base: usize,
527        ov: OpenUpValue,
528    ) -> (Range<usize>, &[RawVal]) {
529        let OpenUpValue { size, .. } = ov;
530        // log::trace!("upper base:{}, upvalue:{}", upper_base, offset);
531        let abs_pos = Self::get_upvalue_offset(upper_base, ov);
532        let end = abs_pos + size as usize;
533        let slice = unsafe {
534            let vstart = self.stack.as_slice().as_ptr().add(abs_pos);
535            slice::from_raw_parts(vstart, size as usize)
536        };
537        (abs_pos..end, slice)
538    }
539    pub fn get_closure(&self, idx: ClosureIdx) -> &Closure {
540        debug_assert!(
541            self.closures.contains_key(idx.0),
542            "Invalid Closure Id referred"
543        );
544        unsafe { self.closures.get_unchecked(idx.0) }
545    }
546    pub(crate) fn get_closure_mut(&mut self, idx: ClosureIdx) -> &mut Closure {
547        debug_assert!(
548            self.closures.contains_key(idx.0),
549            "Invalid Closure Id referred"
550        );
551        unsafe { self.closures.get_unchecked_mut(idx.0) }
552    }
553    fn get_current_state(&mut self) -> &mut StateStorage {
554        if self.states_stack.0.is_empty() {
555            &mut self.global_states
556        } else {
557            let idx = unsafe { self.states_stack.0.last().unwrap_unchecked() };
558            &mut self.get_closure_mut(*idx).state_storage
559        }
560    }
561    fn return_general(&mut self, iret: Reg, nret: Reg) -> &[u64] {
562        let base = self.base_pointer as usize;
563        let iret_abs = base + iret as usize;
564        self.stack
565            .copy_within(iret_abs..(iret_abs + nret as usize), base - 1);
566        // clean up temporary variables to ensure that `nret`
567        // at the top of the stack is the return value
568        self.stack.truncate(base - 1 + nret as usize);
569        let res_slice = self.stack.split_at(base).1;
570        res_slice
571    }
572
573    pub fn get_as<T>(v: RawVal) -> T {
574        unsafe { std::mem::transmute_copy::<RawVal, T>(&v) }
575    }
576    pub fn get_as_array<T>(v: &[RawVal]) -> &[T] {
577        unsafe { std::mem::transmute::<&[RawVal], &[T]>(v) }
578    }
579    pub fn to_value<T>(v: T) -> RawVal {
580        assert_eq!(std::mem::size_of::<T>(), 8);
581        unsafe { std::mem::transmute_copy::<T, RawVal>(&v) }
582    }
583    fn call_function<F>(
584        &mut self,
585        func_pos: u8,
586        _nargs: u8,
587        nret_req: u8,
588        mut action: F,
589    ) -> ReturnCode
590    where
591        F: FnMut(&mut Self) -> ReturnCode,
592    {
593        let offset = (func_pos + 1) as u64;
594        self.delaysizes_pos_stack.push(0);
595        self.base_pointer += offset;
596        let nret = action(self);
597
598        if nret_req > nret as u8 {
599            panic!("invalid number of return value {nret_req} required but accepts only {nret}.");
600        }
601        // shrink stack so as to match with number of return values
602        self.stack
603            .truncate((self.base_pointer as i64 + nret_req as i64) as usize);
604        self.base_pointer -= offset;
605        self.delaysizes_pos_stack.pop();
606        nret
607    }
608    fn allocate_closure(&mut self, fn_i: usize, upv_map: &mut LocalUpValueMap) -> ClosureIdx {
609        let idx = self
610            .closures
611            .insert(Closure::new(&self.prog, self.base_pointer, fn_i, upv_map));
612        ClosureIdx(idx)
613    }
614    /// This API is used for defining higher-order external function that returns some external rust closure.
615    /// Because the native closure cannot be called with CallCls directly, the vm appends an additional function the program,
616    /// that wraps external closure call with an internal closure.
617    pub fn wrap_extern_cls(&mut self, extcls: ExtClsInfo) -> ClosureIdx {
618        let ExtClsInfo { name, fun, ty } = extcls;
619
620        self.prog.ext_fun_table.push((name.to_string(), ty));
621        let prog_funid = self.prog.ext_fun_table.len() - 1;
622        self.ext_cls_table.push((name, fun));
623        let vm_clsid = self.ext_cls_table.len() - 1;
624        self.fn_map.insert(prog_funid, ExtFnIdx::Cls(vm_clsid));
625        let (bytecodes, nargs, nret) = if let Type::Function { arg, ret } = ty.to_type() {
626            let mut wrap_bytecode = Vec::<Instruction>::new();
627            // todo: decouple bytecode generator dependency
628            let asize = ByteCodeGenerator::word_size_for_type(arg);
629            // if there are 2 arguments of float for instance, base pointer should be 2
630            let nargs = match arg.to_type() {
631                Type::Tuple(args) => args.len(),
632                Type::Record(fields) => fields.len(),
633                _ => unreachable!("single argument should be 1 element record"),
634            } as u8;
635            let base = nargs as u8;
636            let nret = ByteCodeGenerator::word_size_for_type(ret);
637            wrap_bytecode.push(Instruction::MoveConst(base, 0));
638            wrap_bytecode.push(Instruction::MoveRange(base + 1, 0, asize));
639
640            wrap_bytecode.extend_from_slice(&[
641                Instruction::CallExtFun(base, nargs, nret as _),
642                Instruction::Return(base, nret as _),
643            ]);
644            (wrap_bytecode, nargs, nret)
645        } else {
646            panic!("non-function type called for wrapping external closure");
647        };
648        let newfunc = FuncProto {
649            nparam: nargs as _,
650            nret: nret as _,
651            bytecodes,
652            constants: vec![prog_funid as _],
653            ..Default::default()
654        };
655        self.prog.global_fn_table.push((name.to_string(), newfunc));
656        let fn_i = self.prog.global_fn_table.len() - 1;
657        let mut cls = Closure::new(
658            &self.prog,
659            self.base_pointer,
660            fn_i,
661            &mut LocalUpValueMap(vec![]),
662        );
663        // wrapper closure will not be released automatically.
664        cls.is_closed = true;
665        let idx = self.closures.insert(cls);
666        ClosureIdx(idx)
667    }
668    fn close_upvalues(&mut self, src: Reg) {
669        let clsidx = Self::get_as::<ClosureIdx>(self.get_stack(src as _));
670
671        let clsidxs = self
672            .get_closure(clsidx)
673            .upvalues
674            .iter()
675            .map(|upv| {
676                let upv = &mut *upv.borrow_mut();
677                match upv {
678                    UpValue::Open(ov) => {
679                        let (_range, ov_raw) =
680                            self.get_open_upvalue(self.base_pointer as usize, *ov);
681                        let is_closure = ov.is_closure;
682                        *upv = UpValue::Closed(ov_raw.to_vec(), is_closure);
683                        is_closure.then_some(Self::get_as::<ClosureIdx>(ov_raw[0]))
684                    }
685                    UpValue::Closed(v, is_closure) => {
686                        is_closure.then_some(Self::get_as::<ClosureIdx>(v[0]))
687                    }
688                }
689            })
690            .collect::<Vec<_>>();
691        clsidxs.iter().for_each(|i| {
692            if let Some(ci) = i {
693                let cls = self.get_closure_mut(*ci);
694                cls.refcount += 1;
695            }
696        });
697        let cls = self.get_closure_mut(clsidx);
698        cls.is_closed = true;
699    }
700    fn release_open_closures(&mut self, local_closures: &[ClosureIdx]) {
701        for clsidx in local_closures.iter() {
702            let cls = self.get_closure(*clsidx);
703            if !cls.is_closed {
704                // log::debug!("release {:?}", clsidx);
705                drop_closure(&mut self.closures, *clsidx)
706            }
707        }
708    }
709    fn get_fnproto(&self, func_i: usize) -> &FuncProto {
710        &self.prog.global_fn_table[func_i].1
711    }
712    /// Execute a function within the VM.
713    ///
714    /// `func_i` is an index into the program's function table and `cls_i` is an
715    /// optional closure that provides the environment for the call.
716    /// The returned [`ReturnCode`] is the number of values pushed on the stack
717    /// as a result of the call.
718    pub fn execute(&mut self, func_i: usize, cls_i: Option<ClosureIdx>) -> ReturnCode {
719        let mut local_closures: Vec<ClosureIdx> = vec![];
720        let mut upv_map = LocalUpValueMap::default();
721        let mut pcounter = 0;
722        // if cfg!(test) {
723        //     log::trace!("{:?}", func);
724        // }
725
726        loop {
727            // if cfg!(debug_assertions) && log::max_level() >= log::Level::Trace {
728            //     let mut line = String::new();
729            //     line += &format!("{: <20} {}", func.bytecodes[pcounter], ": [");
730            //     for i in 0..self.stack.len() {
731            //         if i == self.base_pointer as usize {
732            //             line += "!";
733            //         }
734            //         line += &match self.debug_stacktype[i] {
735            //             RawValType::Float => format!("{0:.5}f", Self::get_as::<f64>(self.stack[i])),
736            //             RawValType::Int => format!("{0:.5}i", Self::get_as::<i64>(self.stack[i])),
737            //             RawValType::UInt => format!("{0:.5}u", Self::get_as::<u64>(self.stack[i])),
738            //         };
739            //         if i < self.stack.len() - 1 {
740            //             line += ",";
741            //         }
742            //     }
743            //     line += "]";
744            //     log::trace!("{line}");
745            // }
746            let mut increment = 1;
747            match self.get_fnproto(func_i).bytecodes[pcounter] {
748                Instruction::Move(dst, src) => {
749                    self.set_stack(dst as i64, self.get_stack(src as i64));
750                }
751                Instruction::MoveConst(dst, pos) => {
752                    self.set_stack(dst as i64, self.get_fnproto(func_i).constants[pos as usize]);
753                }
754                Instruction::MoveImmF(dst, v) => {
755                    self.set_stack(dst as i64, Self::to_value(Into::<f64>::into(v)));
756                }
757                Instruction::MoveRange(dst, src, n) => {
758                    let (range, _slice) = self.get_stack_range(src as _, n);
759                    self.move_stack_range(dst as i64, range);
760                }
761                Instruction::CallCls(func, nargs, nret_req) => {
762                    let addr = self.get_stack(func as i64);
763                    let cls_i = Self::get_as::<ClosureIdx>(addr);
764                    let cls = self.get_closure(cls_i);
765                    let pos_of_f = cls.fn_proto_pos;
766                    self.states_stack.push(cls_i);
767                    self.call_function(func, nargs, nret_req, move |machine| {
768                        machine.execute(pos_of_f, Some(cls_i))
769                    });
770                    self.states_stack.pop();
771                }
772                Instruction::Call(func, nargs, nret_req) => {
773                    let pos_of_f = Self::get_as::<usize>(self.get_stack(func as i64));
774                    self.call_function(func, nargs, nret_req, move |machine| {
775                        machine.execute(pos_of_f, None)
776                    });
777                }
778                Instruction::CallExtFun(func, nargs, nret_req) => {
779                    let ext_fn_idx = self.get_stack(func as i64) as usize;
780                    let fidx = self.fn_map.get(&ext_fn_idx).unwrap();
781                    let nret = match fidx {
782                        ExtFnIdx::Fun(fi) => {
783                            let f = self.ext_fun_table[*fi].1;
784                            self.call_function(func, nargs, nret_req, f)
785                        }
786                        ExtFnIdx::Cls(ci) => {
787                            let (_name, cls) = &self.ext_cls_table[*ci];
788                            let cls = cls.clone();
789                            self.call_function(func, nargs, nret_req, move |machine| {
790                                cls.borrow_mut()(machine)
791                            })
792                        }
793                    };
794
795                    // return
796                    let base = self.base_pointer as usize;
797                    let iret = base + func as usize + 1;
798                    self.stack
799                        .copy_within(iret..(iret + nret as usize), base + func as usize);
800                    self.stack.truncate(base + func as usize + nret as usize);
801                }
802                Instruction::Closure(dst, fn_index) => {
803                    let fn_proto_pos = self.get_stack(fn_index as i64) as usize;
804                    let vaddr = self.allocate_closure(fn_proto_pos, &mut upv_map);
805                    local_closures.push(vaddr);
806                    self.set_stack(dst as i64, Self::to_value(vaddr));
807                }
808                Instruction::Close(src) => {
809                    self.close_upvalues(src);
810                }
811                Instruction::Return0 => {
812                    self.stack.truncate((self.base_pointer - 1) as usize);
813                    self.release_open_closures(&local_closures);
814                    return 0;
815                }
816                Instruction::Return(iret, nret) => {
817                    let _ = self.return_general(iret, nret);
818                    self.release_open_closures(&local_closures);
819                    return nret.into();
820                }
821                Instruction::GetUpValue(dst, index, _size) => {
822                    {
823                        let up_i = cls_i.unwrap();
824                        let cls = self.get_closure(up_i);
825                        let upvalues = &cls.upvalues;
826                        let rv = &upvalues[index as usize];
827                        let vs = match &*rv.borrow() {
828                            UpValue::Open(i) => {
829                                let upper_base = cls.base_ptr as usize;
830                                let (_range, rawv) = self.get_open_upvalue(upper_base, *i);
831                                // log::trace!("open {}", unsafe {
832                                //     std::mem::transmute::<u64, f64>(rawv[0])
833                                // });
834                                // assert_eq!(rawv.len(), size as usize);
835                                let rawv: &[RawVal] = unsafe { std::mem::transmute(rawv) };
836                                rawv
837                            }
838                            UpValue::Closed(rawval, _) => {
839                                //force borrow because closure cell and stack never collisions
840                                let rawv: &[RawVal] =
841                                    unsafe { std::mem::transmute(rawval.as_slice()) };
842                                rawv
843                                //
844                            }
845                        };
846                        self.set_stack_range(dst as i64, vs);
847                    };
848                }
849                Instruction::SetUpValue(index, src, size) => {
850                    let up_i = cls_i.unwrap();
851                    let cls = self.get_closure(up_i);
852                    let upper_base = cls.base_ptr as usize;
853                    let upvalues = &cls.upvalues;
854                    let (_range, v) = self.get_stack_range(src as i64, size);
855                    let rv = &mut *upvalues[index as usize].borrow_mut();
856                    match rv {
857                        UpValue::Open(OpenUpValue { pos: i, size, .. }) => {
858                            let (range, _v) = self.get_stack_range(src as i64, *size);
859                            let dest = upper_base + *i;
860                            unsafe {
861                                //force borrow because closure cell and stack never collisions
862                                let dst = slice::from_raw_parts_mut(
863                                    std::mem::transmute::<*const RawVal, *mut RawVal>(
864                                        self.stack.as_ptr(),
865                                    ),
866                                    self.stack.len(),
867                                );
868                                dst.copy_within(range, dest);
869                            }
870                        }
871                        UpValue::Closed(uv, _) => {
872                            uv.as_mut_slice().copy_from_slice(v);
873                        }
874                    };
875                }
876                Instruction::GetGlobal(dst, gid, size) => {
877                    let gvs = unsafe {
878                        let vstart = self.global_vals.as_ptr().offset(gid as _);
879                        debug_assert!(!vstart.is_null());
880                        // debug_assert!(vstart.is_aligned());
881                        slice::from_raw_parts(vstart, size as _)
882                    };
883                    self.set_stack_range(dst as i64, gvs)
884                }
885                Instruction::SetGlobal(gid, src, size) => {
886                    let gvs = unsafe {
887                        let vstart = self.global_vals.as_mut_ptr().offset(gid as _);
888                        debug_assert!(!vstart.is_null());
889                        // debug_assert!(vstart.is_aligned());
890                        slice::from_raw_parts_mut(vstart, size as _)
891                    };
892                    let (_, slice) = self.get_stack_range(src as i64, size);
893                    gvs.copy_from_slice(slice);
894                }
895                Instruction::Jmp(offset) => {
896                    // -1 is for the offset in last increment
897                    increment = offset;
898                }
899                Instruction::JmpIfNeg(cond, offset) => {
900                    let cond_v = self.get_stack(cond as i64);
901                    if Self::get_as::<f64>(cond_v) <= 0.0 {
902                        increment = offset;
903                    }
904                }
905                Instruction::AddF(dst, src1, src2) => binop!(+,f64,dst,src1,src2,self),
906                Instruction::SubF(dst, src1, src2) => {
907                    binop!(-,f64,dst,src1,src2,self)
908                }
909                Instruction::MulF(dst, src1, src2) => binop!(*,f64,dst,src1,src2,self),
910                Instruction::DivF(dst, src1, src2) => binop!(/,f64,dst,src1,src2,self),
911                Instruction::ModF(dst, src1, src2) => binop!(%,f64,dst,src1,src2,self),
912                Instruction::NegF(dst, src) => uniop!(-,f64,dst,src,self),
913                Instruction::AbsF(dst, src) => uniopmethod!(abs, f64, dst, src, self),
914                Instruction::SqrtF(dst, src) => uniopmethod!(sqrt, f64, dst, src, self),
915                Instruction::SinF(dst, src) => uniopmethod!(sin, f64, dst, src, self),
916                Instruction::CosF(dst, src) => uniopmethod!(cos, f64, dst, src, self),
917                Instruction::PowF(dst, src1, src2) => {
918                    binopmethod!(powf, f64, dst, src1, src2, self)
919                }
920                Instruction::LogF(dst, src) => uniopmethod!(ln, f64, dst, src, self),
921                Instruction::AddI(dst, src1, src2) => binop!(+,i64,dst,src1,src2,self),
922                Instruction::SubI(dst, src1, src2) => binop!(-,i64,dst,src1,src2,self),
923                Instruction::MulI(dst, src1, src2) => binop!(*,i64,dst,src1,src2,self),
924                Instruction::DivI(dst, src1, src2) => binop!(/,i64,dst,src1,src2,self),
925                Instruction::ModI(dst, src1, src2) => binop!(%,i64,dst,src1,src2,self),
926                Instruction::NegI(dst, src) => uniop!(-,i64,dst,src,self),
927                Instruction::AbsI(dst, src) => uniopmethod!(abs, i64, dst, src, self),
928                Instruction::PowI(dst, lhs, rhs) => binop!(^,i64,dst,lhs,rhs,self),
929                Instruction::LogI(_, _, _) => todo!(),
930                Instruction::Not(dst, src) => uniop_bool!(!, dst, src, self),
931                Instruction::Eq(dst, src1, src2) => binop_bool!(==,dst,src1,src2,self),
932                Instruction::Ne(dst, src1, src2) => binop_bool!(!=,dst,src1,src2,self),
933                Instruction::Gt(dst, src1, src2) => binop_bool!(>,dst,src1,src2,self),
934                Instruction::Ge(dst, src1, src2) => binop_bool!(>=,dst,src1,src2,self),
935                Instruction::Lt(dst, src1, src2) => binop_bool!(<,dst,src1,src2,self),
936                Instruction::Le(dst, src1, src2) => binop_bool!(<=,dst,src1,src2,self),
937                Instruction::And(dst, src1, src2) => binop_bool_compose!(&&,dst,src1,src2,self),
938                Instruction::Or(dst, src1, src2) => binop_bool_compose!(||,dst,src1,src2,self),
939                Instruction::CastFtoI(dst, src) => self.set_stack(
940                    dst as i64,
941                    Self::to_value::<i64>(Self::get_as::<f64>(self.get_stack(src as i64)) as i64),
942                ),
943                Instruction::CastItoF(dst, src) => self.set_stack(
944                    dst as i64,
945                    Self::to_value::<f64>(Self::get_as::<i64>(self.get_stack(src as i64)) as f64),
946                ),
947                Instruction::CastItoB(dst, src) => self.set_stack(
948                    dst as i64,
949                    Self::to_value::<bool>(Self::get_as::<i64>(self.get_stack(src as i64)) != 0),
950                ),
951                Instruction::AllocArray(dst, len, elem_size) => {
952                    // Allocate an array of the given length and element size
953                    let key = self.arrays.alloc_array(len as _, elem_size as _);
954                    // Set the stack to point to the start of the new array
955                    self.set_stack(dst as i64, key);
956                }
957                Instruction::GetArrayElem(dst, arr, idx) => {
958                    // Get the array and index values
959                    let array = self.get_stack(arr as i64);
960                    let index = self.get_stack(idx as i64);
961                    let index_val = Self::get_as::<f64>(index);
962                    let adata = self.arrays.get_array(array);
963                    let elem_word_size = adata.elem_word_size as usize;
964                    let buffer = unsafe {
965                        let address = adata
966                            .data
967                            .as_ptr()
968                            .wrapping_add(index_val as usize * elem_word_size);
969                        std::slice::from_raw_parts(address, elem_word_size)
970                    };
971                    set_vec_range(
972                        &mut self.stack,
973                        (self.base_pointer + dst as u64) as usize,
974                        buffer,
975                    );
976                    // todo: implement automatic interpolation and out-of-bounds handling for primitive arrays.
977                }
978                Instruction::SetArrayElem(arr, idx, val) => {
979                    // Get the array, index, and value
980                    let array = self.get_stack(arr as i64);
981                    let index = self.get_stack(idx as i64);
982                    let index_val = Self::get_as::<f64>(index);
983                    let index_int = index_val as usize;
984                    let adata = self.arrays.get_array_mut(array);
985                    let elem_word_size = adata.elem_word_size as usize;
986                    let buffer = unsafe {
987                        let address = adata
988                            .data
989                            .as_mut_ptr()
990                            .wrapping_add(index_int * elem_word_size);
991                        std::slice::from_raw_parts_mut(address, elem_word_size)
992                    };
993                    let (_range, buf_src) = self.get_stack_range(val as _, elem_word_size as _);
994                    buffer.copy_from_slice(buf_src);
995                }
996                Instruction::GetState(dst, size) => {
997                    //force borrow because state storage and stack never collisions
998                    let v: &[RawVal] = unsafe {
999                        std::mem::transmute(self.get_current_state().get_state(size as _))
1000                    };
1001                    self.set_stack_range(dst as i64, v);
1002                }
1003                Instruction::SetState(src, size) => {
1004                    let vs = {
1005                        let (_range, v) = self.get_stack_range(src as i64, size as _);
1006                        unsafe { std::mem::transmute::<&[RawVal], &[RawVal]>(v) }
1007                    };
1008                    let dst = self.get_current_state().get_state_mut(size as _);
1009                    dst.copy_from_slice(vs);
1010                }
1011                Instruction::PushStatePos(v) => self.get_current_state().push_pos(v),
1012                Instruction::PopStatePos(v) => self.get_current_state().pop_pos(v),
1013                Instruction::Delay(dst, src, time) => {
1014                    let i = self.get_stack(src as i64);
1015                    let t = self.get_stack(time as i64);
1016                    let delaysize_i =
1017                        unsafe { self.delaysizes_pos_stack.last().unwrap_unchecked() };
1018
1019                    let size_in_samples = unsafe {
1020                        *self
1021                            .get_fnproto(func_i)
1022                            .delay_sizes
1023                            .get_unchecked(*delaysize_i)
1024                    };
1025                    let mut ringbuf = self.get_current_state().get_as_ringbuffer(size_in_samples);
1026
1027                    let res = ringbuf.process(i, t);
1028                    self.set_stack(dst as i64, res);
1029                }
1030                Instruction::Mem(dst, src) => {
1031                    let s = self.get_stack(src as i64);
1032                    let ptr = self.get_current_state().get_state_mut(1);
1033                    let v = Self::to_value(ptr[0]);
1034                    self.set_stack(dst as i64, v);
1035                    let ptr = self.get_current_state().get_state_mut(1);
1036                    ptr[0] = s;
1037                }
1038                Instruction::Dummy => {
1039                    unreachable!()
1040                }
1041            }
1042            pcounter = (pcounter as i64 + increment as i64) as usize;
1043        }
1044    }
1045    pub fn install_extern_fn(&mut self, name: Symbol, f: ExtFunType) -> usize {
1046        self.ext_fun_table.push((name, f));
1047        self.ext_fun_table.len() - 1
1048    }
1049    pub fn install_extern_cls(&mut self, name: Symbol, f: ExtClsType) -> usize {
1050        self.ext_cls_table.push((name, f));
1051        self.ext_cls_table.len() - 1
1052    }
1053
1054    fn link_functions(&mut self) {
1055        //link external functions
1056        let global_mem_size = self
1057            .prog
1058            .global_vals
1059            .iter()
1060            .map(|WordSize(size)| *size as usize)
1061            .sum();
1062        self.global_vals = vec![0; global_mem_size];
1063        self.prog
1064            .ext_fun_table
1065            .iter_mut()
1066            .enumerate()
1067            .for_each(|(i, (name, _ty))| {
1068                if let Some((j, _)) = self
1069                    .ext_fun_table
1070                    .iter()
1071                    .enumerate()
1072                    .find(|(_j, (fname, _fn))| name == fname.as_str())
1073                {
1074                    let _ = self.fn_map.insert(i, ExtFnIdx::Fun(j));
1075                } else if let Some((j, _)) = self
1076                    .ext_cls_table
1077                    .iter()
1078                    .enumerate()
1079                    .find(|(_j, (fname, _fn))| name == fname.as_str())
1080                {
1081                    let _ = self.fn_map.insert(i, ExtFnIdx::Cls(j));
1082                } else {
1083                    panic!("external function {} cannot be found", name);
1084                }
1085            });
1086    }
1087    pub fn execute_idx(&mut self, idx: usize) -> ReturnCode {
1088        let (_name, func) = &self.prog.global_fn_table[idx];
1089        if !func.bytecodes.is_empty() {
1090            self.global_states
1091                .resize(func.state_skeleton.total_size() as usize);
1092            // 0 is always base pointer to the main function
1093            if !self.stack.is_empty() {
1094                self.stack[0] = 0;
1095            }
1096            self.base_pointer = 1;
1097            self.execute(idx, None)
1098        } else {
1099            0
1100        }
1101    }
1102    pub fn execute_entry(&mut self, entry: &str) -> ReturnCode {
1103        if let Some(idx) = self.prog.get_fun_index(entry) {
1104            self.execute_idx(idx)
1105        } else {
1106            -1
1107        }
1108    }
1109    pub fn execute_main(&mut self) -> ReturnCode {
1110        // 0 is always base pointer to the main function
1111        self.base_pointer += 1;
1112        self.execute(0, None)
1113    }
1114}
1115
1116#[cfg(test)]
1117mod test;