1use crate::core::cons::Cons;
3use crate::core::env::{CallFrame, Env, sym};
4use crate::core::gc::{Context, IntoRoot, Rt, Rto, Slot};
5use crate::core::object::{
6 ByteFn, ByteString, FnArgs, Function, FunctionType, Gc, LispVec, NIL, Object, ObjectType,
7 Symbol, WithLifetime,
8};
9use crate::data::LispError;
10use crate::eval::{ErrorType, EvalError, EvalResult};
11use anyhow::{Result, bail};
12use rune_core::macros::{bail_err, rebind, root};
13use rune_macros::{Trace, defun};
14
15mod opcode;
16
17#[derive(Clone, Debug)]
20struct ProgramCounter {
21 range: std::ops::Range<*const u8>,
23 pc: *const u8,
25}
26
27impl ProgramCounter {
28 fn new(vec: &[u8]) -> Self {
29 ProgramCounter { range: vec.as_ptr_range(), pc: vec.as_ptr() }
30 }
31
32 fn with_offset(vec: &[u8], offset: usize) -> Self {
33 ProgramCounter { range: vec.as_ptr_range(), pc: vec.as_ptr().map_addr(|a| a + offset) }
34 }
35
36 fn as_offset(&self) -> usize {
37 self.pc.addr() - self.range.start.addr()
38 }
39
40 fn goto(&mut self, offset: u16) {
41 unsafe {
42 self.pc = self.range.start.add(offset as usize);
43 debug_assert!(self.range.contains(&self.pc));
44 }
45 }
46
47 fn next(&mut self) -> u8 {
49 unsafe {
50 debug_assert!(self.range.contains(&self.pc));
51 let value = *self.pc;
52 self.pc = self.pc.add(1);
53 value
54 }
55 }
56
57 fn arg1(&mut self) -> u16 {
58 unsafe {
59 debug_assert!(self.range.contains(&self.pc));
60 let value = *self.pc;
61 self.pc = self.pc.add(1);
62 if cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled() {
63 println!(" arg: {value}");
64 }
65 value.into()
66 }
67 }
68
69 fn arg2(&mut self) -> u16 {
70 unsafe {
71 debug_assert!(self.range.contains(&self.pc.add(1)));
72 let value = u16::from_le(self.pc.cast::<u16>().read_unaligned());
73 self.pc = self.pc.add(2);
74 if cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled() {
75 println!(" arg: {value}");
76 }
77 value
78 }
79 }
80}
81
82#[derive(Debug, Trace)]
83struct Handler<'ob> {
86 #[no_trace]
87 jump_code: u16,
88 #[no_trace]
89 stack_size: usize,
90 #[no_trace]
91 stack_frame: usize,
92 condition: Slot<Object<'ob>>,
93}
94
95impl<'new> IntoRoot<Handler<'new>> for Handler<'_> {
96 unsafe fn into_root(self) -> Handler<'new> {
97 self.with_lifetime()
98 }
99}
100
101impl<'old, 'new> WithLifetime<'new> for Handler<'old> {
102 type Out = Handler<'new>;
103
104 unsafe fn with_lifetime(self) -> Self::Out {
105 std::mem::transmute::<Handler<'old>, Handler<'new>>(self)
106 }
107}
108
109#[derive(Trace)]
112struct VM<'brw, 'env, 'rt> {
113 #[no_trace]
114 pc: ProgramCounter,
116 func: Slot<&'rt ByteFn>,
119 handlers: Vec<Handler<'rt>>,
121 #[no_trace]
123 env: &'brw mut Rt<Env<'env>>,
124}
125
126impl<'brw, 'env> IntoRoot<VM<'brw, 'env, 'static>> for VM<'brw, 'env, '_> {
127 unsafe fn into_root(self) -> VM<'brw, 'env, 'static> {
128 std::mem::transmute(self)
129 }
130}
131
132impl<'ob> RootedVM<'_, '_, '_> {
133 fn varref(&mut self, idx: u16, cx: &'ob Context) -> Result<()> {
134 let symbol = self.get_const(idx as usize, cx);
135 if let ObjectType::Symbol(sym) = symbol.untag() {
136 let Some(var) = self.env.vars.get(sym) else { bail!("Void Variable: {sym}") };
137 let var = var.bind(cx);
138 self.env.stack.push(var);
139 Ok(())
140 } else {
141 unreachable!("Varref was not a symbol: {:?}", symbol);
142 }
143 }
144
145 fn varset(&mut self, idx: usize, cx: &Context) -> Result<()> {
146 let obj = self.get_const(idx, cx);
147 let symbol: Symbol = obj.try_into()?;
148 let value = self.env.stack.pop(cx);
149 crate::data::set(symbol, value, self.env)?;
150 Ok(())
151 }
152
153 fn varbind(&mut self, idx: u16, cx: &'ob Context) {
154 let value = self.env.stack.pop(cx);
155 let symbol = self.get_const(idx as usize, cx);
156 let ObjectType::Symbol(sym) = symbol.untag() else {
157 unreachable!("Varbind was not a symbol: {:?}", symbol)
158 };
159 self.env.varbind(sym, value, cx);
160 }
161
162 fn unbind(&mut self, idx: u16, cx: &'ob Context) {
163 self.env.unbind(idx, cx);
164 }
165
166 fn get_const(&self, i: usize, cx: &'ob Context) -> Object<'ob> {
167 *self.func.bind(cx).consts().get(i).expect("constant had invalid index")
168 }
169
170 fn set_current_frame(&mut self, f: &ByteFn, offset: usize) {
171 self.func.set(f);
172 self.pc = ProgramCounter::with_offset(f.codes(), offset);
173 }
174
175 fn unwind(&mut self, idx: usize, cx: &'ob Context) {
176 if idx == self.env.stack.current_frame() {
177 return;
178 }
179 assert!(idx < self.env.stack.current_frame());
180 if let Some((f, offset)) = self.env.stack.get_bytecode_frame(idx) {
181 self.set_current_frame(f.bind(cx), offset);
182 self.env.stack.unwind_frames(idx);
183 } else {
184 unreachable!("Unwind frame not found")
185 }
186 }
187
188 #[inline(always)]
189 fn debug_enabled() -> bool {
190 cfg!(test) || (cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled())
191 }
192
193 fn prepare_lisp_args(
197 &mut self,
198 func: &ByteFn,
199 arg_cnt: usize,
200 name: &str,
201 cx: &'ob Context,
202 ) -> Result<()> {
203 let arg_cnt = arg_cnt as u16;
204 let fill_args = num_of_fill_args(func.args, arg_cnt, name, cx)?;
205 self.env.stack.fill_extra_args(fill_args);
206 let total_args = arg_cnt + fill_args;
207 let rest_size = total_args - (func.args.required + func.args.optional);
208 if rest_size > 0 {
209 let slice = &self.env.stack[..rest_size as usize];
210 let list = crate::fns::slice_into_list(Rt::bind_slice(slice, cx), None, cx);
211 self.env.stack.remove_top(rest_size as usize - 1);
212 self.env.stack[0].set(list);
213 self.env.stack.set_arg_count(total_args - rest_size + 1, true);
214 } else if func.args.rest {
215 self.env.stack.push(NIL);
216 self.env.stack.set_arg_count(total_args + 1, true)
217 } else {
218 self.env.stack.set_arg_count(total_args, false)
219 };
220 Ok(())
221 }
222
223 fn call(&mut self, arg_cnt: u16, cx: &'ob mut Context) -> Result<(), EvalError> {
224 let arg_cnt = usize::from(arg_cnt);
225 let func: Function = self.env.stack[arg_cnt].bind(cx).try_into()?;
226 let name = match func.untag() {
227 FunctionType::Symbol(x) => x.name().to_owned(),
228 _ => String::from("lambda"),
229 };
230 if let FunctionType::ByteFn(next_fn) = func.untag() {
231 let len = self.env.stack.len();
234 let pc_offset = self.pc.as_offset();
235 let prev_fn = self.func.bind(cx);
236 self.set_current_frame(next_fn, 0);
237 let frame_start = len - (arg_cnt + 1);
238 self.env
239 .stack
240 .push_bytecode_frame(frame_start, next_fn.depth, prev_fn, pc_offset);
241 self.prepare_lisp_args(next_fn, arg_cnt, &name, cx)?;
242 } else {
243 let mut frame = CallFrame::new_with_args(self.env, arg_cnt);
245 root!(func, cx);
246 let result = func.call(&mut frame, Some(&name), cx)?;
247 drop(frame); self.env.stack.top().set(result);
249 cx.garbage_collect(false);
250 }
251 Ok(())
252 }
253
254 fn run(&mut self, cx: &'ob mut Context) -> EvalResult<'ob> {
255 'main: loop {
256 let err = match self.execute_bytecode(cx) {
257 Ok(x) => return Ok(rebind!(x, cx)),
258 Err(e) => e,
259 };
260
261 #[expect(clippy::never_loop)]
263 while let Some(handler) = self.handlers.bind_mut(cx).pop() {
264 match handler.condition.untag() {
265 ObjectType::Symbol(sym::ERROR) => {}
266 ObjectType::Cons(conditions) => {
267 for condition in conditions {
268 let condition = condition?;
269 if condition != sym::DEBUG && condition != sym::ERROR {
271 bail_err!("non-error conditions {condition} not yet supported")
272 }
273 }
274 }
275 x => bail_err!("Invalid condition handler: {x}"),
276 }
277
278 let error = if let EvalError { error: ErrorType::Signal(id), .. } = err {
279 let Some((sym, data)) = self.env.get_exception(id) else {
280 unreachable!("Exception not found")
281 };
282 Cons::new(sym, data, cx)
283 } else {
284 Cons::new(sym::ERROR, format!("{err}"), cx)
287 };
288 self.unwind(handler.stack_frame, cx);
289 self.env.stack.truncate(handler.stack_size);
290 self.env.stack.push(Object::from(error));
291 self.pc.goto(handler.jump_code);
292 continue 'main;
293 }
294 return Err(err);
295 }
296 }
297
298 #[expect(clippy::too_many_lines)]
299 fn execute_bytecode(&mut self, cx: &'ob mut Context) -> EvalResult<'ob> {
301 use crate::{alloc, arith, data, fns};
302 use opcode::OpCode as op;
303 loop {
304 let op = match self.pc.next().try_into() {
305 Ok(x) => x,
306 Err(e) => panic!("Invalid Bytecode: {e}"),
307 };
308
309 if Self::debug_enabled() {
310 println!("[");
311 for (idx, x) in self.env.stack.frames().iter().rev().enumerate() {
312 println!(" {idx}: {x},");
313 }
314 println!("]");
315 let byte_offset = self.pc.pc as i64 - self.pc.range.start as i64 - 1;
316 println!("op :{byte_offset}: {op:?}");
317 }
318 match op {
319 op::StackRef0 => self.env.stack.push_ref(0, cx),
320 op::StackRef1 => self.env.stack.push_ref(1, cx),
321 op::StackRef2 => self.env.stack.push_ref(2, cx),
322 op::StackRef3 => self.env.stack.push_ref(3, cx),
323 op::StackRef4 => self.env.stack.push_ref(4, cx),
324 op::StackRef5 => self.env.stack.push_ref(5, cx),
325 op::StackRefN => {
326 let idx = self.pc.arg1();
327 self.env.stack.push_ref(idx, cx);
328 }
329 op::StackRefN2 => {
330 let idx = self.pc.arg2();
331 self.env.stack.push_ref(idx, cx);
332 }
333 op::StackSetN => {
334 let idx = self.pc.arg1();
335 self.env.stack.set_ref(idx);
336 }
337 op::StackSetN2 => {
338 let idx = self.pc.arg2();
339 self.env.stack.set_ref(idx);
340 }
341 op::VarRef0 => self.varref(0, cx)?,
342 op::VarRef1 => self.varref(1, cx)?,
343 op::VarRef2 => self.varref(2, cx)?,
344 op::VarRef3 => self.varref(3, cx)?,
345 op::VarRef4 => self.varref(4, cx)?,
346 op::VarRef5 => self.varref(5, cx)?,
347 op::VarRefN => {
348 let idx = self.pc.arg1();
349 self.varref(idx, cx)?;
350 }
351 op::VarRefN2 => {
352 let idx = self.pc.arg2();
353 self.varref(idx, cx)?;
354 }
355 op::VarSet0 => self.varset(0, cx)?,
356 op::VarSet1 => self.varset(1, cx)?,
357 op::VarSet2 => self.varset(2, cx)?,
358 op::VarSet3 => self.varset(3, cx)?,
359 op::VarSet4 => self.varset(4, cx)?,
360 op::VarSet5 => self.varset(5, cx)?,
361 op::VarSetN => {
362 let idx = self.pc.arg1();
363 self.varset(idx.into(), cx)?;
364 }
365 op::VarSetN2 => {
366 let idx = self.pc.arg2();
367 self.varset(idx.into(), cx)?;
368 }
369 op::VarBind0 => self.varbind(0, cx),
370 op::VarBind1 => self.varbind(1, cx),
371 op::VarBind2 => self.varbind(2, cx),
372 op::VarBind3 => self.varbind(3, cx),
373 op::VarBind4 => self.varbind(4, cx),
374 op::VarBind5 => self.varbind(5, cx),
375 op::VarBindN => {
376 let idx = self.pc.arg1();
377 self.varbind(idx, cx);
378 }
379 op::VarBindN2 => {
380 let idx = self.pc.arg2();
381 self.varbind(idx, cx);
382 }
383 op::Call0 => self.call(0, cx)?,
384 op::Call1 => self.call(1, cx)?,
385 op::Call2 => self.call(2, cx)?,
386 op::Call3 => self.call(3, cx)?,
387 op::Call4 => self.call(4, cx)?,
388 op::Call5 => self.call(5, cx)?,
389 op::CallN => {
390 let idx = self.pc.arg1();
391 self.call(idx, cx)?;
392 }
393 op::CallN2 => {
394 let idx = self.pc.arg2();
395 self.call(idx, cx)?;
396 }
397 op::Unbind0 => self.unbind(0, cx),
398 op::Unbind1 => self.unbind(1, cx),
399 op::Unbind2 => self.unbind(2, cx),
400 op::Unbind3 => self.unbind(3, cx),
401 op::Unbind4 => self.unbind(4, cx),
402 op::Unbind5 => self.unbind(5, cx),
403 op::UnbindN => {
404 let idx = self.pc.arg1();
405 self.unbind(idx, cx);
406 }
407 op::UnbindN2 => {
408 let idx = self.pc.arg2();
409 self.unbind(idx, cx);
410 }
411 op::PopHandler => {
412 self.handlers.pop();
413 }
414 op::PushCondtionCase => {
415 let condition = self.env.stack.pop(cx);
417 let handler = Handler {
418 jump_code: self.pc.arg2(),
419 stack_size: self.env.stack.len(),
420 stack_frame: self.env.stack.current_frame(),
421 condition: Slot::new(condition),
422 };
423 self.handlers.push(handler);
424 }
425 op::PushCatch => todo!("PushCatch bytecode"),
426 op::Nth => {
427 let list = self.env.stack.pop(cx);
428 let top = self.env.stack.top();
429 top.set(fns::nth(top.bind_as(cx)?, list.try_into()?)?);
430 }
431 op::Symbolp => {
432 let top = self.env.stack.top();
433 top.set(data::symbolp(top.bind(cx)));
434 }
435 op::Consp => {
436 let top = self.env.stack.top();
437 top.set(data::consp(top.bind(cx)));
438 }
439 op::Stringp => {
440 let top = self.env.stack.top();
441 top.set(data::stringp(top.bind(cx)));
442 }
443 op::Listp => {
444 let top = self.env.stack.top();
445 top.set(data::listp(top.bind(cx)));
446 }
447 op::Eq => {
448 let v1 = self.env.stack.pop(cx);
449 let top = self.env.stack.top();
450 top.set(fns::eq(top.bind(cx), v1));
451 }
452 op::Memq => {
453 let list = self.env.stack.pop(cx);
454 let elt = self.env.stack.top();
455 elt.set(fns::memq(elt.bind(cx), list.try_into()?)?);
456 }
457 op::Not => {
458 let top = self.env.stack.top();
459 top.set(data::null(top.bind(cx)));
460 }
461 op::Car => {
462 let top = self.env.stack.top();
463 top.set(data::car(top.bind_as(cx)?));
464 }
465 op::Cdr => {
466 let top = self.env.stack.top();
467 top.set(data::cdr(top.bind_as(cx)?));
468 }
469 op::Cons => {
470 let cdr = self.env.stack.pop(cx);
471 let car = self.env.stack.top();
472 car.set(data::cons(car.bind(cx), cdr, cx));
473 }
474 op::List1 => {
475 let top = self.env.stack.top();
476 top.set(alloc::list(&[top.bind(cx)], cx));
477 }
478 op::List2 => {
479 let a2 = self.env.stack.pop(cx);
480 let top = self.env.stack.top();
481 top.set(alloc::list(&[top.bind(cx), a2], cx));
482 }
483 op::List3 => {
484 let a3 = self.env.stack.pop(cx);
485 let a2 = self.env.stack.pop(cx);
486 let top = self.env.stack.top();
487 top.set(alloc::list(&[top.bind(cx), a2, a3], cx));
488 }
489 op::List4 => {
490 let a4 = self.env.stack.pop(cx);
491 let a3 = self.env.stack.pop(cx);
492 let a2 = self.env.stack.pop(cx);
493 let top = self.env.stack.top();
494 top.set(alloc::list(&[top.bind(cx), a2, a3, a4], cx));
495 }
496 op::Length => {
497 let top = self.env.stack.top();
498 top.set(fns::length(top.bind(cx))? as i64);
499 }
500 op::Aref => {
501 let idx = self.env.stack.pop(cx);
502 let top = self.env.stack.top();
503 top.set(data::aref(top.bind(cx), idx.try_into()?, cx)?);
504 }
505 op::Aset => {
506 let newlet = self.env.stack.pop(cx);
507 let idx = self.env.stack.pop(cx);
508 let top = self.env.stack.top();
509 top.set(data::aset(top.bind(cx), idx.try_into()?, newlet)?);
510 }
511 op::SymbolValue => {
512 let top = self.env.stack.top().bind_as(cx)?;
513 let value = data::symbol_value(top, self.env, cx).unwrap_or_default();
514 self.env.stack.top().set(value);
515 }
516 op::SymbolFunction => {
517 let top = self.env.stack.top();
518 top.set(data::symbol_function(top.bind_as(cx)?, cx));
519 }
520 op::Set => {
521 let newlet = self.env.stack.pop(cx);
522 let top = self.env.stack.top().bind_as(cx)?;
523 let value = data::set(top, newlet, self.env)?;
524 self.env.stack.top().set(value);
525 }
526 op::Fset => {
527 let def = self.env.stack.pop(cx);
528 let top = self.env.stack.top();
529 top.set::<Object>(data::fset(top.bind_as(cx)?, def)?.into());
530 }
531 op::Get => {
532 let prop = self.env.stack.pop(cx).try_into()?;
533 let top = self.env.stack.top().bind_as(cx)?;
534 let value = data::get(top, prop, self.env, cx);
535 self.env.stack.top().set(value);
536 }
537 op::Substring => todo!("Substring bytecode"),
538 op::Concat2 => todo!("Concat2 bytecode"),
539 op::Concat3 => todo!("Concat3 bytecode"),
540 op::Concat4 => todo!("Concat4 bytecode"),
541 op::Sub1 => {
542 let top = self.env.stack.top();
543 top.set(cx.add(arith::sub_one(top.bind_as(cx)?)));
544 }
545 op::Add1 => {
546 let top = self.env.stack.top();
547 top.set(cx.add(arith::add_one(top.bind_as(cx)?)));
548 }
549 op::EqlSign => {
550 let rhs = self.env.stack.pop(cx);
551 let top = self.env.stack.top();
552 top.set::<Object>(arith::num_eq(top.bind_as(cx)?, &[rhs.try_into()?]).into());
553 }
554 op::GreaterThan => {
555 let v1 = self.env.stack.pop(cx);
556 let top = self.env.stack.top();
557 top.set(arith::greater_than(top.bind_as(cx)?, &[v1.try_into()?]));
558 }
559 op::LessThan => {
560 let v1 = self.env.stack.pop(cx);
561 let top = self.env.stack.top();
562 top.set(arith::less_than(top.bind_as(cx)?, &[v1.try_into()?]));
563 }
564 op::LessThanOrEqual => {
565 let v1 = self.env.stack.pop(cx);
566 let top = self.env.stack.top();
567 top.set(arith::less_than_or_eq(top.bind_as(cx)?, &[v1.try_into()?]));
568 }
569 op::GreaterThanOrEqual => {
570 let v1 = &[self.env.stack.pop(cx).try_into()?];
571 let top = self.env.stack.top();
572 top.set(arith::greater_than_or_eq(top.bind_as(cx)?, v1));
573 }
574 op::Diff => todo!("Diff bytecode"),
575 op::Negate => {
576 let top = self.env.stack.top();
577 top.set(cx.add(arith::sub(top.bind_as(cx)?, &[])));
578 }
579 op::Plus => {
580 let arg1 = self.env.stack.pop(cx);
581 let top = self.env.stack.top();
582 let args = &[top.bind_as(cx)?, arg1.try_into()?];
583 top.set(cx.add(arith::add(args)));
584 }
585 op::Max => {
586 let arg1 = self.env.stack.pop(cx);
587 let top = self.env.stack.top();
588 let args = &[arg1.try_into()?];
589 top.set(cx.add(arith::max(top.bind_as(cx)?, args)));
590 }
591 op::Min => {
592 let arg1 = self.env.stack.pop(cx);
593 let top = self.env.stack.top();
594 let args = &[arg1.try_into()?];
595 top.set(cx.add(arith::min(top.bind_as(cx)?, args)));
596 }
597 op::Multiply => {
598 let arg1 = self.env.stack.pop(cx);
599 let top = self.env.stack.top();
600 let args = &[top.bind_as(cx)?, arg1.try_into()?];
601 top.set(cx.add(arith::mul(args)));
602 }
603 op::Point => todo!("Point bytecode"),
604 op::GotoChar => todo!("GotoChar bytecode"),
605 op::Insert => todo!("Insert bytecode"),
606 op::PointMax => todo!("PointMax bytecode"),
607 op::PointMin => todo!("PointMin bytecode"),
608 op::CharAfter => todo!("CharAfter bytecode"),
609 op::FollowingChar => todo!("FollowingChar bytecode"),
610 op::PrecedingChar => todo!("PrecedingChar bytecode"),
611 op::CurrentColumn => todo!("CurrentColumn bytecode"),
612 op::IndentTo => todo!("IndentTo bytecode"),
613 op::EndOfLineP => todo!("EndOfLineP bytecode"),
614 op::EndOfBufferP => todo!("EndOfBufferP bytecode"),
615 op::BeginningOfLineP => todo!("BeginningOfLineP bytecode"),
616 op::BeginningOfBufferP => todo!("BeginningOfBufferP bytecode"),
617 op::CurrentBuffer => todo!("CurrentBuffer bytecode"),
618 op::SetBuffer => todo!("SetBuffer bytecode"),
619 op::SaveCurrentBuffer1 => todo!("SaveCurrentBuffer1 bytecode"),
620 op::ForwardChar => todo!("ForwardChar bytecode"),
621 op::ForwardWord => todo!("ForwardWord bytecode"),
622 op::SkipCharsForward => todo!("SkipCharsForward bytecode"),
623 op::SkipCharsBackward => todo!("SkipCharsBackward bytecode"),
624 op::ForwardLine => todo!("ForwardLine bytecode"),
625 op::CharSyntax => todo!("CharSyntax bytecode"),
626 op::BufferSubstring => todo!("BufferSubstring bytecode"),
627 op::DeleteRegion => todo!("DeleteRegion bytecode"),
628 op::NarrowToRegion => todo!("NarrowToRegion bytecode"),
629 op::Widen => todo!("Widen bytecode"),
630 op::EndOfLine => todo!("EndOfLine bytecode"),
631 op::ConstantN2 => {
632 let idx = self.pc.arg2();
633 let cnst = self.get_const(idx.into(), cx);
634 self.env.stack.push(cnst);
635 }
636 op::Goto => {
637 let offset = self.pc.arg2();
638 self.pc.goto(offset);
639 }
640 op::GotoIfNil => {
641 let cond = self.env.stack.pop(cx);
642 let offset = self.pc.arg2();
643 if cond.is_nil() {
644 self.pc.goto(offset);
645 }
646 }
647 op::GotoIfNonNil => {
648 let cond = self.env.stack.pop(cx);
649 let offset = self.pc.arg2();
650 if !cond.is_nil() {
651 self.pc.goto(offset);
652 }
653 }
654 op::GotoIfNilElsePop => {
655 let offset = self.pc.arg2();
656 if self.env.stack[0].bind(cx).is_nil() {
657 self.pc.goto(offset);
658 } else {
659 self.env.stack.pop(cx);
660 }
661 }
662 op::GotoIfNonNilElsePop => {
663 let offset = self.pc.arg2();
664 if self.env.stack[0].bind(cx).is_nil() {
665 self.env.stack.pop(cx);
666 } else {
667 self.pc.goto(offset);
668 }
669 }
670 op::Return => {
671 if let Some((f, offset)) = self.env.stack.prev_bytecode_frame() {
672 self.set_current_frame(f.bind(cx), offset);
673 let top = self.env.stack.top().bind(cx);
674 self.env.stack.pop_frame();
675 self.env.stack.push(top);
676 } else {
677 let top = self.env.stack.pop(cx);
678 return Ok(top);
679 }
680 }
681 op::Discard => {
682 self.env.stack.pop(cx);
683 }
684 op::DiscardN => {
685 let arg = self.pc.arg1();
686 let cur_len = self.env.stack.len();
687 let keep_tos = (arg & 0x80) != 0;
688 let count = (arg & 0x7F) as usize;
689 if keep_tos {
690 let top = self.env.stack.top().bind(cx);
691 self.env.stack.truncate(cur_len - count);
692 self.env.stack.top().set(top);
693 } else {
694 self.env.stack.truncate(cur_len - count);
695 }
696 }
697 op::Duplicate => {
698 let top = self.env.stack[0].bind(cx);
699 self.env.stack.push(top);
700 }
701 op::SaveExcursion => todo!("SaveExcursion bytecode"),
702 op::SaveRestriction => todo!("SaveRestriction bytecode"),
703 op::UnwindProtect => todo!("UnwindProtect bytecode"),
704 op::SetMarker => todo!("SetMarker bytecode"),
705 op::MatchBeginning => todo!("MatchBeginning bytecode"),
706 op::MatchEnd => todo!("MatchEnd bytecode"),
707 op::Upcase => todo!("Upcase bytecode"),
708 op::Downcase => todo!("Downcase bytecode"),
709 op::StringEqlSign => todo!("StringEqlSign bytecode"),
710 op::StringLessThan => todo!("StringLessThan bytecode"),
711 op::Equal => {
712 let rhs = self.env.stack.pop(cx);
713 let top = self.env.stack.top();
714 top.set(fns::equal(top.bind(cx), rhs));
715 }
716 op::Nthcdr => {
717 let list = self.env.stack.pop(cx);
718 let top = self.env.stack.top();
719 top.set(fns::nthcdr(top.bind_as(cx)?, list.try_into()?)?.as_obj_copy());
720 }
721 op::Elt => {
722 let n = self.env.stack.pop(cx);
723 let top = self.env.stack.top();
724 top.set(fns::elt(top.bind(cx), n.try_into()?, cx)?);
725 }
726 op::Member => {
727 let list = self.env.stack.pop(cx);
728 let top = self.env.stack.top();
729 top.set(fns::member(top.bind(cx), list.try_into()?)?);
730 }
731 op::Assq => {
732 let alist = self.env.stack.pop(cx);
733 let top = self.env.stack.top();
734 top.set(fns::assq(top.bind(cx), alist.try_into()?)?);
735 }
736 op::Nreverse => {
737 let elt = self.env.stack.top();
738 elt.set(fns::nreverse(elt.bind_as(cx)?)?);
739 }
740 op::Setcar => {
741 let newcar = self.env.stack.pop(cx);
742 let top = self.env.stack.top();
743 top.set(data::setcar(top.bind_as(cx)?, newcar)?);
744 }
745 op::Setcdr => {
746 let newcdr = self.env.stack.pop(cx);
747 let top = self.env.stack.top();
748 top.set(data::setcdr(top.bind_as(cx)?, newcdr)?);
749 }
750 op::CarSafe => {
751 let top = self.env.stack.top();
752 top.set(data::car_safe(top.bind(cx)));
753 }
754 op::CdrSafe => {
755 let top = self.env.stack.top();
756 top.set(data::cdr_safe(top.bind(cx)));
757 }
758 op::Nconc => {
759 let list2 = self.env.stack.pop(cx);
760 let top = self.env.stack.top();
761 top.set(fns::nconc(&[top.bind_as(cx)?, list2.try_into()?])?);
762 }
763 op::Quo => todo!("Quo bytecode"),
764 op::Rem => todo!("Rem bytecode"),
765 op::Numberp => {
766 let top = self.env.stack.top();
767 top.set(data::numberp(top.bind(cx)));
768 }
769 op::Integerp => {
770 let top = self.env.stack.top();
771 top.set(data::integerp(top.bind(cx)));
772 }
773 op::ListN => {
774 let size = self.pc.arg1() as usize;
775 let slice = Rt::bind_slice(&self.env.stack[..size], cx);
776 let list = alloc::list(slice, cx);
777 let len = self.env.stack.len();
778 self.env.stack.truncate(len - (size - 1));
779 self.env.stack.top().set(list);
780 }
781 op::ConcatN => todo!("ConcatN bytecode"),
782 op::InsertN => todo!("InsertN bytecode"),
783 op::Switch => {
784 let ObjectType::HashTable(table) = self.env.stack.pop(cx).untag() else {
785 unreachable!("switch table was not a hash table")
786 };
787 let cond = self.env.stack.pop(cx);
788 if let Some(offset) = table.get(cond) {
789 let ObjectType::Int(offset) = offset.untag() else {
790 unreachable!("switch value was not a int")
791 };
792 self.pc.goto(offset as u16);
793 }
794 }
795 op::Constant0
796 | op::Constant1
797 | op::Constant2
798 | op::Constant3
799 | op::Constant4
800 | op::Constant5
801 | op::Constant6
802 | op::Constant7
803 | op::Constant8
804 | op::Constant9
805 | op::Constant10
806 | op::Constant11
807 | op::Constant12
808 | op::Constant13
809 | op::Constant14
810 | op::Constant15
811 | op::Constant16
812 | op::Constant17
813 | op::Constant18
814 | op::Constant19
815 | op::Constant20
816 | op::Constant21
817 | op::Constant22
818 | op::Constant23
819 | op::Constant24
820 | op::Constant25
821 | op::Constant26
822 | op::Constant27
823 | op::Constant28
824 | op::Constant29
825 | op::Constant30
826 | op::Constant31
827 | op::Constant32
828 | op::Constant33
829 | op::Constant34
830 | op::Constant35
831 | op::Constant36
832 | op::Constant37
833 | op::Constant38
834 | op::Constant39
835 | op::Constant40
836 | op::Constant41
837 | op::Constant42
838 | op::Constant43
839 | op::Constant44
840 | op::Constant45
841 | op::Constant46
842 | op::Constant47
843 | op::Constant48
844 | op::Constant49
845 | op::Constant50
846 | op::Constant51
847 | op::Constant52
848 | op::Constant53
849 | op::Constant54
850 | op::Constant55
851 | op::Constant56
852 | op::Constant57
853 | op::Constant58
854 | op::Constant59
855 | op::Constant60
856 | op::Constant61
857 | op::Constant62
858 | op::Constant63 => {
859 let idx = (op as u8) - (op::Constant0 as u8);
860 let cnst = self.get_const(idx as usize, cx);
861 self.env.stack.push(cnst);
862 }
863 }
864 }
865 }
866}
867
868#[defun]
869fn byte_code<'ob>(
870 bytestr: &Rto<Gc<&ByteString>>,
871 vector: &Rto<Gc<&LispVec>>,
872 maxdepth: usize,
873 env: &mut Rt<Env>,
874 cx: &'ob mut Context,
875) -> Result<Object<'ob>> {
876 let fun = crate::alloc::make_byte_code(
877 0,
878 bytestr.untag(cx),
879 vector.untag(cx),
880 maxdepth,
881 None,
882 None,
883 &[],
884 cx,
885 )?;
886 root!(fun, cx);
887 Ok(call(fun, 0, "unnamed", &mut CallFrame::new(env), cx)?)
888}
889
890fn num_of_fill_args(spec: FnArgs, args: u16, name: &str, cx: &Context) -> Result<u16> {
895 if args < spec.required {
896 bail!(LispError::arg_cnt(name, spec.required, args, cx));
897 }
898 let total = spec.required + spec.optional;
899 if !spec.rest && (args > total) {
900 bail!(LispError::arg_cnt(name, total, args, cx));
901 }
902 Ok(total.saturating_sub(args))
903}
904
905#[defun]
906fn fetch_bytecode(_object: Object) {
907 }
909
910pub(crate) fn call<'ob>(
911 func: &Rto<&ByteFn>,
912 arg_cnt: usize,
913 name: &str,
914 frame: &mut CallFrame,
915 cx: &'ob mut Context,
916) -> EvalResult<'ob> {
917 frame.stack.set_depth(func.bind(cx).depth);
918 let func = func.bind(cx);
919 let vm = VM {
920 pc: ProgramCounter::new(func.codes()),
921 func: Slot::new(func),
922 env: frame,
923 handlers: Vec::new(),
924 };
925 root!(vm, cx);
926 vm.prepare_lisp_args(func, arg_cnt, name, cx)?;
927 vm.run(cx).map_err(|e| e.add_trace(name, vm.env.stack.current_args()))
928}
929
930#[cfg(test)]
931mod test {
932 use crate::core::{
933 gc::RootSet,
934 object::{HashTable, IntoObject},
935 };
936 use rune_core::macros::{list, rebind, root};
937
938 use super::{opcode::OpCode, *};
939
940 macro_rules! make_bytecode { (
941 $name:ident,
942 $arglist:expr,
943 [$($opcodes:expr),* $(,)?],
944 [$($constants:expr),* $(,)?],
945 $cx:expr $(,)?
946 ) => (
947 let cx1: &Context = $cx;
949 let constants: &LispVec = {
950 let vec: Vec<Object> = vec![$(cx1.add($constants)),*];
951 vec.into_obj(cx1).untag()
952 };
953 let opcodes = {
954 #[allow(trivial_numeric_casts)]
955 let opcodes = vec![$($opcodes as u8),*];
956 println!("Test seq: {opcodes:?}");
957 opcodes.into_obj(cx1).untag()
958 };
959 let depth = 10;
961 let bytecode = crate::alloc::make_byte_code(
962 $arglist,
963 &opcodes,
964 constants,
965 depth,
966 None,
967 None,
968 &[],
969 cx1
970 ).unwrap();
971 root!(bytecode, cx1);
972 let $name = bytecode;
973 )
974 }
975
976 macro_rules! check_bytecode { (
977 $bytecode:expr,
978 [$($args:expr),* $(,)?],
979 $expect:expr,
980 $cx:expr $(,)?
981 ) => ({
982 let bytecode: &Rto<&ByteFn> = $bytecode;
983 let cx: &mut Context = $cx;
984
985 let args: Vec<Object> = { vec![$(cx.add($args)),*] };
986 let expect = cx.add($expect);
987
988 root!(args, cx);
989 root!(expect, cx);
990
991 check_bytecode_internal(
992 args,
993 bytecode,
994 expect,
995 cx
996 );
997 })
998 }
999
1000 fn check_bytecode_internal(
1001 args: &mut Rt<Vec<Slot<Object>>>,
1002 bytecode: &Rto<&ByteFn>,
1003 expect: &Rto<Object>,
1004 cx: &mut Context,
1005 ) {
1006 root!(env, new(Env), cx);
1007 let frame = &mut CallFrame::new(env);
1008 frame.push_arg_slice(Rt::bind_slice(args, cx));
1009 frame.finalize_arguments();
1010 let val = rebind!(call(bytecode, frame.arg_count(), "test", frame, cx).unwrap());
1011 let expect = expect.bind(cx);
1012 assert_eq!(val, expect);
1013 }
1014
1015 #[test]
1016 fn test_basic() {
1017 use OpCode::*;
1018 let roots = &RootSet::default();
1019 let cx = &mut Context::new(roots);
1020 make_bytecode!(bytecode, 0, [Constant0, Return], [5], cx);
1022 check_bytecode!(bytecode, [], 5, cx);
1023 make_bytecode!(bytecode, 257, [Duplicate, Constant0, Plus, Return], [5], cx);
1025 check_bytecode!(bytecode, [7], 12, cx);
1026 make_bytecode!(bytecode, 513, [StackRef1, StackRef1, Plus, Return], [], cx);
1028 check_bytecode!(bytecode, [3, 4], 7, cx);
1029 make_bytecode!(
1031 bytecode,
1032 257,
1033 [Duplicate, GotoIfNil, 0x06, 0x00, Constant0, Return, Constant1, Return],
1034 [2, 3],
1035 cx
1036 );
1037 check_bytecode!(bytecode, [false], 3, cx);
1038 check_bytecode!(bytecode, [true], 2, cx);
1039
1040 make_bytecode!(
1046 bytecode,
1047 257,
1048 [
1049 Constant0, Constant0, StackRef2, LessThan, GotoIfNil, VarSet2, 0x00, StackRef1,
1050 Sub1, StackSetN, 0x02, Duplicate, Add1, StackSetN, 0x01, Goto, 0x01, 0x00, Return
1051 ],
1052 [0],
1053 cx
1054 );
1055 check_bytecode!(bytecode, [5], 5, cx);
1056 check_bytecode!(bytecode, [0], 0, cx);
1057 }
1058
1059 #[test]
1060 fn test_bytecode_call() {
1061 use OpCode::*;
1062 let roots = &RootSet::default();
1063 let cx = &mut Context::new(roots);
1064 sym::init_symbols();
1065 make_bytecode!(
1067 bytecode,
1068 257,
1069 [Constant0, StackRef1, Call1, Return],
1070 [sym::SYMBOL_NAME],
1071 cx
1072 );
1073 check_bytecode!(bytecode, [sym::SYMBOL_NAME], "symbol-name", cx);
1074 check_bytecode!(bytecode, [sym::AREF], "aref", cx);
1075 check_bytecode!(bytecode, [sym::ADD], "+", cx);
1076
1077 make_bytecode!(
1079 bytecode,
1080 771,
1081 [Constant0, StackRef3, StackRef3, StackRef3, Call3, Return],
1082 [sym::ADD],
1083 cx
1084 );
1085 check_bytecode!(bytecode, [1, 2, 3], 6, cx);
1086
1087 make_bytecode!(
1089 bytecode,
1090 128,
1091 [Constant0, Constant1, StackRef2, Call2, Return],
1092 [sym::APPLY, sym::ADD],
1093 cx
1094 );
1095 check_bytecode!(bytecode, [1, 2, 3], 6, cx);
1096
1097 make_bytecode!(bytecode, 513, [StackRef1, StackRef1, Plus, Return], [], cx);
1099 check_bytecode!(bytecode, [1, 2], 3, cx);
1100 }
1101
1102 #[test]
1103 fn test_bytecode_variables() {
1104 use OpCode::*;
1105 let roots = &RootSet::default();
1106 let cx = &mut Context::new(roots);
1107 sym::init_symbols();
1108
1109 make_bytecode!(
1111 bytecode,
1112 0,
1113 [Constant1, VarBind0, VarRef0, Unbind1, Return],
1114 [sym::LOAD_PATH, 5],
1115 cx
1116 );
1117 check_bytecode!(bytecode, [], 5, cx);
1118 }
1119
1120 #[test]
1121 fn test_bytecode_advanced() {
1122 use OpCode::*;
1123 let roots = &RootSet::default();
1124 let cx = &mut Context::new(roots);
1125
1126 let mut table = HashTable::default();
1127 table.insert(1.into(), 6.into());
1128 table.insert(2.into(), 8.into());
1129 table.insert(3.into(), 10.into());
1130
1131 make_bytecode!(
1136 bytecode,
1137 257,
1138 [
1139 Duplicate, Constant0, Switch, Goto, 0x0C, 0x00, Constant1, Return, Constant2,
1140 Return, Constant3, Return, Constant4, Return
1141 ],
1142 [table, 4, 5, 6, false],
1143 cx
1144 );
1145 check_bytecode!(bytecode, [1], 4, cx);
1146 check_bytecode!(bytecode, [2], 5, cx);
1147 check_bytecode!(bytecode, [3], 6, cx);
1148 check_bytecode!(bytecode, [4], false, cx);
1149
1150 make_bytecode!(
1152 bytecode,
1153 0,
1154 [Constant0, Constant1, Duplicate, StackRef2, DiscardN, 0x83, Add1, Return],
1155 [1, false],
1156 cx
1157 );
1158 check_bytecode!(bytecode, [], 2, cx);
1159
1160 make_bytecode!(
1162 bytecode,
1163 0,
1164 [
1165 Constant0, Constant1, Constant2, Constant3, Constant4, Constant5, ListN, 6, Return
1166 ],
1167 [1, 2, 3, 4, 5, 6],
1168 cx
1169 );
1170 let list = list![1, 2, 3, 4, 5, 6; cx];
1171 root!(list, cx);
1172 check_bytecode!(bytecode, [], list, cx);
1173
1174 make_bytecode!(
1177 bytecode,
1178 0,
1179 [
1180 Constant6, Constant0, Constant1, Constant2, Constant3, Constant4, Constant5, ListN,
1181 6, DiscardN, 1, Return
1182 ],
1183 [1, 2, 3, 4, 5, 6, 7],
1184 cx
1185 );
1186 check_bytecode!(bytecode, [], 7, cx);
1187 }
1188
1189 #[test]
1190 fn test_handlers() {
1191 use OpCode as O;
1192
1193 let roots = &RootSet::default();
1194 let cx = &mut Context::new(roots);
1195 sym::init_symbols();
1196 let err = Cons::new1(sym::ERROR, cx);
1197
1198 make_bytecode!(
1202 bytecode,
1203 257,
1204 [
1205 O::Constant0,
1206 O::PushCondtionCase,
1207 0x09,
1208 0x0,
1209 O::Constant1,
1210 O::StackRef1,
1211 O::Call1,
1212 O::PopHandler,
1213 O::Return,
1214 O::Discard,
1215 O::Duplicate,
1216 O::Constant2,
1217 O::Plus,
1218 O::Return
1219 ],
1220 [err, sym::SYMBOL_NAME, 4],
1221 cx
1222 );
1223 check_bytecode!(bytecode, [3], 7, cx);
1224 check_bytecode!(bytecode, [sym::FLOOR], "floor", cx);
1225 }
1226
1227 #[test]
1228 fn test_recursive_handlers() {
1229 use OpCode as O;
1230
1231 let roots = &RootSet::default();
1232 let cx = &mut Context::new(roots);
1233 sym::init_symbols();
1234 let err = Cons::new1(sym::ERROR, cx);
1235
1236 make_bytecode!(inner, 0, [O::Constant0, O::Call0, O::Return], [sym::FLOOR], cx);
1239
1240 make_bytecode!(
1245 outer,
1246 257,
1247 [
1248 O::Constant0,
1249 O::PushCondtionCase,
1250 0x08,
1251 0x0,
1252 O::Duplicate,
1253 O::Call0,
1254 O::PopHandler,
1255 O::Return,
1256 O::Discard,
1257 O::Constant1,
1258 O::Return
1259 ],
1260 [err, 7],
1261 cx
1262 );
1263 let inner = cx.add(inner.bind(cx));
1264 root!(inner, cx);
1265 check_bytecode!(outer, [inner], 7, cx);
1266 }
1267}