X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions .cspell.dict/cpython.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ CONVFUNC
convparam
copyslot
cpucount
datastack
defaultdict
denom
deopt
Expand Down Expand Up @@ -118,13 +119,15 @@ mult
multibytecodec
nameobj
nameop
ncells
nconsts
newargs
newfree
NEWLOCALS
newsemlockobject
nfrees
nkwargs
nlocalsplus
nkwelts
Nondescriptor
noninteger
Expand Down Expand Up @@ -192,6 +195,7 @@ testconsole
ticketer
tmptype
tok_oldval
tstate
tvars
typeobject
typeparam
Expand Down
2 changes: 1 addition & 1 deletion crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license.workspace = true
[features]
default = ["std"]
std = []
threading = ["parking_lot"]
threading = ["parking_lot", "std"]
wasm_js = ["getrandom/wasm_js"]

[dependencies]
Expand Down
18 changes: 14 additions & 4 deletions crates/common/src/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,28 @@ cfg_if::cfg_if! {
if #[cfg(feature = "threading")] {
pub use parking_lot::{RawMutex, RawRwLock, RawThreadId};

pub use std::sync::{LazyLock, OnceLock as OnceCell};
pub use std::sync::OnceLock as OnceCell;
pub use core::cell::LazyCell;
} else {
mod cell_lock;
pub use cell_lock::{RawCellMutex as RawMutex, RawCellRwLock as RawRwLock, SingleThreadId as RawThreadId};

pub use core::cell::{LazyCell, OnceCell};
}
}

/// `core::cell::LazyCell` with `Sync` for use in `static` items.
/// SAFETY: Without threading, there can be no concurrent access.
// LazyLock: uses std::sync::LazyLock when std is available (even without
// threading, because Rust test runner uses parallel threads).
// Without std, uses a LazyCell wrapper (truly single-threaded only).
cfg_if::cfg_if! {
if #[cfg(any(feature = "threading", feature = "std"))] {
pub use std::sync::LazyLock;
} else {
pub struct LazyLock<T, F = fn() -> T>(core::cell::LazyCell<T, F>);
// SAFETY: Without threading, there can be no concurrent access.
// SAFETY: This branch is only active when both "std" and "threading"
// features are absent — i.e., truly single-threaded no_std environments
// (e.g., embedded or bare-metal WASM). Without std, the Rust runtime
// cannot spawn threads, so Sync is trivially satisfied.
unsafe impl<T, F> Sync for LazyLock<T, F> {}

impl<T, F: FnOnce() -> T> LazyLock<T, F> {
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/builtins/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ impl Py<Frame> {
// Clear fastlocals
// SAFETY: Frame is not executing (detached or stopped).
{
let fastlocals = unsafe { self.fastlocals.borrow_mut() };
let fastlocals = unsafe { self.fastlocals_mut() };
for slot in fastlocals.iter_mut() {
*slot = None;
}
Expand Down
41 changes: 33 additions & 8 deletions crates/vm/src/builtins/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl PyFunction {
// https://github.com/python/cpython/blob/main/Python/ceval.c#L3681

// SAFETY: Frame was just created and not yet executing.
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
let fastlocals = unsafe { frame.fastlocals_mut() };

let mut args_iter = func_args.args.into_iter();

Expand Down Expand Up @@ -562,6 +562,7 @@ impl Py<PyFunction> {

let is_gen = code.flags.contains(bytecode::CodeFlags::GENERATOR);
let is_coro = code.flags.contains(bytecode::CodeFlags::COROUTINE);
let use_datastack = !(is_gen || is_coro);

// Construct frame:
let frame = Frame::new(
Expand All @@ -570,6 +571,7 @@ impl Py<PyFunction> {
self.builtins.clone(),
self.closure.as_ref().map_or(&[], |c| c.as_slice()),
Some(self.to_owned().into()),
use_datastack,
vm,
)
.into_ref(&vm.ctx);
Expand All @@ -594,7 +596,16 @@ impl Py<PyFunction> {
frame.set_generator(&obj);
Ok(obj)
}
(false, false) => vm.run_frame(frame),
(false, false) => {
let result = vm.run_frame(frame.clone());
// Release data stack memory after frame execution completes.
unsafe {
if let Some(base) = frame.materialize_localsplus() {
vm.datastack_pop(base);
}
}
result
}
}
}

Expand Down Expand Up @@ -665,28 +676,35 @@ impl Py<PyFunction> {
self.builtins.clone(),
self.closure.as_ref().map_or(&[], |c| c.as_slice()),
Some(self.to_owned().into()),
true, // Always use datastack (invoke_exact_args is never gen/coro)
vm,
)
.into_ref(&vm.ctx);

// Move args directly into fastlocals (no clone/refcount needed)
{
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
let fastlocals = unsafe { frame.fastlocals_mut() };
for (slot, arg) in fastlocals.iter_mut().zip(args.drain(..)) {
*slot = Some(arg);
}
}

// Handle cell2arg
if let Some(cell2arg) = code.cell2arg.as_deref() {
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
let fastlocals = unsafe { frame.fastlocals_mut() };
for (cell_idx, arg_idx) in cell2arg.iter().enumerate().filter(|(_, i)| **i != -1) {
let x = fastlocals[*arg_idx as usize].take();
frame.set_cell_contents(cell_idx, x);
}
}

vm.run_frame(frame)
let result = vm.run_frame(frame.clone());
unsafe {
if let Some(base) = frame.materialize_localsplus() {
vm.datastack_pop(base);
}
}
result
}
}

Expand Down Expand Up @@ -1291,26 +1309,33 @@ pub(crate) fn vectorcall_function(
zelf.builtins.clone(),
zelf.closure.as_ref().map_or(&[], |c| c.as_slice()),
Some(zelf.to_owned().into()),
true, // Always use datastack (is_simple excludes gen/coro)
vm,
)
.into_ref(&vm.ctx);

{
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
let fastlocals = unsafe { frame.fastlocals_mut() };
for (slot, arg) in fastlocals.iter_mut().zip(args.drain(..nargs)) {
*slot = Some(arg);
}
}

if let Some(cell2arg) = code.cell2arg.as_deref() {
let fastlocals = unsafe { frame.fastlocals.borrow_mut() };
let fastlocals = unsafe { frame.fastlocals_mut() };
for (cell_idx, arg_idx) in cell2arg.iter().enumerate().filter(|(_, i)| **i != -1) {
let x = fastlocals[*arg_idx as usize].take();
frame.set_cell_contents(cell_idx, x);
}
}

return vm.run_frame(frame);
let result = vm.run_frame(frame.clone());
unsafe {
if let Some(base) = frame.materialize_localsplus() {
vm.datastack_pop(base);
}
}
return result;
}

// SLOW PATH: construct FuncArgs from owned Vec and delegate to invoke()
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/builtins/super.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Initializer for PySuper {
return Err(vm.new_runtime_error("super(): no arguments"));
}
// SAFETY: Frame is current and not concurrently mutated.
let obj = unsafe { frame.fastlocals.borrow() }[0]
let obj = unsafe { frame.fastlocals() }[0]
.clone()
.or_else(|| {
if let Some(cell2arg) = frame.code.cell2arg.as_deref() {
Expand Down
Loading
Loading
X Tutup