From 1e50322af0785bd3d802ff376f5b613c54abf8ff Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Thu, 15 May 2025 19:11:34 +0800 Subject: [PATCH] optimize: dedup consts --- src/bytecode.rs | 5 +++-- src/compile.rs | 6 +++--- src/ir.rs | 40 +++++++++++++++++++--------------------- src/ty/internal/cnst.rs | 16 ++++++++++++++++ src/ty/internal/func.rs | 2 +- src/ty/internal/mod.rs | 2 +- src/ty/public/cnst.rs | 3 +++ src/vm/mod.rs | 8 +++++--- 8 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/bytecode.rs b/src/bytecode.rs index 90e7991..45c1bfe 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -8,10 +8,10 @@ type Slice = Box<[T]>; pub type OpCodes = Slice; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum OpCode { /// load a constant onto stack - Const { value: Const }, + Const { idx: usize }, /// load a dynamic var onto stack LookUp { sym: usize }, /// load a thunk lazily onto stack @@ -114,4 +114,5 @@ pub struct Program { pub funcs: Slice, pub symbols: Vec, pub symmap: HashMap, + pub consts: Box<[Const]> } diff --git a/src/compile.rs b/src/compile.rs index e7afaca..d833972 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,6 +1,5 @@ use crate::bytecode::*; use crate::ir; -use crate::ty::internal::Const; pub struct Compiler { opcodes: Vec, @@ -23,7 +22,8 @@ pub fn compile(downgraded: ir::Downgraded) -> Program { }) .collect(), symbols: downgraded.symbols, - symmap: downgraded.symmap + symmap: downgraded.symmap, + consts: downgraded.consts } } @@ -79,7 +79,7 @@ impl CompileWithLength for T { impl Compile for ir::Const { fn compile(self, comp: &mut Compiler) { - comp.push(OpCode::Const { value: self.value }); + comp.push(OpCode::Const { idx: self.idx }); } } diff --git a/src/ir.rs b/src/ir.rs index 01c1f4e..82f9b52 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -112,7 +112,7 @@ ir! { With => { namespace: Box, expr: Box }, Assert => { assertion: Box, expr: Box }, ConcatStrings => { parts: Vec }, - Const => { value: i::Const }, + Const => { idx: usize }, Var => { sym: usize }, #[derive(Copy)] Thunk => { idx: usize }, @@ -127,6 +127,7 @@ pub struct DowngradeContext { thunks: Vec, funcs: Vec, consts: Vec, + constmap: HashMap, symbols: Vec, symmap: HashMap, } @@ -157,6 +158,16 @@ impl DowngradeContext { LoadFunc { idx } } + fn new_const(&mut self, cnst: i::Const) -> Const { + if let Some(&idx) = self.constmap.get(&cnst) { + Const { idx } + } else { + self.constmap.insert(cnst.clone(), self.consts.len()); + self.consts.push(cnst); + Const { idx: self.consts.len() - 1 } + } + } + fn new_sym(&mut self, sym: impl Into) -> usize { let sym = sym.into(); if let Some(&idx) = self.symmap.get(&sym) { @@ -414,9 +425,7 @@ impl Downgrade for ast::Path { let parts = self .parts() .map(|part| match part { - ast::InterpolPart::Literal(lit) => Const { - value: lit.to_string().into(), - } + ast::InterpolPart::Literal(lit) => ctx.new_const(lit.to_string().into()) .ir() .ok(), ast::InterpolPart::Interpolation(interpol) => { @@ -444,7 +453,7 @@ impl Downgrade for ast::Str { .normalized_parts() .into_iter() .map(|part| match part { - ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), + ast::InterpolPart::Literal(lit) => ctx.new_const(lit.into()).ir().ok(), ast::InterpolPart::Interpolation(interpol) => { interpol.expr().unwrap().downgrade(ctx) } @@ -459,17 +468,11 @@ impl Downgrade for ast::Str { } impl Downgrade for ast::Literal { - fn downgrade(self, _ctx: &mut DowngradeContext) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { match self.kind() { - ast::LiteralKind::Integer(int) => Const { - value: int.value().unwrap().into(), - }, - ast::LiteralKind::Float(float) => Const { - value: float.value().unwrap().into(), - }, - ast::LiteralKind::Uri(uri) => Const { - value: uri.to_string().into(), - }, + ast::LiteralKind::Integer(int) => ctx.new_const(int.value().unwrap().into()), + ast::LiteralKind::Float(float) => ctx.new_const(float.value().unwrap().into()), + ast::LiteralKind::Uri(uri) => ctx.new_const(uri.to_string().into()) } .ir() .ok() @@ -519,11 +522,6 @@ impl Downgrade for ast::HasAttr { fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let attrs = self.expr().unwrap().downgrade(ctx)?; let path = downgrade_attrpath(self.attrpath().unwrap(), ctx)?; - if let Some(attrs) = Downcast::::downcast_ref(&attrs) { - if let Some(res) = attrs.has_attr(&path) { - return Const { value: res.into() }.ir().ok(); - } - } HasAttr { lhs: attrs.boxed(), rhs: path, @@ -730,7 +728,7 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result { let parts = parts .into_iter() .map(|part| match part { - Literal(lit) => Const { value: lit.into() }.ir().ok(), + Literal(lit) => ctx.new_const(lit.into()).ir().ok(), Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx), }) .collect::>>()?; diff --git a/src/ty/internal/cnst.rs b/src/ty/internal/cnst.rs index 7ee884f..e47b183 100644 --- a/src/ty/internal/cnst.rs +++ b/src/ty/internal/cnst.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; + use derive_more::{IsVariant, Unwrap}; use ecow::EcoString; @@ -7,6 +9,20 @@ pub enum Const { Int(i64), Float(f64), String(EcoString), + Null +} + +impl Hash for Const { + fn hash(&self, state: &mut H) { + use Const::*; + match self { + Int(x) => x.hash(state), + Float(x) => x.to_bits().hash(state), + Bool(x) => x.hash(state), + String(x) => x.hash(state), + x @ Null => x.hash(state), + } + } } impl From for Const { diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index f5578be..0910268 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -89,7 +89,7 @@ impl<'vm> Func<'vm> { } } - vm.eval(self.func.opcodes.clone(), env) + vm.eval(self.func.opcodes.iter().copied(), env) } } diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index 8b8beb3..ffc5093 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -458,7 +458,7 @@ impl<'vm> Thunk<'vm> { _Thunk::SuspendedFrom(self as *const Thunk), ) .unwrap_code(); - let value = vm.eval(opcodes.clone(), env.get().unwrap().clone())?; + let value = vm.eval(opcodes.iter().copied(), env.get().unwrap().clone())?; let _ = std::mem::replace( &mut *self.thunk.borrow_mut(), _Thunk::Value(value.clone().into()), diff --git a/src/ty/public/cnst.rs b/src/ty/public/cnst.rs index 3b9c69e..f376b00 100644 --- a/src/ty/public/cnst.rs +++ b/src/ty/public/cnst.rs @@ -13,6 +13,7 @@ pub enum Const { Int(i64), Float(f64), String(EcoString), + Null } impl Display for Const { @@ -23,6 +24,7 @@ impl Display for Const { Int(i) => write!(f, "{i}"), Float(float) => write!(f, "{float}"), String(s) => write!(f, "{s}"), + Null => write!(f, "null") } } } @@ -35,6 +37,7 @@ impl From for Const { Int(int) => Const::Int(int), Float(float) => Const::Float(float), String(string) => Const::String(string), + Null => Const::Null } } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 9db67d1..4174956 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -29,10 +29,11 @@ pub fn run(prog: Program, jit: JITContext<'_>) -> Result { prog.funcs, RefCell::new(prog.symbols), RefCell::new(prog.symmap), + prog.consts, jit ); let env = env(&vm); - let temp = vm.eval(prog.top_level, env)?; + let temp = vm.eval(prog.top_level.into_iter(), env)?; let temp = temp.to_public(&vm); Ok(temp) } @@ -43,6 +44,7 @@ pub struct VM<'jit> { funcs: Box<[F]>, symbols: RefCell>, symmap: RefCell>, + consts: Box<[Const]>, jit: JITContext<'jit>, } @@ -70,7 +72,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { } } - pub fn eval(&'vm self, opcodes: OpCodes, env: Rc>) -> Result> { + pub fn eval(&'vm self, opcodes: impl Iterator, env: Rc>) -> Result> { let mut stack = Stack::<_, STACK_SIZE>::new(); let mut iter = opcodes.into_iter(); while let Some(opcode) = iter.next() { @@ -94,7 +96,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { ) -> Result { match opcode { OpCode::Illegal => panic!("illegal opcode"), - OpCode::Const { value } => stack.push(Value::Const(value))?, + OpCode::Const { idx } => stack.push(Value::Const(self.consts[idx].clone()))?, OpCode::LoadThunk { idx } => { stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx))))? }