diff --git a/fix/src/codegen.rs b/fix/src/codegen.rs index 9a63893..7068017 100644 --- a/fix/src/codegen.rs +++ b/fix/src/codegen.rs @@ -6,7 +6,7 @@ use num_enum::TryFromPrimitive; use rnix::TextRange; use string_interner::Symbol as _; -use crate::ir::{ArgId, Attr, BinOpKind, Ir, Param, RawIrRef, StringId, ThunkId, UnOpKind}; +use crate::ir::{Attr, BinOpKind, Ir, Param, RawIrRef, StringId, ThunkId, UnOpKind}; use crate::runtime::BUILTINS; use crate::runtime::value::{Null, PrimOp, StaticValue}; @@ -28,7 +28,7 @@ pub(crate) trait BytecodeContext { } #[repr(u8)] -#[derive(Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive)] #[allow(clippy::enum_variant_names)] pub enum Op { PushSmi, @@ -102,7 +102,6 @@ pub enum Op { struct ScopeInfo { depth: u16, - arg_id: Option, thunk_map: HashMap, } @@ -161,10 +160,10 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { let (layer, local) = self.resolve_thunk(id); InlineOperand::Local { layer, local } } - &Ir::Arg(id) => { - let (layer, local) = self.resolve_arg(id); - InlineOperand::Local { layer, local } - } + &Ir::Arg { layer } => InlineOperand::Local { + layer: layer.try_into().expect("scope too deep!"), + local: 0, + }, &Ir::Builtin(id) => { let arity = BUILTINS[id as usize].1; InlineOperand::Const(StaticValue::new_inline(PrimOp { id, arity })) @@ -286,16 +285,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { panic!("ThunkId {:?} not found in any scope", id); } - fn resolve_arg(&self, id: ArgId) -> (u16, u32) { - for scope in self.scope_stack.iter().rev() { - if scope.arg_id == Some(id) { - let layer = self.current_depth() - scope.depth; - return (layer, 0); - } - } - panic!("ArgId {:?} not found in any scope", id); - } - fn emit_load(&mut self, layer: u16, local: u32) { if layer == 0 { self.emit_op(Op::LoadLocal); @@ -433,7 +422,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { } } - fn push_scope(&mut self, has_arg: bool, arg_id: Option, thunk_ids: &[ThunkId]) { + fn push_scope(&mut self, has_arg: bool, thunk_ids: &[ThunkId]) { let depth = self.scope_stack.len() as u16; let thunk_base = if has_arg { 1u32 } else { 0u32 }; let thunk_map = thunk_ids @@ -443,7 +432,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { .collect(); self.scope_stack.push(ScopeInfo { depth, - arg_id, thunk_map, }); } @@ -461,7 +449,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { let all_thunks = self.collect_all_thunks(thunks, body); let thunk_ids: Vec = all_thunks.iter().map(|&(id, _)| id).collect(); - self.push_scope(false, None, &thunk_ids); + self.push_scope(false, &thunk_ids); if total_slots > 0 { self.emit_op(Op::AllocLocals); @@ -475,7 +463,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { self.pop_scope(); } _ => { - self.push_scope(false, None, &[]); + self.push_scope(false, &[]); self.emit_expr(ir); self.emit_op(Op::Return); self.pop_scope(); @@ -485,9 +473,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) { for &(id, inner) in thunks { - let label = format!("e{}", id.0); - let label_idx = self.ctx.intern_string(&label); - let skip_patch = self.emit_jump_placeholder(); let entry_point = self.ctx.get_code_mut().len() as u32; self.emit_expr(inner); @@ -495,7 +480,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { self.patch_jump_target(skip_patch); self.emit_op(Op::MakeThunk); self.emit_u32(entry_point); - self.emit_str_id(label_idx); let (_, local_idx) = self.resolve_thunk(id); self.emit_op(Op::StoreLocal); self.emit_u32(local_idx); @@ -566,10 +550,9 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { &Ir::Func { body, ref param, - arg, ref thunks, } => { - self.emit_func(arg, thunks, param, body); + self.emit_func(thunks, param, body); } Ir::AttrSet { stcs, dyns } => { self.emit_attrset(stcs, dyns); @@ -593,9 +576,11 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { self.emit_op(Op::Call); self.emit_u32(span_id); } - &Ir::Arg(id) => { - let (layer, local) = self.resolve_arg(id); - self.emit_load(layer, local); + &Ir::Arg { layer } => { + self.emit_load( + layer.try_into().expect("scope too deep!"), + 0, + ); } &Ir::TopLevel { body, ref thunks } => { self.emit_toplevel_inner(body, thunks); @@ -777,7 +762,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { fn emit_func( &mut self, - arg: ArgId, thunks: &[(ThunkId, RawIrRef<'_>)], param: &Option>, body: RawIrRef<'_>, @@ -790,7 +774,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { let skip_patch = self.emit_jump_placeholder(); let entry_point = self.ctx.get_code().len() as u32; - self.push_scope(true, Some(arg), &thunk_ids); + self.push_scope(true, &thunk_ids); self.emit_scope_thunks(thunks); self.emit_expr(body); self.emit_op(Op::Return); diff --git a/fix/src/disassembler.rs b/fix/src/disassembler.rs index b1bbb1d..415ddcd 100644 --- a/fix/src/disassembler.rs +++ b/fix/src/disassembler.rs @@ -208,9 +208,7 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> { Op::MakeThunk => { let offset = self.read_u32(); - let label_idx = self.read_u32(); - let label = self.ctx.lookup_string(label_idx); - ("MakeThunk", format!("-> {:04x} label={}", offset, label)) + ("MakeThunk", format!("-> {:04x}", offset)) } Op::MakeClosure => { let offset = self.read_u32(); diff --git a/fix/src/downgrade.rs b/fix/src/downgrade.rs index 5be19fc..c2283c7 100644 --- a/fix/src/downgrade.rs +++ b/fix/src/downgrade.rs @@ -48,7 +48,6 @@ impl BoxIn for T {} pub trait DowngradeContext<'id: 'ir, 'ir> { fn new_expr(&self, expr: Ir<'ir, IrRef<'id, 'ir>>) -> IrRef<'id, 'ir>; - fn new_arg(&mut self) -> ArgId; fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir>; fn new_sym(&mut self, sym: String) -> StringId; @@ -57,7 +56,7 @@ pub trait DowngradeContext<'id: 'ir, 'ir> { fn get_current_source(&self) -> Source; - fn with_param_scope(&mut self, param: StringId, arg: ArgId, f: F) -> R + fn with_param_scope(&mut self, param: StringId, f: F) -> R where F: FnOnce(&mut Self) -> R; fn with_let_scope(&mut self, bindings: &[StringId], f: F) -> Result @@ -380,7 +379,6 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo let span = self.syntax().text_range(); let raw_param = self.param().require(ctx, span)?; let body_ast = self.body().require(ctx, span)?; - let arg = ctx.new_arg(); struct Ret<'id, 'ir> { param: Option>, @@ -397,7 +395,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo param = None; body = ctx - .with_param_scope(param_sym, arg, |ctx| body_ast.clone().downgrade(ctx))?; + .with_param_scope(param_sym, |ctx| body_ast.downgrade(ctx))?; } ast::Param::Pattern(pattern) => { let alias = pattern @@ -415,7 +413,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo body: inner_body, required, optional, - } = downgrade_pattern_bindings(pat_entries, alias, arg, ctx, |ctx, _| { + } = downgrade_pattern_bindings(pat_entries, alias, ctx, |ctx, _| { body_ast.clone().downgrade(ctx) })?; @@ -436,7 +434,6 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo Ok(ctx.new_expr(Ir::Func { body, param, - arg, thunks, })) } @@ -936,14 +933,12 @@ struct PatternBindings<'id, 'ir> { fn downgrade_pattern_bindings<'id, 'ir, Ctx>( pat_entries: impl Iterator, alias: Option, - arg: ArgId, ctx: &mut Ctx, body_fn: impl FnOnce(&mut Ctx, &[StringId]) -> Result>, ) -> Result> where Ctx: DowngradeContext<'id, 'ir>, { - let arg = ctx.new_expr(Ir::Arg(arg)); struct Param { sym: StringId, sym_span: TextRange, @@ -997,6 +992,7 @@ where } } + let arg= ctx.new_expr(Ir::Arg { layer: 0 }); ctx.with_let_scope(&keys, |ctx| { let vals = params .into_iter() diff --git a/fix/src/ir.rs b/fix/src/ir.rs index 10da383..70d1906 100644 --- a/fix/src/ir.rs +++ b/fix/src/ir.rs @@ -1,4 +1,4 @@ -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::ops::Deref; use bumpalo::Bump; @@ -126,10 +126,9 @@ pub enum Ir<'ir, Ref> { Func { body: Ref, param: Option>, - arg: ArgId, thunks: Vec<'ir, (ThunkId, Ref)>, }, - Arg(ArgId), + Arg { layer: usize }, Call { func: Ref, arg: Ref, @@ -161,10 +160,6 @@ pub struct ThunkId(pub usize); #[collect(require_static)] pub struct StringId(pub SymbolU32); -#[repr(transparent)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ArgId(pub u32); - #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SpanId(pub u32); @@ -261,433 +256,3 @@ pub struct Param<'ir> { pub optional: Vec<'ir, (StringId, TextRange)>, pub ellipsis: bool, } - -#[derive(Clone, Copy)] -pub(crate) struct IrKey<'id, 'ir, 'a>(pub IrRef<'id, 'ir>, pub &'a GhostToken<'id>); - -impl std::hash::Hash for IrKey<'_, '_, '_> { - fn hash(&self, state: &mut H) { - ir_content_hash(self.0, self.1, state); - } -} - -impl PartialEq for IrKey<'_, '_, '_> { - fn eq(&self, other: &Self) -> bool { - ir_content_eq(self.0, other.0, self.1) - } -} - -impl Eq for IrKey<'_, '_, '_> {} - -fn attr_content_hash<'id>( - attr: &Attr>, - token: &GhostToken<'id>, - state: &mut impl Hasher, -) { - core::mem::discriminant(attr).hash(state); - match attr { - Attr::Dynamic(expr, _) => ir_content_hash(*expr, token, state), - Attr::Str(sym, _) => sym.hash(state), - } -} - -fn attr_content_eq<'id, 'ir>( - a: &Attr>, - b: &Attr>, - token: &GhostToken<'id>, -) -> bool { - match (a, b) { - (Attr::Dynamic(ae, _), Attr::Dynamic(be, _)) => ir_content_eq(*ae, *be, token), - (Attr::Str(a, _), Attr::Str(b, _)) => a == b, - _ => false, - } -} - -fn param_content_hash(param: &Param<'_>, state: &mut impl Hasher) { - param.required.len().hash(state); - for (sym, _) in param.required.iter() { - sym.hash(state); - } - param.optional.len().hash(state); - for (sym, _) in param.optional.iter() { - sym.hash(state); - } - param.ellipsis.hash(state); -} - -fn param_content_eq(a: &Param<'_>, b: &Param<'_>) -> bool { - a.ellipsis == b.ellipsis - && a.required.len() == b.required.len() - && a.optional.len() == b.optional.len() - && a.required - .iter() - .zip(b.required.iter()) - .all(|((a, _), (b, _))| a == b) - && a.optional - .iter() - .zip(b.optional.iter()) - .all(|((a, _), (b, _))| a == b) -} - -fn thunks_content_hash<'id>( - thunks: &[(ThunkId, IrRef<'id, '_>)], - token: &GhostToken<'id>, - state: &mut impl Hasher, -) { - thunks.len().hash(state); - for &(id, ir) in thunks { - id.hash(state); - ir_content_hash(ir, token, state); - } -} - -fn thunks_content_eq<'id, 'ir>( - a: &[(ThunkId, IrRef<'id, 'ir>)], - b: &[(ThunkId, IrRef<'id, 'ir>)], - token: &GhostToken<'id>, -) -> bool { - a.len() == b.len() - && a.iter() - .zip(b.iter()) - .all(|(&(ai, ae), &(bi, be))| ai == bi && ir_content_eq(ae, be, token)) -} - -fn ir_content_hash<'id>(ir: IrRef<'id, '_>, token: &GhostToken<'id>, state: &mut impl Hasher) { - let ir = ir.borrow(token); - core::mem::discriminant(ir).hash(state); - match ir { - Ir::Int(x) => x.hash(state), - Ir::Float(x) => x.to_bits().hash(state), - Ir::Bool(x) => x.hash(state), - Ir::Null => {} - Ir::Str(x) => x.hash(state), - Ir::AttrSet { stcs, dyns } => { - stcs.len().hash(state); - let mut combined: u64 = 0; - for (&key, &(val, _)) in stcs.iter() { - let mut h = std::hash::DefaultHasher::new(); - key.hash(&mut h); - ir_content_hash(val, token, &mut h); - combined = combined.wrapping_add(h.finish()); - } - combined.hash(state); - dyns.len().hash(state); - for &(k, v, _) in dyns.iter() { - ir_content_hash(k, token, state); - ir_content_hash(v, token, state); - } - } - Ir::List { items } => { - items.len().hash(state); - for &item in items.iter() { - ir_content_hash(item, token, state); - } - } - Ir::HasAttr { lhs, rhs } => { - ir_content_hash(*lhs, token, state); - rhs.len().hash(state); - for attr in rhs.iter() { - attr_content_hash(attr, token, state); - } - } - &Ir::BinOp { lhs, rhs, kind } => { - ir_content_hash(lhs, token, state); - ir_content_hash(rhs, token, state); - kind.hash(state); - } - &Ir::UnOp { rhs, kind } => { - ir_content_hash(rhs, token, state); - kind.hash(state); - } - Ir::Select { - expr, - attrpath, - default, - .. - } => { - ir_content_hash(*expr, token, state); - attrpath.len().hash(state); - for attr in attrpath.iter() { - attr_content_hash(attr, token, state); - } - default.is_some().hash(state); - if let Some(d) = default { - ir_content_hash(*d, token, state); - } - } - &Ir::If { cond, consq, alter } => { - ir_content_hash(cond, token, state); - ir_content_hash(consq, token, state); - ir_content_hash(alter, token, state); - } - &Ir::Call { func, arg, .. } => { - ir_content_hash(func, token, state); - ir_content_hash(arg, token, state); - } - Ir::Assert { - assertion, - expr, - assertion_raw, - .. - } => { - ir_content_hash(*assertion, token, state); - ir_content_hash(*expr, token, state); - assertion_raw.hash(state); - } - Ir::ConcatStrings { - force_string, - parts, - } => { - force_string.hash(state); - parts.len().hash(state); - for &part in parts.iter() { - ir_content_hash(part, token, state); - } - } - &Ir::Path(expr) => ir_content_hash(expr, token, state), - Ir::Func { - body, - arg, - param, - thunks, - } => { - ir_content_hash(*body, token, state); - arg.hash(state); - param.is_some().hash(state); - if let Some(p) = param { - param_content_hash(p, state); - } - thunks_content_hash(thunks, token, state); - } - Ir::TopLevel { body, thunks } => { - ir_content_hash(*body, token, state); - thunks_content_hash(thunks, token, state); - } - Ir::Arg(x) => x.hash(state), - Ir::Thunk(x) => x.hash(state), - Ir::Builtins => {} - Ir::Builtin(x) => x.hash(state), - Ir::BuiltinConst(x) => x.hash(state), - Ir::CurPos(x) => x.hash(state), - Ir::ReplBinding(x) => x.hash(state), - Ir::ScopedImportBinding(x) => x.hash(state), - &Ir::With { - namespace, - body, - ref thunks, - } => { - ir_content_hash(namespace, token, state); - ir_content_hash(body, token, state); - thunks_content_hash(thunks, token, state); - } - Ir::WithLookup(x) => x.hash(state), - } -} - -pub(crate) fn ir_content_eq<'id, 'ir>( - a: IrRef<'id, 'ir>, - b: IrRef<'id, 'ir>, - token: &GhostToken<'id>, -) -> bool { - std::ptr::eq(a.0, b.0) - || match (a.borrow(token), b.borrow(token)) { - (Ir::Int(a), Ir::Int(b)) => a == b, - (Ir::Float(a), Ir::Float(b)) => a.to_bits() == b.to_bits(), - (Ir::Bool(a), Ir::Bool(b)) => a == b, - (Ir::Null, Ir::Null) => true, - (Ir::Str(a), Ir::Str(b)) => **a == **b, - ( - Ir::AttrSet { - stcs: a_stcs, - dyns: a_dyns, - }, - Ir::AttrSet { - stcs: b_stcs, - dyns: b_dyns, - }, - ) => { - a_stcs.len() == b_stcs.len() - && a_dyns.len() == b_dyns.len() - && a_stcs.iter().all(|(&k, &(av, _))| { - b_stcs - .get(&k) - .is_some_and(|&(bv, _)| ir_content_eq(av, bv, token)) - }) - && a_dyns - .iter() - .zip(b_dyns.iter()) - .all(|(&(ak, av, _), &(bk, bv, _))| { - ir_content_eq(ak, bk, token) && ir_content_eq(av, bv, token) - }) - } - (Ir::List { items: a }, Ir::List { items: b }) => { - a.len() == b.len() - && a.iter() - .zip(b.iter()) - .all(|(&a, &b)| ir_content_eq(a, b, token)) - } - (Ir::HasAttr { lhs: al, rhs: ar }, Ir::HasAttr { lhs: bl, rhs: br }) => { - ir_content_eq(*al, *bl, token) - && ar.len() == br.len() - && ar - .iter() - .zip(br.iter()) - .all(|(a, b)| attr_content_eq(a, b, token)) - } - ( - &Ir::BinOp { - lhs: al, - rhs: ar, - kind: ak, - }, - &Ir::BinOp { - lhs: bl, - rhs: br, - kind: bk, - }, - ) => ak == bk && ir_content_eq(al, bl, token) && ir_content_eq(ar, br, token), - (&Ir::UnOp { rhs: ar, kind: ak }, &Ir::UnOp { rhs: br, kind: bk }) => { - ak == bk && ir_content_eq(ar, br, token) - } - ( - Ir::Select { - expr: ae, - attrpath: aa, - default: ad, - .. - }, - Ir::Select { - expr: be, - attrpath: ba, - default: bd, - .. - }, - ) => { - ir_content_eq(*ae, *be, token) - && aa.len() == ba.len() - && aa - .iter() - .zip(ba.iter()) - .all(|(a, b)| attr_content_eq(a, b, token)) - && match (ad, bd) { - (Some(a), Some(b)) => ir_content_eq(*a, *b, token), - (None, None) => true, - _ => false, - } - } - ( - &Ir::If { - cond: ac, - consq: acs, - alter: aa, - }, - &Ir::If { - cond: bc, - consq: bcs, - alter: ba, - }, - ) => { - ir_content_eq(ac, bc, token) - && ir_content_eq(acs, bcs, token) - && ir_content_eq(aa, ba, token) - } - ( - &Ir::Call { - func: af, arg: aa, .. - }, - &Ir::Call { - func: bf, arg: ba, .. - }, - ) => ir_content_eq(af, bf, token) && ir_content_eq(aa, ba, token), - ( - Ir::Assert { - assertion: aa, - expr: ae, - assertion_raw: ar, - .. - }, - Ir::Assert { - assertion: ba, - expr: be, - assertion_raw: br, - .. - }, - ) => ar == br && ir_content_eq(*aa, *ba, token) && ir_content_eq(*ae, *be, token), - ( - Ir::ConcatStrings { - force_string: af, - parts: ap, - }, - Ir::ConcatStrings { - force_string: bf, - parts: bp, - }, - ) => { - af == bf - && ap.len() == bp.len() - && ap - .iter() - .zip(bp.iter()) - .all(|(&a, &b)| ir_content_eq(a, b, token)) - } - (&Ir::Path(a), &Ir::Path(b)) => ir_content_eq(a, b, token), - ( - Ir::Func { - body: ab, - arg: aa, - param: ap, - thunks: at, - }, - Ir::Func { - body: bb, - arg: ba, - param: bp, - thunks: bt, - }, - ) => { - ir_content_eq(*ab, *bb, token) - && aa == ba - && match (ap, bp) { - (Some(a), Some(b)) => param_content_eq(a, b), - (None, None) => true, - _ => false, - } - && thunks_content_eq(at, bt, token) - } - ( - Ir::TopLevel { - body: ab, - thunks: at, - }, - Ir::TopLevel { - body: bb, - thunks: bt, - }, - ) => ir_content_eq(*ab, *bb, token) && thunks_content_eq(at, bt, token), - (Ir::Arg(a), Ir::Arg(b)) => a == b, - (Ir::Thunk(a), Ir::Thunk(b)) => a == b, - (Ir::Builtins, Ir::Builtins) => true, - (Ir::Builtin(a), Ir::Builtin(b)) => a == b, - (Ir::CurPos(a), Ir::CurPos(b)) => a == b, - (Ir::ReplBinding(a), Ir::ReplBinding(b)) => a == b, - (Ir::ScopedImportBinding(a), Ir::ScopedImportBinding(b)) => a == b, - ( - Ir::With { - namespace: a_ns, - body: a_body, - thunks: a_thunks, - }, - Ir::With { - namespace: b_ns, - body: b_body, - thunks: b_thunks, - }, - ) => { - ir_content_eq(*a_ns, *b_ns, token) - && ir_content_eq(*a_body, *b_body, token) - && thunks_content_eq(a_thunks, b_thunks, token) - } - (Ir::WithLookup(a), Ir::WithLookup(b)) => a == b, - _ => false, - } -} diff --git a/fix/src/runtime.rs b/fix/src/runtime.rs index 847c1ac..6b53c86 100644 --- a/fix/src/runtime.rs +++ b/fix/src/runtime.rs @@ -1,9 +1,7 @@ -use std::hash::BuildHasher; - use bumpalo::Bump; use gc_arena::{Arena, Rootable}; use ghost_cell::{GhostCell, GhostToken}; -use hashbrown::{DefaultHashBuilder, HashMap, HashSet, HashTable}; +use hashbrown::{HashMap, HashSet}; use rnix::TextRange; use string_interner::symbol::SymbolU32; use string_interner::{DefaultStringInterner, Symbol as _}; @@ -12,7 +10,7 @@ use crate::codegen::{BytecodeContext, InstructionPtr}; use crate::disassembler::{Disassembler, DisassemblerContext}; use crate::downgrade::{Downgrade as _, DowngradeContext}; use crate::error::{Error, Result, Source}; -use crate::ir::{ArgId, Ir, IrKey, IrRef, RawIrRef, StringId, ThunkId, ir_content_eq}; +use crate::ir::{Ir, IrRef, RawIrRef, StringId, ThunkId}; use crate::runtime::builtins::init_builtins; use crate::runtime::value::StaticValue; use crate::runtime::vm::{ForceMode, new_gc_root}; @@ -282,26 +280,11 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, IrRef::new(self.bump.alloc(GhostCell::new(expr))) } - fn new_arg(&mut self) -> ArgId { - self.arg_count += 1; - ArgId(self.arg_count - 1) - } - fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir> { if !should_thunk(ir, &self.token) { return ir; } - let cached = self - .thunk_scopes - .last() - .expect("no active cache scope") - .lookup_cache(ir, &self.token); - - if let Some(id) = cached { - return IrRef::alloc(self.bump, Ir::Thunk(id)); - } - let id = ThunkId(*self.thunk_count); *self.thunk_count = self.thunk_count.checked_add(1).expect("thunk id overflow"); self.thunk_scopes @@ -349,9 +332,14 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, return Ok(self.new_expr(Ir::Thunk(expr))); } } - &Scope::Param(param_sym, id) => { + &Scope::Param { + sym: param_sym, + abs_layer, + } => { if param_sym == sym { - return Ok(self.new_expr(Ir::Arg(id))); + return Ok(self.new_expr(Ir::Arg { + layer: self.thunk_scopes.len() - abs_layer, + })); } } } @@ -398,11 +386,14 @@ impl<'ctx: 'ir, 'id, 'ir> DowngradeContext<'id, 'ir> for DowngradeCtx<'ctx, 'id, Ok(ret) } - fn with_param_scope(&mut self, param: StringId, arg: ArgId, f: F) -> R + fn with_param_scope(&mut self, sym: StringId, f: F) -> R where F: FnOnce(&mut Self) -> R, { - self.scopes.push(Scope::Param(param, arg)); + self.scopes.push(Scope::Param { + sym, + abs_layer: self.thunk_scopes.len(), + }); let mut guard = ScopeGuard { ctx: self }; f(guard.as_ctx()) } @@ -458,32 +449,17 @@ impl<'id, 'ir, 'ctx: 'ir> DowngradeCtx<'ctx, 'id, 'ir> { struct ThunkScope<'id, 'ir> { bindings: bumpalo::collections::Vec<'ir, (ThunkId, IrRef<'id, 'ir>)>, - cache: HashTable<(IrRef<'id, 'ir>, ThunkId)>, - hasher: DefaultHashBuilder, } impl<'id, 'ir> ThunkScope<'id, 'ir> { fn new_in(bump: &'ir Bump) -> Self { Self { bindings: bumpalo::collections::Vec::new_in(bump), - cache: HashTable::new(), - hasher: DefaultHashBuilder::default(), } } - fn lookup_cache(&self, key: IrRef<'id, 'ir>, token: &GhostToken<'id>) -> Option { - let hash = self.hasher.hash_one(IrKey(key, token)); - self.cache - .find(hash, |&(ir, _)| ir_content_eq(key, ir, token)) - .map(|&(_, id)| id) - } - - fn add_binding(&mut self, id: ThunkId, ir: IrRef<'id, 'ir>, token: &GhostToken<'id>) { + fn add_binding(&mut self, id: ThunkId, ir: IrRef<'id, 'ir>, _token: &GhostToken<'id>) { self.bindings.push((id, ir)); - let hash = self.hasher.hash_one(IrKey(ir, token)); - self.cache.insert_unique(hash, (ir, id), |&(ir, _)| { - self.hasher.hash_one(IrKey(ir, token)) - }); } fn extend_bindings(&mut self, iter: impl IntoIterator)>) { @@ -496,7 +472,7 @@ enum Scope<'ctx> { Repl(&'ctx HashSet), ScopedImport(HashSet), Let(HashMap), - Param(StringId, ArgId), + Param { sym: StringId, abs_layer: usize }, } struct ScopeGuard<'a, 'ctx, 'id, 'ir> { diff --git a/fix/src/runtime/vm.rs b/fix/src/runtime/vm.rs index fd8f7f7..c8d9aed 100644 --- a/fix/src/runtime/vm.rs +++ b/fix/src/runtime/vm.rs @@ -361,7 +361,6 @@ impl Runtime { MakeThunk => { let entry_point = self.read_u32(); - let _label = self.read_string_id(); self.arena.mutate_root(|mc, root| { let thunk = Gc::new( mc,