feat(tvix/eval): implement OpFinalise instruction
This instruction finalises the initialisation of deferred upvalues in closures (and soon, thunks). The compiler does not yet emit this instruction, some more accounting is needed for that. Change-Id: Ic4181b26e19779e206f51e17388559400da5f93a Reviewed-on: https://cl.tvl.fyi/c/depot/+/6337 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
1bfe32f412
commit
025a9a4a0a
3 changed files with 28 additions and 1 deletions
|
@ -32,7 +32,6 @@ pub struct JumpOffset(pub usize);
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Count(pub usize);
|
pub struct Count(pub usize);
|
||||||
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
#[warn(variant_size_differences)]
|
#[warn(variant_size_differences)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
|
@ -108,6 +107,10 @@ pub enum OpCode {
|
||||||
OpGetUpvalue(UpvalueIdx),
|
OpGetUpvalue(UpvalueIdx),
|
||||||
OpClosure(ConstantIdx),
|
OpClosure(ConstantIdx),
|
||||||
|
|
||||||
|
/// Finalise initialisation of the upvalues of the value in the
|
||||||
|
/// given stack index after the scope is fully bound.
|
||||||
|
OpFinalise(StackIdx),
|
||||||
|
|
||||||
// The closure and thunk creation instructions have a variable
|
// The closure and thunk creation instructions have a variable
|
||||||
// number of arguments to the instruction, which is represented
|
// number of arguments to the instruction, which is represented
|
||||||
// here by making their data part of the opcodes.
|
// here by making their data part of the opcodes.
|
||||||
|
|
|
@ -60,4 +60,15 @@ impl Closure {
|
||||||
pub fn push_upvalue(&self, value: Value) {
|
pub fn push_upvalue(&self, value: Value) {
|
||||||
self.0.borrow_mut().upvalues.push(value)
|
self.0.borrow_mut().upvalues.push(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve the deferred upvalues in the closure from a slice of
|
||||||
|
/// the current stack, using the indices stored in the deferred
|
||||||
|
/// values.
|
||||||
|
pub fn resolve_deferred_upvalues(&self, stack: &[Value]) {
|
||||||
|
for upvalue in self.0.borrow_mut().upvalues.iter_mut() {
|
||||||
|
if let Value::DeferredUpvalue(idx) = upvalue {
|
||||||
|
*upvalue = stack[idx.0].clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,6 +435,19 @@ impl VM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpCode::OpFinalise(StackIdx(idx)) => {
|
||||||
|
match &self.stack[self.frame().stack_offset + idx] {
|
||||||
|
Value::Closure(closure) => closure
|
||||||
|
.resolve_deferred_upvalues(&self.stack[self.frame().stack_offset..]),
|
||||||
|
|
||||||
|
v => {
|
||||||
|
#[cfg(feature = "disassembler")]
|
||||||
|
drop(tracer);
|
||||||
|
panic!("compiler error: invalid finaliser value: {}", v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Data-carrying operands should never be executed,
|
// Data-carrying operands should never be executed,
|
||||||
// that is a critical error in the VM.
|
// that is a critical error in the VM.
|
||||||
OpCode::DataLocalIdx(_)
|
OpCode::DataLocalIdx(_)
|
||||||
|
|
Loading…
Reference in a new issue