Visitar URL original
Isolate interpreter heaps and redesign cyclic garbage collection by 1ndahous3 · Pull Request #8939 · RustPython/RustPython · GitHub
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
1 change: 0 additions & 1 deletion Lib/test/test_gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ def test_function(self):
# is 3 because it includes f's code object.
self.assertIn(gc.collect(), (2, 3))

@unittest.expectedFailure # TODO: RUSTPYTHON; - weakref clear ordering differs from 3.15+
def test_function_tp_clear_leaves_consistent_state(self):
# https://github.com/python/cpython/issues/91636
code = """if 1:
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,6 @@ class D:
del c1, c2, C, D
gc.collect()

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_callback_in_cycle_resurrection(self):
import gc

Expand Down Expand Up @@ -798,7 +797,6 @@ def C_went_away(ignore):
gc.collect()
self.assertEqual(alist, [])

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_callbacks_on_callback(self):
import gc

Expand Down
28 changes: 17 additions & 11 deletions benches/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,23 @@ 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() });
// SAFETY: compilation and execution retain no objects beyond this entry.
unsafe {
builder
.add_native_modules(&defs)
.build()
.enter_unchecked(|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
99 changes: 51 additions & 48 deletions benches/microbenchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,58 +111,61 @@ 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();
interp.enter(|vm| {
let setup_code = vm
.compile(&bench.setup, Mode::Exec, &bench.name)
.expect("Error compiling setup code");
let bench_code = vm
.compile(&bench.code, Mode::Exec, &bench.name)
.expect("Error compiling bench code");

let bench_func = |scope| {
let res: PyResult = vm.run_code_obj(bench_code.clone(), scope);
vm.unwrap_pyresult(res);
};
let defs = rustpython_stdlib::stdlib_module_defs(unsafe { builder.context() });
let interp = unsafe { builder.add_native_modules(&defs) }.build();
// SAFETY: benchmark scopes and code objects are released before leaving.
unsafe {
interp.enter_unchecked(|vm| {
let setup_code = vm
.compile(&bench.setup, Mode::Exec, &bench.name)
.expect("Error compiling setup code");
let bench_code = vm
.compile(&bench.code, Mode::Exec, &bench.name)
.expect("Error compiling bench code");

let bench_func = |scope| {
let res: PyResult = vm.run_code_obj(bench_code.clone(), scope);
vm.unwrap_pyresult(res);
};

let bench_setup = |iterations| {
let scope = vm.new_scope_with_builtins();
if let Some(idx) = iterations {
let bench_setup = |iterations| {
let scope = vm.new_scope_with_builtins();
if let Some(idx) = iterations {
scope
.locals
.as_ref()
.expect("new_scope_with_builtins always provides locals")
.as_object()
.set_item("ITERATIONS", vm.new_pyobj(idx), vm)
.expect("Error adding ITERATIONS local variable");
}
let setup_result = vm.run_code_obj(setup_code.clone(), scope.clone());
vm.unwrap_pyresult(setup_result);
scope
.locals
.as_ref()
.expect("new_scope_with_builtins always provides locals")
.as_object()
.set_item("ITERATIONS", vm.new_pyobj(idx), vm)
.expect("Error adding ITERATIONS local variable");
}
let setup_result = vm.run_code_obj(setup_code.clone(), scope.clone());
vm.unwrap_pyresult(setup_result);
scope
};
};

if bench.iterate {
for idx in iteration_counts() {
group.throughput(Throughput::Elements(idx as u64));
group.bench_with_input(
BenchmarkId::new("rustpython", &bench.name),
&idx,
|b, idx| {
b.iter_batched(
|| bench_setup(Some(*idx)),
bench_func,
BatchSize::LargeInput,
);
},
);
if bench.iterate {
for idx in iteration_counts() {
group.throughput(Throughput::Elements(idx as u64));
group.bench_with_input(
BenchmarkId::new("rustpython", &bench.name),
&idx,
|b, idx| {
b.iter_batched(
|| bench_setup(Some(*idx)),
bench_func,
BatchSize::LargeInput,
);
},
);
}
} else {
group.bench_function(BenchmarkId::new("rustpython", &bench.name), move |b| {
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::LargeInput);
});
}
} else {
group.bench_function(BenchmarkId::new("rustpython", &bench.name), move |b| {
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::LargeInput);
});
}
})
})
}
}

/// `true` when the benchmarks are executed by the CodSpeed runner.
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
4 changes: 2 additions & 2 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 @@ -144,7 +144,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 @@ -61,7 +61,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
2 changes: 1 addition & 1 deletion crates/capi/src/object/pytype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,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.bits() as u32 as c_ulong
ty.effective_flags().bits() as u32 as c_ulong
}

#[unsafe(no_mangle)]
Expand Down
7 changes: 5 additions & 2 deletions crates/capi/src/objimpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ pub unsafe extern "C" fn PyObject_GC_Track(op: *mut PyObject) {
with_vm(|_vm| {
let obj = unsafe { op.assume_borrowed() };
if !obj.is_gc_tracked() {
unsafe { gc_state::gc_state().track_object(obj.into(), gc_state::current_owner()) };
unsafe {
gc_state::gc_state_unchecked()
.track_object(obj.into(), gc_state::current_owner_unchecked())
};
}
})
}
Expand All @@ -20,7 +23,7 @@ pub unsafe extern "C" fn PyObject_GC_UnTrack(op: *mut PyObject) {
with_vm(|_vm| {
let obj = unsafe { op.assume_borrowed() };
if obj.is_gc_tracked() {
unsafe { gc_state::gc_state().untrack_object(obj.into()) };
unsafe { gc_state::gc_state_unchecked().untrack_object(obj.into()) };
}
})
}
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
Loading
Loading