Skip to content

Commit b031a1f

Browse files
committed
feat(vm): preserve non-yielding registry bindings
1 parent eacf272 commit b031a1f

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

src/vm/host.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ enum RegistryEntryKind {
105105
StackStatic(StaticHostStackFunction),
106106
ArgsFactory(Arc<HostArgsFactory>),
107107
ArgsStatic(StaticHostArgsFunction),
108+
ArgsStaticNonYielding(StaticHostArgsFunction),
108109
}
109110

110111
#[derive(Clone)]
@@ -308,6 +309,32 @@ impl HostFunctionRegistry {
308309
self.invalidate_plan_cache();
309310
}
310311

312+
pub fn register_static_non_yielding_args(
313+
&mut self,
314+
name: impl Into<String>,
315+
arity: u8,
316+
function: StaticHostArgsFunction,
317+
) {
318+
let name = name.into();
319+
if let Some(&slot) = self.by_name.get(&name)
320+
&& let Some(entry) = Arc::make_mut(&mut self.entries).get_mut(slot as usize)
321+
{
322+
entry.arity = arity;
323+
entry.kind = RegistryEntryKind::ArgsStaticNonYielding(function);
324+
self.invalidate_plan_cache();
325+
return;
326+
}
327+
328+
let entries = Arc::make_mut(&mut self.entries);
329+
let slot = entries.len() as u16;
330+
entries.push(RegistryEntry {
331+
arity,
332+
kind: RegistryEntryKind::ArgsStaticNonYielding(function),
333+
});
334+
Arc::make_mut(&mut self.by_name).insert(name, slot);
335+
self.invalidate_plan_cache();
336+
}
337+
311338
pub fn bind_vm_cached(&self, vm: &mut Vm) -> VmResult<()> {
312339
let plan = self.prepare_shared_plan(&vm.program.imports)?;
313340
self.bind_vm_with_plan(vm, &plan)
@@ -415,6 +442,9 @@ impl HostFunctionRegistry {
415442
RegistryEntryKind::ArgsStatic(function) => {
416443
vm.register_static_args_function(*function);
417444
}
445+
RegistryEntryKind::ArgsStaticNonYielding(function) => {
446+
vm.register_static_non_yielding_args_function(*function);
447+
}
418448
}
419449
}
420450
vm.install_resolved_calls(plan.resolved_calls.clone())?;

tests/compiler/compiler_common_tests.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,37 @@ fn host_function_registry_caches_static_args_function_pointer_plan_across_vms()
577577
assert_eq!(vm2.stack(), &[Value::Int(6)]);
578578
}
579579

580+
#[test]
581+
fn host_function_registry_caches_static_non_yielding_args_function_pointer_plan_across_vms() {
582+
let source = include_str!("../../examples/example.rss");
583+
let compiled = compile_source(source).expect("compile should succeed");
584+
585+
let mut registry = HostFunctionRegistry::new();
586+
registry.register_static_non_yielding_args("print", 1, |args| {
587+
Ok(CallOutcome::Return(args.to_vec().into()))
588+
});
589+
registry.register_static_non_yielding_args("add_one", 1, static_add_one_args);
590+
let plan = registry
591+
.prepare_plan(&compiled.program.imports)
592+
.expect("plan should build");
593+
594+
let mut vm1 = Vm::new(compiled.program.clone());
595+
registry
596+
.bind_vm_with_plan(&mut vm1, &plan)
597+
.expect("cached static non-yielding args host binding should succeed");
598+
let status1 = vm1.run().expect("vm should run");
599+
assert_eq!(status1, VmStatus::Halted);
600+
assert_eq!(vm1.stack(), &[Value::Int(6)]);
601+
602+
let mut vm2 = Vm::new(compiled.program);
603+
registry
604+
.bind_vm_with_plan(&mut vm2, &plan)
605+
.expect("cached static non-yielding args host binding should succeed");
606+
let status2 = vm2.run().expect("vm should run");
607+
assert_eq!(status2, VmStatus::Halted);
608+
assert_eq!(vm2.stack(), &[Value::Int(6)]);
609+
}
610+
580611
#[test]
581612
fn break_and_continue_outside_loop_are_rejected() {
582613
let break_err = match compile_source("break;") {

0 commit comments

Comments
 (0)