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
2 changes: 0 additions & 2 deletions Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,8 +591,6 @@ def test_format_spec_errors(self):
for code in 'xXobns':
self.assertRaises(ValueError, format, 0, ',' + code)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_internal_sizes(self):
self.assertGreater(object.__basicsize__, 0)
self.assertGreater(tuple.__itemsize__, 0)
Expand Down
1 change: 1 addition & 0 deletions crates/derive-impl/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ 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.
let basicsize = if is_repr_transparent && base.is_some() {
quote!(0)
} else {
Expand Down
31 changes: 17 additions & 14 deletions crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,8 @@ impl PyType {
}

#[pygetset]
const fn __basicsize__(&self) -> usize {
self.slots.basicsize
fn __basicsize__(&self) -> usize {
crate::object::SIZEOF_PYOBJECT_HEAD + self.slots.basicsize
}

#[pygetset]
Expand Down Expand Up @@ -1338,17 +1338,24 @@ impl Constructor for PyType {
let member_count: usize = base_member_count + heaptype_member_count;

let mut flags = PyTypeFlags::heap_type_flags();

// Check if we may add dict
// We can only add a dict if the primary base class doesn't already have one
// In CPython, this checks tp_dictoffset == 0
let may_add_dict = !base.slots.flags.has_feature(PyTypeFlags::HAS_DICT);

// Add HAS_DICT and MANAGED_DICT if:
// 1. __slots__ is not defined, OR
// 1. __slots__ is not defined AND base doesn't have dict, OR
// 2. __dict__ is in __slots__
if heaptype_slots.is_none() || add_dict {
if (heaptype_slots.is_none() && may_add_dict) || add_dict {
flags |= PyTypeFlags::HAS_DICT | PyTypeFlags::MANAGED_DICT;
}

let (slots, heaptype_ext) = {
let slots = PyTypeSlots {
flags,
member_count,
itemsize: base.slots.itemsize,
..PyTypeSlots::heap_default()
};
let heaptype_ext = HeapTypeExt {
Expand Down Expand Up @@ -2009,23 +2016,19 @@ fn calculate_meta_class(
Ok(winner)
}

/// Returns true if the two types have different instance layouts.
fn shape_differs(t1: &Py<PyType>, t2: &Py<PyType>) -> bool {
t1.__basicsize__() != t2.__basicsize__() || t1.slots.itemsize != t2.slots.itemsize
}

fn solid_base<'a>(typ: &'a Py<PyType>, vm: &VirtualMachine) -> &'a Py<PyType> {
let base = if let Some(base) = &typ.base {
solid_base(base, vm)
} else {
vm.ctx.types.object_type
};

// Check for extra instance variables (CPython's extra_ivars)
let t_size = typ.__basicsize__();
let b_size = base.__basicsize__();
let t_itemsize = typ.slots.itemsize;
let b_itemsize = base.slots.itemsize;

// Has extra ivars if: sizes differ AND (has items OR t_size > b_size)
let has_extra_ivars = t_size != b_size && (t_itemsize > 0 || b_itemsize > 0 || t_size > b_size);

if has_extra_ivars { typ } else { base }
if shape_differs(typ, base) { typ } else { base }
}

fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<&'a Py<PyType>> {
Expand Down
1 change: 1 addition & 0 deletions crates/vm/src/object/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub(super) struct PyInner<T> {

pub(super) payload: T,
}
pub(crate) const SIZEOF_PYOBJECT_HEAD: usize = std::mem::size_of::<PyInner<()>>();

impl<T: fmt::Debug> fmt::Debug for PyInner<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
1 change: 1 addition & 0 deletions crates/vm/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ mod traverse_object;
pub use self::core::*;
pub use self::ext::*;
pub use self::payload::*;
pub(crate) use core::SIZEOF_PYOBJECT_HEAD;
pub use traverse::{MaybeTraverse, Traverse, TraverseFn};
Loading