remove ArgId and Ir caching mechanism
This commit is contained in:
+16
-32
@@ -6,7 +6,7 @@ use num_enum::TryFromPrimitive;
|
|||||||
use rnix::TextRange;
|
use rnix::TextRange;
|
||||||
use string_interner::Symbol as _;
|
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::BUILTINS;
|
||||||
use crate::runtime::value::{Null, PrimOp, StaticValue};
|
use crate::runtime::value::{Null, PrimOp, StaticValue};
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ pub(crate) trait BytecodeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, TryFromPrimitive)]
|
#[derive(Debug, Clone, Copy, TryFromPrimitive)]
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
PushSmi,
|
PushSmi,
|
||||||
@@ -102,7 +102,6 @@ pub enum Op {
|
|||||||
|
|
||||||
struct ScopeInfo {
|
struct ScopeInfo {
|
||||||
depth: u16,
|
depth: u16,
|
||||||
arg_id: Option<ArgId>,
|
|
||||||
thunk_map: HashMap<ThunkId, u32>,
|
thunk_map: HashMap<ThunkId, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,10 +160,10 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
let (layer, local) = self.resolve_thunk(id);
|
let (layer, local) = self.resolve_thunk(id);
|
||||||
InlineOperand::Local { layer, local }
|
InlineOperand::Local { layer, local }
|
||||||
}
|
}
|
||||||
&Ir::Arg(id) => {
|
&Ir::Arg { layer } => InlineOperand::Local {
|
||||||
let (layer, local) = self.resolve_arg(id);
|
layer: layer.try_into().expect("scope too deep!"),
|
||||||
InlineOperand::Local { layer, local }
|
local: 0,
|
||||||
}
|
},
|
||||||
&Ir::Builtin(id) => {
|
&Ir::Builtin(id) => {
|
||||||
let arity = BUILTINS[id as usize].1;
|
let arity = BUILTINS[id as usize].1;
|
||||||
InlineOperand::Const(StaticValue::new_inline(PrimOp { id, arity }))
|
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);
|
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) {
|
fn emit_load(&mut self, layer: u16, local: u32) {
|
||||||
if layer == 0 {
|
if layer == 0 {
|
||||||
self.emit_op(Op::LoadLocal);
|
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<ArgId>, thunk_ids: &[ThunkId]) {
|
fn push_scope(&mut self, has_arg: bool, thunk_ids: &[ThunkId]) {
|
||||||
let depth = self.scope_stack.len() as u16;
|
let depth = self.scope_stack.len() as u16;
|
||||||
let thunk_base = if has_arg { 1u32 } else { 0u32 };
|
let thunk_base = if has_arg { 1u32 } else { 0u32 };
|
||||||
let thunk_map = thunk_ids
|
let thunk_map = thunk_ids
|
||||||
@@ -443,7 +432,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
.collect();
|
.collect();
|
||||||
self.scope_stack.push(ScopeInfo {
|
self.scope_stack.push(ScopeInfo {
|
||||||
depth,
|
depth,
|
||||||
arg_id,
|
|
||||||
thunk_map,
|
thunk_map,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -461,7 +449,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
let all_thunks = self.collect_all_thunks(thunks, body);
|
let all_thunks = self.collect_all_thunks(thunks, body);
|
||||||
let thunk_ids: Vec<ThunkId> = all_thunks.iter().map(|&(id, _)| id).collect();
|
let thunk_ids: Vec<ThunkId> = all_thunks.iter().map(|&(id, _)| id).collect();
|
||||||
|
|
||||||
self.push_scope(false, None, &thunk_ids);
|
self.push_scope(false, &thunk_ids);
|
||||||
|
|
||||||
if total_slots > 0 {
|
if total_slots > 0 {
|
||||||
self.emit_op(Op::AllocLocals);
|
self.emit_op(Op::AllocLocals);
|
||||||
@@ -475,7 +463,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.pop_scope();
|
self.pop_scope();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.push_scope(false, None, &[]);
|
self.push_scope(false, &[]);
|
||||||
self.emit_expr(ir);
|
self.emit_expr(ir);
|
||||||
self.emit_op(Op::Return);
|
self.emit_op(Op::Return);
|
||||||
self.pop_scope();
|
self.pop_scope();
|
||||||
@@ -485,9 +473,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
|
|
||||||
fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) {
|
fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) {
|
||||||
for &(id, inner) in thunks {
|
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 skip_patch = self.emit_jump_placeholder();
|
||||||
let entry_point = self.ctx.get_code_mut().len() as u32;
|
let entry_point = self.ctx.get_code_mut().len() as u32;
|
||||||
self.emit_expr(inner);
|
self.emit_expr(inner);
|
||||||
@@ -495,7 +480,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
self.patch_jump_target(skip_patch);
|
self.patch_jump_target(skip_patch);
|
||||||
self.emit_op(Op::MakeThunk);
|
self.emit_op(Op::MakeThunk);
|
||||||
self.emit_u32(entry_point);
|
self.emit_u32(entry_point);
|
||||||
self.emit_str_id(label_idx);
|
|
||||||
let (_, local_idx) = self.resolve_thunk(id);
|
let (_, local_idx) = self.resolve_thunk(id);
|
||||||
self.emit_op(Op::StoreLocal);
|
self.emit_op(Op::StoreLocal);
|
||||||
self.emit_u32(local_idx);
|
self.emit_u32(local_idx);
|
||||||
@@ -566,10 +550,9 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
&Ir::Func {
|
&Ir::Func {
|
||||||
body,
|
body,
|
||||||
ref param,
|
ref param,
|
||||||
arg,
|
|
||||||
ref thunks,
|
ref thunks,
|
||||||
} => {
|
} => {
|
||||||
self.emit_func(arg, thunks, param, body);
|
self.emit_func(thunks, param, body);
|
||||||
}
|
}
|
||||||
Ir::AttrSet { stcs, dyns } => {
|
Ir::AttrSet { stcs, dyns } => {
|
||||||
self.emit_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_op(Op::Call);
|
||||||
self.emit_u32(span_id);
|
self.emit_u32(span_id);
|
||||||
}
|
}
|
||||||
&Ir::Arg(id) => {
|
&Ir::Arg { layer } => {
|
||||||
let (layer, local) = self.resolve_arg(id);
|
self.emit_load(
|
||||||
self.emit_load(layer, local);
|
layer.try_into().expect("scope too deep!"),
|
||||||
|
0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
&Ir::TopLevel { body, ref thunks } => {
|
&Ir::TopLevel { body, ref thunks } => {
|
||||||
self.emit_toplevel_inner(body, thunks);
|
self.emit_toplevel_inner(body, thunks);
|
||||||
@@ -777,7 +762,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
|
|
||||||
fn emit_func(
|
fn emit_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
arg: ArgId,
|
|
||||||
thunks: &[(ThunkId, RawIrRef<'_>)],
|
thunks: &[(ThunkId, RawIrRef<'_>)],
|
||||||
param: &Option<Param<'_>>,
|
param: &Option<Param<'_>>,
|
||||||
body: RawIrRef<'_>,
|
body: RawIrRef<'_>,
|
||||||
@@ -790,7 +774,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
|||||||
|
|
||||||
let skip_patch = self.emit_jump_placeholder();
|
let skip_patch = self.emit_jump_placeholder();
|
||||||
let entry_point = self.ctx.get_code().len() as u32;
|
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_scope_thunks(thunks);
|
||||||
self.emit_expr(body);
|
self.emit_expr(body);
|
||||||
self.emit_op(Op::Return);
|
self.emit_op(Op::Return);
|
||||||
|
|||||||
@@ -208,9 +208,7 @@ impl<'a, Ctx: DisassemblerContext> Disassembler<'a, Ctx> {
|
|||||||
|
|
||||||
Op::MakeThunk => {
|
Op::MakeThunk => {
|
||||||
let offset = self.read_u32();
|
let offset = self.read_u32();
|
||||||
let label_idx = self.read_u32();
|
("MakeThunk", format!("-> {:04x}", offset))
|
||||||
let label = self.ctx.lookup_string(label_idx);
|
|
||||||
("MakeThunk", format!("-> {:04x} label={}", offset, label))
|
|
||||||
}
|
}
|
||||||
Op::MakeClosure => {
|
Op::MakeClosure => {
|
||||||
let offset = self.read_u32();
|
let offset = self.read_u32();
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ impl<T: Sized> BoxIn for T {}
|
|||||||
|
|
||||||
pub trait DowngradeContext<'id: 'ir, 'ir> {
|
pub trait DowngradeContext<'id: 'ir, 'ir> {
|
||||||
fn new_expr(&self, expr: Ir<'ir, IrRef<'id, 'ir>>) -> IrRef<'id, '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 maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir>;
|
||||||
|
|
||||||
fn new_sym(&mut self, sym: String) -> StringId;
|
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 get_current_source(&self) -> Source;
|
||||||
|
|
||||||
fn with_param_scope<F, R>(&mut self, param: StringId, arg: ArgId, f: F) -> R
|
fn with_param_scope<F, R>(&mut self, param: StringId, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> R;
|
F: FnOnce(&mut Self) -> R;
|
||||||
fn with_let_scope<F, R>(&mut self, bindings: &[StringId], f: F) -> Result<R>
|
fn with_let_scope<F, R>(&mut self, bindings: &[StringId], f: F) -> Result<R>
|
||||||
@@ -380,7 +379,6 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
let span = self.syntax().text_range();
|
let span = self.syntax().text_range();
|
||||||
let raw_param = self.param().require(ctx, span)?;
|
let raw_param = self.param().require(ctx, span)?;
|
||||||
let body_ast = self.body().require(ctx, span)?;
|
let body_ast = self.body().require(ctx, span)?;
|
||||||
let arg = ctx.new_arg();
|
|
||||||
|
|
||||||
struct Ret<'id, 'ir> {
|
struct Ret<'id, 'ir> {
|
||||||
param: Option<Param<'ir>>,
|
param: Option<Param<'ir>>,
|
||||||
@@ -397,7 +395,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
param = None;
|
param = None;
|
||||||
|
|
||||||
body = ctx
|
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) => {
|
ast::Param::Pattern(pattern) => {
|
||||||
let alias = pattern
|
let alias = pattern
|
||||||
@@ -415,7 +413,7 @@ impl<'id: 'ir, 'ir, Ctx: DowngradeContext<'id, 'ir>> Downgrade<'id, 'ir, Ctx> fo
|
|||||||
body: inner_body,
|
body: inner_body,
|
||||||
required,
|
required,
|
||||||
optional,
|
optional,
|
||||||
} = downgrade_pattern_bindings(pat_entries, alias, arg, ctx, |ctx, _| {
|
} = downgrade_pattern_bindings(pat_entries, alias, ctx, |ctx, _| {
|
||||||
body_ast.clone().downgrade(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 {
|
Ok(ctx.new_expr(Ir::Func {
|
||||||
body,
|
body,
|
||||||
param,
|
param,
|
||||||
arg,
|
|
||||||
thunks,
|
thunks,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -936,14 +933,12 @@ struct PatternBindings<'id, 'ir> {
|
|||||||
fn downgrade_pattern_bindings<'id, 'ir, Ctx>(
|
fn downgrade_pattern_bindings<'id, 'ir, Ctx>(
|
||||||
pat_entries: impl Iterator<Item = ast::PatEntry>,
|
pat_entries: impl Iterator<Item = ast::PatEntry>,
|
||||||
alias: Option<StringId>,
|
alias: Option<StringId>,
|
||||||
arg: ArgId,
|
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
body_fn: impl FnOnce(&mut Ctx, &[StringId]) -> Result<IrRef<'id, 'ir>>,
|
body_fn: impl FnOnce(&mut Ctx, &[StringId]) -> Result<IrRef<'id, 'ir>>,
|
||||||
) -> Result<PatternBindings<'id, 'ir>>
|
) -> Result<PatternBindings<'id, 'ir>>
|
||||||
where
|
where
|
||||||
Ctx: DowngradeContext<'id, 'ir>,
|
Ctx: DowngradeContext<'id, 'ir>,
|
||||||
{
|
{
|
||||||
let arg = ctx.new_expr(Ir::Arg(arg));
|
|
||||||
struct Param {
|
struct Param {
|
||||||
sym: StringId,
|
sym: StringId,
|
||||||
sym_span: TextRange,
|
sym_span: TextRange,
|
||||||
@@ -997,6 +992,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let arg= ctx.new_expr(Ir::Arg { layer: 0 });
|
||||||
ctx.with_let_scope(&keys, |ctx| {
|
ctx.with_let_scope(&keys, |ctx| {
|
||||||
let vals = params
|
let vals = params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
+2
-437
@@ -1,4 +1,4 @@
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
@@ -126,10 +126,9 @@ pub enum Ir<'ir, Ref> {
|
|||||||
Func {
|
Func {
|
||||||
body: Ref,
|
body: Ref,
|
||||||
param: Option<Param<'ir>>,
|
param: Option<Param<'ir>>,
|
||||||
arg: ArgId,
|
|
||||||
thunks: Vec<'ir, (ThunkId, Ref)>,
|
thunks: Vec<'ir, (ThunkId, Ref)>,
|
||||||
},
|
},
|
||||||
Arg(ArgId),
|
Arg { layer: usize },
|
||||||
Call {
|
Call {
|
||||||
func: Ref,
|
func: Ref,
|
||||||
arg: Ref,
|
arg: Ref,
|
||||||
@@ -161,10 +160,6 @@ pub struct ThunkId(pub usize);
|
|||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
pub struct StringId(pub SymbolU32);
|
pub struct StringId(pub SymbolU32);
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
||||||
pub struct ArgId(pub u32);
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct SpanId(pub u32);
|
pub struct SpanId(pub u32);
|
||||||
@@ -261,433 +256,3 @@ pub struct Param<'ir> {
|
|||||||
pub optional: Vec<'ir, (StringId, TextRange)>,
|
pub optional: Vec<'ir, (StringId, TextRange)>,
|
||||||
pub ellipsis: bool,
|
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<H: Hasher>(&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<IrRef<'id, '_>>,
|
|
||||||
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<IrRef<'id, 'ir>>,
|
|
||||||
b: &Attr<IrRef<'id, 'ir>>,
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+16
-40
@@ -1,9 +1,7 @@
|
|||||||
use std::hash::BuildHasher;
|
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use gc_arena::{Arena, Rootable};
|
use gc_arena::{Arena, Rootable};
|
||||||
use ghost_cell::{GhostCell, GhostToken};
|
use ghost_cell::{GhostCell, GhostToken};
|
||||||
use hashbrown::{DefaultHashBuilder, HashMap, HashSet, HashTable};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use rnix::TextRange;
|
use rnix::TextRange;
|
||||||
use string_interner::symbol::SymbolU32;
|
use string_interner::symbol::SymbolU32;
|
||||||
use string_interner::{DefaultStringInterner, Symbol as _};
|
use string_interner::{DefaultStringInterner, Symbol as _};
|
||||||
@@ -12,7 +10,7 @@ use crate::codegen::{BytecodeContext, InstructionPtr};
|
|||||||
use crate::disassembler::{Disassembler, DisassemblerContext};
|
use crate::disassembler::{Disassembler, DisassemblerContext};
|
||||||
use crate::downgrade::{Downgrade as _, DowngradeContext};
|
use crate::downgrade::{Downgrade as _, DowngradeContext};
|
||||||
use crate::error::{Error, Result, Source};
|
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::builtins::init_builtins;
|
||||||
use crate::runtime::value::StaticValue;
|
use crate::runtime::value::StaticValue;
|
||||||
use crate::runtime::vm::{ForceMode, new_gc_root};
|
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)))
|
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> {
|
fn maybe_thunk(&mut self, ir: IrRef<'id, 'ir>) -> IrRef<'id, 'ir> {
|
||||||
if !should_thunk(ir, &self.token) {
|
if !should_thunk(ir, &self.token) {
|
||||||
return ir;
|
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);
|
let id = ThunkId(*self.thunk_count);
|
||||||
*self.thunk_count = self.thunk_count.checked_add(1).expect("thunk id overflow");
|
*self.thunk_count = self.thunk_count.checked_add(1).expect("thunk id overflow");
|
||||||
self.thunk_scopes
|
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)));
|
return Ok(self.new_expr(Ir::Thunk(expr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Scope::Param(param_sym, id) => {
|
&Scope::Param {
|
||||||
|
sym: param_sym,
|
||||||
|
abs_layer,
|
||||||
|
} => {
|
||||||
if param_sym == sym {
|
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)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_param_scope<F, R>(&mut self, param: StringId, arg: ArgId, f: F) -> R
|
fn with_param_scope<F, R>(&mut self, sym: StringId, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> R,
|
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 };
|
let mut guard = ScopeGuard { ctx: self };
|
||||||
f(guard.as_ctx())
|
f(guard.as_ctx())
|
||||||
}
|
}
|
||||||
@@ -458,32 +449,17 @@ impl<'id, 'ir, 'ctx: 'ir> DowngradeCtx<'ctx, 'id, 'ir> {
|
|||||||
|
|
||||||
struct ThunkScope<'id, 'ir> {
|
struct ThunkScope<'id, 'ir> {
|
||||||
bindings: bumpalo::collections::Vec<'ir, (ThunkId, IrRef<'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> {
|
impl<'id, 'ir> ThunkScope<'id, 'ir> {
|
||||||
fn new_in(bump: &'ir Bump) -> Self {
|
fn new_in(bump: &'ir Bump) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bindings: bumpalo::collections::Vec::new_in(bump),
|
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<ThunkId> {
|
fn add_binding(&mut self, id: ThunkId, ir: IrRef<'id, 'ir>, _token: &GhostToken<'id>) {
|
||||||
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>) {
|
|
||||||
self.bindings.push((id, ir));
|
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<Item = (ThunkId, IrRef<'id, 'ir>)>) {
|
fn extend_bindings(&mut self, iter: impl IntoIterator<Item = (ThunkId, IrRef<'id, 'ir>)>) {
|
||||||
@@ -496,7 +472,7 @@ enum Scope<'ctx> {
|
|||||||
Repl(&'ctx HashSet<StringId>),
|
Repl(&'ctx HashSet<StringId>),
|
||||||
ScopedImport(HashSet<StringId>),
|
ScopedImport(HashSet<StringId>),
|
||||||
Let(HashMap<StringId, ThunkId>),
|
Let(HashMap<StringId, ThunkId>),
|
||||||
Param(StringId, ArgId),
|
Param { sym: StringId, abs_layer: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScopeGuard<'a, 'ctx, 'id, 'ir> {
|
struct ScopeGuard<'a, 'ctx, 'id, 'ir> {
|
||||||
|
|||||||
@@ -361,7 +361,6 @@ impl Runtime {
|
|||||||
|
|
||||||
MakeThunk => {
|
MakeThunk => {
|
||||||
let entry_point = self.read_u32();
|
let entry_point = self.read_u32();
|
||||||
let _label = self.read_string_id();
|
|
||||||
self.arena.mutate_root(|mc, root| {
|
self.arena.mutate_root(|mc, root| {
|
||||||
let thunk = Gc::new(
|
let thunk = Gc::new(
|
||||||
mc,
|
mc,
|
||||||
|
|||||||
Reference in New Issue
Block a user