pub struct Vm<'a> {
pub step_limit: u64,
pub steps: u64,
pub pure_memo_hits: u64,
pub pure_memo_misses: u64,
pub pure_memo_skips: u64,
pub stack_record_allocs: u64,
pub stack_record_heap_fallbacks: u64,
pub heap_record_allocs: u64,
/* private fields */
}Fields§
§step_limit: u64Soft cap to avoid runaway computations in tests.
steps: u64§pure_memo_hits: u64Diagnostic counters for --trace observability (#229).
pure_memo_misses: u64§pure_memo_skips: u64Number of effect-free calls that skipped the cache entirely because adaptive memoization disabled their function (#229 adaptive). Observability only.
stack_record_allocs: u64Per-Vm counters for #464 acceptance measurement. Incremented
on every Op::MakeRecord / Op::AllocStackRecord dispatch.
The bench reads these to compute the stack-allocation rate
(≥ 60% of records on the stack is the acceptance bar). Cheap
in the hot path — two unconditional u64 increments per record.
stack_record_heap_fallbacks: u64§heap_record_allocs: u64Implementations§
Source§impl<'a> Vm<'a>
impl<'a> Vm<'a>
pub fn new(program: &'a Program) -> Self
pub fn with_handler( program: &'a Program, handler: Box<dyn EffectHandler + 'a>, ) -> Self
pub fn set_tracer(&mut self, tracer: Box<dyn Tracer + 'a>)
Sourcepub fn set_step_limit(&mut self, limit: u64)
pub fn set_step_limit(&mut self, limit: u64)
Cap the number of opcode dispatches before the VM aborts with
step limit exceeded. Useful as a runtime DoS guard against
untrusted code (e.g. the agent-tool sandbox, where an LLM
could emit list.fold(list.range(0, 1_000_000_000), …) to hang
the host). Default is 10_000_000.
pub fn call(&mut self, name: &str, args: Vec<Value>) -> Result<Value, VmError>
Sourcepub fn invoke_closure_value(
&mut self,
closure: Value,
args: Vec<Value>,
) -> Result<Value, VmError>
pub fn invoke_closure_value( &mut self, closure: Value, args: Vec<Value>, ) -> Result<Value, VmError>
Invoke a Value::Closure by combining its captures with the
supplied call args and dispatching to the underlying function.
Used by the parser interpreter (#221) to call user-supplied
f arguments inside parser.map / parser.and_then nodes.
Sourcepub fn invoke_closure_1(
&mut self,
closure: Value,
arg: Value,
) -> Result<Value, VmError>
pub fn invoke_closure_1( &mut self, closure: Value, arg: Value, ) -> Result<Value, VmError>
Invoke a 1-arg closure without allocating a separate args
Vec (#464 call-overhead). The closure’s own captures Vec
is reused as the combined captures ++ [arg] argument buffer,
so the per-element call in ListMap/ListFilter/SortByKey
allocates at most once (the push) instead of twice (a fresh
vec![arg] plus the extend). Semantically identical to
invoke_closure_value(closure, vec![arg]).
Sourcepub fn invoke_closure_2(
&mut self,
closure: Value,
a: Value,
b: Value,
) -> Result<Value, VmError>
pub fn invoke_closure_2( &mut self, closure: Value, a: Value, b: Value, ) -> Result<Value, VmError>
Invoke a 2-arg closure without a separate args Vec — the
ListFold combiner path. See invoke_closure_1.
Sourcepub fn enter_request_scope(&mut self) -> u64
pub fn enter_request_scope(&mut self) -> u64
Open a request-scoped arena via the underlying
EffectHandler::enter_request_scope (#463 scaffolding).
Runtime layers — net.serve_fn, net.serve_ws,
net.serve_quic — call this immediately before invoking the
user handler closure for a single request. Pair with
exit_request_scope once the response has been built and
any lazy iterators in it have been drained (#477).
Returns the scope id the runtime should pass back to
exit_request_scope. The handler’s default impl returns 0
and the matching exit is a no-op; DefaultHandler’s
implementation actually allocates an arena.
Sourcepub fn exit_request_scope(&mut self, scope_id: u64)
pub fn exit_request_scope(&mut self, scope_id: u64)
Close the request scope opened by enter_request_scope.
Drops the associated arena.
pub fn invoke(&mut self, fn_id: u32, args: Vec<Value>) -> Result<Value, VmError>
Trait Implementations§
Source§impl<'a> ClosureCaller for Vm<'a>
Vm exposes itself as a ClosureCaller so the parser interpreter
can invoke user-supplied closures during a parser.run walk
(#221). The Vm is reentrant for closure invocation: pushing a new
frame onto an active call stack is supported, and the handler
stays in place so any effects the closure body fires dispatch
normally.
impl<'a> ClosureCaller for Vm<'a>
Vm exposes itself as a ClosureCaller so the parser interpreter
can invoke user-supplied closures during a parser.run walk
(#221). The Vm is reentrant for closure invocation: pushing a new
frame onto an active call stack is supported, and the handler
stays in place so any effects the closure body fires dispatch
normally.