1#[cfg(feature = "profile")]
2use crate::profiler::Profiler;
3use crate::{
4 Error, Exception, StackSlot,
5 code::{INTEGER_BASE, NUMBER_BASE, SHARE_BASE, TAG_BASE},
6 cons::{Cons, NEVER},
7 heap::Heap,
8 instruction::Instruction,
9 memory::Memory,
10 number::Number,
11 primitive_set::PrimitiveSet,
12 r#type::Type,
13 value::{TypedValue, Value},
14};
15#[cfg(feature = "profile")]
16use core::cell::RefCell;
17use core::{
18 fmt::{self, Display, Formatter, Write},
19 marker::PhantomData,
20};
21use stak_lzss::{Lzss, MAX_WINDOW_SIZE};
22use stak_util::block_on;
23use winter_maybe_async::{maybe_async, maybe_await};
24
25macro_rules! trace {
26 ($prefix:literal, $data:expr) => {
27 #[cfg(feature = "trace_instruction")]
28 std::eprintln!("{}: {}", $prefix, $data);
29 };
30}
31
32macro_rules! trace_memory {
33 ($self:expr) => {
34 #[cfg(feature = "trace_memory")]
35 std::eprintln!("{}", $self);
36 };
37}
38
39macro_rules! profile_event {
40 ($self:expr, $name:literal) => {
41 #[cfg(feature = "profile")]
42 (&$self).profile_event($name)?;
43 };
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
47struct Arity {
48 count: usize,
50 variadic: bool,
51}
52
53pub struct Vm<'a, T: PrimitiveSet<H>, H = &'a mut [Value]> {
55 primitive_set: T,
56 memory: Memory<H>,
57 #[cfg(feature = "profile")]
58 profiler: Option<RefCell<&'a mut dyn Profiler<H>>>,
59 _profiler: PhantomData<&'a ()>,
60}
61
62impl<'a, T: PrimitiveSet<H>, H: Heap> Vm<'a, T, H> {
65 pub fn new(heap: H, primitive_set: T) -> Result<Self, Error> {
67 Ok(Self {
68 primitive_set,
69 memory: Memory::new(heap)?,
70 #[cfg(feature = "profile")]
71 profiler: None,
72 _profiler: Default::default(),
73 })
74 }
75
76 #[cfg(feature = "profile")]
78 pub fn with_profiler(self, profiler: &'a mut dyn Profiler<H>) -> Self {
79 Self {
80 profiler: Some(profiler.into()),
81 ..self
82 }
83 }
84
85 pub const fn primitive_set(&self) -> &T {
87 &self.primitive_set
88 }
89
90 pub const fn primitive_set_mut(&mut self) -> &mut T {
92 &mut self.primitive_set
93 }
94
95 pub fn run(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), T::Error> {
101 block_on!(self.run_async(input))
102 }
103
104 #[cfg_attr(not(feature = "async"), doc(hidden))]
106 #[maybe_async]
107 pub fn run_async(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), T::Error> {
108 self.initialize(input)?;
109
110 while let Err(error) = maybe_await!(self.run_with_continuation()) {
111 if error.is_critical() {
112 return Err(error);
113 }
114
115 let Some(continuation) = self.memory.cdr(self.memory.null()?)?.to_cons() else {
116 return Err(error);
117 };
118
119 if self.memory.cdr(continuation)?.tag() != Type::Procedure as _ {
120 return Err(error);
121 }
122
123 self.memory.set_register(continuation);
124 let string = self.memory.build_string("")?;
125 let symbol = self.memory.allocate(
126 self.memory.register().into(),
127 string.set_tag(Type::Symbol as _).into(),
128 )?;
129 let code = self.memory.allocate(
130 symbol.into(),
131 self.memory
132 .code()
133 .set_tag(
134 Instruction::Call as u16
135 + Self::build_arity(Arity {
136 count: 1,
137 variadic: false,
138 }) as u16,
139 )
140 .into(),
141 )?;
142 self.memory.set_code(code);
143
144 self.memory.set_register(self.memory.null()?);
145 write!(&mut self.memory, "{error}").map_err(Error::from)?;
146 let code = self.memory.allocate(
147 self.memory.register().into(),
148 self.memory
149 .code()
150 .set_tag(Instruction::Constant as _)
151 .into(),
152 )?;
153 self.memory.set_code(code);
154 }
155
156 Ok(())
157 }
158
159 #[maybe_async]
160 fn run_with_continuation(&mut self) -> Result<(), T::Error> {
161 while self.memory.code() != self.memory.null()? {
162 let instruction = self.memory.cdr(self.memory.code())?.assume_cons();
163
164 trace!("instruction", instruction.tag());
165
166 match instruction.tag() {
167 Instruction::CONSTANT => self.constant()?,
168 Instruction::GET => self.get()?,
169 Instruction::SET => self.set()?,
170 Instruction::IF => self.r#if()?,
171 code => maybe_await!(
172 self.call(instruction, code as usize - Instruction::CALL as usize)
173 )?,
174 }
175
176 self.advance_code()?;
177
178 trace_memory!(self);
179 }
180
181 Ok(())
182 }
183
184 fn constant(&mut self) -> Result<(), Error> {
185 let constant = self.operand()?;
186
187 trace!("constant", constant);
188
189 self.memory.push(constant)?;
190
191 Ok(())
192 }
193
194 fn get(&mut self) -> Result<(), Error> {
195 let operand = self.operand_cons()?;
196 let value = self.memory.car(operand)?;
197
198 trace!("operand", operand);
199 trace!("value", value);
200
201 self.memory.push(value)?;
202
203 Ok(())
204 }
205
206 fn set(&mut self) -> Result<(), Error> {
207 let operand = self.operand_cons()?;
208 let value = self.memory.pop()?;
209
210 trace!("operand", operand);
211 trace!("value", value);
212
213 self.memory.set_car(operand, value)?;
214
215 Ok(())
216 }
217
218 fn r#if(&mut self) -> Result<(), Error> {
219 let cons = self.memory.stack();
220
221 if self.memory.pop()? != self.memory.boolean(false)?.into() {
222 self.memory.set_cdr(cons, self.operand()?)?;
223 self.memory.set_code(cons);
224 }
225
226 Ok(())
227 }
228
229 #[maybe_async]
230 fn call(&mut self, instruction: Cons, arity: usize) -> Result<(), T::Error> {
231 let procedure = self.procedure()?;
232
233 trace!("procedure", procedure);
234
235 if self.environment(procedure)?.tag() != Type::Procedure as _ {
236 return Err(Error::ProcedureExpected.into());
237 }
238
239 let arguments = Self::parse_arity(arity);
240 let r#return = instruction == self.memory.null()?;
241
242 trace!("return", r#return);
243
244 match self.code(procedure)?.to_typed() {
245 TypedValue::Cons(code) => {
246 #[cfg(feature = "profile")]
247 self.profile_call(self.memory.code(), r#return)?;
248
249 let parameters =
250 Self::parse_arity(self.memory.car(code)?.assume_number().to_i64() as usize);
251
252 trace!("argument count", arguments.count);
253 trace!("argument variadic", arguments.variadic);
254 trace!("parameter count", parameters.count);
255 trace!("parameter variadic", parameters.variadic);
256
257 self.memory.set_register(procedure);
258
259 let mut list = if arguments.variadic {
260 self.memory.pop()?.assume_cons()
261 } else {
262 self.memory.null()?
263 };
264
265 for _ in 0..arguments.count {
266 let value = self.memory.pop()?;
267 list = self.memory.cons(value, list)?;
268 }
269
270 let code = self.memory.code();
272 self.memory.set_code(self.memory.register());
273 self.memory.set_register(list);
274
275 let continuation = if r#return {
276 self.continuation()?
277 } else {
278 self.memory
279 .allocate(code.into(), self.memory.stack().into())?
280 };
281 let stack = self.memory.allocate(
282 continuation.into(),
283 self.environment(self.memory.code())?
284 .set_tag(StackSlot::Frame as _)
285 .into(),
286 )?;
287 self.memory.set_stack(stack);
288 self.memory
289 .set_code(self.code(self.memory.code())?.assume_cons());
290
291 for _ in 0..parameters.count {
292 if self.memory.register() == self.memory.null()? {
293 return Err(Error::ArgumentCount.into());
294 }
295
296 self.memory.push(self.memory.car(self.memory.register())?)?;
297 self.memory
298 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
299 }
300
301 if parameters.variadic {
302 self.memory.push(self.memory.register().into())?;
303 } else if self.memory.register() != self.memory.null()? {
304 return Err(Error::ArgumentCount.into());
305 }
306 }
307 TypedValue::Number(primitive) => {
308 if arguments.variadic {
309 let list = self.memory.pop()?.assume_cons();
310 self.memory.set_register(list);
311
312 while self.memory.register() != self.memory.null()? {
313 self.memory.push(self.memory.car(self.memory.register())?)?;
314 self.memory
315 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
316 }
317 }
318
319 maybe_await!(
320 self.primitive_set
321 .operate(&mut self.memory, primitive.to_i64() as _)
322 )?;
323 }
324 }
325
326 Ok(())
327 }
328
329 const fn parse_arity(info: usize) -> Arity {
330 Arity {
331 count: info / 2,
332 variadic: info % 2 == 1,
333 }
334 }
335
336 const fn build_arity(arity: Arity) -> usize {
337 2 * arity.count + arity.variadic as usize
338 }
339
340 fn advance_code(&mut self) -> Result<(), Error> {
341 let mut code = self.memory.cdr(self.memory.code())?.assume_cons();
342
343 if code == self.memory.null()? {
344 #[cfg(feature = "profile")]
345 self.profile_return()?;
346
347 let continuation = self.continuation()?;
348 self.memory
350 .set_cdr(self.memory.stack(), self.memory.cdr(continuation)?)?;
351
352 code = self
353 .memory
354 .cdr(self.memory.car(continuation)?.assume_cons())?
355 .assume_cons();
356 }
357
358 self.memory.set_code(code);
359
360 Ok(())
361 }
362
363 fn operand(&self) -> Result<Value, Error> {
364 self.memory.car(self.memory.code())
365 }
366
367 fn operand_cons(&self) -> Result<Cons, Error> {
368 Ok(match self.operand()?.to_typed() {
369 TypedValue::Cons(cons) => cons,
370 TypedValue::Number(index) => {
371 self.memory.tail(self.memory.stack(), index.to_i64() as _)?
372 }
373 })
374 }
375
376 fn procedure(&self) -> Result<Cons, Error> {
378 Ok(self.memory.car(self.operand_cons()?)?.assume_cons())
379 }
380
381 fn code(&self, procedure: Cons) -> Result<Value, Error> {
383 self.memory.car(procedure)
384 }
385
386 fn environment(&self, procedure: Cons) -> Result<Cons, Error> {
387 Ok(self.memory.cdr(procedure)?.assume_cons())
388 }
389
390 fn continuation(&self) -> Result<Cons, Error> {
392 let mut stack = self.memory.stack();
393
394 while self.memory.cdr(stack)?.assume_cons().tag() != StackSlot::Frame as _ {
395 stack = self.memory.cdr(stack)?.assume_cons();
396 }
397
398 Ok(self.memory.car(stack)?.assume_cons())
399 }
400
401 #[cfg(feature = "profile")]
404 fn profile_call(&self, call_code: Cons, r#return: bool) -> Result<(), Error> {
405 if let Some(profiler) = &self.profiler {
406 profiler
407 .borrow_mut()
408 .profile_call(&self.memory, call_code, r#return)?;
409 }
410
411 Ok(())
412 }
413
414 #[cfg(feature = "profile")]
415 fn profile_return(&self) -> Result<(), Error> {
416 if let Some(profiler) = &self.profiler {
417 profiler.borrow_mut().profile_return(&self.memory)?;
418 }
419
420 Ok(())
421 }
422
423 #[cfg(feature = "profile")]
424 fn profile_event(&self, name: &str) -> Result<(), Error> {
425 if let Some(profiler) = &self.profiler {
426 profiler.borrow_mut().profile_event(name)?;
427 }
428
429 Ok(())
430 }
431
432 #[doc(hidden)]
434 pub fn initialize(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), super::Error> {
435 profile_event!(self, "initialization_start");
436 profile_event!(self, "decode_start");
437
438 let program = self.decode_ribs(input.into_iter())?;
439 self.memory
440 .set_false(self.memory.car(program)?.assume_cons())?;
441 self.memory
442 .set_code(self.memory.cdr(program)?.assume_cons());
443
444 profile_event!(self, "decode_end");
445
446 let codes = self
448 .memory
449 .cons(Number::default().into(), self.memory.null()?)?
450 .into();
451 let continuation = self.memory.cons(codes, self.memory.null()?)?.into();
452 let stack = self.memory.allocate(
453 continuation,
454 self.memory.null()?.set_tag(StackSlot::Frame as _).into(),
455 )?;
456 self.memory.set_stack(stack);
457 self.memory.set_register(NEVER);
458
459 profile_event!(self, "initialization_end");
460
461 Ok(())
462 }
463
464 fn decode_ribs(&mut self, input: impl Iterator<Item = u8>) -> Result<Cons, Error> {
465 let mut input = input.decompress::<{ MAX_WINDOW_SIZE }>();
466
467 while let Some(head) = input.next() {
468 if head & 0b1 == 0 {
469 let head = head >> 1;
470
471 if head == 0 {
472 let cons = self.memory.cons(self.memory.top()?, self.memory.code())?;
473 self.memory.set_code(cons);
474 } else {
475 let integer = Self::decode_integer_tail(&mut input, head - 1, SHARE_BASE)?;
476 let index = integer >> 1;
477
478 if index > 0 {
479 let cons = self.memory.tail(self.memory.code(), index as usize - 1)?;
480 let head = self.memory.cdr(cons)?.assume_cons();
481 self.memory.set_cdr(cons, self.memory.cdr(head)?)?;
482 self.memory.set_cdr(head, self.memory.code().into())?;
483 self.memory.set_code(head);
484 }
485
486 let value = self.memory.car(self.memory.code())?;
487
488 if integer & 1 == 0 {
489 self.memory
490 .set_code(self.memory.cdr(self.memory.code())?.assume_cons());
491 }
492
493 self.memory.push(value)?;
494 }
495 } else if head & 0b10 == 0 {
496 let head = head >> 2;
497 let cdr = self.memory.pop()?;
498 let car = self.memory.pop()?;
499
500 if head == 0 {
501 let cons = self.memory.top()?.assume_cons();
502 self.memory.set_car(cons, car)?;
503 self.memory.set_cdr(cons, cdr)?;
504 } else {
505 let cons =
506 self.memory.allocate(
507 car,
508 cdr.set_tag(
509 Self::decode_integer_tail(&mut input, head - 1, TAG_BASE)? as _
510 ),
511 )?;
512 self.memory.push(cons.into())?;
513 }
514 } else {
515 self.memory
516 .push(Self::decode_number(&mut input, head)?.into())?;
517 }
518 }
519
520 self.memory.pop()?.to_cons().ok_or(Error::BytecodeEnd)
521 }
522
523 fn decode_number(input: &mut impl Iterator<Item = u8>, head: u8) -> Result<Number, Error> {
524 let integer = Self::decode_integer_tail(input, head >> 2, NUMBER_BASE)?;
525
526 Ok(if integer & 1 == 0 {
527 Number::from_i64((integer >> 1) as _)
528 } else if integer & 0b10 == 0 {
529 Number::from_i64(-((integer >> 2) as i64))
530 } else {
531 let integer = integer >> 2;
532 let head = input.next().ok_or(Error::BytecodeEnd)?;
533 let mantissa = Self::decode_integer_tail(input, head, INTEGER_BASE)?;
534
535 Number::from_f64(
536 if integer.is_multiple_of(2) { 1.0 } else { -1.0 }
537 * mantissa as f64
538 * f64::from_bits(((integer as u64 >> 1) % (1 << 11)) << 52),
539 )
540 })
541 }
542
543 fn decode_integer_tail(
544 input: &mut impl Iterator<Item = u8>,
545 mut x: u8,
546 mut base: u128,
547 ) -> Result<u128, Error> {
548 let mut y = (x >> 1) as u128;
549
550 while x & 1 != 0 {
551 x = input.next().ok_or(Error::BytecodeEnd)?;
552 y += (x as u128 >> 1) * base;
553 base *= INTEGER_BASE;
554 }
555
556 Ok(y)
557 }
558}
559
560impl<T: PrimitiveSet<H>, H: Heap> Display for Vm<'_, T, H> {
561 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
562 write!(formatter, "{}", &self.memory)
563 }
564}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569 #[cfg(feature = "float")]
570 use alloc::{vec, vec::Vec};
571
572 struct FakePrimitiveSet {}
573
574 impl<H: Heap> PrimitiveSet<H> for FakePrimitiveSet {
575 type Error = Error;
576
577 #[maybe_async]
578 fn operate(
579 &mut self,
580 _memory: &mut Memory<H>,
581 _primitive: usize,
582 ) -> Result<(), Self::Error> {
583 Ok(())
584 }
585 }
586
587 type VoidVm = Vm<'static, FakePrimitiveSet>;
588
589 #[test]
590 fn arity() {
591 for arity in [
592 Arity {
593 count: 0,
594 variadic: false,
595 },
596 Arity {
597 count: 1,
598 variadic: false,
599 },
600 Arity {
601 count: 2,
602 variadic: false,
603 },
604 Arity {
605 count: 0,
606 variadic: true,
607 },
608 Arity {
609 count: 1,
610 variadic: true,
611 },
612 Arity {
613 count: 2,
614 variadic: true,
615 },
616 ] {
617 assert_eq!(VoidVm::parse_arity(VoidVm::build_arity(arity)), arity);
618 }
619 }
620
621 #[cfg(feature = "float")]
622 #[test]
623 fn decode_float() {
624 fn encode_number(value: f64) -> Vec<u8> {
625 fn encode_integer(bytes: &mut Vec<u8>, mut integer: u128, base: u128) {
626 let digit = (integer % base) as u8;
627 integer /= base;
628 bytes.push(2 * digit + u8::from(integer != 0));
629
630 while integer != 0 {
631 let digit = (integer % INTEGER_BASE) as u8;
632 integer /= INTEGER_BASE;
633 bytes.push(2 * digit + u8::from(integer != 0));
634 }
635 }
636
637 let mut mantissa = value.abs();
638 let mut exponent = 0i64;
639
640 while mantissa != mantissa.floor() {
641 mantissa *= 2.0;
642 exponent -= 1;
643 }
644
645 let mut bytes = vec![];
646
647 encode_integer(
648 &mut bytes,
649 3 + 4 * (u128::from(value < 0.0) + 2 * (exponent + 1023) as u128),
650 NUMBER_BASE,
651 );
652 encode_integer(&mut bytes, mantissa as u128, INTEGER_BASE);
653 bytes[0] = 3 + 4 * bytes[0];
654
655 bytes
656 }
657
658 for value in [
659 0.5,
660 -0.5,
661 0.75,
662 -0.75,
663 0.125,
664 1.5,
665 -2.25,
666 12.5,
667 -40.5,
668 0.001953125,
670 -0.0009765625,
671 137438953471.5,
673 -137438953471.5,
674 2251799813685247.5,
675 4503599627370495.5,
677 -4503599627370495.5,
678 f64::MIN_POSITIVE,
680 ] {
681 let mut input = encode_number(value).into_iter();
682 let head = input.next().unwrap();
683
684 assert_eq!(
685 VoidVm::decode_number(&mut input, head).unwrap(),
686 Number::from_f64(value),
687 );
688 }
689 }
690
691 fn literals<const N: usize>(bytes: [u8; N]) -> [u8; N] {
692 bytes.map(|byte| byte * 2)
693 }
694
695 fn decode<const N: usize>(bytes: [u8; N]) -> (Cons, Memory<[Value; 1 << 9]>) {
696 let mut vm = Vm::new([Default::default(); 1 << 9], FakePrimitiveSet {}).unwrap();
697 let cons = vm.decode_ribs(literals(bytes).into_iter()).unwrap();
698
699 (cons, vm.memory)
700 }
701
702 #[test]
703 fn decode_shared_value() {
704 let (rib, memory) = decode([
706 3, 3, 5, 0, 6, 2, 5,
711 ]);
712
713 let car = memory.car(rib).unwrap().assume_cons();
714
715 assert_eq!(memory.cdr(rib).unwrap(), car.into());
716 assert_eq!(memory.car(car).unwrap(), Number::from_i64(0).into());
717 assert_eq!(memory.cdr(car).unwrap(), Number::from_i64(0).into());
718 }
719
720 #[test]
721 fn decode_self_loop() {
722 let (rib, memory) = decode([
724 3, 3, 5, 0, 3, 2, 1,
729 ]);
730
731 assert_eq!(memory.car(rib).unwrap(), Number::from_i64(0).into());
732 assert_eq!(memory.cdr(rib).unwrap(), rib.into());
733 }
734
735 #[test]
736 fn decode_swapped_reference() {
737 let (first, memory) = decode([
741 3, 3, 5, 0, 3, 3, 5, 0, 3, 14, 1, 6, 3, 10, 1,
747 ]);
748
749 let second = memory.cdr(first).unwrap().assume_cons();
750
751 assert_eq!(memory.car(first).unwrap(), Number::from_i64(0).into());
752 assert_eq!(memory.car(second).unwrap(), Number::from_i64(0).into());
753 assert_eq!(memory.cdr(second).unwrap(), first.into());
754 }
755}