1#[cfg(feature = "profile")]
2use crate::profiler::Profiler;
3use crate::{
4 Error, 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};
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
39struct Arity {
40 count: Number,
42 variadic: bool,
43}
44
45pub struct Vm<'a, T: PrimitiveSet> {
47 primitive_set: T,
48 memory: Memory<'a>,
49 #[cfg(feature = "profile")]
50 profiler: Option<RefCell<&'a mut dyn Profiler>>,
51}
52
53impl<'a, T: PrimitiveSet> Vm<'a, T> {
56 pub fn new(heap: &'a mut [Value], primitive_set: T) -> Result<Self, Error> {
58 Ok(Self {
59 primitive_set,
60 memory: Memory::new(heap)?,
61 #[cfg(feature = "profile")]
62 profiler: None,
63 })
64 }
65
66 #[cfg(feature = "profile")]
68 pub fn with_profiler(self, profiler: &'a mut dyn Profiler) -> Self {
69 Self {
70 profiler: Some(profiler.into()),
71 ..self
72 }
73 }
74
75 pub const fn primitive_set(&self) -> &T {
77 &self.primitive_set
78 }
79
80 pub fn primitive_set_mut(&mut self) -> &mut T {
82 &mut self.primitive_set
83 }
84
85 pub fn run(&mut self) -> Result<(), T::Error> {
87 while self.memory.code() != self.memory.null() {
88 let instruction = self.memory.cdr(self.memory.code()).assume_cons();
89
90 trace!("instruction", instruction.tag());
91
92 match instruction.tag() {
93 Instruction::CONSTANT => self.constant()?,
94 Instruction::GET => self.get()?,
95 Instruction::SET => self.set(),
96 Instruction::IF => self.r#if(),
97 Instruction::NOP => self.advance_code(),
98 code => self.call(instruction, code as usize - Instruction::CALL as usize)?,
99 }
100
101 trace_memory!(self);
102 }
103
104 Ok(())
105 }
106
107 fn constant(&mut self) -> Result<(), Error> {
108 let constant = self.operand();
109
110 trace!("constant", constant);
111
112 self.memory.push(constant)?;
113 self.advance_code();
114
115 Ok(())
116 }
117
118 fn get(&mut self) -> Result<(), Error> {
119 let operand = self.operand_cons();
120 let value = self.memory.car(operand);
121
122 trace!("operand", operand);
123 trace!("value", value);
124
125 self.memory.push(value)?;
126 self.advance_code();
127
128 Ok(())
129 }
130
131 fn set(&mut self) {
132 let operand = self.operand_cons();
133 let value = self.memory.pop();
134
135 trace!("operand", operand);
136 trace!("value", value);
137
138 self.memory.set_car(operand, value);
139 self.advance_code();
140 }
141
142 fn r#if(&mut self) {
143 let value = self.memory.pop();
144
145 self.memory.set_code(
146 (if value == self.memory.boolean(false).into() {
147 self.memory.cdr(self.memory.code())
148 } else {
149 self.operand()
150 })
151 .assume_cons(),
152 );
153 }
154
155 fn call(&mut self, instruction: Cons, arity: usize) -> Result<(), T::Error> {
156 let r#return = instruction == self.memory.null();
157 let procedure = self.procedure();
158
159 trace!("procedure", procedure);
160 trace!("return", r#return);
161
162 if self.environment(procedure).tag() != Type::Procedure as _ {
163 return Err(Error::ProcedureExpected.into());
164 }
165
166 match self.code(procedure).to_typed() {
167 TypedValue::Cons(code) => {
168 #[cfg(feature = "profile")]
169 self.profile_call(self.memory.code(), r#return);
170
171 let arguments = Self::parse_arity(arity);
172 let parameters =
173 Self::parse_arity(self.memory.car(code).assume_number().to_i64() as usize);
174
175 trace!("argument count", arguments.count);
176 trace!("argument variadic", arguments.variadic);
177 trace!("parameter count", parameters.count);
178 trace!("parameter variadic", parameters.variadic);
179
180 self.memory.set_register(procedure);
181
182 let mut list = if arguments.variadic {
183 self.memory.pop().assume_cons()
184 } else {
185 self.memory.null()
186 };
187
188 for _ in 0..arguments.count.to_i64() {
189 let value = self.memory.pop();
190 list = self.memory.cons(value, list)?;
191 }
192
193 let code = self.memory.code();
195 self.memory.set_code(self.memory.register());
196 self.memory.set_register(list);
197
198 let continuation = if r#return {
199 self.continuation()
200 } else {
201 self.memory
202 .allocate(code.into(), self.memory.stack().into())?
203 };
204 let stack = self.memory.allocate(
205 continuation.into(),
206 self.environment(self.memory.code())
207 .set_tag(StackSlot::Frame as _)
208 .into(),
209 )?;
210 self.memory.set_stack(stack);
211 self.memory.set_code(
212 self.memory
213 .cdr(self.code(self.memory.code()).assume_cons())
214 .assume_cons(),
215 );
216
217 for _ in 0..parameters.count.to_i64() {
218 if self.memory.register() == self.memory.null() {
219 return Err(Error::ArgumentCount.into());
220 }
221
222 self.memory.push(self.memory.car(self.memory.register()))?;
223 self.memory
224 .set_register(self.memory.cdr(self.memory.register()).assume_cons());
225 }
226
227 if parameters.variadic {
228 self.memory.push(self.memory.register().into())?;
229 } else if self.memory.register() != self.memory.null() {
230 return Err(Error::ArgumentCount.into());
231 }
232 }
233 TypedValue::Number(primitive) => {
234 if Self::parse_arity(arity).variadic {
235 let list = self.memory.pop().assume_cons();
236 self.memory.set_register(list);
237
238 while self.memory.register() != self.memory.null() {
239 self.memory.push(self.memory.car(self.memory.register()))?;
240 self.memory
241 .set_register(self.memory.cdr(self.memory.register()).assume_cons());
242 }
243 }
244
245 self.primitive_set
246 .operate(&mut self.memory, primitive.to_i64() as _)?;
247 self.advance_code();
248 }
249 }
250
251 Ok(())
252 }
253
254 #[inline]
255 const fn parse_arity(info: usize) -> Arity {
256 Arity {
257 count: Number::from_i64((info / 2) as _),
258 variadic: info % 2 == 1,
259 }
260 }
261
262 #[inline]
263 fn advance_code(&mut self) {
264 let mut code = self.memory.cdr(self.memory.code()).assume_cons();
265
266 if code == self.memory.null() {
267 #[cfg(feature = "profile")]
268 self.profile_return();
269
270 let continuation = self.continuation();
271 self.memory
273 .set_cdr(self.memory.stack(), self.memory.cdr(continuation));
274
275 code = self
276 .memory
277 .cdr(self.memory.car(continuation).assume_cons())
278 .assume_cons();
279 }
280
281 self.memory.set_code(code);
282 }
283
284 const fn operand(&self) -> Value {
285 self.memory.car(self.memory.code())
286 }
287
288 const fn operand_cons(&self) -> Cons {
289 match self.operand().to_typed() {
290 TypedValue::Cons(cons) => cons,
291 TypedValue::Number(index) => self.memory.tail(self.memory.stack(), index.to_i64() as _),
292 }
293 }
294
295 const fn procedure(&self) -> Cons {
297 self.memory.car(self.operand_cons()).assume_cons()
298 }
299
300 const fn code(&self, procedure: Cons) -> Value {
302 self.memory.car(procedure)
303 }
304
305 const fn environment(&self, procedure: Cons) -> Cons {
306 self.memory.cdr(procedure).assume_cons()
307 }
308
309 const fn continuation(&self) -> Cons {
311 let mut stack = self.memory.stack();
312
313 while self.memory.cdr(stack).assume_cons().tag() != StackSlot::Frame as _ {
314 stack = self.memory.cdr(stack).assume_cons();
315 }
316
317 self.memory.car(stack).assume_cons()
318 }
319
320 #[cfg(feature = "profile")]
323 fn profile_call(&self, call_code: Cons, r#return: bool) {
324 if let Some(profiler) = &self.profiler {
325 profiler
326 .borrow_mut()
327 .profile_call(&self.memory, call_code, r#return);
328 }
329 }
330
331 #[cfg(feature = "profile")]
332 fn profile_return(&self) {
333 if let Some(profiler) = &self.profiler {
334 profiler.borrow_mut().profile_return(&self.memory);
335 }
336 }
337
338 #[cfg(feature = "profile")]
339 fn profile_event(&self, name: &str) {
340 if let Some(profiler) = &self.profiler {
341 profiler.borrow_mut().profile_event(name);
342 }
343 }
344
345 pub fn initialize(&mut self, input: impl IntoIterator<Item = u8>) -> Result<(), super::Error> {
347 profile_event!(self, "initialization_start");
348 profile_event!(self, "decode_start");
349
350 let program = self.decode_ribs(&mut input.into_iter())?;
351 self.memory
352 .set_false(self.memory.car(program).assume_cons());
353 self.memory.set_code(self.memory.cdr(program).assume_cons());
354
355 profile_event!(self, "decode_end");
356
357 let codes = self
359 .memory
360 .cons(Number::default().into(), self.memory.null())?
361 .into();
362 let continuation = self.memory.cons(codes, self.memory.null())?.into();
363 let stack = self.memory.allocate(
364 continuation,
365 self.memory.null().set_tag(StackSlot::Frame as _).into(),
366 )?;
367 self.memory.set_stack(stack);
368 self.memory.set_register(NEVER);
369
370 profile_event!(self, "initialization_end");
371
372 Ok(())
373 }
374
375 fn decode_ribs(&mut self, input: &mut impl Iterator<Item = u8>) -> Result<Cons, Error> {
376 while let Some(head) = input.next() {
377 if head & 1 == 0 {
378 let cdr = self.memory.pop();
379 let cons = self
380 .memory
381 .allocate(Number::from_i64((head >> 1) as _).into(), cdr)?;
382 self.memory.push(cons.into())?;
383 } else if head & 0b10 == 0 {
384 let head = head >> 2;
385
386 if head == 0 {
387 let value = self.memory.top();
388 let cons = self.memory.cons(value, self.memory.code())?;
389 self.memory.set_code(cons);
390 } else {
391 let integer = Self::decode_integer_tail(input, head - 1, SHARE_BASE)?;
392 let index = integer >> 1;
393
394 if index > 0 {
395 let cons = self.memory.tail(self.memory.code(), index as usize - 1);
396 let head = self.memory.cdr(cons).assume_cons();
397 let tail = self.memory.cdr(head);
398 self.memory.set_cdr(head, self.memory.code().into());
399 self.memory.set_cdr(cons, tail);
400 self.memory.set_code(head);
401 }
402
403 let value = self.memory.car(self.memory.code());
404
405 if integer & 1 == 0 {
406 self.memory
407 .set_code(self.memory.cdr(self.memory.code()).assume_cons());
408 }
409
410 self.memory.push(value)?;
411 }
412 } else if head & 0b100 == 0 {
413 let cdr = self.memory.pop();
414 let car = self.memory.pop();
415 let r#type = Self::decode_integer_tail(input, head >> 3, TAG_BASE)?;
416 let cons = self.memory.allocate(car, cdr.set_tag(r#type as _))?;
417 self.memory.push(cons.into())?;
418 } else {
419 self.memory.push(
420 Self::decode_number(Self::decode_integer_tail(input, head >> 3, NUMBER_BASE)?)
421 .into(),
422 )?;
423 }
424 }
425
426 self.memory.pop().to_cons().ok_or(Error::BytecodeEnd)
427 }
428
429 fn decode_number(integer: u128) -> Number {
430 if integer & 1 == 0 {
431 Number::from_i64((integer >> 1) as _)
432 } else if integer & 0b10 == 0 {
433 Number::from_i64(-((integer >> 2) as i64))
434 } else {
435 let integer = integer >> 2;
436 let mantissa = if integer % 2 == 0 { 1.0 } else { -1.0 } * (integer >> 12) as f64;
437 let exponent = ((integer >> 1) % (1 << 11)) as isize - 1023;
438
439 Number::from_f64(if exponent < 0 {
440 mantissa / (1u64 << exponent.abs()) as f64
441 } else {
442 mantissa * (1u64 << exponent) as f64
443 })
444 }
445 }
446
447 fn decode_integer_tail(
448 input: &mut impl Iterator<Item = u8>,
449 mut x: u8,
450 mut base: u128,
451 ) -> Result<u128, Error> {
452 let mut y = (x >> 1) as u128;
453
454 while x & 1 != 0 {
455 x = input.next().ok_or(Error::BytecodeEnd)?;
456 y += (x as u128 >> 1) * base;
457 base *= INTEGER_BASE;
458 }
459
460 Ok(y)
461 }
462}
463
464impl<T: PrimitiveSet> Display for Vm<'_, T> {
465 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
466 write!(formatter, "{}", &self.memory)
467 }
468}