feat: add experimental tailcall vm backend

This commit is contained in:
2026-04-19 22:13:54 +08:00
parent 800249cb1e
commit 98b07f00e4
16 changed files with 501 additions and 111 deletions
+22 -26
View File
@@ -72,25 +72,22 @@ impl<'gc> crate::Vm<'gc> {
Some(v) => {
self.replace_stack(0, v);
}
None => {
loop {
let byte = reader.bytecode()[reader.pc()];
if byte == fix_codegen::Op::SelectStatic as u8 {
reader.set_pc(reader.pc() + 1 + 4 + 4);
} else if byte == fix_codegen::Op::SelectDynamic as u8 {
reader.set_pc(reader.pc() + 1 + 4);
} else if byte == fix_codegen::Op::JumpIfSelectSucceeded as u8 {
reader.set_pc(reader.pc() + 1 + 4);
let _ = self.pop_stack();
break;
} else {
let name = ctx.resolve_string(key);
return self.finish_err(Error::eval_error(format!(
"attribute '{name}' missing"
)));
}
None => loop {
let byte = reader.bytecode()[reader.pc()];
if byte == fix_codegen::Op::SelectStatic as u8 {
reader.set_pc(reader.pc() + 1 + 4 + 4);
} else if byte == fix_codegen::Op::SelectDynamic as u8 {
reader.set_pc(reader.pc() + 1 + 4);
} else if byte == fix_codegen::Op::JumpIfSelectSucceeded as u8 {
reader.set_pc(reader.pc() + 1 + 4);
let _ = self.pop_stack();
break;
} else {
let name = ctx.resolve_string(key);
return self
.finish_err(Error::eval_error(format!("attribute '{name}' missing")));
}
}
},
}
StepResult::Continue
}
@@ -119,9 +116,7 @@ impl<'gc> crate::Vm<'gc> {
} else if let Some(ns) = key_val.as_gc::<NixString>() {
ctx.intern_string(ns.as_str())
} else {
return self.finish_err(Error::eval_error(
"dynamic select key must be a string",
));
return self.finish_err(Error::eval_error("dynamic select key must be a string"));
};
let attrset_val = self.stack[self.stack.len() - 2].restrict().expect("forced");
@@ -138,16 +133,17 @@ impl<'gc> crate::Vm<'gc> {
}
None => {
let name = ctx.resolve_string(key_sid);
return self.finish_err(Error::eval_error(format!(
"attribute '{name}' missing"
)));
return self.finish_err(Error::eval_error(format!("attribute '{name}' missing")));
}
}
StepResult::Continue
}
#[inline(always)]
pub(crate) fn op_jump_if_select_succeeded(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult<'gc> {
pub(crate) fn op_jump_if_select_succeeded(
&mut self,
reader: &mut BytecodeReader<'_>,
) -> StepResult<'gc> {
let offset = reader.read_i32();
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
StepResult::Continue
@@ -186,4 +182,4 @@ impl<'gc> crate::Vm<'gc> {
pub(crate) struct AttrEntry {
pub(crate) key: AttrKeyData,
pub(crate) val: OperandData,
}
}