optimize: dedup consts

This commit is contained in:
2025-05-15 19:11:34 +08:00
parent 864be73e77
commit 1e50322af0
8 changed files with 51 additions and 31 deletions

View File

@@ -8,10 +8,10 @@ type Slice<T> = Box<[T]>;
pub type OpCodes = Slice<OpCode>;
#[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<Func>,
pub symbols: Vec<EcoString>,
pub symmap: HashMap<EcoString, usize>,
pub consts: Box<[Const]>
}

View File

@@ -1,6 +1,5 @@
use crate::bytecode::*;
use crate::ir;
use crate::ty::internal::Const;
pub struct Compiler {
opcodes: Vec<OpCode>,
@@ -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<T: Compile> 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 });
}
}

View File

@@ -112,7 +112,7 @@ ir! {
With => { namespace: Box<Ir>, expr: Box<Ir> },
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
ConcatStrings => { parts: Vec<Ir> },
Const => { value: i::Const },
Const => { idx: usize },
Var => { sym: usize },
#[derive(Copy)]
Thunk => { idx: usize },
@@ -127,6 +127,7 @@ pub struct DowngradeContext {
thunks: Vec<Ir>,
funcs: Vec<Func>,
consts: Vec<i::Const>,
constmap: HashMap<i::Const, usize>,
symbols: Vec<EcoString>,
symmap: HashMap<EcoString, usize>,
}
@@ -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<EcoString>) -> 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<Ir> {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
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<Ir> {
let attrs = self.expr().unwrap().downgrade(ctx)?;
let path = downgrade_attrpath(self.attrpath().unwrap(), ctx)?;
if let Some(attrs) = Downcast::<Attrs>::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<Attr> {
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::<Result<Vec<_>>>()?;

View File

@@ -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<H: std::hash::Hasher>(&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<bool> for Const {

View File

@@ -89,7 +89,7 @@ impl<'vm> Func<'vm> {
}
}
vm.eval(self.func.opcodes.clone(), env)
vm.eval(self.func.opcodes.iter().copied(), env)
}
}

View File

@@ -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()),

View File

@@ -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<i::Const> for Const {
Int(int) => Const::Int(int),
Float(float) => Const::Float(float),
String(string) => Const::String(string),
Null => Const::Null
}
}
}

View File

@@ -29,10 +29,11 @@ pub fn run(prog: Program, jit: JITContext<'_>) -> Result<p::Value> {
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<Vec<EcoString>>,
symmap: RefCell<HashMap<EcoString, usize>>,
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<Env<'vm>>) -> Result<Value<'vm>> {
pub fn eval(&'vm self, opcodes: impl Iterator<Item = OpCode>, env: Rc<Env<'vm>>) -> Result<Value<'vm>> {
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<usize> {
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))))?
}