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_util::block_on;
21use winter_maybe_async::{maybe_async, maybe_await};
22
23macro_rules! trace {
24 ($prefix:literal, $data:expr) => {
25 #[cfg(feature = "trace_instruction")]
26 std::eprintln!("{}: {}", $prefix, $data);
27 };
28}
29
30macro_rules! trace_memory {
31 ($self:expr) => {
32 #[cfg(feature = "trace_memory")]
33 std::eprintln!("{}", $self);
34 };
35}
36
37macro_rules! profile_event {
38 ($self:expr, $name:literal) => {
39 #[cfg(feature = "profile")]
40 (&$self).profile_event($name)?;
41 };
42}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45struct Arity {
46 count: usize,
48 variadic: bool,
49}
50
51pub struct Vm<'a, T: PrimitiveSet<H>, H = &'a mut [Value]> {
53 primitive_set: T,
54 memory: Memory<H>,
55 #[cfg(feature = "profile")]
56 profiler: Option<RefCell<&'a mut dyn Profiler<H>>>,
57 _profiler: PhantomData<&'a ()>,
58}
59
60impl<'a, T: PrimitiveSet<H>, H: Heap> Vm<'a, T, H> {
63 pub fn new(heap: H, primitive_set: T) -> Result<Self, Error> {
65 Ok(Self {
66 primitive_set,
67 memory: Memory::new(heap)?,
68 #[cfg(feature = "profile")]
69 profiler: None,
70 _profiler: Default::default(),
71 })
72 }
73
74 #[cfg(feature = "profile")]
76 pub fn with_profiler(self, profiler: &'a mut dyn Profiler<H>) -> Self {
77 Self {
78 profiler: Some(profiler.into()),
79 ..self
80 }
81 }
82
83 pub const fn primitive_set(&self) -> &T {
85 &self.primitive_set
86 }
87
88 pub const fn primitive_set_mut(&mut self) -> &mut T {
90 &mut self.primitive_set
91 }
92
93 pub fn run(&mut self) -> Result<(), T::Error> {
99 block_on!(self.run_async())
100 }
101
102 #[cfg_attr(not(feature = "async"), doc(hidden))]
104 #[maybe_async]
105 pub fn run_async(&mut self) -> Result<(), T::Error> {
106 while let Err(error) = maybe_await!(self.run_with_continuation()) {
107 if error.is_critical() {
108 return Err(error);
109 }
110
111 let Some(continuation) = self.memory.cdr(self.memory.null()?)?.to_cons() else {
112 return Err(error);
113 };
114
115 if self.memory.cdr(continuation)?.tag() != Type::Procedure as _ {
116 return Err(error);
117 }
118
119 self.memory.set_register(continuation);
120 let string = self.memory.build_string("")?;
121 let symbol = self.memory.allocate(
122 self.memory.register().into(),
123 string.set_tag(Type::Symbol as _).into(),
124 )?;
125 let code = self.memory.allocate(
126 symbol.into(),
127 self.memory
128 .code()
129 .set_tag(
130 Instruction::Call as u16
131 + Self::build_arity(Arity {
132 count: 1,
133 variadic: false,
134 }) as u16,
135 )
136 .into(),
137 )?;
138 self.memory.set_code(code);
139
140 self.memory.set_register(self.memory.null()?);
141 write!(&mut self.memory, "{error}").map_err(Error::from)?;
142 let code = self.memory.allocate(
143 self.memory.register().into(),
144 self.memory
145 .code()
146 .set_tag(Instruction::Constant as _)
147 .into(),
148 )?;
149 self.memory.set_code(code);
150 }
151
152 Ok(())
153 }
154
155 #[maybe_async]
156 fn run_with_continuation(&mut self) -> Result<(), T::Error> {
157 while self.memory.code() != self.memory.null()? {
158 let instruction = self.memory.cdr(self.memory.code())?.assume_cons();
159
160 trace!("instruction", instruction.tag());
161
162 match instruction.tag() {
163 Instruction::CONSTANT => self.constant()?,
164 Instruction::GET => self.get()?,
165 Instruction::SET => self.set()?,
166 Instruction::IF => self.r#if()?,
167 code => maybe_await!(
168 self.call(instruction, code as usize - Instruction::CALL as usize)
169 )?,
170 }
171
172 self.advance_code()?;
173
174 trace_memory!(self);
175 }
176
177 Ok(())
178 }
179
180 #[inline]
181 fn constant(&mut self) -> Result<(), Error> {
182 let constant = self.operand()?;
183
184 trace!("constant", constant);
185
186 self.memory.push(constant)?;
187
188 Ok(())
189 }
190
191 #[inline]
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 #[inline]
205 fn set(&mut self) -> Result<(), Error> {
206 let operand = self.operand_cons()?;
207 let value = self.memory.pop()?;
208
209 trace!("operand", operand);
210 trace!("value", value);
211
212 self.memory.set_car(operand, value)?;
213
214 Ok(())
215 }
216
217 #[inline]
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 #[inline(always)]
230 #[maybe_async]
231 fn call(&mut self, instruction: Cons, arity: usize) -> Result<(), T::Error> {
232 let r#return = instruction == self.memory.null()?;
233 let procedure = self.procedure()?;
234
235 trace!("procedure", procedure);
236 trace!("return", r#return);
237
238 if self.environment(procedure)?.tag() != Type::Procedure as _ {
239 return Err(Error::ProcedureExpected.into());
240 }
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 arguments = Self::parse_arity(arity);
248 let parameters =
249 Self::parse_arity(self.memory.car(code)?.assume_number().to_i64() as usize);
250
251 trace!("argument count", arguments.count);
252 trace!("argument variadic", arguments.variadic);
253 trace!("parameter count", parameters.count);
254 trace!("parameter variadic", parameters.variadic);
255
256 self.memory.set_register(procedure);
257
258 let mut list = if arguments.variadic {
259 self.memory.pop()?.assume_cons()
260 } else {
261 self.memory.null()?
262 };
263
264 for _ in 0..arguments.count {
265 let value = self.memory.pop()?;
266 list = self.memory.cons(value, list)?;
267 }
268
269 let code = self.memory.code();
271 self.memory.set_code(self.memory.register());
272 self.memory.set_register(list);
273
274 let continuation = if r#return {
275 self.continuation()?
276 } else {
277 self.memory
278 .allocate(code.into(), self.memory.stack().into())?
279 };
280 let stack = self.memory.allocate(
281 continuation.into(),
282 self.environment(self.memory.code())?
283 .set_tag(StackSlot::Frame as _)
284 .into(),
285 )?;
286 self.memory.set_stack(stack);
287 self.memory
288 .set_code(self.code(self.memory.code())?.assume_cons());
289
290 for _ in 0..parameters.count {
291 if self.memory.register() == self.memory.null()? {
292 return Err(Error::ArgumentCount.into());
293 }
294
295 self.memory.push(self.memory.car(self.memory.register())?)?;
296 self.memory
297 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
298 }
299
300 if parameters.variadic {
301 self.memory.push(self.memory.register().into())?;
302 } else if self.memory.register() != self.memory.null()? {
303 return Err(Error::ArgumentCount.into());
304 }
305 }
306 TypedValue::Number(primitive) => {
307 if Self::parse_arity(arity).variadic {
308 let list = self.memory.pop()?.assume_cons();
309 self.memory.set_register(list);
310
311 while self.memory.register() != self.memory.null()? {
312 self.memory.push(self.memory.car(self.memory.register())?)?;
313 self.memory
314 .set_register(self.memory.cdr(self.memory.register())?.assume_cons());
315 }
316 }
317
318 maybe_await!(
319 self.primitive_set
320 .operate(&mut self.memory, primitive.to_i64() as _)
321 )?;
322 }
323 }
324
325 Ok(())
326 }
327
328 #[inline]
329 const fn parse_arity(info: usize) -> Arity {
330 Arity {
331 count: info / 2,
332 variadic: info % 2 == 1,
333 }
334 }
335
336 #[inline]
337 const fn build_arity(arity: Arity) -> usize {
338 2 * arity.count + arity.variadic as usize
339 }
340
341 #[inline]
342 fn advance_code(&mut self) -> Result<(), Error> {
343 let mut code = self.memory.cdr(self.memory.code())?.assume_cons();
344
345 if code == self.memory.null()? {
346 #[cfg(feature = "profile")]
347 self.profile_return()?;
348
349 let continuation = self.continuation()?;
350 self.memory
352 .set_cdr(self.memory.stack(), self.memory.cdr(continuation)?)?;
353
354 code = self
355 .memory
356 .cdr(self.memory.car(continuation)?.assume_cons())?
357 .assume_cons();
358 }
359
360 self.memory.set_code(code);
361
362 Ok(())
363 }
364
365 fn operand(&self) -> Result<Value, Error> {
366 self.memory.car(self.memory.code())
367 }
368
369 fn operand_cons(&self) -> Result<Cons, Error> {
370 Ok(match self.operand()?.to_typed() {
371 TypedValue::Cons(cons) => cons,
372 TypedValue::Number(index) => {
373 self.memory.tail(self.memory.stack(), index.to_i64() as _)?
374 }
375 })
376 }
377
378 fn procedure(&self) -> Result<Cons, Error> {
380 Ok(self.memory.car(self.operand_cons()?)?.assume_cons())
381 }
382
383 fn code(&self, procedure: Cons) -> Result<Value, Error> {
385 self.memory.car(procedure)
386 }
387
388 fn environment(&self, procedure: Cons) -> Result<Cons, Error> {
389 Ok(self.memory.cdr(procedure)?.assume_cons())
390 }
391
392 fn continuation(&self) -> Result<Cons, Error> {
394 let mut stack = self.memory.stack();
395
396 while self.memory.cdr(stack)?.assume_cons().tag() != StackSlot::Frame as _ {
397 stack = self.memory.cdr(stack)?.assume_cons();
398 }
399
400 Ok(self.memory.car(stack)?.assume_cons())
401 }
402
403 #[cfg(feature = "profile")]
406 fn profile_call(&self, call_code: Cons, r#return: bool) -> Result<(), Error> {
407 if let Some(profiler) = &self.profiler {
408 profiler
409 .borrow_mut()
410 .profile_call(&self.memory, call_code, r#return)?;
411 }
412
413 Ok(())
414 }
415
416 #[cfg(feature = "profile")]
417 fn profile_return(&self) -> Result<(), Error> {
418 if let Some(profiler) = &self.profiler {
419 profiler.borrow_mut().profile_return(&self.memory)?;
420 }
421
422 Ok(())
423 }
424
425 #[cfg(feature = "profile")]
426 fn profile_event(&self, name: &str) -> Result<(), Error> {
427 if let Some(profiler) = &self.profiler {
428 profiler.borrow_mut().profile_event(name)?;
429 }
430
431 Ok(())
432 }
433
434 pub fn initialize(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), super::Error> {
436 profile_event!(self, "initialization_start");
437 profile_event!(self, "decode_start");
438
439 let program = self.decode_ribs(&mut input.into_iter())?;
440 self.memory
441 .set_false(self.memory.car(program)?.assume_cons());
442 self.memory
443 .set_code(self.memory.cdr(program)?.assume_cons());
444
445 profile_event!(self, "decode_end");
446
447 let codes = self
449 .memory
450 .cons(Number::default().into(), self.memory.null()?)?
451 .into();
452 let continuation = self.memory.cons(codes, self.memory.null()?)?.into();
453 let stack = self.memory.allocate(
454 continuation,
455 self.memory.null()?.set_tag(StackSlot::Frame as _).into(),
456 )?;
457 self.memory.set_stack(stack);
458 self.memory.set_register(NEVER);
459
460 profile_event!(self, "initialization_end");
461
462 Ok(())
463 }
464
465 fn decode_ribs(&mut self, input: &mut impl Iterator<Item = u8>) -> Result<Cons, Error> {
466 while let Some(head) = input.next() {
467 if head & 1 == 0 {
468 let cdr = self.memory.top()?;
469 let cons = self
470 .memory
471 .allocate(Number::from_i64((head >> 1) as _).into(), cdr)?;
472 self.memory.set_top(cons.into())?;
473 } else if head & 0b10 == 0 {
474 let head = head >> 2;
475
476 if head == 0 {
477 let value = self.memory.top()?;
478 let cons = self.memory.cons(value, self.memory.code())?;
479 self.memory.set_code(cons);
480 } else {
481 let integer = Self::decode_integer_tail(input, head - 1, SHARE_BASE)?;
482 let index = integer >> 1;
483
484 if index > 0 {
485 let cons = self.memory.tail(self.memory.code(), index as usize - 1)?;
486 let head = self.memory.cdr(cons)?.assume_cons();
487 let tail = self.memory.cdr(head)?;
488 self.memory.set_cdr(head, self.memory.code().into())?;
489 self.memory.set_cdr(cons, tail)?;
490 self.memory.set_code(head);
491 }
492
493 let value = self.memory.car(self.memory.code())?;
494
495 if integer & 1 == 0 {
496 self.memory
497 .set_code(self.memory.cdr(self.memory.code())?.assume_cons());
498 }
499
500 self.memory.push(value)?;
501 }
502 } else if head & 0b100 == 0 {
503 let cons = self.memory.stack();
504 let cdr = self.memory.pop()?;
505 let car = self.memory.top()?;
506 let tag = Self::decode_integer_tail(input, head >> 3, TAG_BASE)?;
507 self.memory.set_car(cons, car)?;
508 self.memory.set_raw_cdr(cons, cdr.set_tag(tag as _))?;
509 self.memory.set_top(cons.into())?;
510 } else {
511 self.memory.push(
512 Self::decode_number(Self::decode_integer_tail(input, head >> 3, NUMBER_BASE)?)
513 .into(),
514 )?;
515 }
516 }
517
518 self.memory.pop()?.to_cons().ok_or(Error::BytecodeEnd)
519 }
520
521 fn decode_number(integer: u128) -> Number {
522 if integer & 1 == 0 {
523 Number::from_i64((integer >> 1) as _)
524 } else if integer & 0b10 == 0 {
525 Number::from_i64(-((integer >> 2) as i64))
526 } else {
527 let integer = integer >> 2;
528 let mantissa =
529 if integer.is_multiple_of(2) { 1.0 } else { -1.0 } * (integer >> 12) as f64;
530 let exponent = ((integer >> 1) % (1 << 11)) as isize - 1023;
531
532 Number::from_f64(if exponent < 0 {
533 mantissa / (1u64 << exponent.abs()) as f64
534 } else {
535 mantissa * (1u64 << exponent) as f64
536 })
537 }
538 }
539
540 fn decode_integer_tail(
541 input: &mut impl Iterator<Item = u8>,
542 mut x: u8,
543 mut base: u128,
544 ) -> Result<u128, Error> {
545 let mut y = (x >> 1) as u128;
546
547 while x & 1 != 0 {
548 x = input.next().ok_or(Error::BytecodeEnd)?;
549 y += (x as u128 >> 1) * base;
550 base *= INTEGER_BASE;
551 }
552
553 Ok(y)
554 }
555}
556
557impl<T: PrimitiveSet<H>, H: Heap> Display for Vm<'_, T, H> {
558 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
559 write!(formatter, "{}", &self.memory)
560 }
561}
562
563#[cfg(test)]
564mod tests {
565 use super::*;
566
567 struct FakePrimitiveSet {}
568
569 impl<H: Heap> PrimitiveSet<H> for FakePrimitiveSet {
570 type Error = Error;
571
572 #[maybe_async]
573 fn operate(
574 &mut self,
575 _memory: &mut Memory<H>,
576 _primitive: usize,
577 ) -> Result<(), Self::Error> {
578 Ok(())
579 }
580 }
581
582 type VoidVm = Vm<'static, FakePrimitiveSet>;
583
584 #[test]
585 fn arity() {
586 for arity in [
587 Arity {
588 count: 0,
589 variadic: false,
590 },
591 Arity {
592 count: 1,
593 variadic: false,
594 },
595 Arity {
596 count: 2,
597 variadic: false,
598 },
599 Arity {
600 count: 0,
601 variadic: true,
602 },
603 Arity {
604 count: 1,
605 variadic: true,
606 },
607 Arity {
608 count: 2,
609 variadic: true,
610 },
611 ] {
612 assert_eq!(VoidVm::parse_arity(VoidVm::build_arity(arity)), arity);
613 }
614 }
615}