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