impl basicsize (#6557)

* shape_differs

* may_add_dict

* basicsize
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2025-12-28 14:25:10 +09:00
1 parent ee747134b5
commit f8199d7099
5 files changed
+20 -16

No files matched your search

-2
View File
@@ -591,8 +591,6 @@ class TypesTests(unittest.TestCase):
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)
+1
View File
@@ -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 {
+17 -14
View File
@@ -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]
@@ -1338,10 +1338,16 @@ 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;
}
@@ -1349,6 +1355,7 @@ impl Constructor for PyType {
let slots = PyTypeSlots {
flags,
member_count,
itemsize: base.slots.itemsize,
..PyTypeSlots::heap_default()
};
let heaptype_ext = HeapTypeExt {
@@ -2009,6 +2016,11 @@ 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)
@@ -2016,16 +2028,7 @@ fn solid_base<'a>(typ: &'a Py<PyType>, vm: &VirtualMachine) -> &'a Py<PyType> {
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>> {
+1
View File
@@ -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 {
+1
View File
@@ -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};