1use core::slice;
2use slotmap::{DefaultKey, SlotMap};
3use std::{cell::RefCell, cmp::Ordering, collections::HashMap, ops::Range, rc::Rc};
4pub mod bytecode;
5pub mod heap;
6pub mod program;
7mod ringbuffer;
8pub use bytecode::*;
9use ringbuffer::Ringbuffer;
10
11use program::OpenUpValue;
12pub use program::{FuncProto, Program};
13
14use crate::{
15 compiler::bytecodegen::ByteCodeGenerator,
16 interner::{Symbol, TypeNodeId},
17 plugin::{ExtClsInfo, ExtClsType, ExtFunInfo, ExtFunType, MachineFunction},
18 runtime::vm::program::WordSize,
19 types::{Type, TypeSize},
20};
21pub type RawVal = u64;
22pub type ReturnCode = i64;
23
24#[derive(Debug, Default, PartialEq)]
25struct StateStorage {
26 pos: usize,
27 rawdata: Vec<u64>,
28}
29impl StateStorage {
30 fn resize(&mut self, size: usize) {
31 self.rawdata.resize(size, 0)
32 }
33 fn get_state(&self, size: u64) -> &[RawVal] {
34 unsafe {
35 let head = self.rawdata.as_ptr().add(self.pos);
36 slice::from_raw_parts(head, size as _)
37 }
38 }
39 fn get_state_mut(&mut self, size: usize) -> &mut [RawVal] {
40 unsafe {
41 let head = self.rawdata.as_mut_ptr().add(self.pos);
42 slice::from_raw_parts_mut(head, size as _)
43 }
44 }
45 fn get_as_ringbuffer(&mut self, size_in_samples: u64) -> Ringbuffer<'_> {
46 let data_head = unsafe { self.rawdata.as_mut_ptr().add(self.pos) };
47 Ringbuffer::new(data_head, size_in_samples)
48 }
49 fn push_pos(&mut self, offset: StateOffset) {
50 self.pos = (self.pos as u64 + (std::convert::Into::<u64>::into(offset))) as usize;
51 }
52 fn pop_pos(&mut self, offset: StateOffset) {
53 self.pos = (self.pos as u64 - (std::convert::Into::<u64>::into(offset))) as usize;
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct ClosureIdx(pub slotmap::DefaultKey);
59
60#[derive(Debug, Clone, Default)]
61struct StateStorageStack(Vec<ClosureIdx>);
62
63impl StateStorageStack {
64 pub fn push(&mut self, i: ClosureIdx) {
65 self.0.push(i)
66 }
67 pub fn pop(&mut self) {
68 let _ = self.0.pop();
69 }
70}
71
72#[derive(Debug, Clone, Default)]
73pub(crate) struct ArrayHeap {
74 elem_word_size: u64,
75 data: Vec<RawVal>,
76}
77impl ArrayHeap {
78 pub fn get_length_array(&self) -> u64 {
79 self.data.len() as u64 / self.elem_word_size
80 }
81 pub fn get_elem_word_size(&self) -> u64 {
82 self.elem_word_size
83 }
84 pub fn get_data(&self) -> &[RawVal] {
85 &self.data
86 }
87 pub fn get_data_mut(&mut self) -> &mut [RawVal] {
88 &mut self.data
89 }
90}
91#[derive(Debug, Clone, Default)]
92pub(crate) struct ArrayStorage {
93 data: SlotMap<DefaultKey, ArrayHeap>,
94}
95pub(crate) type ArrayIdx = slotmap::DefaultKey;
96impl ArrayStorage {
97 pub fn alloc_array(&mut self, len: u64, elem_size: u64) -> RawVal {
98 let array = ArrayHeap {
99 elem_word_size: elem_size,
100 data: vec![0u64; (len * elem_size) as usize],
101 };
102 let key = self.data.insert(array);
103 debug_assert!(
104 std::mem::size_of::<ArrayIdx>() == 8,
105 "ArrayIdx size must be 8 bytes"
106 );
107 unsafe { std::mem::transmute_copy::<ArrayIdx, RawVal>(&key) }
108 }
109 pub fn get_array(&self, id: RawVal) -> &ArrayHeap {
110 let key: ArrayIdx = unsafe { std::mem::transmute_copy::<RawVal, ArrayIdx>(&id) };
111 self.data.get(key).expect("Invalid ArrayIdx")
112 }
113 pub fn get_array_mut(&mut self, id: RawVal) -> &mut ArrayHeap {
114 let key: ArrayIdx = unsafe { std::mem::transmute_copy::<RawVal, ArrayIdx>(&id) };
115 self.data.get_mut(key).expect("Invalid ArrayIdx")
116 }
117}
118#[derive(Debug, Clone, PartialEq)]
121enum UpValue {
122 Open(OpenUpValue),
123 Closed(Vec<RawVal>, bool),
124}
125type SharedUpValue = Rc<RefCell<UpValue>>;
126impl From<OpenUpValue> for UpValue {
127 fn from(value: OpenUpValue) -> Self {
128 Self::Open(value)
129 }
130}
131
132#[derive(Default)]
133struct LocalUpValueMap(Vec<(Reg, SharedUpValue)>);
134
135impl LocalUpValueMap {
136 pub fn get_or_insert(&mut self, ov: OpenUpValue) -> SharedUpValue {
137 let OpenUpValue { pos, .. } = ov;
138 self.0
139 .iter()
140 .find_map(|(i2, v)| (pos == *i2 as _).then_some(v.clone()))
141 .unwrap_or_else(|| {
142 let v = Rc::new(RefCell::new(UpValue::Open(ov)));
143 self.0.push((pos as Reg, v.clone()));
144 v
145 })
146 }
147}
148
149#[derive(Debug, Default, PartialEq)]
150pub struct Closure {
152 pub fn_proto_pos: usize, pub base_ptr: u64, pub is_closed: bool,
155 pub refcount: u64,
156 pub(self) upvalues: Vec<SharedUpValue>,
157 state_storage: StateStorage,
158}
159impl Closure {
160 pub(self) fn new(
161 program: &Program,
162 base_ptr: u64,
163 fn_i: usize,
164 upv_map: &mut LocalUpValueMap,
165 ) -> Self {
166 let fnproto = &program.global_fn_table[fn_i].1;
167 let upvalues = fnproto
168 .upindexes
169 .iter()
170 .map(|ov| upv_map.get_or_insert(*ov))
171 .collect::<Vec<_>>();
172 let mut state_storage = StateStorage::default();
173 state_storage.resize(fnproto.state_skeleton.total_size() as usize);
174 Self {
175 fn_proto_pos: fn_i,
176 upvalues,
177 is_closed: false,
178 refcount: 1,
179 base_ptr,
180 state_storage,
181 }
182 }
183}
184
185pub type ClosureStorage = SlotMap<DefaultKey, Closure>;
186
187#[derive(Clone, Copy, Default)]
188enum RawValType {
189 Float,
190 #[default]
191 Int,
192 }
194
195#[derive(Clone, Copy)]
196enum ExtFnIdx {
197 Fun(usize),
198 Cls(usize),
199}
200pub struct Machine {
206 pub prog: Program,
208 stack: Vec<RawVal>,
209 base_pointer: u64,
210 pub closures: ClosureStorage, pub heap: heap::HeapStorage, pub ext_fun_table: Vec<(Symbol, ExtFunType)>,
213 pub ext_cls_table: Vec<(Symbol, ExtClsType)>,
214 pub arrays: ArrayStorage,
215 fn_map: HashMap<usize, ExtFnIdx>, global_states: StateStorage,
218 states_stack: StateStorageStack,
219 delaysizes_pos_stack: Vec<usize>,
220 global_vals: Vec<RawVal>,
221 debug_stacktype: Vec<RawValType>,
222}
223
224macro_rules! binop {
225 ($op:tt,$t:ty, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
226 {
227 $self.set_stacktype($dst as i64, RawValType::Float);
228 $self.set_stack($dst as i64, Self::to_value::<$t>(
229 Self::get_as::<$t>($self.get_stack($src1 as i64))
230 $op Self::get_as::<$t>($self.get_stack($src2 as i64))))
231 }
232 };
233}
234macro_rules! binop_bool {
235 ($op:tt, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
236 {
237 $self.set_stacktype($dst as i64, RawValType::Float);
238 let bres:bool =
239 Self::get_as::<f64>($self.get_stack($src1 as i64))
240 $op Self::get_as::<f64>($self.get_stack($src2 as i64));
241 let fres = if bres{
242 1.0f64
243 }else{
244 0.0f64
245 };
246 $self.set_stack($dst as i64,Self::to_value::<f64>(fres))
247 }
248 };
249}
250macro_rules! binop_bool_compose {($op:tt, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {
252 {
253 $self.set_stacktype($dst as i64, RawValType::Float);
254 let bres:bool =
255 Self::get_as::<f64>($self.get_stack($src1 as i64))>0.0
256 $op Self::get_as::<f64>($self.get_stack($src2 as i64))>0.0;
257 let fres = if bres{ 1.0f64 }else{ 0.0f64 };
258 $self.set_stack($dst as i64,Self::to_value::<f64>(fres))
259 }
260 };
261}
262macro_rules! binopmethod {
263 ($op:ident,$t:ty, $dst:expr,$src1:expr,$src2:expr,$self:ident) => {{
264 $self.set_stacktype($dst as i64, RawValType::Float);
265 $self.set_stack(
266 $dst as i64,
267 Self::to_value::<$t>(
268 Self::get_as::<$t>($self.get_stack($src1 as i64))
269 .$op(Self::get_as::<$t>($self.get_stack($src2 as i64))),
270 ),
271 )
272 }};
273}
274macro_rules! uniop {
275 ($op:tt,$t:ty, $dst:expr,$src:expr,$self:ident) => {
276 $self.set_stack($dst as i64,
277 Self::to_value::<$t>(
278 $op Self::get_as::<$t>($self.get_stack($src as i64))))
279 };
280}
281macro_rules! uniop_bool {
282 ($op:tt, $dst:expr,$src:expr,$self:ident) => {{
283 let bres: bool = $op(matches!(
284 Self::get_as::<f64>($self.get_stack($src as i64)).partial_cmp(&0.0),
285 Some(std::cmp::Ordering::Greater)
286 ));
287 let fres = if bres { 1.0f64 } else { 0.0f64 };
288 $self.set_stack($dst as i64, Self::to_value::<f64>(fres))
289 }};
290}
291macro_rules! uniopmethod {
292 ($op:tt,$t:ty, $dst:expr,$src:expr,$self:ident) => {{
293 $self.set_stack(
294 $dst as i64,
295 Self::to_value::<$t>(Self::get_as::<$t>($self.get_stack($src as i64)).$op()),
296 )
297 }};
298}
299
300fn set_vec<T>(vec: &mut Vec<T>, i: usize, value: T)
301where
302 T: Clone + std::default::Default,
303{
304 match i.cmp(&vec.len()) {
305 Ordering::Less => vec[i] = value,
306 Ordering::Equal => vec.push(value),
307 Ordering::Greater => {
308 vec.resize(i, T::default());
309 vec.push(value);
310 }
311 }
312}
313fn set_vec_range<T>(vec: &mut Vec<T>, i: usize, values: &[T])
314where
315 T: std::fmt::Debug + Copy + std::default::Default,
316{
317 let start = i;
321 let end = i + values.len();
322 if end > vec.len() {
323 vec.resize(i, T::default());
324 }
325 match start.cmp(&vec.len()) {
326 Ordering::Less => {
327 let range = i..(i + values.len());
328 for (v, i) in values.iter().zip(range.into_iter()) {
329 vec[i] = *v;
330 }
331 }
332 Ordering::Equal => values.iter().for_each(|v| vec.push(*v)),
333 Ordering::Greater => values.iter().for_each(|v| vec.push(*v)),
334 }
335}
336
337impl Machine {
338 pub fn drop_closure(&mut self, id: ClosureIdx) {
341 let cls = self.closures.get_mut(id.0).unwrap();
342 cls.refcount -= 1;
343 if cls.refcount == 0 {
344 let refs = self
345 .closures
346 .get_mut(id.0)
347 .unwrap()
348 .upvalues
349 .iter()
350 .map(|v| {
351 let v = v.borrow();
352 match &*v {
353 UpValue::Closed(data, true) => {
354 let heap_idx = Self::get_as::<heap::HeapIdx>(data[0]);
356 self.heap.get(heap_idx).and_then(|obj| {
357 (!obj.data.is_empty())
358 .then_some((heap_idx, Self::get_as::<ClosureIdx>(obj.data[0])))
359 })
360 }
361 _ => None,
362 }
363 })
364 .collect::<Vec<_>>();
365 refs.iter().filter_map(|i| *i).for_each(|(heap_idx, clsi)| {
366 self.drop_closure(clsi);
367 heap::heap_release(&mut self.heap, heap_idx);
368 });
369 self.closures.remove(id.0);
370 }
371 }
372
373 pub fn new(
375 prog: Program,
376 extfns: impl Iterator<Item = ExtFunInfo>,
377 extcls: impl Iterator<Item = Box<dyn MachineFunction>>,
378 ) -> Self {
379 let mut res = Self {
380 prog,
381 stack: vec![],
382 base_pointer: 0,
383 closures: Default::default(),
384 heap: Default::default(),
385 ext_fun_table: vec![],
386 ext_cls_table: vec![],
387 fn_map: HashMap::new(),
388 arrays: ArrayStorage::default(),
390 global_states: Default::default(),
391 states_stack: Default::default(),
392 delaysizes_pos_stack: vec![0],
393 global_vals: vec![],
394 debug_stacktype: vec![RawValType::Int; 255],
395 };
396 extfns.for_each(|ExtFunInfo { name, fun, .. }| {
397 let _ = res.install_extern_fn(name, fun);
398 });
399 extcls.for_each(|machine_function| {
400 let _ = res.install_extern_cls(machine_function.get_name(), machine_function.get_fn());
401 });
402 res.link_functions();
403 res
404 }
405 pub fn new_resume(&self, prog: Program) -> Self {
407 let mut new_vm = Self {
408 prog,
409 stack: vec![],
410 base_pointer: 0,
411 closures: Default::default(),
412 heap: Default::default(),
413 ext_fun_table: vec![],
414 ext_cls_table: vec![],
415 fn_map: HashMap::new(),
416 arrays: ArrayStorage::default(),
418 global_states: Default::default(),
419 states_stack: Default::default(),
420 delaysizes_pos_stack: vec![0],
421 global_vals: vec![],
422 debug_stacktype: vec![RawValType::Int; 255],
423 };
424 new_vm.ext_fun_table = self.ext_fun_table.clone();
427 new_vm.ext_cls_table = self.ext_cls_table.clone();
428 new_vm.global_vals = self.global_vals.clone();
429 new_vm.arrays = self.arrays.clone();
430
431 let new_state = state_tree::update_state_storage(
432 &self.global_states.rawdata,
433 self.prog
434 .get_dsp_state_skeleton()
435 .cloned()
436 .expect("dsp function not found"),
437 new_vm
438 .prog
439 .get_dsp_state_skeleton()
440 .cloned()
441 .expect("dsp function not found"),
442 );
443 match new_state {
444 Ok(Some(s)) => {
445 new_vm.global_states.rawdata = s;
446 }
447 Ok(None) => {
448 log::info!("No state structure change detected. Just copies buffer");
449 new_vm.global_states.rawdata = self.global_states.rawdata.clone();
450 }
451 Err(e) => {
452 log::error!("Failed to migrate global state: {e}");
453 }
454 }
455 new_vm.link_functions();
456 new_vm.execute_main();
457 new_vm
458 }
459 pub fn clear_stack(&mut self) {
460 self.stack.fill(0);
461 }
462 pub fn get_stack(&self, offset: i64) -> RawVal {
463 self.get_stack_range(offset, 1).1[0]
469 }
470 pub fn get_stack_range(&self, offset: i64, word_size: TypeSize) -> (Range<usize>, &[RawVal]) {
471 let addr_start = self.base_pointer as usize + offset as usize;
472 let addr_end = addr_start + word_size as usize;
473 let start = self.stack.as_slice().as_ptr();
474 let slice = unsafe {
475 let vstart = start.add(addr_start);
479 slice::from_raw_parts(vstart, word_size as usize)
480 };
481 (addr_start..addr_end, slice)
482 }
483 pub fn get_stack_range_mut(
484 &mut self,
485 offset: i64,
486 word_size: TypeSize,
487 ) -> (Range<usize>, &mut [RawVal]) {
488 let addr_start = self.base_pointer as usize + offset as usize;
489 let addr_end = addr_start + word_size as usize;
490 let start = self.stack.as_mut_ptr();
491 let slice = unsafe {
492 let vstart = start.add(addr_start);
496 slice::from_raw_parts_mut(vstart, word_size as usize)
497 };
498 (addr_start..addr_end, slice)
499 }
500 pub fn set_stack(&mut self, offset: i64, v: RawVal) {
501 self.set_stack_range(offset, &[v])
502 }
503 pub fn set_stack_range(&mut self, offset: i64, vs: &[RawVal]) {
504 set_vec_range(
508 &mut self.stack,
509 (self.base_pointer as i64 + offset) as usize,
510 vs,
511 )
512 }
513 fn move_stack_range(&mut self, offset: i64, srcrange: Range<usize>) {
514 let dest = (self.base_pointer as i64 + offset) as usize;
515 if srcrange.end > self.stack.len() {
516 self.stack.resize(srcrange.end, 0);
517 }
518 let dest_end = dest + (srcrange.end - srcrange.start);
519 if dest_end > self.stack.len() {
520 self.stack.resize(dest_end, 0);
521 }
522 self.stack.copy_within(srcrange, dest)
523 }
524 fn set_stacktype(&mut self, offset: i64, t: RawValType) {
525 }
531 pub fn get_top_n(&self, n: usize) -> &[RawVal] {
532 let len = self.stack.len();
533 &self.stack[(len - n)..]
534 }
535 pub fn get_closure_idx_from_heap(&self, heap_idx: heap::HeapIdx) -> ClosureIdx {
542 let heap_obj = self.heap.get(heap_idx).expect("Invalid HeapIdx");
543 Self::get_as::<ClosureIdx>(heap_obj.data[0])
544 }
545 fn get_upvalue_offset(upper_base: usize, offset: OpenUpValue) -> usize {
546 upper_base + offset.pos
547 }
548 pub fn get_open_upvalue(
549 &self,
550 upper_base: usize,
551 ov: OpenUpValue,
552 ) -> (Range<usize>, &[RawVal]) {
553 let OpenUpValue { size, .. } = ov;
554 let abs_pos = Self::get_upvalue_offset(upper_base, ov);
556 let end = abs_pos + size as usize;
557 let slice = unsafe {
558 let vstart = self.stack.as_slice().as_ptr().add(abs_pos);
559 slice::from_raw_parts(vstart, size as usize)
560 };
561 (abs_pos..end, slice)
562 }
563 pub fn get_closure(&self, idx: ClosureIdx) -> &Closure {
564 debug_assert!(
565 self.closures.contains_key(idx.0),
566 "Invalid Closure Id referred"
567 );
568 unsafe { self.closures.get_unchecked(idx.0) }
569 }
570 pub(crate) fn get_closure_mut(&mut self, idx: ClosureIdx) -> &mut Closure {
571 debug_assert!(
572 self.closures.contains_key(idx.0),
573 "Invalid Closure Id referred"
574 );
575 unsafe { self.closures.get_unchecked_mut(idx.0) }
576 }
577 fn get_current_state(&mut self) -> &mut StateStorage {
578 if self.states_stack.0.is_empty() {
579 &mut self.global_states
580 } else {
581 let idx = unsafe { self.states_stack.0.last().unwrap_unchecked() };
582 &mut self.get_closure_mut(*idx).state_storage
583 }
584 }
585 fn return_general(&mut self, iret: Reg, nret: Reg) -> &[u64] {
586 let base = self.base_pointer as usize;
587 let iret_abs = base + iret as usize;
588 self.stack
589 .copy_within(iret_abs..(iret_abs + nret as usize), base - 1);
590 self.stack.truncate(base - 1 + nret as usize);
593
594 (self.stack.split_at(base).1) as _
595 }
596
597 pub fn get_as<T>(v: RawVal) -> T {
598 unsafe { std::mem::transmute_copy::<RawVal, T>(&v) }
599 }
600 pub fn get_as_array<T>(v: &[RawVal]) -> &[T] {
601 unsafe { std::mem::transmute::<&[RawVal], &[T]>(v) }
602 }
603 pub fn to_value<T>(v: T) -> RawVal {
604 assert_eq!(std::mem::size_of::<T>(), 8);
605 unsafe { std::mem::transmute_copy::<T, RawVal>(&v) }
606 }
607 fn call_function<F>(
608 &mut self,
609 func_pos: u8,
610 _nargs: u8,
611 nret_req: u8,
612 mut action: F,
613 ) -> ReturnCode
614 where
615 F: FnMut(&mut Self) -> ReturnCode,
616 {
617 let offset = (func_pos + 1) as u64;
618 self.delaysizes_pos_stack.push(0);
619 self.base_pointer += offset;
620 let nret = action(self);
621
622 if nret_req > nret as u8 {
623 panic!("invalid number of return value {nret_req} required but accepts only {nret}.");
624 }
625 self.stack
627 .truncate((self.base_pointer as i64 + nret_req as i64) as usize);
628 self.base_pointer -= offset;
629 self.delaysizes_pos_stack.pop();
630 nret
631 }
632 fn allocate_closure(&mut self, fn_i: usize, upv_map: &mut LocalUpValueMap) -> ClosureIdx {
633 let idx = self
634 .closures
635 .insert(Closure::new(&self.prog, self.base_pointer, fn_i, upv_map));
636 ClosureIdx(idx)
637 }
638
639 fn allocate_heap_closure(
642 &mut self,
643 fn_i: usize,
644 upv_map: &mut LocalUpValueMap,
645 ) -> heap::HeapIdx {
646 let closure_idx = self.allocate_closure(fn_i, upv_map);
649
650 let heap_obj = heap::HeapObject::with_data(vec![Self::to_value(closure_idx)]);
653 let heap_idx = self.heap.insert(heap_obj);
654
655 log::trace!(
656 "allocate_heap_closure: fn_i={fn_i}, heap_idx={heap_idx:?}, closure_idx={closure_idx:?}"
657 );
658 heap_idx
659 }
660
661 fn release_heap_closure(&mut self, heap_idx: heap::HeapIdx) {
667 log::trace!("release_heap_closure: heap_idx={heap_idx:?}");
668
669 let maybe_closure = self.heap.get(heap_idx).and_then(|obj| {
671 (!obj.data.is_empty()).then_some(Self::get_as::<ClosureIdx>(obj.data[0]))
672 });
673
674 if let Some(closure_idx) = maybe_closure {
675 if !self.get_closure(closure_idx).is_closed {
676 self.drop_closure(closure_idx);
677 }
678 }
679
680 heap::heap_release(&mut self.heap, heap_idx);
685 }
686
687 fn close_heap_upvalues(&mut self, heap_idx: heap::HeapIdx) {
689 log::trace!("close_heap_upvalues: heap_idx={heap_idx:?}");
690
691 if let Some(heap_obj) = self.heap.get(heap_idx) {
693 if !heap_obj.data.is_empty() {
694 let closure_idx = Self::get_as::<ClosureIdx>(heap_obj.data[0]);
695 self.close_upvalues_by_idx(closure_idx);
697 }
698 }
699 }
700
701 fn release_heap_closures(&mut self, local_heap_closures: &[heap::HeapIdx]) {
711 for &heap_idx in local_heap_closures {
712 self.release_heap_closure(heap_idx);
713 }
714 }
715
716 pub fn wrap_extern_cls(&mut self, extcls: ExtClsInfo) -> ClosureIdx {
720 let ExtClsInfo { name, fun, ty } = extcls;
721
722 self.prog.ext_fun_table.push((name.to_string(), ty));
723 let prog_funid = self.prog.ext_fun_table.len() - 1;
724 self.ext_cls_table.push((name, fun));
725 let vm_clsid = self.ext_cls_table.len() - 1;
726 self.fn_map.insert(prog_funid, ExtFnIdx::Cls(vm_clsid));
727 let (bytecodes, nargs, nret) = if let Type::Function { arg, ret } = ty.to_type() {
728 let mut wrap_bytecode = Vec::<Instruction>::new();
729 let asize = ByteCodeGenerator::word_size_for_type(arg);
731 let nargs = match arg.to_type() {
733 Type::Tuple(args) => args.len(),
734 Type::Record(fields) => fields.len(),
735 _ => unreachable!("single argument should be 1 element record"),
736 } as u8;
737 let base = nargs as u8;
738 let nret = ByteCodeGenerator::word_size_for_type(ret);
739 wrap_bytecode.push(Instruction::MoveConst(base, 0));
740 wrap_bytecode.push(Instruction::MoveRange(base + 1, 0, asize));
741
742 wrap_bytecode.extend_from_slice(&[
743 Instruction::CallExtFun(base, nargs, nret as _),
744 Instruction::Return(base, nret as _),
745 ]);
746 (wrap_bytecode, nargs, nret)
747 } else {
748 panic!("non-function type called for wrapping external closure");
749 };
750 let newfunc = FuncProto {
751 nparam: nargs as _,
752 nret: nret as _,
753 bytecodes,
754 constants: vec![prog_funid as _],
755 ..Default::default()
756 };
757 self.prog.global_fn_table.push((name.to_string(), newfunc));
758 let fn_i = self.prog.global_fn_table.len() - 1;
759 let mut cls = Closure::new(
760 &self.prog,
761 self.base_pointer,
762 fn_i,
763 &mut LocalUpValueMap(vec![]),
764 );
765 cls.is_closed = true;
767 let idx = self.closures.insert(cls);
768 ClosureIdx(idx)
769 }
770 fn close_upvalues(&mut self, src: Reg) {
771 let clsidx = Self::get_as::<ClosureIdx>(self.get_stack(src as _));
772 self.close_upvalues_by_idx(clsidx);
773 }
774 fn close_upvalues_by_idx(&mut self, clsidx: ClosureIdx) {
777 let closure_base_ptr = self.get_closure(clsidx).base_ptr as usize;
778
779 let refs = self
782 .get_closure(clsidx)
783 .upvalues
784 .iter()
785 .map(|upv| {
786 let upv = &mut *upv.borrow_mut();
787 match upv {
788 UpValue::Open(ov) => {
789 let (_range, ov_raw) = self.get_open_upvalue(closure_base_ptr, *ov);
790 let is_closure = ov.is_closure;
791 *upv = UpValue::Closed(ov_raw.to_vec(), is_closure);
792 if is_closure {
793 let heap_idx = Self::get_as::<heap::HeapIdx>(ov_raw[0]);
795 Some(heap_idx)
796 } else {
797 None
798 }
799 }
800 UpValue::Closed(v, is_closure) => {
801 if *is_closure {
802 Some(Self::get_as::<heap::HeapIdx>(v[0]))
803 } else {
804 None
805 }
806 }
807 }
808 })
809 .collect::<Vec<_>>();
810 refs.iter().for_each(|heap_opt| {
812 if let Some(heap_idx) = heap_opt {
813 heap::heap_retain(&mut self.heap, *heap_idx);
815 if let Some(heap_obj) = self.heap.get(*heap_idx) {
817 if !heap_obj.data.is_empty() {
818 let ci = Self::get_as::<ClosureIdx>(heap_obj.data[0]);
819 self.get_closure_mut(ci).refcount += 1;
820 }
821 }
822 }
823 });
824 let cls = self.get_closure_mut(clsidx);
825 cls.is_closed = true;
826 }
827 fn release_open_closures(&mut self, local_closures: &[ClosureIdx]) {
828 for clsidx in local_closures.iter() {
829 let cls = self.get_closure(*clsidx);
830 if !cls.is_closed {
831 self.drop_closure(*clsidx)
833 }
834 }
835 }
836 fn get_fnproto(&self, func_i: usize) -> &FuncProto {
837 &self.prog.global_fn_table[func_i].1
838 }
839 pub fn execute(&mut self, func_i: usize, cls_i: Option<ClosureIdx>) -> ReturnCode {
846 let mut local_closures: Vec<ClosureIdx> = vec![];
847 let mut local_heap_closures: Vec<heap::HeapIdx> = vec![];
848 let mut upv_map = LocalUpValueMap::default();
849 let mut pcounter = 0;
850 loop {
855 let mut increment = 1;
875 match self.get_fnproto(func_i).bytecodes[pcounter] {
876 Instruction::Move(dst, src) => {
877 self.set_stack(dst as i64, self.get_stack(src as i64));
878 }
879 Instruction::MoveConst(dst, pos) => {
880 self.set_stack(dst as i64, self.get_fnproto(func_i).constants[pos as usize]);
881 }
882 Instruction::MoveImmF(dst, v) => {
883 self.set_stack(dst as i64, Self::to_value(Into::<f64>::into(v)));
884 }
885 Instruction::MoveRange(dst, src, n) => {
886 let (range, _slice) = self.get_stack_range(src as _, n);
887 self.move_stack_range(dst as i64, range);
888 }
889 Instruction::CallCls(func, nargs, nret_req) => {
890 let addr = self.get_stack(func as i64);
891 let cls_i = Self::get_as::<ClosureIdx>(addr);
892 let cls = self.get_closure(cls_i);
893 let pos_of_f = cls.fn_proto_pos;
894 self.states_stack.push(cls_i);
895 self.call_function(func, nargs, nret_req, move |machine| {
896 machine.execute(pos_of_f, Some(cls_i))
897 });
898 self.states_stack.pop();
899 }
900 Instruction::Call(func, nargs, nret_req) => {
901 let pos_of_f = Self::get_as::<usize>(self.get_stack(func as i64));
902 self.call_function(func, nargs, nret_req, move |machine| {
903 machine.execute(pos_of_f, None)
904 });
905 }
906 Instruction::CallExtFun(func, nargs, nret_req) => {
907 let ext_fn_idx = self.get_stack(func as i64) as usize;
908 let fidx = self.fn_map.get(&ext_fn_idx).unwrap();
909 let nret = match fidx {
910 ExtFnIdx::Fun(fi) => {
911 let f = self.ext_fun_table[*fi].1;
912 self.call_function(func, nargs, nret_req, f)
913 }
914 ExtFnIdx::Cls(ci) => {
915 let (_name, cls) = &self.ext_cls_table[*ci];
916 let cls = cls.clone();
917 self.call_function(func, nargs, nret_req, move |machine| {
918 cls.borrow_mut()(machine)
919 })
920 }
921 };
922
923 let base = self.base_pointer as usize;
925 let iret = base + func as usize + 1;
926 self.stack
927 .copy_within(iret..(iret + nret as usize), base + func as usize);
928 self.stack.truncate(base + func as usize + nret as usize);
929 }
930 Instruction::Closure(dst, fn_index) => {
931 let fn_proto_pos = self.get_stack(fn_index as i64) as usize;
932 let vaddr = self.allocate_closure(fn_proto_pos, &mut upv_map);
933 local_closures.push(vaddr);
934 self.set_stack(dst as i64, Self::to_value(vaddr));
935 }
936 Instruction::Close(src) => {
937 self.close_upvalues(src);
938 }
939 Instruction::MakeHeapClosure(dst, fn_index, _size) => {
941 let fn_proto_pos = self.get_stack(fn_index as i64) as usize;
942 let heap_idx = self.allocate_heap_closure(fn_proto_pos, &mut upv_map);
943 local_heap_closures.push(heap_idx);
944 self.set_stack(dst as i64, Self::to_value(heap_idx));
946 }
947 Instruction::CloseHeapClosure(src) => {
948 let heap_addr = self.get_stack(src as i64);
949 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
950 self.close_heap_upvalues(heap_idx);
951 }
952 Instruction::CloneHeap(src) => {
953 let heap_addr = self.get_stack(src as i64);
954 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
955 heap::heap_retain(&mut self.heap, heap_idx);
956 }
957 Instruction::BoxAlloc(dst, src, inner_size) => {
958 let (_, src_data) = self.get_stack_range(src as i64, inner_size);
960 let data = src_data.to_vec();
961 let heap_idx = self.heap.insert(heap::HeapObject::with_data(data));
962 self.set_stack(dst as i64, Self::to_value(heap_idx));
963 }
964 Instruction::BoxLoad(dst, src, inner_size) => {
965 let heap_addr = self.get_stack(src as i64);
967 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
968 let heap_obj = self
969 .heap
970 .get(heap_idx)
971 .expect("BoxLoad: invalid heap index");
972 let data: Vec<u64> = heap_obj.data[..inner_size as usize].to_vec();
973 self.set_stack_range(dst as i64, &data);
974 }
975 Instruction::BoxClone(src) => {
976 let heap_addr = self.get_stack(src as i64);
977 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
978 heap::heap_retain(&mut self.heap, heap_idx);
979 }
980 Instruction::BoxRelease(src) => {
981 let heap_addr = self.get_stack(src as i64);
982 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
983 heap::heap_release(&mut self.heap, heap_idx);
984 }
985 Instruction::BoxStore(ptr_reg, src, inner_size) => {
986 let heap_addr = self.get_stack(ptr_reg as i64);
987 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
988 let (_, src_data) = self.get_stack_range(src as i64, inner_size);
989 let data = src_data.to_vec();
990 let heap_obj = self
991 .heap
992 .get_mut(heap_idx)
993 .expect("BoxStore: invalid heap index");
994 heap_obj.data[..inner_size as usize].copy_from_slice(&data);
995 }
996 Instruction::CloneUserSum(value_reg, value_size, type_idx) => {
997 let (_, value_data) = self.get_stack_range(value_reg as i64, value_size);
998 let value_vec = value_data.to_vec();
999 let ty = self
1000 .prog
1001 .get_type_from_table(type_idx)
1002 .expect("Invalid type table index in CloneUserSum");
1003 Self::clone_usersum_recursive(&value_vec, &ty, &mut self.heap);
1004 }
1005 Instruction::ReleaseUserSum(value_reg, value_size, type_idx) => {
1006 let (_, value_data) = self.get_stack_range(value_reg as i64, value_size);
1007 let value_vec = value_data.to_vec();
1008 let ty = self
1009 .prog
1010 .get_type_from_table(type_idx)
1011 .expect("Invalid type table index in ReleaseUserSum");
1012 let tt = &self.prog.type_table;
1013 Self::release_usersum_recursive(&value_vec, &ty, &mut self.heap, tt);
1014 }
1015 Instruction::CallIndirect(func, nargs, nret_req) => {
1016 let heap_addr = self.get_stack(func as i64);
1018 let heap_idx = Self::get_as::<heap::HeapIdx>(heap_addr);
1019
1020 let heap_obj = self.heap.get(heap_idx).expect("Invalid heap index");
1022 let cls_i = Self::get_as::<ClosureIdx>(heap_obj.data[0]);
1023
1024 let cls = self.get_closure(cls_i);
1025 let pos_of_f = cls.fn_proto_pos;
1026 self.states_stack.push(cls_i);
1027 self.call_function(func, nargs, nret_req, move |machine| {
1028 machine.execute(pos_of_f, Some(cls_i))
1029 });
1030 self.states_stack.pop();
1031 }
1032 Instruction::Return0 => {
1033 self.stack.truncate((self.base_pointer - 1) as usize);
1034 self.release_open_closures(&local_closures);
1035 self.release_heap_closures(&local_heap_closures);
1036 return 0;
1037 }
1038 Instruction::Return(iret, nret) => {
1039 let _ = self.return_general(iret, nret);
1040 self.release_open_closures(&local_closures);
1041 self.release_heap_closures(&local_heap_closures);
1042 return nret.into();
1043 }
1044 Instruction::GetUpValue(dst, index, _size) => {
1045 {
1046 let up_i = cls_i.unwrap();
1047 let cls = self.get_closure(up_i);
1048 let upvalues = &cls.upvalues;
1049 let rv = &upvalues[index as usize];
1050 let vs = match &*rv.borrow() {
1051 UpValue::Open(i) => {
1052 let upper_base = cls.base_ptr as usize;
1053 let (_range, rawv) = self.get_open_upvalue(upper_base, *i);
1054 let rawv: &[RawVal] = unsafe { std::mem::transmute(rawv) };
1055 rawv
1056 }
1057 UpValue::Closed(rawval, _) => {
1058 let rawv: &[RawVal] =
1059 unsafe { std::mem::transmute(rawval.as_slice()) };
1060 rawv
1061 }
1062 };
1063 self.set_stack_range(dst as i64, vs);
1064 };
1065 }
1066 Instruction::SetUpValue(index, src, size) => {
1067 let up_i = cls_i.unwrap();
1068 let cls = self.get_closure(up_i);
1069 let upper_base = cls.base_ptr as usize;
1070 let upvalues = &cls.upvalues;
1071 let (_range, v) = self.get_stack_range(src as i64, size);
1072 let rv = &mut *upvalues[index as usize].borrow_mut();
1073 match rv {
1074 UpValue::Open(OpenUpValue { pos: i, size, .. }) => {
1075 let (range, _v) = self.get_stack_range(src as i64, *size);
1076 let dest = upper_base + *i;
1077 unsafe {
1078 let dst = slice::from_raw_parts_mut(
1080 std::mem::transmute::<*const RawVal, *mut RawVal>(
1081 self.stack.as_ptr(),
1082 ),
1083 self.stack.len(),
1084 );
1085 dst.copy_within(range, dest);
1086 }
1087 }
1088 UpValue::Closed(uv, _) => {
1089 uv.as_mut_slice().copy_from_slice(v);
1090 }
1091 };
1092 }
1093 Instruction::GetGlobal(dst, gid, size) => {
1094 let gvs = unsafe {
1095 let vstart = self.global_vals.as_ptr().offset(gid as _);
1096 debug_assert!(!vstart.is_null());
1097 slice::from_raw_parts(vstart, size as _)
1099 };
1100 self.set_stack_range(dst as i64, gvs)
1101 }
1102 Instruction::SetGlobal(gid, src, size) => {
1103 let gvs = unsafe {
1104 let vstart = self.global_vals.as_mut_ptr().offset(gid as _);
1105 debug_assert!(!vstart.is_null());
1106 slice::from_raw_parts_mut(vstart, size as _)
1108 };
1109 let (_, slice) = self.get_stack_range(src as i64, size);
1110 gvs.copy_from_slice(slice);
1111 }
1112 Instruction::Jmp(offset) => {
1113 increment = offset;
1114 }
1115 Instruction::JmpIfNeg(cond, offset) => {
1116 let cond_v = self.get_stack(cond as i64);
1117 if Self::get_as::<f64>(cond_v) <= 0.0 {
1118 increment = offset;
1119 }
1120 }
1121 Instruction::JmpTable(scrut, table_idx) => {
1122 let scrut_val = self.get_stack(scrut as i64);
1123 let val = Self::get_as::<i64>(scrut_val);
1125 let fn_proto = self.get_fnproto(func_i);
1126 debug_assert!(
1127 !fn_proto.jump_tables.is_empty(),
1128 "JmpTable instruction requires non-empty jump_tables"
1129 );
1130 let table = &fn_proto.jump_tables[table_idx as usize];
1131 let idx = (val - table.min) as usize;
1132 let default_idx = table.offsets.len() - 1;
1134 increment = table
1135 .offsets
1136 .get(idx)
1137 .copied()
1138 .unwrap_or(table.offsets[default_idx]);
1139 }
1140 Instruction::AddF(dst, src1, src2) => binop!(+,f64,dst,src1,src2,self),
1141 Instruction::SubF(dst, src1, src2) => {
1142 binop!(-,f64,dst,src1,src2,self)
1143 }
1144 Instruction::MulF(dst, src1, src2) => binop!(*,f64,dst,src1,src2,self),
1145 Instruction::DivF(dst, src1, src2) => binop!(/,f64,dst,src1,src2,self),
1146 Instruction::ModF(dst, src1, src2) => binop!(%,f64,dst,src1,src2,self),
1147 Instruction::NegF(dst, src) => uniop!(-,f64,dst,src,self),
1148 Instruction::AbsF(dst, src) => uniopmethod!(abs, f64, dst, src, self),
1149 Instruction::SqrtF(dst, src) => uniopmethod!(sqrt, f64, dst, src, self),
1150 Instruction::SinF(dst, src) => uniopmethod!(sin, f64, dst, src, self),
1151 Instruction::CosF(dst, src) => uniopmethod!(cos, f64, dst, src, self),
1152 Instruction::PowF(dst, src1, src2) => {
1153 binopmethod!(powf, f64, dst, src1, src2, self)
1154 }
1155 Instruction::LogF(dst, src) => uniopmethod!(ln, f64, dst, src, self),
1156 Instruction::AddI(dst, src1, src2) => binop!(+,i64,dst,src1,src2,self),
1157 Instruction::SubI(dst, src1, src2) => binop!(-,i64,dst,src1,src2,self),
1158 Instruction::MulI(dst, src1, src2) => binop!(*,i64,dst,src1,src2,self),
1159 Instruction::DivI(dst, src1, src2) => binop!(/,i64,dst,src1,src2,self),
1160 Instruction::ModI(dst, src1, src2) => binop!(%,i64,dst,src1,src2,self),
1161 Instruction::NegI(dst, src) => uniop!(-,i64,dst,src,self),
1162 Instruction::AbsI(dst, src) => uniopmethod!(abs, i64, dst, src, self),
1163 Instruction::PowI(dst, lhs, rhs) => binop!(^,i64,dst,lhs,rhs,self),
1164 Instruction::LogI(_, _, _) => todo!(),
1165 Instruction::Not(dst, src) => uniop_bool!(!, dst, src, self),
1166 Instruction::Eq(dst, src1, src2) => binop_bool!(==,dst,src1,src2,self),
1167 Instruction::Ne(dst, src1, src2) => binop_bool!(!=,dst,src1,src2,self),
1168 Instruction::Gt(dst, src1, src2) => binop_bool!(>,dst,src1,src2,self),
1169 Instruction::Ge(dst, src1, src2) => binop_bool!(>=,dst,src1,src2,self),
1170 Instruction::Lt(dst, src1, src2) => binop_bool!(<,dst,src1,src2,self),
1171 Instruction::Le(dst, src1, src2) => binop_bool!(<=,dst,src1,src2,self),
1172 Instruction::And(dst, src1, src2) => binop_bool_compose!(&&,dst,src1,src2,self),
1173 Instruction::Or(dst, src1, src2) => binop_bool_compose!(||,dst,src1,src2,self),
1174 Instruction::CastFtoI(dst, src) => self.set_stack(
1175 dst as i64,
1176 Self::to_value::<i64>(Self::get_as::<f64>(self.get_stack(src as i64)) as i64),
1177 ),
1178 Instruction::CastItoF(dst, src) => self.set_stack(
1179 dst as i64,
1180 Self::to_value::<f64>(Self::get_as::<i64>(self.get_stack(src as i64)) as f64),
1181 ),
1182 Instruction::CastItoB(dst, src) => self.set_stack(
1183 dst as i64,
1184 Self::to_value::<bool>(Self::get_as::<i64>(self.get_stack(src as i64)) != 0),
1185 ),
1186 Instruction::AllocArray(dst, len, elem_size) => {
1187 let key = self.arrays.alloc_array(len as _, elem_size as _);
1189 self.set_stack(dst as i64, key);
1191 }
1192 Instruction::GetArrayElem(dst, arr, idx) => {
1193 let array = self.get_stack(arr as i64);
1195 let index = self.get_stack(idx as i64);
1196 let index_val = Self::get_as::<f64>(index);
1197 let adata = self.arrays.get_array(array);
1198 let elem_word_size = adata.elem_word_size as usize;
1199 let buffer = unsafe {
1200 let address = adata
1201 .data
1202 .as_ptr()
1203 .wrapping_add(index_val as usize * elem_word_size);
1204 std::slice::from_raw_parts(address, elem_word_size)
1205 };
1206 set_vec_range(
1207 &mut self.stack,
1208 (self.base_pointer + dst as u64) as usize,
1209 buffer,
1210 );
1211 }
1213 Instruction::SetArrayElem(arr, idx, val) => {
1214 let array = self.get_stack(arr as i64);
1216 let index = self.get_stack(idx as i64);
1217 let index_val = Self::get_as::<f64>(index);
1218 let index_int = index_val as usize;
1219 let adata = self.arrays.get_array_mut(array);
1220 let elem_word_size = adata.elem_word_size as usize;
1221 let buffer = unsafe {
1222 let address = adata
1223 .data
1224 .as_mut_ptr()
1225 .wrapping_add(index_int * elem_word_size);
1226 std::slice::from_raw_parts_mut(address, elem_word_size)
1227 };
1228 let (_range, buf_src) = self.get_stack_range(val as _, elem_word_size as _);
1229 buffer.copy_from_slice(buf_src);
1230 }
1231 Instruction::GetState(dst, size) => {
1232 let v: &[RawVal] = unsafe {
1234 std::mem::transmute(self.get_current_state().get_state(size as _))
1235 };
1236 self.set_stack_range(dst as i64, v);
1237 }
1238 Instruction::SetState(src, size) => {
1239 let vs = {
1240 let (_range, v) = self.get_stack_range(src as i64, size as _);
1241 unsafe { std::mem::transmute::<&[RawVal], &[RawVal]>(v) }
1242 };
1243 let dst = self.get_current_state().get_state_mut(size as _);
1244 dst.copy_from_slice(vs);
1245 }
1246 Instruction::PushStatePos(v) => self.get_current_state().push_pos(v),
1247 Instruction::PopStatePos(v) => self.get_current_state().pop_pos(v),
1248 Instruction::Delay(dst, src, time) => {
1249 let i = self.get_stack(src as i64);
1250 let t = self.get_stack(time as i64);
1251 let delaysize_i =
1252 unsafe { self.delaysizes_pos_stack.last().unwrap_unchecked() };
1253
1254 let size_in_samples = unsafe {
1255 *self
1256 .get_fnproto(func_i)
1257 .delay_sizes
1258 .get_unchecked(*delaysize_i)
1259 };
1260 let mut ringbuf = self.get_current_state().get_as_ringbuffer(size_in_samples);
1261
1262 let res = ringbuf.process(i, t);
1263 self.set_stack(dst as i64, res);
1264 }
1265 Instruction::Mem(dst, src) => {
1266 let s = self.get_stack(src as i64);
1267 let ptr = self.get_current_state().get_state_mut(1);
1268 let v = Self::to_value(ptr[0]);
1269 self.set_stack(dst as i64, v);
1270 let ptr = self.get_current_state().get_state_mut(1);
1271 ptr[0] = s;
1272 }
1273 Instruction::Dummy => {
1274 unreachable!()
1275 }
1276 }
1277 pcounter = (pcounter as i64 + increment as i64) as usize;
1278 }
1279 }
1280 pub fn install_extern_fn(&mut self, name: Symbol, f: ExtFunType) -> usize {
1281 self.ext_fun_table.push((name, f));
1282 self.ext_fun_table.len() - 1
1283 }
1284 pub fn install_extern_cls(&mut self, name: Symbol, f: ExtClsType) -> usize {
1285 self.ext_cls_table.push((name, f));
1286 self.ext_cls_table.len() - 1
1287 }
1288
1289 fn link_functions(&mut self) {
1290 let global_mem_size = self
1292 .prog
1293 .global_vals
1294 .iter()
1295 .map(|WordSize(size)| *size as usize)
1296 .sum();
1297 self.global_vals = vec![0; global_mem_size];
1298 self.prog
1299 .ext_fun_table
1300 .iter_mut()
1301 .enumerate()
1302 .for_each(|(i, (name, _ty))| {
1303 if let Some((j, _)) = self
1304 .ext_fun_table
1305 .iter()
1306 .enumerate()
1307 .find(|(_j, (fname, _fn))| name == fname.as_str())
1308 {
1309 let _ = self.fn_map.insert(i, ExtFnIdx::Fun(j));
1310 } else if let Some((j, _)) = self
1311 .ext_cls_table
1312 .iter()
1313 .enumerate()
1314 .find(|(_j, (fname, _fn))| name == fname.as_str())
1315 {
1316 let _ = self.fn_map.insert(i, ExtFnIdx::Cls(j));
1317 } else {
1318 panic!("external function {name} cannot be found");
1319 }
1320 });
1321 }
1322 pub fn execute_idx(&mut self, idx: usize) -> ReturnCode {
1323 let (_name, func) = &self.prog.global_fn_table[idx];
1324 if !func.bytecodes.is_empty() {
1325 self.global_states
1326 .resize(func.state_skeleton.total_size() as usize);
1327 if !self.stack.is_empty() {
1329 self.stack[0] = 0;
1330 }
1331 self.base_pointer = 1;
1332 self.execute(idx, None)
1333 } else {
1334 0
1335 }
1336 }
1337 pub fn execute_entry(&mut self, entry: &str) -> ReturnCode {
1338 if let Some(idx) = self.prog.get_fun_index(entry) {
1339 self.execute_idx(idx)
1340 } else {
1341 -1
1342 }
1343 }
1344
1345 fn clone_usersum_recursive(
1349 value_data: &[RawVal],
1350 ty: &TypeNodeId,
1351 heap: &mut heap::HeapStorage,
1352 ) {
1353 use crate::types::Type;
1354 match ty.to_type() {
1355 Type::Boxed(_) => {
1356 if !value_data.is_empty() {
1358 let heap_idx = Self::get_as::<heap::HeapIdx>(value_data[0]);
1359 heap::heap_retain(heap, heap_idx);
1360 }
1361 }
1362 Type::UserSum { variants, .. } => {
1363 if value_data.is_empty() {
1365 return;
1366 }
1367 let tag = value_data[0] as usize;
1368 if tag >= variants.len() {
1369 return;
1370 }
1371 if let Some(payload_ty) = variants[tag].1 {
1373 Self::clone_usersum_recursive(&value_data[1..], &payload_ty, heap);
1375 }
1376 }
1377 Type::Tuple(elem_types) => {
1378 let mut offset = 0;
1380 for elem_ty in elem_types {
1381 let elem_size = elem_ty.word_size() as usize;
1382 if offset + elem_size <= value_data.len() {
1383 Self::clone_usersum_recursive(
1384 &value_data[offset..offset + elem_size],
1385 &elem_ty,
1386 heap,
1387 );
1388 }
1389 offset += elem_size;
1390 }
1391 }
1392 Type::Record(fields) => {
1393 let mut offset = 0;
1395 for field in fields {
1396 let field_size = field.ty.word_size() as usize;
1397 if offset + field_size <= value_data.len() {
1398 Self::clone_usersum_recursive(
1399 &value_data[offset..offset + field_size],
1400 &field.ty,
1401 heap,
1402 );
1403 }
1404 offset += field_size;
1405 }
1406 }
1407 Type::TypeAlias(_name) => {
1408 if !value_data.is_empty() {
1412 let heap_idx = Self::get_as::<heap::HeapIdx>(value_data[0]);
1413 heap::heap_retain(heap, heap_idx);
1414 }
1415 }
1416 _ => {
1417 }
1419 }
1420 }
1421
1422 fn release_usersum_recursive(
1426 value_data: &[RawVal],
1427 ty: &TypeNodeId,
1428 heap: &mut heap::HeapStorage,
1429 type_table: &[TypeNodeId],
1430 ) {
1431 use crate::types::Type;
1432 match ty.to_type() {
1433 Type::Boxed(inner) => {
1434 if !value_data.is_empty() {
1437 let heap_idx = Self::get_as::<heap::HeapIdx>(value_data[0]);
1438 let should_release_inner = heap
1439 .get(heap_idx)
1440 .map(|obj| obj.refcount <= 1)
1441 .unwrap_or(false);
1442 if should_release_inner {
1443 let inner_data = heap
1445 .get(heap_idx)
1446 .map(|obj| obj.data.clone())
1447 .unwrap_or_default();
1448 Self::release_usersum_recursive(&inner_data, &inner, heap, type_table);
1449 }
1450 heap::heap_release(heap, heap_idx);
1451 }
1452 }
1453 Type::UserSum { variants, .. } => {
1454 if value_data.is_empty() {
1456 return;
1457 }
1458 let tag = value_data[0] as usize;
1459 if tag >= variants.len() {
1460 return;
1461 }
1462 if let Some(payload_ty) = variants[tag].1 {
1464 Self::release_usersum_recursive(
1466 &value_data[1..],
1467 &payload_ty,
1468 heap,
1469 type_table,
1470 );
1471 }
1472 }
1473 Type::Tuple(elem_types) => {
1474 let mut offset = 0;
1476 for elem_ty in elem_types {
1477 let elem_size = elem_ty.word_size() as usize;
1478 if offset + elem_size <= value_data.len() {
1479 Self::release_usersum_recursive(
1480 &value_data[offset..offset + elem_size],
1481 &elem_ty,
1482 heap,
1483 type_table,
1484 );
1485 }
1486 offset += elem_size;
1487 }
1488 }
1489 Type::Record(fields) => {
1490 let mut offset = 0;
1492 for field in fields {
1493 let field_size = field.ty.word_size() as usize;
1494 if offset + field_size <= value_data.len() {
1495 Self::release_usersum_recursive(
1496 &value_data[offset..offset + field_size],
1497 &field.ty,
1498 heap,
1499 type_table,
1500 );
1501 }
1502 offset += field_size;
1503 }
1504 }
1505 Type::TypeAlias(name) => {
1506 if !value_data.is_empty() {
1511 let heap_idx = Self::get_as::<heap::HeapIdx>(value_data[0]);
1512 let resolved_sum = type_table.iter().find(
1514 |tid| matches!(tid.to_type(), Type::UserSum { name: n, .. } if n == name),
1515 );
1516 let should_release_inner = heap
1517 .get(heap_idx)
1518 .map(|obj| obj.refcount <= 1)
1519 .unwrap_or(false);
1520 if should_release_inner {
1521 if let Some(inner_ty) = resolved_sum {
1522 let inner_data = heap
1523 .get(heap_idx)
1524 .map(|obj| obj.data.clone())
1525 .unwrap_or_default();
1526 Self::release_usersum_recursive(
1527 &inner_data,
1528 inner_ty,
1529 heap,
1530 type_table,
1531 );
1532 }
1533 }
1534 heap::heap_release(heap, heap_idx);
1535 }
1536 }
1537 _ => {
1538 }
1540 }
1541 }
1542
1543 pub fn execute_main(&mut self) -> ReturnCode {
1544 self.base_pointer += 1;
1546 self.execute(0, None)
1547 }
1548}
1549
1550#[cfg(test)]
1551mod test;