diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs index 684817e..2c8ef63 100644 --- a/crates/core/src/eval.rs +++ b/crates/core/src/eval.rs @@ -59,9 +59,23 @@ impl Vm { arguments: &[Value], limits: ExecutionLimits, ) -> Result<(Value, Vec), VmError> { + let (value, reads) = + self.call_read_only_precise_with_limits(function, arguments, limits)?; + Ok((value, reads.objects)) + } + + /// Synchronous read-only call with precise observations as well as the + /// conservative object list. Result ownership and hard limits match call(). + /// ReadSet and all identities/value snapshots inside it are borrowed only. + pub fn call_read_only_precise_with_limits( + &mut self, + function: ObjectRef, + arguments: &[Value], + limits: ExecutionLimits, + ) -> Result<(Value, crate::ReadSet), VmError> { let scope = self.objects.begin_read_only(); let result = self.call_with_limits(function, arguments, limits); - let reads = self.objects.end_read_only(scope)?; + let reads = self.objects.end_read_only_precise(scope)?; result.map(|value| (value, reads)) } diff --git a/crates/core/tests/execution.rs b/crates/core/tests/execution.rs index a3e08f5..58a1a39 100644 --- a/crates/core/tests/execution.rs +++ b/crates/core/tests/execution.rs @@ -1749,6 +1749,18 @@ fn named_reads_ignore_unrelated_globals_but_track_missing_shadow_and_payload_kin assert!(reads.contains(&globals) && reads.contains(&builtins)); vm.release_value(value).unwrap(); vm.dict_set(globals, text("_"), text("unrelated")).unwrap(); + let (value, synchronous) = vm + .call_read_only_precise_with_limits(function, &[], ExecutionLimits::default()) + .unwrap(); + assert_eq!(value, text("builtin")); + assert_eq!(synchronous.dependencies, dependencies); + assert_eq!(synchronous.objects, reads); + vm.release_value(value).unwrap(); + let (value, conservative) = vm + .call_read_only_with_limits(function, &[], ExecutionLimits::default()) + .unwrap(); + assert_eq!(conservative, reads); + vm.release_value(value).unwrap(); assert!( dependencies .iter()