avoid thunking trivial values
This commit is contained in:
+60
-42
@@ -8,7 +8,10 @@ use fix_codegen::{BytecodeContext, InstructionPtr, Op};
|
||||
use fix_common::{StringId, Symbol};
|
||||
use fix_error::{Error, Result, Source};
|
||||
use fix_ir::downgrade::{Downgrade as _, DowngradeContext};
|
||||
use fix_ir::{GhostMaybeThunkRef, GhostRef, Ir, IrRef, MaybeThunk, RawIrRef, RawRef, ThunkId};
|
||||
use fix_ir::{
|
||||
GhostMaybeThunkRef, GhostRoIrRef, GhostRoMaybeThunkRef, GhostRoRef, Ir, MaybeThunk, RawIrRef,
|
||||
ThunkId,
|
||||
};
|
||||
use fix_vm::{ForceMode, StaticValue, Vm, VmCode, VmContext, VmRuntimeCtx};
|
||||
use ghost_cell::{GhostCell, GhostToken};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
@@ -30,7 +33,7 @@ pub struct CodeState {
|
||||
pub sources: Vec<Source>,
|
||||
pub spans: Vec<(usize, rnix::TextRange)>,
|
||||
pub thunk_count: usize,
|
||||
pub global_env: HashMap<StringId, Ir<'static, RawRef<'static>>>,
|
||||
pub global_env: HashMap<StringId, MaybeThunk>,
|
||||
}
|
||||
|
||||
pub struct Evaluator {
|
||||
@@ -323,7 +326,7 @@ impl<'ctx, 'id, 'ir, R: VmRuntimeCtx> DowngradeCtx<'ctx, 'id, 'ir, R> {
|
||||
bump: &'ir Bump,
|
||||
token: GhostToken<'id>,
|
||||
runtime: &'ctx mut R,
|
||||
global: &'ctx HashMap<StringId, Ir<'static, RawRef<'static>>>,
|
||||
global: &'ctx HashMap<StringId, MaybeThunk>,
|
||||
extra_scope: Option<Scope<'ctx, 'id, 'ir>>,
|
||||
thunk_count: &'ctx mut usize,
|
||||
source: Source,
|
||||
@@ -347,11 +350,11 @@ impl<'ctx, 'id, 'ir, R: VmRuntimeCtx> DowngradeCtx<'ctx, 'id, 'ir, R> {
|
||||
impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
for DowngradeCtx<'ctx, 'id, 'ir, R>
|
||||
{
|
||||
fn new_expr(&self, expr: Ir<'ir, GhostRef<'id, 'ir>>) -> IrRef<'id, 'ir> {
|
||||
self.bump.alloc(GhostCell::new(expr))
|
||||
fn new_expr(&self, expr: Ir<'ir, GhostRoRef<'id, 'ir>>) -> GhostRoIrRef<'id, 'ir> {
|
||||
self.bump.alloc(GhostCell::new(expr).into())
|
||||
}
|
||||
|
||||
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> GhostMaybeThunkRef<'id, 'ir> {
|
||||
fn maybe_thunk(&mut self, ir: GhostRoIrRef<'id, 'ir>) -> GhostRoMaybeThunkRef<'id, 'ir> {
|
||||
use MaybeThunk::*;
|
||||
let expr = (|| {
|
||||
let expr = match *ir.borrow(&self.token) {
|
||||
@@ -366,7 +369,7 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
Ir::MaybeThunk(thunk) => return Some(thunk),
|
||||
_ => return None,
|
||||
};
|
||||
Some(self.bump.alloc(GhostCell::new(expr)))
|
||||
Some(self.bump.alloc(GhostCell::new(expr).into()))
|
||||
})();
|
||||
if let Some(thunk) = expr {
|
||||
return thunk;
|
||||
@@ -376,8 +379,8 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
self.thunk_scopes
|
||||
.last_mut()
|
||||
.expect("no active cache scope")
|
||||
.add_binding(id, ir, &self.token);
|
||||
self.bump.alloc(GhostCell::new(Thunk(id)))
|
||||
.add_binding(id, ir);
|
||||
self.bump.alloc(GhostCell::new(Thunk(id)).into())
|
||||
}
|
||||
|
||||
fn intern_string(&mut self, sym: impl AsRef<str>) -> StringId {
|
||||
@@ -388,39 +391,35 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
self.runtime.resolve_string(id).into()
|
||||
}
|
||||
|
||||
fn lookup(&self, sym: StringId, span: rnix::TextRange) -> Result<GhostMaybeThunkRef<'id, 'ir>> {
|
||||
fn lookup(
|
||||
&self,
|
||||
sym: StringId,
|
||||
span: rnix::TextRange,
|
||||
) -> Result<GhostRoMaybeThunkRef<'id, 'ir>> {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
&Scope::Global(global_scope) => {
|
||||
use MaybeThunk::*;
|
||||
if let Some(expr) = global_scope.get(&sym) {
|
||||
let val = match expr {
|
||||
Ir::Builtins => Builtins,
|
||||
Ir::Builtin(s) => Builtin(*s),
|
||||
Ir::Bool(b) => Bool(*b),
|
||||
Ir::Null => Null,
|
||||
_ => unreachable!("globals should only contain leaf IR nodes"),
|
||||
};
|
||||
return Ok(self.bump.alloc(GhostCell::new(val)));
|
||||
return Ok(expr.into());
|
||||
}
|
||||
}
|
||||
&Scope::Repl(repl_bindings) => {
|
||||
if repl_bindings.contains(&sym) {
|
||||
return Ok(self
|
||||
.bump
|
||||
.alloc(GhostCell::new(MaybeThunk::ReplBinding(sym))));
|
||||
.alloc(GhostCell::new(MaybeThunk::ReplBinding(sym)).into()));
|
||||
}
|
||||
}
|
||||
Scope::ScopedImport(scoped_bindings) => {
|
||||
if scoped_bindings.contains(&sym) {
|
||||
return Ok(self
|
||||
.bump
|
||||
.alloc(GhostCell::new(MaybeThunk::ScopedImportBinding(sym))));
|
||||
.alloc(GhostCell::new(MaybeThunk::ScopedImportBinding(sym)).into()));
|
||||
}
|
||||
}
|
||||
Scope::Let(let_scope) => {
|
||||
if let Some(&expr) = let_scope.get(&sym) {
|
||||
return Ok(expr);
|
||||
return Ok(expr.into());
|
||||
}
|
||||
}
|
||||
&Scope::Param {
|
||||
@@ -431,14 +430,18 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
let layers: u8 =
|
||||
self.thunk_scopes.len().try_into().expect("scope too deep!");
|
||||
let layer = layers - abs_layer;
|
||||
return Ok(self.bump.alloc(GhostCell::new(MaybeThunk::Arg { layer })));
|
||||
return Ok(self
|
||||
.bump
|
||||
.alloc(GhostCell::new(MaybeThunk::Arg { layer }).into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.with_scope_count > 0 {
|
||||
Ok(self.bump.alloc(GhostCell::new(MaybeThunk::WithLookup(sym))))
|
||||
Ok(self
|
||||
.bump
|
||||
.alloc(GhostCell::new(MaybeThunk::WithLookup(sym)).into()))
|
||||
} else {
|
||||
Err(Error::downgrade_error(
|
||||
format!("'{}' not found", self.resolve_sym(sym)),
|
||||
@@ -454,28 +457,40 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
|
||||
fn with_let_scope<F, Ret>(&mut self, keys: &[StringId], f: F) -> Result<Ret>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Result<(bumpalo::collections::Vec<'ir, IrRef<'id, 'ir>>, Ret)>,
|
||||
F: FnOnce(
|
||||
&mut Self,
|
||||
) -> Result<(
|
||||
bumpalo::collections::Vec<'ir, GhostRoMaybeThunkRef<'id, 'ir>>,
|
||||
Ret,
|
||||
)>,
|
||||
{
|
||||
let base = *self.thunk_count;
|
||||
*self.thunk_count = self
|
||||
.thunk_count
|
||||
.checked_add(keys.len())
|
||||
.expect("thunk id overflow");
|
||||
let scope = {
|
||||
let mut scope = HashMap::new();
|
||||
for (offset, &key) in keys.iter().enumerate() {
|
||||
scope.insert(key, &*self.bump.alloc(GhostCell::new(MaybeThunk::Thunk(ThunkId(base + offset)))));
|
||||
}
|
||||
scope
|
||||
};
|
||||
let handles = (base..base + keys.len())
|
||||
.map(|id| {
|
||||
&*self
|
||||
.bump
|
||||
.alloc(GhostCell::new(MaybeThunk::Thunk(ThunkId(id))))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let scope = keys.iter().copied().zip(handles.iter().copied()).collect();
|
||||
self.scopes.push(Scope::Let(scope));
|
||||
let (vals, ret) = {
|
||||
let mut guard = ScopeGuard { ctx: self };
|
||||
f(guard.as_ctx())?
|
||||
};
|
||||
let (vals, ret) = { f(self)? };
|
||||
self.scopes.pop();
|
||||
assert_eq!(keys.len(), vals.len());
|
||||
let scope = self.thunk_scopes.last_mut().expect("no active thunk scope");
|
||||
scope.extend_bindings((base..base + keys.len()).map(ThunkId).zip(vals));
|
||||
for (i, (val, handle)) in vals.into_iter().zip(handles).enumerate() {
|
||||
let thunk = *val.borrow(&self.token);
|
||||
*handle.borrow_mut(&mut self.token) = thunk;
|
||||
let id = ThunkId(base + i);
|
||||
let ir_ref = self
|
||||
.bump
|
||||
.alloc(GhostCell::new(Ir::MaybeThunk(handle.into())).into());
|
||||
scope.add_binding(id, ir_ref);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -506,7 +521,7 @@ impl<'ctx: 'ir, 'id, 'ir, R: VmRuntimeCtx> DowngradeContext<'id, 'ir>
|
||||
f: F,
|
||||
) -> (
|
||||
Ret,
|
||||
bumpalo::collections::Vec<'ir, (ThunkId, IrRef<'id, 'ir>)>,
|
||||
bumpalo::collections::Vec<'ir, (ThunkId, GhostRoIrRef<'id, 'ir>)>,
|
||||
)
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Ret,
|
||||
@@ -546,7 +561,7 @@ impl<'id, 'ir, 'ctx: 'ir, R: VmRuntimeCtx> DowngradeCtx<'ctx, 'id, 'ir, R> {
|
||||
}
|
||||
|
||||
struct ThunkScope<'id, 'ir> {
|
||||
bindings: bumpalo::collections::Vec<'ir, (ThunkId, IrRef<'id, 'ir>)>,
|
||||
bindings: bumpalo::collections::Vec<'ir, (ThunkId, GhostRoIrRef<'id, 'ir>)>,
|
||||
}
|
||||
|
||||
impl<'id, 'ir> ThunkScope<'id, 'ir> {
|
||||
@@ -556,17 +571,20 @@ impl<'id, 'ir> ThunkScope<'id, 'ir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_binding(&mut self, id: ThunkId, ir: IrRef<'id, 'ir>, _token: &GhostToken<'id>) {
|
||||
fn add_binding(&mut self, id: ThunkId, ir: GhostRoIrRef<'id, 'ir>) {
|
||||
self.bindings.push((id, ir));
|
||||
}
|
||||
|
||||
fn extend_bindings(&mut self, iter: impl IntoIterator<Item = (ThunkId, IrRef<'id, 'ir>)>) {
|
||||
fn extend_bindings(
|
||||
&mut self,
|
||||
iter: impl IntoIterator<Item = (ThunkId, GhostRoIrRef<'id, 'ir>)>,
|
||||
) {
|
||||
self.bindings.extend(iter);
|
||||
}
|
||||
}
|
||||
|
||||
enum Scope<'ctx, 'id, 'ir> {
|
||||
Global(&'ctx HashMap<StringId, Ir<'static, RawRef<'static>>>),
|
||||
Global(&'ctx HashMap<StringId, MaybeThunk>),
|
||||
Repl(&'ctx HashSet<StringId>),
|
||||
ScopedImport(HashSet<StringId>),
|
||||
Let(HashMap<StringId, GhostMaybeThunkRef<'id, 'ir>>),
|
||||
|
||||
Reference in New Issue
Block a user