fix: 统一 reset 与 rerun 的运行态清理

This commit is contained in:
2026-06-08 23:16:21 +08:00
parent 1c68a03654
commit e5edbed91d
+64 -20
View File
@@ -290,13 +290,24 @@ impl Vm {
&self.epoch &self.epoch
} }
pub fn reset(&mut self) { fn clear_execution_state(&mut self) {
self.regs = [JsValue::undefined(); 256]; self.regs = [JsValue::undefined(); 256];
self.pc = 0; self.pc = 0;
self.bytecode.clear();
self.constants.clear();
self.frames.clear(); self.frames.clear();
self.for_in_iters.clear(); self.for_in_iters.clear();
self.for_of_iters.clear();
self.saved_bytecode_stack.clear();
self.saved_constants_stack.clear();
self.try_stack.clear();
self.exception_value = None;
self.pending_exception = None;
self.pending_error_kind = None;
}
pub fn reset(&mut self) {
self.clear_execution_state();
self.bytecode.clear();
self.constants.clear();
self.epoch.reset(); self.epoch.reset();
self.interned_strings.clear(); self.interned_strings.clear();
self.root_reg_limit = 0; self.root_reg_limit = 0;
@@ -511,15 +522,8 @@ impl Vm {
} }
pub fn rerun(&mut self) -> Result<JsValue, String> { pub fn rerun(&mut self) -> Result<JsValue, String> {
self.pc = 0; self.clear_execution_state();
self.regs = [JsValue::undefined(); 256];
self.active_reg_limit = self.root_reg_limit; self.active_reg_limit = self.root_reg_limit;
self.frames.clear();
self.for_in_iters.clear();
self.try_stack.clear();
self.exception_value = None;
self.pending_exception = None;
self.pending_error_kind = None;
self.clear_ic_caches(); self.clear_ic_caches();
self.dispatch() self.dispatch()
} }
@@ -542,21 +546,13 @@ impl Vm {
} }
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> { pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
self.clear_execution_state();
self.constants = self.convert_constants(module); self.constants = self.convert_constants(module);
self.sub_modules = module.sub_modules.clone(); self.sub_modules = module.sub_modules.clone();
self.sub_module_constants = vec![Vec::new(); self.sub_modules.len()]; self.sub_module_constants = vec![Vec::new(); self.sub_modules.len()];
self.bytecode = module.bytecode.clone(); self.bytecode = module.bytecode.clone();
self.pc = 0;
self.regs = [JsValue::undefined(); 256];
self.root_reg_limit = module.n_registers.max(1); self.root_reg_limit = module.n_registers.max(1);
self.active_reg_limit = self.root_reg_limit; self.active_reg_limit = self.root_reg_limit;
self.frames.clear();
self.saved_bytecode_stack.clear();
self.saved_constants_stack.clear();
self.try_stack.clear();
self.exception_value = None;
self.pending_exception = None;
self.pending_error_kind = None;
for (name, reg) in &module.builtin_reg_map { for (name, reg) in &module.builtin_reg_map {
let si = self.kernel.string_forge().intern(name.as_str()).0; let si = self.kernel.string_forge().intern(name.as_str()).0;
@@ -1910,3 +1906,51 @@ impl Default for Vm {
Self::new() Self::new()
} }
} }
#[cfg(test)]
mod tests {
use super::{opcode, JsValue, TryHandler, Vm};
#[test]
fn reset_clears_runtime_state_like_rerun() {
let mut vm = Vm::new();
vm.regs[1] = JsValue::int(7);
vm.pc = 3;
vm.frames.push(super::CallFrame {
return_addr: 1,
function_name: 0,
caller_reg_limit: 2,
saved_regs: vec![JsValue::undefined()].into_boxed_slice(),
saved_this: JsValue::undefined(),
saved_new_target: JsValue::undefined(),
});
vm.for_in_iters.push(std::ptr::dangling_mut::<u8>());
vm.for_of_iters.push(std::ptr::dangling_mut::<u8>());
vm.saved_bytecode_stack
.push(vec![opcode::encode(opcode::OpCode::HALT, 0, 0, 0)]);
vm.saved_constants_stack.push(vec![JsValue::int(1)]);
vm.try_stack.push(TryHandler {
catch_pc: Some(1),
finally_pc: None,
frame_depth: 0,
});
vm.exception_value = Some(JsValue::int(2));
vm.pending_exception = Some(JsValue::int(3));
vm.pending_error_kind = Some("TypeError");
vm.reset();
assert_eq!(vm.pc, 0);
assert!(vm.frames.is_empty());
assert!(vm.for_in_iters.is_empty());
assert!(vm.for_of_iters.is_empty());
assert!(vm.saved_bytecode_stack.is_empty());
assert!(vm.saved_constants_stack.is_empty());
assert!(vm.try_stack.is_empty());
assert!(vm.exception_value.is_none());
assert!(vm.pending_exception.is_none());
assert!(vm.pending_error_kind.is_none());
assert!(vm.bytecode.is_empty());
assert!(vm.constants.is_empty());
}
}