optimize: dedup consts
This commit is contained in:
@@ -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]>
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
src/ir.rs
40
src/ir.rs
@@ -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<_>>>()?;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -89,7 +89,7 @@ impl<'vm> Func<'vm> {
|
||||
}
|
||||
}
|
||||
|
||||
vm.eval(self.func.opcodes.clone(), env)
|
||||
vm.eval(self.func.opcodes.iter().copied(), env)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))))?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user