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 instruction::Instruction,
8 memory::{Heap, Memory},
9 number::Number,
10 primitive_set::PrimitiveSet,
11 r#type::Type,
12 value::{TypedValue, Value},
13};
14#[cfg(feature = "profile")]
15use core::cell::RefCell;
16use core::{
17 fmt::{self, Display, Formatter, Write},
18 marker::PhantomData,
19};
20use stak_lzss::Lzss;
21use stak_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) -> Result<(), T::Error> {
101 block_on!(self.run_async())
102 }
103
104 #[cfg_attr(not(feature = "async"), doc(hidden))]
106 #[maybe_async]
107 pub fn run_async(&mut self) -> Result<(), T::Error> {
108 while let Err(error) = maybe_await!(self.run_with_continuation()) {
109 if error.is_critical() {
110 return Err(error);
111 }
112
113 let Some(continuation) = self.memory.cdr(self.memory.null()?)?.to_cons() else {
114 return Err(error);
115 };
116
117 if self.memory.cdr(continuation)?.tag() != Type::Procedure as _ {
118 return Err(error);
119 }
120
121 self.memory.set_register(continuation);
122 let string = self.memory.build_string("")?;
123 let symbol = self.memory.allocate(
124 self.memory.register().into(),
125 string.set_tag(Type::Symbol as _).into(),
126 )?;
127 let code = self.memory.allocate(
128 symbol.into(),
129 self.memory
130 .code()
131 .set_tag(
132 Instruction::Call as u16
133 + Self::build_arity(Arity {
134 count: 1,
135 variadic: false,
136 }) as u16,
137 )
138 .into(),
139 )?;
140 self.memory.set_code(code);
141
142 self.memory.set_register(self.memory.null()?);
143 write!(&mut self.memory, "{error}").map_err(Error::from)?;
144 let code = self.memory.allocate(
145 self.memory.register().into(),
146 self.memory
147 .code()
148 .set_tag(Instruction::Constant as _)
149 .into(),
150 )?;
151 self.memory.set_code(code);
152 }
153
154 Ok(())
155 }
156
157 #[maybe_async]
158 fn run_with_continuation(&mut self) -> Result<(), T::Error> {
159 while self.memory.code() != self.memory.null()? {
160 let instruction = self.memory.cdr(self.memory.code())?.assume_cons();
161
162 trace!("instruction", instruction.tag());
163
164 match instruction.tag() {
165 Instruction::CONSTANT => self.constant()?,
166 Instruction::GET => self.get()?,
167 Instruction::SET => self.set()?,
168 Instruction::IF => self.r#if()?,
169 code => maybe_await!(
170 self.call(instruction, code as usize - Instruction::CALL as usize)
171 )?,
172 }
173
174 self.advance_code()?;
175
176 trace_memory!(self);
177 }
178
179 Ok(())
180 }
181
182 fn constant(&mut self) -> Result<(), Error> {
183 let constant = self.operand()?;
184
185 trace!("constant", constant);
186
187 self.memory.push(constant)?;
188
189 Ok(())
190 }
191
192 fn get(&mut self) -> Result<(), Error> {
193 let operand = self.operand_cons()?;
194 let value = self.memory.car(operand)?;
195
196 trace!("operand", operand);
197 trace!("value", value);
198
199 self.memory.push(value)?;
200
201 Ok(())
202 }
203
204 fn set(&mut self) -> Result<(), Error> {
205 let operand = self.operand_cons()?;
206 let value = self.memory.pop()?;
207
208 trace!("operand", operand);
209 trace!("value", value);
210
211 self.memory.set_car(operand, value)?;
212
213 Ok(())
214 }
215
216 fn r#if(&mut self) -> Result<(), Error> {
217 let cons = self.memory.stack();
218
219 if self.memory.pop()? != self.memory.boolean(false)?.into() {
220 self.memory.set_cdr(cons, self.operand()?)?;
221 self.memory.set_code(cons);
222 }
223
224 Ok(())
225 }
226
227 #[maybe_async]
228 fn call(&mut self, instruction: Cons, arity: usize) -> Result<(), T::Error> {
229 let procedure = self.procedure()?;
230
231 trace!("procedure", procedure);
232
233 if self.environment(procedure)?.tag() != Type::Procedure as _ {
234 return Err(Error::ProcedureExpected.into());
235 }
236
237 let arguments = Self::parse_arity(arity);
238 let r#return = instruction == self.memory.null()?;
239
240 trace!("return", r#return);
241
242 match self.code(procedure)?.to_typed() {
243 TypedValue::Cons(code) => {
244 #[cfg(feature = "profile")]
245 self.profile_call(self.memory.code(), r#return)?;
246
247 let parameters =
248 Self::parse_arity(self.memory.car(code)?.assume_number().to_i64() as usize);
249
250 trace!("argument count", arguments.count);
251 trace!("argument variadic", arguments.variadic);
252 trace!("parameter count", parameters.count);
253 trace!("parameter variadic", parameters.variadic);
254
255 self.memory.set_register(procedure);
256
257 let mut list = if arguments.variadic {
258 self.memory.pop()?.assume_cons()
259 } else {
260 self.memory.null()?
261 };
262
263 for _ in 0..arguments.count {
264 let value = self.memory.pop()?;
265 list = self.memory.cons(value, list)?;
266 }
267
268 let code = self.memory.code();
270 self.memory.set_code(self.memory.register());
271 self.memory.set_register(list);
272
273 let continuation = if r#return {
274 self.continuation()?
275 } else {
276 self.memory
277 .allocate(code.into(), self.memory.stack().into())?
278 };
279 let stack = self.memory.allocate(
280 continuation.into(),
281 self.environment(self.memory.code())?
282 .set_tag(StackSlot::Frame as _)
283 .into(),
284 )?;
285 self.memory.set_stack(stack);
286 self.memory
287 .set_code(self.code(self.memory.code())?.assume_cons());
288
289 for _ in 0..parameters.count {
290 if self.memory.register() == self.memory.null()? {
291 return Err(Error::ArgumentCount.into());
292 }
293
294 self.memory.push(self.memory.car(self.memory.register())?)?;
295 self.memory
296 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
297 }
298
299 if parameters.variadic {
300 self.memory.push(self.memory.register().into())?;
301 } else if self.memory.register() != self.memory.null()? {
302 return Err(Error::ArgumentCount.into());
303 }
304 }
305 TypedValue::Number(primitive) => {
306 if arguments.variadic {
307 let list = self.memory.pop()?.assume_cons();
308 self.memory.set_register(list);
309
310 while self.memory.register() != self.memory.null()? {
311 self.memory.push(self.memory.car(self.memory.register())?)?;
312 self.memory
313 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
314 }
315 }
316
317 maybe_await!(
318 self.primitive_set
319 .operate(&mut self.memory, primitive.to_i64() as _)
320 )?;
321 }
322 }
323
324 Ok(())
325 }
326
327 const fn parse_arity(info: usize) -> Arity {
328 Arity {
329 count: info / 2,
330 variadic: info % 2 == 1,
331 }
332 }
333
334 const fn build_arity(arity: Arity) -> usize {
335 2 * arity.count + arity.variadic as usize
336 }
337
338 fn advance_code(&mut self) -> Result<(), Error> {
339 let mut code = self.memory.cdr(self.memory.code())?.assume_cons();
340
341 if code == self.memory.null()? {
342 #[cfg(feature = "profile")]
343 self.profile_return()?;
344
345 let continuation = self.continuation()?;
346 self.memory
348 .set_cdr(self.memory.stack(), self.memory.cdr(continuation)?)?;
349
350 code = self
351 .memory
352 .cdr(self.memory.car(continuation)?.assume_cons())?
353 .assume_cons();
354 }
355
356 self.memory.set_code(code);
357
358 Ok(())
359 }
360
361 fn operand(&self) -> Result<Value, Error> {
362 self.memory.car(self.memory.code())
363 }
364
365 fn operand_cons(&self) -> Result<Cons, Error> {
366 Ok(match self.operand()?.to_typed() {
367 TypedValue::Cons(cons) => cons,
368 TypedValue::Number(index) => {
369 self.memory.tail(self.memory.stack(), index.to_i64() as _)?
370 }
371 })
372 }
373
374 fn procedure(&self) -> Result<Cons, Error> {
376 Ok(self.memory.car(self.operand_cons()?)?.assume_cons())
377 }
378
379 fn code(&self, procedure: Cons) -> Result<Value, Error> {
381 self.memory.car(procedure)
382 }
383
384 fn environment(&self, procedure: Cons) -> Result<Cons, Error> {
385 Ok(self.memory.cdr(procedure)?.assume_cons())
386 }
387
388 fn continuation(&self) -> Result<Cons, Error> {
390 let mut stack = self.memory.stack();
391
392 while self.memory.cdr(stack)?.assume_cons().tag() != StackSlot::Frame as _ {
393 stack = self.memory.cdr(stack)?.assume_cons();
394 }
395
396 Ok(self.memory.car(stack)?.assume_cons())
397 }
398
399 #[cfg(feature = "profile")]
402 fn profile_call(&self, call_code: Cons, r#return: bool) -> Result<(), Error> {
403 if let Some(profiler) = &self.profiler {
404 profiler
405 .borrow_mut()
406 .profile_call(&self.memory, call_code, r#return)?;
407 }
408
409 Ok(())
410 }
411
412 #[cfg(feature = "profile")]
413 fn profile_return(&self) -> Result<(), Error> {
414 if let Some(profiler) = &self.profiler {
415 profiler.borrow_mut().profile_return(&self.memory)?;
416 }
417
418 Ok(())
419 }
420
421 #[cfg(feature = "profile")]
422 fn profile_event(&self, name: &str) -> Result<(), Error> {
423 if let Some(profiler) = &self.profiler {
424 profiler.borrow_mut().profile_event(name)?;
425 }
426
427 Ok(())
428 }
429
430 pub fn initialize(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), super::Error> {
432 profile_event!(self, "initialization_start");
433 profile_event!(self, "decode_start");
434
435 let program = self.decode_ribs(input.into_iter())?;
436 self.memory
437 .set_false(self.memory.car(program)?.assume_cons());
438 self.memory
439 .set_code(self.memory.cdr(program)?.assume_cons());
440
441 profile_event!(self, "decode_end");
442
443 let codes = self
445 .memory
446 .cons(Number::default().into(), self.memory.null()?)?
447 .into();
448 let continuation = self.memory.cons(codes, self.memory.null()?)?.into();
449 let stack = self.memory.allocate(
450 continuation,
451 self.memory.null()?.set_tag(StackSlot::Frame as _).into(),
452 )?;
453 self.memory.set_stack(stack);
454 self.memory.set_register(NEVER);
455
456 profile_event!(self, "initialization_end");
457
458 Ok(())
459 }
460
461 fn decode_ribs(&mut self, input: impl Iterator<Item = u8>) -> Result<Cons, Error> {
462 let mut input = input.decompress::<{ MAX_WINDOW_SIZE }>();
463
464 while let Some(head) = input.next() {
465 if head & 0b1 == 0 {
466 let head = head >> 1;
467
468 if head == 0 {
469 let value = self.memory.top()?;
470 let cons = self.memory.cons(value, self.memory.code())?;
471 self.memory.set_code(cons);
472 } else {
473 let integer = Self::decode_integer_tail(&mut input, head - 1, SHARE_BASE)?;
474 let index = integer >> 1;
475
476 if index > 0 {
477 let cons = self.memory.tail(self.memory.code(), index as usize - 1)?;
478 let head = self.memory.cdr(cons)?.assume_cons();
479 let tail = self.memory.cdr(head)?;
480 self.memory.set_cdr(head, self.memory.code().into())?;
481 self.memory.set_cdr(cons, tail)?;
482 self.memory.set_code(head);
483 }
484
485 let value = self.memory.car(self.memory.code())?;
486
487 if integer & 1 == 0 {
488 self.memory
489 .set_code(self.memory.cdr(self.memory.code())?.assume_cons());
490 }
491
492 self.memory.push(value)?;
493 }
494 } else if head & 0b10 == 0 {
495 let cons = self.memory.stack();
496 let cdr = self.memory.pop()?;
497 let car = self.memory.top()?;
498 let tag = Self::decode_integer_tail(&mut input, head >> 2, TAG_BASE)?;
499 self.memory.set_car(cons, car)?;
500 self.memory.set_raw_cdr(cons, cdr.set_tag(tag as _))?;
501 self.memory.set_top(cons.into())?;
502 } else {
503 self.memory.push(
504 Self::decode_number(Self::decode_integer_tail(
505 &mut input,
506 head >> 2,
507 NUMBER_BASE,
508 )?)
509 .into(),
510 )?;
511 }
512 }
513
514 self.memory.pop()?.to_cons().ok_or(Error::BytecodeEnd)
515 }
516
517 fn decode_number(integer: u128) -> Number {
518 if integer & 1 == 0 {
519 Number::from_i64((integer >> 1) as _)
520 } else if integer & 0b10 == 0 {
521 Number::from_i64(-((integer >> 2) as i64))
522 } else {
523 let integer = integer >> 2;
524 let mantissa =
525 if integer.is_multiple_of(2) { 1.0 } else { -1.0 } * (integer >> 12) as f64;
526 let exponent = ((integer >> 1) % (1 << 11)) as isize - 1023;
527
528 Number::from_f64(if exponent < 0 {
529 mantissa / (1u64 << exponent.abs()) as f64
530 } else {
531 mantissa * (1u64 << exponent) as f64
532 })
533 }
534 }
535
536 fn decode_integer_tail(
537 input: &mut impl Iterator<Item = u8>,
538 mut x: u8,
539 mut base: u128,
540 ) -> Result<u128, Error> {
541 let mut y = (x >> 1) as u128;
542
543 while x & 1 != 0 {
544 x = input.next().ok_or(Error::BytecodeEnd)?;
545 y += (x as u128 >> 1) * base;
546 base *= INTEGER_BASE;
547 }
548
549 Ok(y)
550 }
551}
552
553impl<T: PrimitiveSet<H>, H: Heap> Display for Vm<'_, T, H> {
554 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
555 write!(formatter, "{}", &self.memory)
556 }
557}
558
559#[cfg(test)]
560mod tests {
561 use super::*;
562
563 struct FakePrimitiveSet {}
564
565 impl<H: Heap> PrimitiveSet<H> for FakePrimitiveSet {
566 type Error = Error;
567
568 #[maybe_async]
569 fn operate(
570 &mut self,
571 _memory: &mut Memory<H>,
572 _primitive: usize,
573 ) -> Result<(), Self::Error> {
574 Ok(())
575 }
576 }
577
578 type VoidVm = Vm<'static, FakePrimitiveSet>;
579
580 #[test]
581 fn arity() {
582 for arity in [
583 Arity {
584 count: 0,
585 variadic: false,
586 },
587 Arity {
588 count: 1,
589 variadic: false,
590 },
591 Arity {
592 count: 2,
593 variadic: false,
594 },
595 Arity {
596 count: 0,
597 variadic: true,
598 },
599 Arity {
600 count: 1,
601 variadic: true,
602 },
603 Arity {
604 count: 2,
605 variadic: true,
606 },
607 ] {
608 assert_eq!(VoidVm::parse_arity(VoidVm::build_arity(arity)), arity);
609 }
610 }
611}