feat: less clone on symbol

This commit is contained in:
2025-05-15 18:19:16 +08:00
parent 3e7a8a1c05
commit 864be73e77
12 changed files with 195 additions and 183 deletions

View File

@@ -1,14 +1,17 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use crate::builtins::env;
use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp, Func as F};
use crate::error::*;
use crate::ty::common::Symbol;
use crate::ty::internal::*;
use crate::ty::public as p;
use crate::ty::public::{self as p, Symbol};
use crate::stack::Stack;
use derive_more::Constructor;
use ecow::EcoString;
pub use env::Env;
pub use jit::JITContext;
@@ -24,37 +27,47 @@ pub fn run(prog: Program, jit: JITContext<'_>) -> Result<p::Value> {
let vm = VM::new(
prog.thunks,
prog.funcs,
RefCell::new(prog.symbols),
RefCell::new(prog.symmap),
jit
);
let env = env();
let env = env(&vm);
let temp = vm.eval(prog.top_level, env)?;
let temp = temp.to_public(&vm);
Ok(temp)
}
#[derive(Constructor)]
pub struct VM<'jit> {
thunks: Box<[OpCodes]>,
funcs: Box<[F]>,
symbols: RefCell<Vec<EcoString>>,
symmap: RefCell<HashMap<EcoString, usize>>,
jit: JITContext<'jit>,
}
impl<'vm, 'jit: 'vm> VM<'jit> {
fn new(thunks: Box<[OpCodes]>, funcs: Box<[F]>, jit: JITContext<'jit>) -> Self {
VM { thunks, funcs, jit }
}
pub fn get_thunk(&self, idx: usize) -> &OpCodes {
// SAFETY: The `idx` is within bounds as `thunks` is initialized with `prog.thunks`
// and `idx` is expected to be a valid index into this collection.
// The lifetime of the returned reference is tied to `&self`.
unsafe { &*(&self.thunks[idx] as *const _) }
&self.thunks[idx]
}
pub fn get_func(&self, idx: usize) -> &F {
// SAFETY: The `idx` is within bounds as `funcs` is initialized with `prog.funcs`
// and `idx` is expected to be a valid index into this collection.
// The lifetime of the returned reference is tied to `&self`.
unsafe { &*(&self.funcs[idx] as *const _) }
&self.funcs[idx]
}
pub fn get_sym(&self, idx: usize) -> Symbol{
self.symbols.borrow()[idx].clone().into()
}
pub fn new_sym(&self, sym: impl Into<EcoString>) -> usize {
let sym = sym.into();
if let Some(&idx) = self.symmap.borrow().get(&sym) {
idx
} else {
self.symmap.borrow_mut().insert(sym.clone(), self.symbols.borrow().len());
self.symbols.borrow_mut().push(sym);
self.symbols.borrow().len() - 1
}
}
pub fn eval(&'vm self, opcodes: OpCodes, env: Rc<Env<'vm>>) -> Result<Value<'vm>> {
@@ -123,6 +136,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
let mut value = stack.pop();
value.force(self)?;
stack.push(match op {
Neg => value.neg(),
Not => value.not(),
})?;
}
@@ -134,9 +148,13 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
rhs.force(self)?;
stack.push(match op {
Add => lhs.add(rhs),
Sub => lhs.add(rhs.neg()),
Mul => lhs.mul(rhs),
Div => lhs.div(rhs),
And => lhs.and(rhs),
Or => lhs.or(rhs),
Eq => lhs.eq(rhs),
Lt => lhs.lt(rhs),
Con => lhs.concat(rhs),
Upd => lhs.update(rhs),
})?;
@@ -169,57 +187,56 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
}
OpCode::PushStaticAttr { name } => {
let val = stack.pop();
stack.tos_mut()?.push_attr(Symbol::new(name.clone()), val);
stack.tos_mut()?.push_attr(name, val);
}
OpCode::PushDynamicAttr => {
let val = stack.pop();
let mut sym = stack.pop();
sym.force(self)?.coerce_to_string();
let sym = sym.unwrap_const().unwrap_string().into();
let sym = self.new_sym(sym.unwrap_const().unwrap_string());
stack.tos_mut()?.push_attr(sym, val);
}
OpCode::Select { sym } => {
stack.tos_mut()?.force(self)?.select(&Symbol::new(sym))?;
stack.tos_mut()?.force(self)?.select(sym)?;
}
OpCode::SelectOrDefault { sym } => {
let default = stack.pop();
stack
.tos_mut()?
.force(self)?
.select_with_default(&Symbol::new(sym), default)?;
.select_with_default(sym, default)?;
}
OpCode::SelectDynamic => {
let mut val = stack.pop();
val.force(self)?;
val.coerce_to_string();
let sym = val.unwrap_const().unwrap_string().into();
stack.tos_mut()?.force(self)?.select(&sym)?;
let sym = self.new_sym(val.unwrap_const().unwrap_string());
stack.tos_mut()?.force(self)?.select(sym)?;
}
OpCode::SelectDynamicOrDefault => {
let default = stack.pop();
let mut val = stack.pop();
val.force(self)?;
val.coerce_to_string();
let sym = val.unwrap_const().unwrap_string().into();
let sym = self.new_sym(val.unwrap_const().unwrap_string());
stack
.tos_mut()?
.force(self)?
.select_with_default(&sym, default)?;
.select_with_default(sym, default)?;
}
OpCode::HasAttr { sym } => {
stack.tos_mut()?.force(self)?.has_attr(&Symbol::new(sym));
stack.tos_mut()?.force(self)?.has_attr(sym);
}
OpCode::HasDynamicAttr => {
let mut val = stack.pop();
val.coerce_to_string();
let sym = val.unwrap_const().unwrap_string().into();
stack.tos_mut()?.force(self)?.has_attr(&sym);
let sym = self.new_sym(val.unwrap_const().unwrap_string());
stack.tos_mut()?.force(self)?.has_attr(sym);
}
OpCode::LookUp { sym } => {
let sym = Symbol::new(sym);
stack.push(
env.lookup(&sym)
.ok_or_else(|| Error::EvalError(format!(r#""{sym}" not found"#)))?,
env.lookup(sym)
.ok_or_else(|| Error::EvalError(format!("{} not found", self.get_sym(sym))))?,
)?;
}
OpCode::EnterEnv => match stack.pop() {