optimize: dedup consts
This commit is contained in:
@@ -8,10 +8,10 @@ type Slice<T> = Box<[T]>;
|
|||||||
|
|
||||||
pub type OpCodes = Slice<OpCode>;
|
pub type OpCodes = Slice<OpCode>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
/// load a constant onto stack
|
/// load a constant onto stack
|
||||||
Const { value: Const },
|
Const { idx: usize },
|
||||||
/// load a dynamic var onto stack
|
/// load a dynamic var onto stack
|
||||||
LookUp { sym: usize },
|
LookUp { sym: usize },
|
||||||
/// load a thunk lazily onto stack
|
/// load a thunk lazily onto stack
|
||||||
@@ -114,4 +114,5 @@ pub struct Program {
|
|||||||
pub funcs: Slice<Func>,
|
pub funcs: Slice<Func>,
|
||||||
pub symbols: Vec<EcoString>,
|
pub symbols: Vec<EcoString>,
|
||||||
pub symmap: HashMap<EcoString, usize>,
|
pub symmap: HashMap<EcoString, usize>,
|
||||||
|
pub consts: Box<[Const]>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::bytecode::*;
|
use crate::bytecode::*;
|
||||||
use crate::ir;
|
use crate::ir;
|
||||||
use crate::ty::internal::Const;
|
|
||||||
|
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
opcodes: Vec<OpCode>,
|
opcodes: Vec<OpCode>,
|
||||||
@@ -23,7 +22,8 @@ pub fn compile(downgraded: ir::Downgraded) -> Program {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
symbols: downgraded.symbols,
|
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 {
|
impl Compile for ir::Const {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
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> },
|
With => { namespace: Box<Ir>, expr: Box<Ir> },
|
||||||
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
||||||
ConcatStrings => { parts: Vec<Ir> },
|
ConcatStrings => { parts: Vec<Ir> },
|
||||||
Const => { value: i::Const },
|
Const => { idx: usize },
|
||||||
Var => { sym: usize },
|
Var => { sym: usize },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Thunk => { idx: usize },
|
Thunk => { idx: usize },
|
||||||
@@ -127,6 +127,7 @@ pub struct DowngradeContext {
|
|||||||
thunks: Vec<Ir>,
|
thunks: Vec<Ir>,
|
||||||
funcs: Vec<Func>,
|
funcs: Vec<Func>,
|
||||||
consts: Vec<i::Const>,
|
consts: Vec<i::Const>,
|
||||||
|
constmap: HashMap<i::Const, usize>,
|
||||||
symbols: Vec<EcoString>,
|
symbols: Vec<EcoString>,
|
||||||
symmap: HashMap<EcoString, usize>,
|
symmap: HashMap<EcoString, usize>,
|
||||||
}
|
}
|
||||||
@@ -157,6 +158,16 @@ impl DowngradeContext {
|
|||||||
LoadFunc { idx }
|
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 {
|
fn new_sym(&mut self, sym: impl Into<EcoString>) -> usize {
|
||||||
let sym = sym.into();
|
let sym = sym.into();
|
||||||
if let Some(&idx) = self.symmap.get(&sym) {
|
if let Some(&idx) = self.symmap.get(&sym) {
|
||||||
@@ -414,9 +425,7 @@ impl Downgrade for ast::Path {
|
|||||||
let parts = self
|
let parts = self
|
||||||
.parts()
|
.parts()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => Const {
|
ast::InterpolPart::Literal(lit) => ctx.new_const(lit.to_string().into())
|
||||||
value: lit.to_string().into(),
|
|
||||||
}
|
|
||||||
.ir()
|
.ir()
|
||||||
.ok(),
|
.ok(),
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
@@ -444,7 +453,7 @@ impl Downgrade for ast::Str {
|
|||||||
.normalized_parts()
|
.normalized_parts()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.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) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
interpol.expr().unwrap().downgrade(ctx)
|
interpol.expr().unwrap().downgrade(ctx)
|
||||||
}
|
}
|
||||||
@@ -459,17 +468,11 @@ impl Downgrade for ast::Str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Downgrade for ast::Literal {
|
impl Downgrade for ast::Literal {
|
||||||
fn downgrade(self, _ctx: &mut DowngradeContext) -> Result<Ir> {
|
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
ast::LiteralKind::Integer(int) => Const {
|
ast::LiteralKind::Integer(int) => ctx.new_const(int.value().unwrap().into()),
|
||||||
value: 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())
|
||||||
ast::LiteralKind::Float(float) => Const {
|
|
||||||
value: float.value().unwrap().into(),
|
|
||||||
},
|
|
||||||
ast::LiteralKind::Uri(uri) => Const {
|
|
||||||
value: uri.to_string().into(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
.ok()
|
.ok()
|
||||||
@@ -519,11 +522,6 @@ impl Downgrade for ast::HasAttr {
|
|||||||
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
|
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
|
||||||
let attrs = self.expr().unwrap().downgrade(ctx)?;
|
let attrs = self.expr().unwrap().downgrade(ctx)?;
|
||||||
let path = downgrade_attrpath(self.attrpath().unwrap(), 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 {
|
HasAttr {
|
||||||
lhs: attrs.boxed(),
|
lhs: attrs.boxed(),
|
||||||
rhs: path,
|
rhs: path,
|
||||||
@@ -730,7 +728,7 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Attr> {
|
|||||||
let parts = parts
|
let parts = parts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.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),
|
Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx),
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
@@ -7,6 +9,20 @@ pub enum Const {
|
|||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
String(EcoString),
|
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 {
|
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),
|
_Thunk::SuspendedFrom(self as *const Thunk),
|
||||||
)
|
)
|
||||||
.unwrap_code();
|
.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(
|
let _ = std::mem::replace(
|
||||||
&mut *self.thunk.borrow_mut(),
|
&mut *self.thunk.borrow_mut(),
|
||||||
_Thunk::Value(value.clone().into()),
|
_Thunk::Value(value.clone().into()),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ pub enum Const {
|
|||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
String(EcoString),
|
String(EcoString),
|
||||||
|
Null
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Const {
|
impl Display for Const {
|
||||||
@@ -23,6 +24,7 @@ impl Display for Const {
|
|||||||
Int(i) => write!(f, "{i}"),
|
Int(i) => write!(f, "{i}"),
|
||||||
Float(float) => write!(f, "{float}"),
|
Float(float) => write!(f, "{float}"),
|
||||||
String(s) => write!(f, "{s}"),
|
String(s) => write!(f, "{s}"),
|
||||||
|
Null => write!(f, "null")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,6 +37,7 @@ impl From<i::Const> for Const {
|
|||||||
Int(int) => Const::Int(int),
|
Int(int) => Const::Int(int),
|
||||||
Float(float) => Const::Float(float),
|
Float(float) => Const::Float(float),
|
||||||
String(string) => Const::String(string),
|
String(string) => Const::String(string),
|
||||||
|
Null => Const::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,11 @@ pub fn run(prog: Program, jit: JITContext<'_>) -> Result<p::Value> {
|
|||||||
prog.funcs,
|
prog.funcs,
|
||||||
RefCell::new(prog.symbols),
|
RefCell::new(prog.symbols),
|
||||||
RefCell::new(prog.symmap),
|
RefCell::new(prog.symmap),
|
||||||
|
prog.consts,
|
||||||
jit
|
jit
|
||||||
);
|
);
|
||||||
let env = env(&vm);
|
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);
|
let temp = temp.to_public(&vm);
|
||||||
Ok(temp)
|
Ok(temp)
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,7 @@ pub struct VM<'jit> {
|
|||||||
funcs: Box<[F]>,
|
funcs: Box<[F]>,
|
||||||
symbols: RefCell<Vec<EcoString>>,
|
symbols: RefCell<Vec<EcoString>>,
|
||||||
symmap: RefCell<HashMap<EcoString, usize>>,
|
symmap: RefCell<HashMap<EcoString, usize>>,
|
||||||
|
consts: Box<[Const]>,
|
||||||
jit: JITContext<'jit>,
|
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 stack = Stack::<_, STACK_SIZE>::new();
|
||||||
let mut iter = opcodes.into_iter();
|
let mut iter = opcodes.into_iter();
|
||||||
while let Some(opcode) = iter.next() {
|
while let Some(opcode) = iter.next() {
|
||||||
@@ -94,7 +96,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
|||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
match opcode {
|
match opcode {
|
||||||
OpCode::Illegal => panic!("illegal 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 } => {
|
OpCode::LoadThunk { idx } => {
|
||||||
stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx))))?
|
stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx))))?
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user