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
3 changes: 2 additions & 1 deletion crates/capi/src/descrobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ impl PyMemberDef {
let mut flags = self.flags;
if flags & PY_RELATIVE_OFFSET != 0 {
// type creation adds tp_basicsize and clears the flag before GetOne.
offset += (rustpython_vm::object::SIZEOF_PYOBJECT_HEAD + ty.slots.basicsize) as isize;
// `slots.basicsize` is already the full tp_basicsize.
offset += ty.slots.basicsize as isize;
flags &= !PY_RELATIVE_OFFSET;
}

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 @@ -59,7 +59,7 @@ pub unsafe extern "C" fn PyType_GetFullyQualifiedName(ptr: *mut PyTypeObject) ->
with_vm(|vm| {
let ty = unsafe { ptr.assume_borrowed() };
let qualname = ty.__qualname__(vm).try_downcast::<PyStr>(vm)?;
let module = ty.__module__(vm);
let module = ty.__module__(vm)?;

if let Some(module) = module.downcast_ref::<PyStr>()
&& module.as_wtf8() != "builtins"
Expand Down
5 changes: 5 additions & 0 deletions crates/compiler-core/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ bitflags! {
}
}

const _: () = {
assert!(core::mem::size_of::<CodeFlags>() == core::mem::size_of::<i32>());
assert!(core::mem::align_of::<CodeFlags>() == core::mem::align_of::<i32>());
};

impl CodeFlags {
/// The `__future__` flags that `compile()` accepts and that a compiled code
/// object inherits from its caller. Mirrors `PyCF_MASK`.
Expand Down
15 changes: 11 additions & 4 deletions crates/derive-impl/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,12 +551,14 @@ fn generate_class_def(
}
});
// If repr(transparent) with a base, the type has the same memory layout as base,
// so basicsize should be 0 (no additional space beyond the base type)
// Otherwise, basicsize = sizeof(payload). The header size is added in __basicsize__ getter.
// so basicsize stays 0 and type creation copies the base's full tp_basicsize.
// Otherwise, basicsize is the object header plus the payload.
let basicsize = if is_repr_transparent && base.is_some() {
quote!(0)
} else {
quote!(std::mem::size_of::<#ident>())
quote!(
::rustpython_vm::object::SIZEOF_PYOBJECT_HEAD + ::core::mem::size_of::<#ident>()
)
};
if base.is_some() && is_pystruct {
bail_span!(ident, "PyStructSequence cannot have `base` class attr",);
Expand Down Expand Up @@ -914,8 +916,13 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: &Item) -> Resul
None => quote! {},
};

let module_attr = match class_meta.optional_module()? {
Some(module) => quote! { module = #module, },
None => quote! { module = false, },
};

let ret = quote! {
#[pyclass(module = false, name = #class_name, base = #base_class_name #traverse_attr #payload_attr)]
#[pyclass(#module_attr name = #class_name, base = #base_class_name #traverse_attr #payload_attr)]
#item
#impl_pyclass
};
Expand Down
9 changes: 9 additions & 0 deletions crates/derive-impl/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,15 @@ impl ExceptionItemMeta {
pub(crate) fn has_impl(&self) -> Result<bool> {
self.inner()._bool("impl")
}

/// `module = "..."` when present. Omitted means a builtin exception.
pub(crate) fn optional_module(&self) -> Result<Option<String>> {
if self.inner().meta_map.contains_key("module") {
self.module()
} else {
Ok(None)
}
}
}

impl core::ops::Deref for ExceptionItemMeta {
Expand Down
2 changes: 2 additions & 0 deletions crates/host_env/src/multiprocessing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use libc::sem_t;
use nix::errno::Errno;

#[cfg(unix)]
#[repr(transparent)]
#[derive(Debug)]
pub struct SemHandle {
raw: *mut sem_t,
Expand Down Expand Up @@ -118,6 +119,7 @@ pub type RawSocket = SOCKET;
pub const INFINITE_TIMEOUT: u32 = INFINITE;

#[cfg(windows)]
#[repr(transparent)]
#[derive(Debug)]
pub struct SemHandle {
raw: HANDLE,
Expand Down
56 changes: 27 additions & 29 deletions crates/stdlib/src/bz2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ pub(crate) use _bz2::module_def;
mod _bz2 {
use crate::compression::DecompressorArgs;
use crate::vm::{
Py, VirtualMachine,
builtins::{PyBaseExceptionRef, PyBytesRef, PyType},
Py, PyObject, VirtualMachine,
builtins::{PyBaseExceptionRef, PyBytes, PyType},
common::lock::PyMutex,
function::ArgBytesLike,
object::PyResult,
object::{PyAtomicRef, PyResult},
types::Constructor,
};
use alloc::fmt;
use core::sync::atomic::{AtomicBool, Ordering};
use rustpython_common::compression::bz2 as backend;

fn map_bz2_error(error: backend::Bz2Error, vm: &VirtualMachine) -> PyBaseExceptionRef {
Expand All @@ -31,15 +32,6 @@ mod _bz2 {

struct PyBZ2DecompressorInner {
decompress: backend::Decompressor,
unused_data: PyBytesRef,
}

impl PyBZ2DecompressorInner {
fn sync_visible_state(&mut self, vm: &VirtualMachine) {
if self.unused_data.as_bytes() != self.decompress.unused_data() {
self.unused_data = vm.ctx.new_bytes(self.decompress.unused_data().to_vec());
}
}
}

#[pyattr]
Expand All @@ -48,6 +40,14 @@ mod _bz2 {
struct BZ2Decompressor {
#[pytraverse(skip)]
inner: PyMutex<PyBZ2DecompressorInner>,
#[pymember]
#[pytraverse(skip)]
eof: AtomicBool,
#[pymember]
#[pytraverse(skip)]
needs_input: AtomicBool,
#[pymember(type = "object_ex")]
unused_data: PyAtomicRef<Option<PyObject>>,
}

impl fmt::Debug for BZ2Decompressor {
Expand All @@ -63,8 +63,10 @@ mod _bz2 {
Ok(Self {
inner: PyMutex::new(PyBZ2DecompressorInner {
decompress: backend::Decompressor::new(),
unused_data: vm.ctx.empty_bytes.clone(),
}),
eof: AtomicBool::new(false),
needs_input: AtomicBool::new(true),
unused_data: PyAtomicRef::from(Some(vm.ctx.empty_bytes.clone().into())),
})
}
}
Expand All @@ -84,25 +86,21 @@ mod _bz2 {
return Err(vm.new_value_error("Decompressor is unusable after a previous error"));
}
let result = inner.decompress.decompress(data, max_length);
inner.sync_visible_state(vm);
self.eof.store(inner.decompress.eof(), Ordering::Relaxed);
self.needs_input
.store(inner.decompress.needs_input(), Ordering::Relaxed);
let stale = self.unused_data.deref().is_none_or(|obj| {
obj.downcast_ref::<PyBytes>()
.is_none_or(|bytes| bytes.as_bytes() != inner.decompress.unused_data())
});
if stale {
let bytes = vm.ctx.new_bytes(inner.decompress.unused_data().to_vec());
// The previous bytes object is dropped after the slot is replaced.
let _previous = unsafe { self.unused_data.swap(Some(bytes.into())) };
}
result.map_err(|error| map_bz2_error(error, vm))
}

#[pygetset]
fn eof(&self) -> bool {
self.inner.lock().decompress.eof()
}

#[pygetset]
fn unused_data(&self) -> PyBytesRef {
self.inner.lock().unused_data.clone()
}

#[pygetset]
fn needs_input(&self) -> bool {
self.inner.lock().decompress.needs_input()
}

#[pymethod(name = "__reduce__")]
fn reduce(&self, vm: &VirtualMachine) -> PyResult<()> {
Err(vm.new_type_error("cannot pickle '_bz2.BZ2Decompressor' object"))
Expand Down
12 changes: 2 additions & 10 deletions crates/stdlib/src/cjkcodecs/multibytecodec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ mod _multibytecodec {
struct MultibyteStreamReader {
#[pytraverse(skip)]
codec: CodecRef,
#[pymember]
stream: PyObjectRef,
#[pytraverse(skip)]
inner: PyMutex<DecoderState>,
Expand Down Expand Up @@ -1006,11 +1007,6 @@ mod _multibytecodec {

#[pyclass(with(Constructor, Initializer), flags(BASETYPE))]
impl MultibyteStreamReader {
#[pygetset]
fn stream(&self) -> PyObjectRef {
self.stream.clone()
}

#[pygetset]
fn errors(&self, vm: &VirtualMachine) -> PyStrRef {
self.inner.lock().errors.name(vm)
Expand Down Expand Up @@ -1134,6 +1130,7 @@ mod _multibytecodec {
struct MultibyteStreamWriter {
#[pytraverse(skip)]
codec: CodecRef,
#[pymember]
stream: PyObjectRef,
#[pytraverse(skip)]
inner: PyMutex<EncoderState>,
Expand Down Expand Up @@ -1166,11 +1163,6 @@ mod _multibytecodec {

#[pyclass(with(Constructor, Initializer), flags(BASETYPE))]
impl MultibyteStreamWriter {
#[pygetset]
fn stream(&self) -> PyObjectRef {
self.stream.clone()
}

#[pygetset]
fn errors(&self, vm: &VirtualMachine) -> PyStrRef {
self.inner.lock().errors.name(vm)
Expand Down
6 changes: 1 addition & 5 deletions crates/stdlib/src/contextvars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ mod _contextvars {
#[pyclass(name, traverse)]
#[derive(PyPayload)]
struct ContextVar {
#[pymember]
name: PyStrRef,
default: Option<PyObjectRef>,
#[pytraverse(skip)]
Expand Down Expand Up @@ -436,11 +437,6 @@ mod _contextvars {

#[pyclass(with(Constructor, Hashable, Representable))]
impl ContextVar {
#[pygetset]
fn name(&self) -> PyStrRef {
self.name.clone()
}

#[pymethod]
fn get(
zelf: &Py<Self>,
Expand Down
41 changes: 14 additions & 27 deletions crates/stdlib/src/elementtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1829,11 +1829,9 @@ pub(crate) mod _elementtree {
/// The `pyexpat.xmlparser` doing the actual scanning, or `None`
/// before `__init__` (and after `close()` dropped it).
parser: Option<PyObjectRef>,
target: Option<PyObjectRef>,
/// The target again, when it is exactly our own `TreeBuilder`, so a
/// per-event dispatch is one clone rather than a type check.
native_target: Option<PyRef<PyTreeBuilder>>,
entity: Option<PyDictRef>,
/// Cache of raw expat names to their `{uri}local` form.
names: Option<PyDictRef>,
handle_start: Option<PyObjectRef>,
Expand All @@ -1855,6 +1853,10 @@ pub(crate) mod _elementtree {
)]
#[derive(Debug, PyPayload)]
pub(crate) struct PyXMLParser {
#[pymember]
entity: crate::vm::object::PyAtomicRef<Option<PyObject>>,
#[pymember]
target: crate::vm::object::PyAtomicRef<Option<PyObject>>,
state: PyRwLock<XMLParserState>,
}

Expand All @@ -1865,9 +1867,9 @@ pub(crate) mod _elementtree {
return;
};
st.parser.traverse(traverse_fn);
st.target.traverse(traverse_fn);
st.native_target.traverse(traverse_fn);
st.entity.traverse(traverse_fn);
self.entity.traverse(traverse_fn);
self.target.traverse(traverse_fn);
st.names.traverse(traverse_fn);
st.handle_start.traverse(traverse_fn);
st.handle_end.traverse(traverse_fn);
Expand All @@ -1887,9 +1889,9 @@ pub(crate) mod _elementtree {
out.extend(
[
st.parser.take(),
st.target.take(),
unsafe { self.entity.swap(None) },
unsafe { self.target.swap(None) },
st.native_target.take().map(Into::into),
st.entity.take().map(Into::into),
st.names.take().map(Into::into),
st.handle_start.take(),
st.handle_end.take(),
Expand Down Expand Up @@ -1920,6 +1922,8 @@ pub(crate) mod _elementtree {
impl Default for PyXMLParser {
fn default() -> Self {
Self {
entity: crate::vm::object::PyAtomicRef::from(None),
target: crate::vm::object::PyAtomicRef::from(None),
state: PyRwLock::new(XMLParserState::default()),
}
}
Expand Down Expand Up @@ -1963,9 +1967,11 @@ pub(crate) mod _elementtree {
_ => PyTreeBuilder::default().into_ref(&vm.ctx).into(),
};

let entity = vm.ctx.new_dict();
let _previous = unsafe { zelf.entity.swap(Some(entity.into())) };
let _previous = unsafe { zelf.target.swap(Some(target.clone())) };
let handlers = XMLParserState {
parser: Some(parser.clone()),
entity: Some(vm.ctx.new_dict()),
names: Some(vm.ctx.new_dict()),
handle_start_ns: optional_handler(&target, "start_ns", vm)?,
handle_end_ns: optional_handler(&target, "end_ns", vm)?,
Expand All @@ -1981,7 +1987,6 @@ pub(crate) mod _elementtree {
.is(PyTreeBuilder::class(&vm.ctx))
.then(|| target.clone().downcast::<PyTreeBuilder>().ok())
.flatten(),
target: Some(target),
};
let has_comment = handlers.handle_comment.is_some();
let has_pi = handlers.handle_pi.is_some();
Expand Down Expand Up @@ -2044,7 +2049,7 @@ pub(crate) mod _elementtree {
impl PyXMLParser {
fn check(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
let st = self.state.read();
if st.target.is_none() {
if self.target.deref().is_none() {
return Err(vm.new_value_error("XMLParser.__init__() wasn't called"));
}
st.parser
Expand Down Expand Up @@ -2125,24 +2130,6 @@ pub(crate) mod _elementtree {

#[pyclass(with(Constructor, Initializer), flags(BASETYPE, HAS_WEAKREF))]
impl PyXMLParser {
#[pygetset]
fn entity(&self, vm: &VirtualMachine) -> PyObjectRef {
self.state
.read()
.entity
.clone()
.map_or_else(|| vm.ctx.none(), Into::into)
}

#[pygetset]
fn target(&self, vm: &VirtualMachine) -> PyObjectRef {
self.state
.read()
.target
.clone()
.unwrap_or_else(|| vm.ctx.none())
}

#[pygetset]
fn version(&self, vm: &VirtualMachine) -> PyResult<String> {
let expat = vm.import("pyexpat", 0)?;
Expand Down
Loading
Loading