pub struct PooledVm { /* private fields */ }Expand description
RAII handle to a pooled VM. Derefs to fusevm::VM; returns the VM to
the pool on drop.
Methods from Deref<Target = VM>§
Sourcepub fn set_numeric_hook(
&mut self,
hook: Arc<dyn Fn(NumOp, &Value, &Value) -> Result<Value, String> + Sync + Send>,
)
pub fn set_numeric_hook( &mut self, hook: Arc<dyn Fn(NumOp, &Value, &Value) -> Result<Value, String> + Sync + Send>, )
Install a NumericHook, switching this VM to strict numeric mode:
arithmetic that cannot be computed exactly in i64/f64 — a
non-numeric operand, or integer overflow — is handed to hook instead
of being coerced or wrapped.
Strict mode also constrains the JIT, which otherwise coerces and wraps
in native code exactly like the default interpreter: the block tier is
skipped whenever a live slot holds a non-numeric value, and JIT-compiled
integer Add/Sub/Mul are emitted with overflow checks that bail back
to the interpreter (where the hook runs). Native code compiled in strict
mode is cached separately from the coercing kind, so the two never mix.
Sourcepub fn is_strict_numeric(&self) -> bool
pub fn is_strict_numeric(&self) -> bool
Whether a NumericHook is installed (strict numeric mode).
Sourcepub fn set_fixnum_range(&mut self, lo: i64, hi: i64)
pub fn set_fixnum_range(&mut self, lo: i64, hi: i64)
Narrow the range the VM keeps as a native Value::Int (strict mode only).
A Lisp whose integers are tagged has fewer than 64 bits for a fixnum —
Emacs gets 62, so most-positive-fixnum is 2^61-1 — and an arithmetic
result outside that range is a bignum, even though it still fits an
i64. Setting the range makes strict mode delegate those results to the
NumericHook alongside true i64 overflow, so the host can widen them.
JIT-compiled code carries the same bounds check (two ALU ops folded into
the overflow accumulator — still no branch on the hot path).
Without this, the host would see only i64 overflow and integers in the
2^61..2^63 band would masquerade as fixnums.
Sourcepub fn enable_tracing_jit(&mut self)
pub fn enable_tracing_jit(&mut self)
Enable the tracing JIT for this VM. After this call, hot loops (loops crossing the backedge threshold) will be recorded and JIT- compiled at runtime; subsequent iterations dispatch through the compiled trace.
Phase 1 limits: only int-slot loops with a single backward branch and no internal jumps are traceable. Loops outside that envelope continue to run in the interpreter.
Sourcepub fn disable_tracing_jit(&mut self)
pub fn disable_tracing_jit(&mut self)
Disable the tracing JIT. Existing compiled traces remain in the thread-local cache but are no longer consulted from this VM.
Sourcepub fn reset(&mut self, chunk: Chunk)
pub fn reset(&mut self, chunk: Chunk)
Reset the VM for re-use with a new chunk, preserving internal
Vec allocations to avoid the construction cost of VM::new.
State that’s cleared:
- Value stack (truncated, capacity preserved)
- Frame stack (rebuilt with one entry pointing at the new chunk)
- Globals (resized to match the new chunk’s name pool)
- Instruction pointer, halted flag, exit status
- Tracing JIT recorder / slot buffers / deopt info
- Cached block-JIT eligibility (the new chunk has a different hash)
State that’s preserved:
- Tracing JIT enabled flag
- Extension handlers (
ext_handler,ext_wide_handler) - Builtin table
- Shell host
This pairs with VMPool for hot-path callers that run many
chunks back-to-back and want to skip the per-call allocation cost
of VM::new.
Sourcepub fn set_shell_host(&mut self, host: Box<dyn ShellHost>)
pub fn set_shell_host(&mut self, host: Box<dyn ShellHost>)
Register the frontend shell host. Replaces any prior host.
Sourcepub fn set_awk_host(&mut self, host: Box<dyn AwkHost>)
pub fn set_awk_host(&mut self, host: Box<dyn AwkHost>)
Register the frontend AWK host. Replaces any prior host. The VM then
routes the reserved AWK op range to it (see crate::awk_host::AwkHost).
Sourcepub fn awk_signal(&self) -> Option<u8>
pub fn awk_signal(&self) -> Option<u8>
AWK control-flow signal raised by the most recent run(), if any. An
awk frontend reads this after run() returns to map Op::AwkSignal
codes (awk_builtins::signal::{NEXT,NEXTFILE,EXIT}) onto its own
record/file/exit control flow. None when no signal was raised (always
the case for zshrs/stryke, which never emit Op::AwkSignal).
Sourcepub fn set_extension_handler(
&mut self,
handler: Box<dyn FnMut(&mut VM, u16, u8) + Send>,
)
pub fn set_extension_handler( &mut self, handler: Box<dyn FnMut(&mut VM, u16, u8) + Send>, )
Register a handler for Op::Extended(id, arg) opcodes.
Sourcepub fn set_extension_wide_handler(
&mut self,
handler: Box<dyn FnMut(&mut VM, u16, usize) + Send>,
)
pub fn set_extension_wide_handler( &mut self, handler: Box<dyn FnMut(&mut VM, u16, usize) + Send>, )
Register a handler for Op::ExtendedWide(id, payload) opcodes.
Sourcepub fn register_builtin(&mut self, id: u16, handler: fn(&mut VM, u8) -> Value)
pub fn register_builtin(&mut self, id: u16, handler: fn(&mut VM, u8) -> Value)
Register a builtin function by ID. CallBuiltin(id, argc) dispatches
directly through the function pointer — no name lookup at runtime.
Sourcepub fn run_builtin_by_name(
&mut self,
name: &str,
args: &[String],
) -> Option<Value>
pub fn run_builtin_by_name( &mut self, name: &str, args: &[String], ) -> Option<Value>
Run a shell builtin by name at run time — the runtime analog of the
compile-time Op::CallBuiltin opcode. The compiler resolves a literal
command name to a builtin id and emits CallBuiltin, so builtins only
dispatch for names known at compile time. A host that resolves a name
only at run time — builtin NAME, $var command indirection, eval
of a computed name — needs this to reach the same builtins.
Resolves name via crate::shell_builtins::builtin_id, pushes args
as string values in argument order (identical to what the compiler emits
ahead of CallBuiltin, which the handler’s arg-pop reverses back), then
invokes the registered handler and returns its status value. Returns
None when name is not a known builtin or has no registered handler,
so the caller falls through to function / external lookup.
Sourcepub fn request_halt(&mut self)
pub fn request_halt(&mut self)
Externally request the VM to halt after the current op finishes.
Used by host-side shell semantics like set -e post-command checks
and exit from inside builtins to stop dispatch at a safe point.
Sourcepub fn push(&mut self, val: Value)
pub fn push(&mut self, val: Value)
Push val onto the value stack. Inlined for hot-path callers
(extension handlers, builtin shims) that bypass the dispatch
loop’s own push.
Sourcepub fn pop(&mut self) -> Value
pub fn pop(&mut self) -> Value
Pop the top of the value stack, returning Value::Undef if the
stack is empty. Returning Undef rather than panicking matches
Perl’s “underflow is undef” semantic and lets extension/builtin
handlers stay panic-free under malformed bytecode.
Sourcepub fn peek(&self) -> &Value
pub fn peek(&self) -> &Value
Borrow the top of the value stack without popping. Returns a
reference to Value::Undef when the stack is empty.
Sourcepub fn run(&mut self) -> VMResult
pub fn run(&mut self) -> VMResult
Execute the loaded chunk until completion or error.
Phase 10: tiered auto-dispatch. When tracing_jit is enabled the
VM consults all three Cranelift tiers in priority order:
- Block JIT — if the entire chunk is block-eligible, the
block-JIT cache returns
Some(result)after its own warmup threshold and the whole chunk runs in native code with zero interpreter dispatch. - Tracing JIT — when block JIT doesn’t apply, the dispatch loop runs with the recorder armed at backward branches; hot loops compile to traces that take over subsequent iterations.
- Interpreter — fallback for cold code and chunks neither tier handles.
Block JIT is tried first because, when it applies, it has zero VM-side overhead (direct fn-ptr through the slot pointer). For chunks block JIT can’t take, control falls through to the interpreter with tracing JIT integrated. The two tiers don’t compete on the same chunk: block-eligible chunks short-circuit before tracing JIT records anything.
Sourcepub fn get_slot(&self, slot: u16) -> Value
pub fn get_slot(&self, slot: u16) -> Value
Read a slot from the current (top) call frame.
Returns Value::Undef when there is no active frame or the slot
index is out of range. Public so frontend extension handlers
(set_extension_handler) can read slot operands without reaching
into frames directly.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for PooledVm
impl !Sync for PooledVm
impl !UnwindSafe for PooledVm
impl Freeze for PooledVm
impl Send for PooledVm
impl Unpin for PooledVm
impl UnsafeUnpin for PooledVm
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<F, W, T, D> Deserialize<With<T, W>, D> for F
impl<F, W, T, D> Deserialize<With<T, W>, D> for F
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more