diff --git a/src/bytecode.rs b/src/bytecode.rs index 52a07ae..531eb0b 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -20,10 +20,14 @@ //! to the length before the call. This means the interpreter has to do some bookkeeping, but it has //! to do that anyways. //! +//! It is the compilers job to generate the correct loading of the arguments and assure that the aritiy +//! is correct before the `Call` instruction. +//! +//! //! # ABI //! Function arguments are passed on the stack and can be loaded just like local variables. They belong //! to the stack frame of the new function and are cleaned up after returning, leaving the return value where -//! the stack frame was. +//! the stack frame was //! //! When a call happens, the current stack offset is pushed onto the stack as a `Value::Native` and //! the element before it is stored as the new offset. @@ -37,14 +41,14 @@ //! returned value. //! //! ```text -//! old stack offset ╮ ╭ Parameters ╮ ╭ local -//! v v v v -//! ───────┬────────────┬───────────┬──────────┬─────────╮ -//! Num(6) │ Native(20) │ Num(5) │ Num(6) │ Num(5) │ -//! ───────┴────────────┴───────────┴──────────┴─────────╯ -//! ╰────────────────────────────────────────────────── current stack frame -//! ^ ^ -//! ╰─ old local ╰╮ +//! old stack offset ╮ old *mut FnBlock ╮ ╭ Parameters ╮ ╭ local +//! v v v v v +//! ───────┬─────────────┬────────────┬──────────┬─────────┬──────────┬─────────╮ +//! Num(6) │ NativeU(20) │ NativeU(4) │ Ptr │ Num(5) │ Num(6) │ Num(5) │ +//! ───────┴─────────────┴────────────┴──────────┴─────────┴──────────┴─────────╯ +//! ^ ╰──────────────────────────────────────────────────────────────────── current stack frame +//! │ ^ ^ +//! ╰─ old local ╰╮ ╰─ old PC //! │ //! │ //! Vm │ diff --git a/src/compile.rs b/src/compile.rs index af2b5e4..0e6fce5 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -152,7 +152,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> { Ok(()) } - fn compile_fn_decl(&mut self, _: &FnDecl) -> CResult { + fn compile_fn_decl(&mut self, decl: &FnDecl) -> CResult { todo!() } @@ -415,13 +415,13 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> { block.stack_sizes.last().copied().unwrap_or(0) } - fn change_instr(&mut self, index: usize, instr: Instr) { + fn change_instr(&mut self, index: usize, instr: Instr<'bc>) { let block = &mut self.blocks[self.current_block]; block.code[index] = instr; } /// Pushes an instruction and returns the index of the new instruction - fn push_instr(&mut self, instr: Instr, stack_change: StackChange, span: Span) -> usize { + fn push_instr(&mut self, instr: Instr<'bc>, stack_change: StackChange, span: Span) -> usize { let block = &mut self.blocks[self.current_block]; let stack_top = block.stack_sizes.last().copied().unwrap_or(0); let new_stack_top = stack_top as isize + stack_change.as_isize(); diff --git a/src/vm.rs b/src/vm.rs index 93df565..220b22e 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -3,6 +3,7 @@ use crate::gc::{Object, RtAlloc, Symbol}; use crate::Config; use std::fmt::{Debug, Display, Formatter}; use std::io::{Read, Write}; +use std::ptr::NonNull; type VmError = &'static str; type VmResult = Result<(), VmError>; @@ -13,7 +14,6 @@ pub fn execute<'bc>( cfg: &mut Config, ) -> Result<(), VmError> { let mut vm = Vm { - _blocks: bytecode, current: bytecode.first().ok_or("no bytecode found")?, pc: 0, stack: Vec::with_capacity(1024 << 5), @@ -40,10 +40,15 @@ pub enum Value { Array, /// A map from string to value Object(Object), - /// A value that is stored by the vm for bookkeeping and should never be accessed for anythign else - Native(usize), + /// A value that is stored by the vm for bookkeeping and should never be accessed for anything else + NativeU(usize), + /// A function + Fn(Ptr), } +#[derive(Debug, Clone, Copy)] +pub struct Ptr(NonNull<()>); + const _: () = _check_val_size(); const fn _check_val_size() { if std::mem::size_of::() != 24 { @@ -55,14 +60,16 @@ const TRUE: Value = Value::Bool(true); const FALSE: Value = Value::Bool(false); struct Vm<'bc, 'io> { - _blocks: &'bc [FnBlock<'bc>], - current: &'bc FnBlock<'bc>, + // -- global _alloc: RtAlloc, - /// Index of the instruction currently being executed - pc: usize, stack: Vec, stdout: &'io mut dyn Write, step: bool, + + // -- local to the current function + current: &'bc FnBlock<'bc>, + /// Index of the instruction currently being executed + pc: usize, } impl<'bc> Vm<'bc, '_> { @@ -179,6 +186,7 @@ impl<'bc> Vm<'bc, '_> { } Instr::Jmp(pos) => self.pc = (self.pc as isize + pos) as usize, Instr::Call(_) => todo!(), + Instr::Return => todo!(), Instr::ShrinkStack(size) => { assert!(self.stack.len() >= size); let new_len = self.stack.len() - size; @@ -232,7 +240,15 @@ impl Display for Value { Value::String(str) => f.write_str(str.as_str()), Value::Array => todo!(), Value::Object(_) => todo!(), - Value::Native(_) => panic!("Called display on native value!"), + Value::NativeU(_) => panic!("Called display on native value!"), + Value::Fn(_) => f.write_str("[function]"), } } } + +#[cfg(feature = "pretty")] +impl debug2::Debug for Ptr { + fn fmt(&self, f: &mut debug2::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Ptr").finish() + } +}