Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use UnsafeCell for pending_tailcall_refs
The VM is per-thread so RefCell's runtime borrow checking is
unnecessary overhead. Replace with UnsafeCell for direct access.

Assisted-by: Claude
  • Loading branch information
youknowone committed Aug 2, 2026
commit 895a53a15eafb7c74d25575673b28d44097cfee9
4 changes: 2 additions & 2 deletions crates/vm/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10665,7 +10665,7 @@ impl ExecutingFrame<'_> {
// the VM side channel, avoiding a per-frame mutex lock on
// temporary_refs.
let callable = self.pop_value();
vm.pending_tailcall_refs.borrow_mut().push(callable);
unsafe { &mut *vm.pending_tailcall_refs.get() }.push(callable);

vm.pending_tailcall_frame
.set(crate::vm::SendPtr(callee_iframe as *mut InterpreterFrame));
Expand Down Expand Up @@ -10720,7 +10720,7 @@ impl ExecutingFrame<'_> {
fastlocals[0] = Some(bound_self);

// Transfer ownership to the trampoline via the VM side channel.
let mut refs = vm.pending_tailcall_refs.borrow_mut();
let refs = unsafe { &mut *vm.pending_tailcall_refs.get() };
refs.push(bound_function);
refs.push(callable);

Expand Down
25 changes: 16 additions & 9 deletions crates/vm/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ pub struct VirtualMachine {
pub(crate) pending_tailcall_frame: Cell<SendPtr<crate::frame::InterpreterFrame>>,
/// Owned references that keep callee raw pointers valid during TailCall.
/// Set by `tailcall_prepare_frame`, drained by the trampoline into
/// its local `owned_refs` Vec. This avoids per-frame mutex lock on
/// `temporary_refs`.
pub(crate) pending_tailcall_refs: RefCell<Vec<PyObjectRef>>,
/// its local `owned_refs` Vec. Uses UnsafeCell because the VM is
/// per-thread and this field is only accessed on the owning thread.
pub(crate) pending_tailcall_refs: core::cell::UnsafeCell<Vec<PyObjectRef>>,
}

/// Non-owning frame pointer for the non-unix threading frames stack.
Expand Down Expand Up @@ -949,7 +949,7 @@ impl VirtualMachine {
callable_cache: CallableCache::default(),
audit_hooks: RefCell::new(vec![]),
pending_tailcall_frame: Cell::new(SendPtr::null()),
pending_tailcall_refs: RefCell::new(Vec::with_capacity(2)),
pending_tailcall_refs: core::cell::UnsafeCell::new(Vec::with_capacity(2)),
};

if vm.state.hash_secret.hash_str("")
Expand Down Expand Up @@ -1443,7 +1443,9 @@ impl VirtualMachine {
debug_assert!(!initial_ptr.is_null());
self.pending_tailcall_frame.set(SendPtr::null());
// Drain the refs that keep the initial callee's raw pointers alive.
let initial_refs = self.pending_tailcall_refs.borrow_mut().drain(..).collect();
let initial_refs = unsafe { &mut *self.pending_tailcall_refs.get() }
.drain(..)
.collect();
frame_stack.push(SuspendedFrame {
iframe: iframe as *mut crate::frame::InterpreterFrame,
entry_state,
Expand All @@ -1460,7 +1462,9 @@ impl VirtualMachine {
let result = crate::frame::run_iframe(callee, self);
match result {
Ok(ExecutionResult::TailCall) => {
let refs = self.pending_tailcall_refs.borrow_mut().drain(..).collect();
let refs = unsafe { &mut *self.pending_tailcall_refs.get() }
.drain(..)
.collect();
frame_stack.push(SuspendedFrame {
iframe: callee_ptr,
entry_state: callee_entry,
Expand Down Expand Up @@ -1509,7 +1513,9 @@ impl VirtualMachine {
let result = crate::frame::run_iframe(caller_iframe, self);
match result {
Ok(ExecutionResult::TailCall) => {
let refs = self.pending_tailcall_refs.borrow_mut().drain(..).collect();
let refs = unsafe { &mut *self.pending_tailcall_refs.get() }
.drain(..)
.collect();
drop(_caller_refs);
frame_stack.push(SuspendedFrame {
iframe: caller_iframe_ptr,
Expand Down Expand Up @@ -1565,8 +1571,9 @@ impl VirtualMachine {
let result = crate::frame::run_iframe(caller_iframe, self);
match result {
Ok(ExecutionResult::TailCall) => {
let refs =
self.pending_tailcall_refs.borrow_mut().drain(..).collect();
let refs = unsafe { &mut *self.pending_tailcall_refs.get() }
.drain(..)
.collect();
drop(_caller_refs);
frame_stack.push(SuspendedFrame {
iframe: caller_iframe_ptr,
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/vm/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ impl VirtualMachine {
callable_cache: self.callable_cache.clone(),
audit_hooks: RefCell::new(vec![]),
pending_tailcall_frame: Cell::new(super::SendPtr::null()),
pending_tailcall_refs: RefCell::new(Vec::with_capacity(2)),
pending_tailcall_refs: core::cell::UnsafeCell::new(Vec::with_capacity(2)),
};
ThreadedVirtualMachine { vm }
}
Expand Down