feat: generalize Stack
This commit is contained in:
@@ -7,18 +7,19 @@ use crate::ty::common::Symbol;
|
||||
use crate::ty::internal::*;
|
||||
use crate::ty::public as p;
|
||||
|
||||
use stack::{STACK_SIZE, Stack};
|
||||
use crate::stack::Stack;
|
||||
|
||||
pub use env::Env;
|
||||
pub use jit::JITContext;
|
||||
|
||||
mod env;
|
||||
mod jit;
|
||||
mod stack;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
||||
|
||||
pub fn run(prog: Program, jit: JITContext<'_>) -> Result<p::Value> {
|
||||
let vm = VM::new(
|
||||
prog.thunks,
|
||||
@@ -57,7 +58,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
||||
}
|
||||
|
||||
pub fn eval(&'vm self, opcodes: OpCodes, env: Rc<Env<'vm>>) -> Result<Value<'vm>> {
|
||||
let mut stack = Stack::<STACK_SIZE>::new();
|
||||
let mut stack = Stack::<_, STACK_SIZE>::new();
|
||||
let mut iter = opcodes.into_iter();
|
||||
while let Some(opcode) = iter.next() {
|
||||
let jmp = self.single_op(opcode, &mut stack, &env)?;
|
||||
@@ -75,7 +76,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
||||
fn single_op<'s, const CAP: usize>(
|
||||
&'vm self,
|
||||
opcode: OpCode,
|
||||
stack: &'s mut Stack<'vm, CAP>,
|
||||
stack: &'s mut Stack<Value<'vm>, CAP>,
|
||||
env: &Rc<Env<'vm>>,
|
||||
) -> Result<usize> {
|
||||
match opcode {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
use std::mem::{MaybeUninit, replace, size_of, transmute};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::ty::internal::Value;
|
||||
|
||||
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
||||
|
||||
pub struct Stack<'vm, const CAP: usize> {
|
||||
// items: Box<[MaybeUninit<Value<'vm>>; CAP]>,
|
||||
items: [MaybeUninit<Value<'vm>>; CAP],
|
||||
top: usize,
|
||||
}
|
||||
|
||||
macro_rules! into {
|
||||
($e:expr) => {
|
||||
// SAFETY: This macro is used to transmute `MaybeUninit<Value<'vm>>` to `Value<'vm>`
|
||||
// or `&MaybeUninit<Value<'vm>>` to `&Value<'vm>`.
|
||||
// This is safe because the `Stack` ensures that only initialized values are accessed
|
||||
// within the `0..top` range.
|
||||
unsafe { transmute($e) }
|
||||
};
|
||||
}
|
||||
|
||||
impl<'vm, const CAP: usize> Stack<'vm, CAP> {
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
items: [const { MaybeUninit::uninit() }; CAP],
|
||||
top: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: Value<'vm>) -> Result<()> {
|
||||
self.items
|
||||
.get_mut(self.top)
|
||||
.map_or_else(
|
||||
|| Err(Error::EvalError("stack overflow".to_string())),
|
||||
|ok| Ok(ok),
|
||||
)?
|
||||
.write(item);
|
||||
self.top += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Value<'vm> {
|
||||
self.top -= 1;
|
||||
let item = self.items.get_mut(self.top).unwrap();
|
||||
|
||||
// SAFETY: `item` at `self.top` was previously written and is initialized.
|
||||
// We replace it with `MaybeUninit::uninit()` and then `assume_init`
|
||||
// on the original value, which is safe as it was initialized.
|
||||
unsafe { replace(item, MaybeUninit::uninit()).assume_init() }
|
||||
}
|
||||
|
||||
pub fn tos(&self) -> Result<&Value<'vm>> {
|
||||
if self.top == 0 {
|
||||
panic!("stack empty")
|
||||
} else {
|
||||
Ok(into!(&self.items[self.top - 1]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tos_mut(&mut self) -> Result<&mut Value<'vm>> {
|
||||
if self.top == 0 {
|
||||
panic!("stack empty")
|
||||
} else {
|
||||
Ok(into!(&mut self.items[self.top - 1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'vm, const CAP: usize> Deref for Stack<'vm, CAP> {
|
||||
type Target = [Value<'vm>];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
into!(&self.items[0..self.top])
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CAP: usize> Drop for Stack<'_, CAP> {
|
||||
fn drop(&mut self) {
|
||||
self.items.as_mut_slice()[0..self.top]
|
||||
.iter_mut()
|
||||
// SAFETY: Items in the range `0..self.top` are guaranteed to be initialized.
|
||||
// `assume_init_drop` is called to correctly drop these initialized `Value`s.
|
||||
.map(|item| unsafe { item.assume_init_drop() })
|
||||
.for_each(drop)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user