Skip to content
Draft
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
1 change: 0 additions & 1 deletion Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1865,7 +1865,6 @@ class D(C):
self.assertEqual(b.foo, 3)
self.assertEqual(b.__class__, D)

@unittest.expectedSuccess # TODO: RUSTPYTHON; The `expectedFailure` here is from CPython, so this test must fail
@unittest.expectedFailure
def test_bad_new(self):
self.assertRaises(TypeError, object.__new__)
Expand Down
22 changes: 12 additions & 10 deletions benches/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,19 @@ fn bench_rustpython_code(b: &mut Bencher<'_>, name: &str, source: &str) {
settings.write_bytecode = false;
settings.user_site_directory = false;
let builder = Interpreter::builder(settings);
let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
builder.add_native_modules(&defs).build().enter(|vm| {
// Note: bench_cpython is both compiling and executing the code.
// As such we compile the code in the benchmark loop as well.
b.iter(|| {
let code = vm.compile(source, Mode::Exec, name).unwrap();
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code, scope);
vm.unwrap_pyresult(res);
let defs = rustpython_stdlib::stdlib_module_defs(unsafe { builder.context() });
unsafe { builder.add_native_modules(&defs) }
.build()
.enter(|vm| {
// Note: bench_cpython is both compiling and executing the code.
// As such we compile the code in the benchmark loop as well.
b.iter(|| {
let code = vm.compile(source, Mode::Exec, name).unwrap();
let scope = vm.new_scope_with_builtins();
let res: PyResult = vm.run_code_obj(code, scope);
vm.unwrap_pyresult(res);
})
})
})
}

pub fn benchmark_file_execution(
Expand Down
4 changes: 2 additions & 2 deletions benches/microbenchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ fn bench_rustpython_code(group: &mut BenchmarkGroup<'_, WallTime>, bench: &Micro
settings.user_site_directory = false;

let builder = Interpreter::builder(settings);
let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
let interp = builder.add_native_modules(&defs).build();
let defs = rustpython_stdlib::stdlib_module_defs(unsafe { builder.context() });
let interp = unsafe { builder.add_native_modules(&defs) }.build();
interp.enter(|vm| {
let setup_code = vm
.compile(&bench.setup, Mode::Exec, &bench.name)
Expand Down
4 changes: 3 additions & 1 deletion crates/capi/src/bytearrayobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ pub unsafe extern "C" fn PyByteArray_Size(bytearray: *mut PyObject) -> isize {
pub unsafe extern "C" fn PyByteArray_AsString(bytearray: *mut PyObject) -> *mut c_char {
with_vm(|vm| {
let bytearray = unsafe { bytearray.assume_borrowed_and_cast::<PyByteArray>(vm) }?;
Ok(bytearray.borrow_buf_mut().as_mut_ptr())
// SAFETY: the C caller owns the PyByteArray_AsString lifetime and
// synchronization contract; no resizable Rust Vec escapes this API.
Ok(unsafe { bytearray.as_mut_ptr_unchecked() })
})
}

Expand Down
2 changes: 1 addition & 1 deletion crates/capi/src/ceval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ mod tests {
#[pyfunction]
fn legacy_locals_is_frame_mapping() -> bool {
let locals = super::PyEval_GetLocals();
rustpython_vm::vm::thread::with_current_vm(|vm| {
crate::pystate::with_current_vm(|vm| {
let frame = vm.current_frame().unwrap();
core::ptr::eq(
locals.cast_const(),
Expand Down
10 changes: 3 additions & 7 deletions crates/capi/src/descrobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::pystate::with_vm;
use crate::util::{CStrExt, FfiPtrExt};
use core::ffi::{c_char, c_int, c_void};
use rustpython_vm::builtins::{
DescriptorMemberDef, MemberAccess, MemberKind, PyDescriptorOwned, PyGetSet, PyMappingProxy,
DescriptorMemberDef, MemberAccess, MemberKind, PyDescriptor, PyGetSet, PyMappingProxy,
PyMemberDescriptor, PyMemberFlags, PyType,
};
use rustpython_vm::common::lock::PyRwLock;
Expand Down Expand Up @@ -40,11 +40,7 @@ impl PyGetSetDef {
}
})
}
pub(crate) fn build(
&self,
ty: &'static Py<PyType>,
vm: &VirtualMachine,
) -> PyResult<PyRef<PyGetSet>> {
pub(crate) fn build(&self, ty: &Py<PyType>, vm: &VirtualMachine) -> PyResult<PyRef<PyGetSet>> {
let name = unsafe { self.name.try_as_str(vm) }?;
let closure = self.closure as usize;

Expand Down Expand Up @@ -167,7 +163,7 @@ impl PyMemberDef {
});

let descriptor = PyMemberDescriptor {
common: PyDescriptorOwned {
common: PyDescriptor {
typ: ty.to_owned(),
name: vm.ctx.intern_str(name),
qualname: PyRwLock::new(None),
Expand Down
2 changes: 1 addition & 1 deletion crates/capi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn init_main_interpreter(interpreter: Interpreter) {
let mut interp = get_main_interpreter();
assert!(interp.is_none(), "Main interpreter is already set");
// Safety: Interpreter was not initialized before, so we can safely assume the statics are not used
unsafe { init_exception_statics(&Context::genesis().exceptions) };
unsafe { init_exception_statics(&Context::genesis_unchecked().exceptions) };
*interp = Some(interpreter);
MAIN_INTERP_PTR.store(
interp.as_ref().unwrap() as *const _ as *mut _,
Expand Down
17 changes: 5 additions & 12 deletions crates/capi/src/object/pytype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub unsafe extern "C" fn Py_IS_TYPE(op: *mut PyObject, ty: *mut PyTypeObject) ->
#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_GetFlags(ptr: *mut PyTypeObject) -> c_ulong {
let ty = unsafe { ptr.assume_borrowed() };
ty.slots.flags.load().bits() as u32 as c_ulong
ty.effective_flags().bits() as u32 as c_ulong
}

#[unsafe(no_mangle)]
Expand Down Expand Up @@ -227,27 +227,20 @@ pub extern "C" fn PyType_FromSlots(slots: *const PySlot) -> *mut PyObject {
|msg| vm.new_system_error(format!("Failed to create type from slots: {msg}")),
)?;

let attrs = &class.attributes;
let class_static = unsafe { &*((&*class) as *const _) };
let attrs = class.attributes();
for (name, method) in methods {
attrs.insert(
vm.ctx.intern_str(name),
method.build_method(class_static, vm).into(),
method.build_method(&class, vm).into(),
);
}
for getset in getsets {
let name = unsafe { getset.name.try_as_str(vm)? };
attrs.insert(
vm.ctx.intern_str(name),
getset.build(class_static, vm)?.into(),
);
attrs.insert(vm.ctx.intern_str(name), getset.build(&class, vm)?.into());
}
for member in members {
let name = unsafe { member.name.try_as_str(vm)? };
attrs.insert(
vm.ctx.intern_str(name),
member.build(class_static, vm)?.into(),
);
attrs.insert(vm.ctx.intern_str(name), member.build(&class, vm)?.into());
}

Ok(class)
Expand Down
6 changes: 3 additions & 3 deletions crates/capi/src/pyframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ mod tests {
use rustpython_vm::AsObject;

fn current_frame_ptr() -> *mut super::PyFrameObject {
rustpython_vm::vm::thread::with_current_vm(|vm| {
crate::pystate::with_current_vm(|vm| {
vm.current_frame()
.unwrap()
.as_object()
Expand Down Expand Up @@ -83,7 +83,7 @@ mod tests {

#[pyfunction]
fn frame_globals_is_globals() -> bool {
rustpython_vm::vm::thread::with_current_vm(|vm| {
crate::pystate::with_current_vm(|vm| {
let frame = vm.current_frame().unwrap();
let got = unsafe { super::PyFrame_GetGlobals(current_frame_ptr()) };
let expected = frame.iframe().globals().as_object().as_raw();
Expand All @@ -95,7 +95,7 @@ mod tests {

#[pyfunction]
fn frame_builtins_is_builtins() -> bool {
rustpython_vm::vm::thread::with_current_vm(|vm| {
crate::pystate::with_current_vm(|vm| {
let frame = vm.current_frame().unwrap();
let got = unsafe { super::PyFrame_GetBuiltins(current_frame_ptr()) };
let expected = frame.iframe().builtins().as_object().as_raw();
Expand Down
30 changes: 15 additions & 15 deletions crates/capi/src/pylifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::pystate::ensure_thread_has_vm_attached;
use alloc::ffi::CString;
use core::ffi::{c_char, c_int, c_ulong};
use core::sync::atomic::{AtomicPtr, Ordering};
use rustpython_vm::common::rc::PyRc;
use rustpython_vm::stdlib::sys;
use rustpython_vm::version::{MAJOR, MICRO, MINOR, RUSTPYTHON_BUILD_INFO, VERSION_HEX};
use rustpython_vm::vm::thread::ThreadedVirtualMachine;
Expand All @@ -19,7 +18,7 @@ pub(crate) fn request_vm_from_interpreter() -> ThreadedVirtualMachine {
get_main_interpreter()
.as_ref()
.expect("Interpreter not initialized")
.enter(|vm| vm.new_thread())
.new_thread()
}

#[unsafe(no_mangle)]
Expand All @@ -40,20 +39,21 @@ pub extern "C" fn Py_InitializeEx(_initsigs: c_int) {
let mut interp = get_main_interpreter();
if interp.is_none() {
// Safety: Interpreter was not initialized before, so we can safely assume the statics are not used
unsafe { init_exception_statics(&Context::genesis().exceptions) };
unsafe { init_exception_statics(&Context::genesis_unchecked().exceptions) };
let builder = Interpreter::builder(Default::default());
let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
*interp = builder
.add_native_modules(&defs)
.init_hook(|vm| {
let state = PyRc::get_mut(&mut vm.state).unwrap();
let path = rustpython_pylib::LIB_PATH.to_owned();

state.config.paths.stdlib_dir = Some(path.clone());
state.config.paths.module_search_paths.insert(0, path);
})
.build()
.into();
let defs = rustpython_stdlib::stdlib_module_defs(unsafe { builder.context() });
*interp = unsafe {
builder
.add_native_modules(&defs)
.configure(|config| {
let path = rustpython_pylib::LIB_PATH.to_owned();

config.paths.stdlib_dir = Some(path.clone());
config.paths.module_search_paths.insert(0, path);
})
.build()
.into()
};
MAIN_INTERP_PTR.store(
interp.as_ref().unwrap() as *const _ as *mut _,
Ordering::Release,
Expand Down
20 changes: 14 additions & 6 deletions crates/capi/src/pystate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ use core::ffi::c_int;
use core::sync::atomic::Ordering;
use rustpython_vm::vm::thread::{
CurrentVmAttachState, SavedThreadState, attach_current_thread, release_current_thread,
restore_current_thread, save_current_thread, with_current_vm,
restore_current_thread_unchecked, save_current_thread_unchecked,
};
use rustpython_vm::{Interpreter, VirtualMachine};

// Native C API callbacks already require an attached interpreter and follow
// CPython's ownership rules. Keep that boundary inside this crate.
pub(crate) fn with_current_vm<R>(f: impl FnOnce(&VirtualMachine) -> R) -> R {
unsafe { rustpython_vm::vm::thread::with_current_vm_unchecked(f) }
}

pub(crate) fn with_vm<R: FfiResult<O>, O>(f: impl FnOnce(&VirtualMachine) -> R) -> O {
with_current_vm(|vm| f(vm).into_output(vm))
}
Expand All @@ -28,7 +34,8 @@ pub struct PyThreadState {
/// Make sure this thread has a running vm attached. This only creates a new vm if we don't already
/// have one. So this will only create a new vm when we are in a new thread created outside RustPython.
pub(crate) fn ensure_thread_has_vm_attached() -> CurrentVmAttachState {
attach_current_thread(request_vm_from_interpreter)
// SAFETY: the C API pairs Ensure/Release on the calling native thread.
unsafe { attach_current_thread(request_vm_from_interpreter) }
}

#[unsafe(no_mangle)]
Expand All @@ -42,7 +49,7 @@ pub extern "C" fn PyGILState_Ensure() -> PyGILState_STATE {
#[unsafe(no_mangle)]
pub extern "C" fn PyGILState_Release(state: PyGILState_STATE) {
if state == PYGILSTATE_UNLOCKED {
release_current_thread(CurrentVmAttachState::Attached);
unsafe { release_current_thread(CurrentVmAttachState::Attached) };
}
}

Expand All @@ -51,7 +58,7 @@ pub extern "C" fn PyEval_SaveThread() -> *mut PyThreadState {
let interp = PyInterpreterState_Get();
let state = Box::new(PyThreadState {
interp,
vm: save_current_thread(),
vm: unsafe { save_current_thread_unchecked() },
});
Box::into_raw(state)
}
Expand All @@ -62,7 +69,7 @@ pub unsafe extern "C" fn PyEval_RestoreThread(state: *mut PyThreadState) {
// SAFETY: PyEval_SaveThread returns this allocation and CPython's API
// requires callers to restore exactly that thread state once.
let state = unsafe { Box::from_raw(state) };
restore_current_thread(state.vm);
unsafe { restore_current_thread_unchecked(state.vm) };
}

#[unsafe(no_mangle)]
Expand All @@ -87,10 +94,11 @@ pub extern "C" fn PyInterpreterState_GetID(interp: *mut PyInterpreterState) -> i

#[cfg(test)]
mod tests {
use super::with_current_vm;
use crate::get_main_interpreter;
use crate::pystate::{PyGILState_Ensure, PyGILState_Release};
use pyo3::prelude::*;
use rustpython_vm::vm::thread::{current_vm_is_set, with_current_vm};
use rustpython_vm::vm::thread::current_vm_is_set;

#[test]
fn new_thread() {
Expand Down
Loading
Loading