Skip to content
Closed
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
1 change: 1 addition & 0 deletions Lib/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,7 @@ def test_threaded_weak_value_dict_copy(self):
# copying should not result in a crash.
self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False)

@unittest.skip("TODO: RUSTPYTHON; flaky test")
def test_threaded_weak_value_dict_deepcopy(self):
# Issue #35615: Weakref keys or values getting GC'ed during dict
# copying should not result in a crash.
Expand Down
5 changes: 1 addition & 4 deletions vm/src/builtins/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,7 @@ impl PyBaseObject {
}
}
PyComparisonOp::Ne => {
let cmp = zelf
.class()
.mro_find_map(|cls| cls.slots.richcompare.load())
.unwrap();
let cmp = zelf.class().slots.richcompare.load().unwrap();
let value = match cmp(zelf, other, PyComparisonOp::Eq, vm)? {
Either::A(obj) => PyArithmeticValue::from_object(vm, obj)
.map(|obj| obj.try_to_bool(vm))
Expand Down
45 changes: 14 additions & 31 deletions vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ impl PyType {
.map(|x| x.iter_mro().cloned().collect())
.collect();
let mro = linearise_mro(mros)?;
slots.inherits(&mro.iter().map(|t| -> &PyType { &t }).collect::<Vec<_>>());
debug_assert!(slots.hash.load().is_some(), "{}", name);

if base.slots.flags.has_feature(PyTypeFlags::HAS_DICT) {
slots.flags |= PyTypeFlags::HAS_DICT
Expand Down Expand Up @@ -141,19 +143,6 @@ impl PyType {
std::iter::once(self).chain(self.mro.iter().map(|cls| -> &PyType { cls }))
}

pub(crate) fn mro_find_map<F, R>(&self, f: F) -> Option<R>
where
F: Fn(&Self) -> Option<R>,
{
// the hot path will be primitive types which usually hit the result from itself.
// try std::intrinsics::likely once it is stablized
if let Some(r) = f(self) {
Some(r)
} else {
self.mro.iter().find_map(|cls| f(cls))
}
}

// This is used for class initialisation where the vm is not yet available.
pub fn set_str_attr<V: Into<PyObjectRef>>(&self, attr_name: &str, value: V) {
self._set_str_attr(attr_name, value.into())
Expand Down Expand Up @@ -521,7 +510,7 @@ impl PyType {
// updated when __slots__ are supported (toggling the flag off if
// a class has __slots__ defined).
let flags = PyTypeFlags::heap_type_flags() | PyTypeFlags::HAS_DICT;
let slots = PyTypeSlots::from_flags(flags);
let slots = PyTypeSlots::with_flags(flags);

let typ = Self::new_verbose_ref(name.as_str(), base, bases, attributes, slots, metatype)
.map_err(|e| vm.new_type_error(e))?;
Expand Down Expand Up @@ -637,11 +626,8 @@ impl GetAttr for PyType {

if let Some(ref attr) = mcl_attr {
let attr_class = attr.class();
if attr_class
.mro_find_map(|cls| cls.slots.descr_set.load())
.is_some()
{
if let Some(descr_get) = attr_class.mro_find_map(|cls| cls.slots.descr_get.load()) {
if attr_class.slots.descr_set.load().is_some() {
if let Some(descr_get) = attr_class.slots.descr_get.load() {
let mcl = mcl.into_owned().into();
return descr_get(attr.clone(), Some(zelf.to_owned().into()), Some(mcl), vm);
}
Expand All @@ -651,7 +637,7 @@ impl GetAttr for PyType {
let zelf_attr = zelf.get_attr(name);

if let Some(ref attr) = zelf_attr {
if let Some(descr_get) = attr.class().mro_find_map(|cls| cls.slots.descr_get.load()) {
if let Some(descr_get) = attr.class().slots.descr_get.load() {
drop(mcl);
return descr_get(attr.clone(), None, Some(zelf.to_owned().into()), vm);
}
Expand Down Expand Up @@ -680,7 +666,7 @@ impl SetAttr for PyType {
vm: &VirtualMachine,
) -> PyResult<()> {
if let Some(attr) = zelf.get_class_attr(attr_name.as_str()) {
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
let descr_set = attr.class().slots.descr_set.load();
if let Some(descriptor) = descr_set {
return descriptor(attr, zelf.to_owned().into(), value, vm);
}
Expand Down Expand Up @@ -719,7 +705,7 @@ impl Callable for PyType {
return Ok(obj);
}

if let Some(init_method) = obj.class().mro_find_map(|cls| cls.slots.init.load()) {
if let Some(init_method) = obj.class().slots.init.load() {
init_method(obj.clone(), args, vm)?;
}
Ok(obj)
Expand Down Expand Up @@ -757,15 +743,12 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -
let cls = obj.class().clone();
match find_base_dict_descr(&cls, vm) {
Some(descr) => {
let descr_set = descr
.class()
.mro_find_map(|cls| cls.slots.descr_set.load())
.ok_or_else(|| {
vm.new_type_error(format!(
"this __dict__ descriptor does not support '{}' objects",
cls.name()
))
})?;
let descr_set = descr.class().slots.descr_set.load().ok_or_else(|| {
vm.new_type_error(format!(
"this __dict__ descriptor does not support '{}' objects",
cls.name()
))
})?;
descr_set(descr, obj, Some(value), vm)
}
None => {
Expand Down
2 changes: 1 addition & 1 deletion vm/src/function/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ where
let iterfn;
{
let cls = obj.class();
iterfn = cls.mro_find_map(|x| x.slots.iter.load());
iterfn = cls.slots.iter.load();
if iterfn.is_none() && !cls.has_attr("__getitem__") {
return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())));
}
Expand Down
2 changes: 1 addition & 1 deletion vm/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ macro_rules! py_class {
( $ctx:expr, $class_name:expr, $class_base:expr, $flags:expr, { $($name:tt => $value:expr),* $(,)* }) => {
{
#[allow(unused_mut)]
let mut slots = $crate::types::PyTypeSlots::from_flags($crate::types::PyTypeFlags::DEFAULT | $flags);
let mut slots = $crate::types::PyTypeSlots::with_flags($crate::types::PyTypeFlags::DEFAULT | $flags);
$($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)*
let py_class = $ctx.new_class(None, $class_name, $class_base, slots);
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*
Expand Down
17 changes: 11 additions & 6 deletions vm/src/object/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ impl PyObject {
}

// CPython-compatible drop implementation
if let Some(slot_del) = self.class().mro_find_map(|cls| cls.slots.del.load()) {
if let Some(slot_del) = self.class().slots.del.load() {
call_slot_del(self, slot_del)?;
}
if let Some(wrl) = self.weak_ref_list() {
Expand Down Expand Up @@ -1081,22 +1081,25 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
static_assertions::assert_eq_size!(MaybeUninit<PyInner<PyType>>, PyInner<PyType>);
static_assertions::assert_eq_align!(MaybeUninit<PyInner<PyType>>, PyInner<PyType>);

let type_payload = PyType {
let object_payload = PyType {
base: None,
bases: vec![],
mro: vec![],
subclasses: PyRwLock::default(),
attributes: PyRwLock::new(Default::default()),
slots: PyType::make_slots(),
slots: object::PyBaseObject::make_slots(),
};
let object_payload = PyType {
let mut type_slots = PyType::make_slots();
type_slots.inherits(&[&object_payload]);
let type_payload = PyType {
base: None,
bases: vec![],
mro: vec![],
subclasses: PyRwLock::default(),
attributes: PyRwLock::new(Default::default()),
slots: object::PyBaseObject::make_slots(),
slots: type_slots,
};

let type_type_ptr = Box::into_raw(Box::new(partially_init!(
PyInner::<PyType> {
ref_count: RefCount::new(),
Expand Down Expand Up @@ -1149,13 +1152,15 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
}
};

let mut weakref_slots = PyWeak::make_slots();
weakref_slots.inherits(&[&object_type]);
let weakref_type = PyType {
base: Some(object_type.clone()),
bases: vec![object_type.clone()],
mro: vec![object_type.clone()],
subclasses: PyRwLock::default(),
attributes: PyRwLock::default(),
slots: PyWeak::make_slots(),
slots: weakref_slots,
};
let weakref_type = PyRef::new_ref(weakref_type, type_type.clone(), None);

Expand Down
2 changes: 1 addition & 1 deletion vm/src/protocol/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl PyBuffer {
impl TryFromBorrowedObject for PyBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
let cls = obj.class();
if let Some(f) = cls.mro_find_map(|cls| cls.slots.as_buffer) {
if let Some(f) = cls.slots.as_buffer {
return f(obj, vm);
}
Err(vm.new_type_error(format!(
Expand Down
10 changes: 5 additions & 5 deletions vm/src/protocol/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ where

impl PyIter<PyObjectRef> {
pub fn check(obj: &PyObject) -> bool {
obj.class()
.mro_find_map(|x| x.slots.iternext.load())
.is_some()
obj.class().slots.iternext.load().is_some()
}
}

Expand All @@ -34,7 +32,9 @@ where
self.0
.borrow()
.class()
.mro_find_map(|x| x.slots.iternext.load())
.slots
.iternext
.load()
.ok_or_else(|| {
vm.new_type_error(format!(
"'{}' object is not an iterator",
Expand Down Expand Up @@ -120,7 +120,7 @@ impl TryFromObject for PyIter<PyObjectRef> {
fn try_from_object(vm: &VirtualMachine, iter_target: PyObjectRef) -> PyResult<Self> {
let getiter = {
let cls = iter_target.class();
cls.mro_find_map(|x| x.slots.iter.load())
cls.slots.iter.load()
};
if let Some(getiter) = getiter {
let iter = getiter(iter_target, vm)?;
Expand Down
6 changes: 1 addition & 5 deletions vm/src/protocol/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ impl PyMapping<'_> {

pub fn methods(&self, vm: &VirtualMachine) -> &PyMappingMethods {
self.methods.get_or_init(|| {
if let Some(f) = self
.obj
.class()
.mro_find_map(|cls| cls.slots.as_mapping.load())
{
if let Some(f) = self.obj.class().slots.as_mapping.load() {
f(self.obj, vm)
} else {
PyMappingMethods::default()
Expand Down
47 changes: 17 additions & 30 deletions vm/src/protocol/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,7 @@ impl PyObject {
#[inline]
fn _get_attr(&self, attr_name: PyStrRef, vm: &VirtualMachine) -> PyResult {
vm_trace!("object.__getattribute__: {:?} {:?}", obj, attr_name);
let getattro = self
.class()
.mro_find_map(|cls| cls.slots.getattro.load())
.unwrap();
let getattro = self.class().slots.getattro.load().unwrap();
getattro(self, attr_name.clone(), vm).map_err(|exc| {
vm.set_attribute_error_context(&exc, self.to_owned(), attr_name);
exc
Expand All @@ -108,18 +105,17 @@ impl PyObject {
) -> PyResult<()> {
let setattro = {
let cls = self.class();
cls.mro_find_map(|cls| cls.slots.setattro.load())
.ok_or_else(|| {
let assign = attr_value.is_some();
let has_getattr = cls.mro_find_map(|cls| cls.slots.getattro.load()).is_some();
vm.new_type_error(format!(
"'{}' object has {} attributes ({} {})",
cls.name(),
if has_getattr { "only read-only" } else { "no" },
if assign { "assign to" } else { "del" },
attr_name
))
})?
cls.slots.setattro.load().ok_or_else(|| {
let assign = attr_value.is_some();
let has_getattr = cls.slots.getattro.load().is_some();
vm.new_type_error(format!(
"'{}' object has {} attributes ({} {})",
cls.name(),
if has_getattr { "only read-only" } else { "no" },
if assign { "assign to" } else { "del" },
attr_name
))
})?
};
setattro(self, attr_name, attr_value, vm)
}
Expand All @@ -145,7 +141,7 @@ impl PyObject {
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);

if let Some(attr) = self.get_class_attr(attr_name.as_str()) {
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
let descr_set = attr.class().slots.descr_set.load();
if let Some(descriptor) = descr_set {
return descriptor(attr, self.to_owned(), value, vm);
}
Expand Down Expand Up @@ -194,12 +190,9 @@ impl PyObject {
let cls_attr = match obj_cls.get_attr(name) {
Some(descr) => {
let descr_cls = descr.class();
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
let descr_get = descr_cls.slots.descr_get.load();
if let Some(descr_get) = descr_get {
if descr_cls
.mro_find_map(|cls| cls.slots.descr_set.load())
.is_some()
{
if descr_cls.slots.descr_set.load().is_some() {
drop(descr_cls);
let cls = obj_cls.into_owned().into();
return descr_get(descr, Some(self.to_owned()), Some(cls), vm).map(Some);
Expand Down Expand Up @@ -254,10 +247,7 @@ impl PyObject {
) -> PyResult<Either<PyObjectRef, bool>> {
let swapped = op.swapped();
let call_cmp = |obj: &PyObject, other: &PyObject, op| {
let cmp = obj
.class()
.mro_find_map(|cls| cls.slots.richcompare.load())
.unwrap();
let cmp = obj.class().slots.richcompare.load().unwrap();
let r = match cmp(obj, other, op, vm)? {
Either::A(obj) => PyArithmeticValue::from_object(vm, obj).map(Either::A),
Either::B(arithmetic) => arithmetic.map(Either::B),
Expand Down Expand Up @@ -496,10 +486,7 @@ impl PyObject {
}

pub fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
let hash = self
.class()
.mro_find_map(|cls| cls.slots.hash.load())
.unwrap(); // hash always exist
let hash = self.class().slots.hash.load().unwrap(); // hash always exist
hash(self, vm)
}

Expand Down
2 changes: 1 addition & 1 deletion vm/src/protocol/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl PySequence<'_> {
self.methods.get_or_init(|| {
let cls = self.obj.class();
if !cls.is(&vm.ctx.types.dict_type) {
if let Some(f) = cls.mro_find_map(|x| x.slots.as_sequence.load()) {
if let Some(f) = cls.slots.as_sequence.load() {
return f(self.obj, vm);
}
}
Expand Down
12 changes: 3 additions & 9 deletions vm/src/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ pub trait MutObjectSequenceOp<'a> {
F: FnMut(),
{
let needle_cls = needle.class();
let needle_cmp = needle_cls
.mro_find_map(|cls| cls.slots.richcompare.load())
.unwrap();
let needle_cmp = needle_cls.slots.richcompare.load().unwrap();

let mut borrower = None;
let mut i = range.start;
Expand Down Expand Up @@ -146,9 +144,7 @@ pub trait MutObjectSequenceOp<'a> {
!elem_cls.is(&needle_cls) && elem_cls.fast_issubclass(&needle_cls);

let eq = if reverse_first {
let elem_cmp = elem_cls
.mro_find_map(|cls| cls.slots.richcompare.load())
.unwrap();
let elem_cmp = elem_cls.slots.richcompare.load().unwrap();
drop(elem_cls);

fn cmp(
Expand Down Expand Up @@ -195,9 +191,7 @@ pub trait MutObjectSequenceOp<'a> {
obj.try_to_bool(vm)?
}
_ => {
let elem_cmp = elem_cls
.mro_find_map(|cls| cls.slots.richcompare.load())
.unwrap();
let elem_cmp = elem_cls.slots.richcompare.load().unwrap();
drop(elem_cls);

fn cmp(
Expand Down
Loading