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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ base64 = "0.23"
blake2b_simd = "1.0.4"
blake2s_simd = "1.0.4"
bitflags = "2.11.0"
bitflagset = "0.0.3"
bitflagset = "0.0.4"
bstr = { version = "1", default-features = false, features = ["unicode"] }
bzip2 = "0.6"
console_error_panic_hook = "0.1"
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.slots.flags.load().bits() as u32 as c_ulong
}

#[unsafe(no_mangle)]
Expand Down
26 changes: 10 additions & 16 deletions crates/derive-impl/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2498,17 +2498,7 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
let mut withs = Vec::new();
let mut with_method_defs = Vec::new();
let mut with_slots = Vec::new();
let mut flags = vec![quote! {
{
#[cfg(not(debug_assertions))] {
::rustpython_vm::types::PyTypeFlags::DEFAULT
}
#[cfg(debug_assertions)] {
::rustpython_vm::types::PyTypeFlags::DEFAULT
.union(::rustpython_vm::types::PyTypeFlags::_CREATED_WITH_FLAGS)
}
}
}];
let mut flag_elems = Vec::new();
let mut payload = None;
let mut itemsize = None;
let mut has_initializer = false;
Expand Down Expand Up @@ -2584,12 +2574,12 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
let ident = path.get_ident().ok_or_else(|| {
err_span!(path, "#[pyclass(flags(...))] arguments should be ident")
})?;
flags.push(quote_spanned! { ident.span() =>
.union(::rustpython_vm::types::PyTypeFlags::#ident)
flag_elems.push(quote_spanned! { ident.span() =>
::rustpython_vm::types::PyTypeFlags::#ident
});
}
flags.push(quote! {
.union(::rustpython_vm::types::PyTypeFlags::IMMUTABLETYPE)
flag_elems.push(quote! {
::rustpython_vm::types::PyTypeFlags::IMMUTABLETYPE
});
} else {
bail_span!(path, "Unknown pyimpl attribute")
Expand Down Expand Up @@ -2619,7 +2609,11 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
Ok(ExtractedImplAttrs {
payload,
flags: quote! {
#(#flags)*
::rustpython_vm::types::PyTypeFlags::from_slice(&[
#[cfg(debug_assertions)]
::rustpython_vm::types::PyTypeFlags::_CREATED_WITH_FLAGS,
#(#flag_elems),*
])
},
with_impl: quote! {
#(#withs)*
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/builtins/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ bitflags::bitflags! {
const AUDIT_READ = 2;
// `_Py_WRITE_RESTRICTED` (4) is deprecated. The bit is reserved and must not be reused.
const RELATIVE_OFFSET = 8;
/// The field is atomic storage (`Atomic*` or `PyAtomicTypeFlags`).
/// The field is atomic storage (`Atomic*` or `AtomicPyTypeFlags`).
///
/// Not a public member flag. The defined flags are `Py_READONLY` (1),
/// `Py_AUDIT_READ` (2), `_Py_WRITE_RESTRICTED` (4, deprecated, do not reuse),
Expand Down
98 changes: 49 additions & 49 deletions crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ pub struct PyType {
/// generic path).
static NEXT_TYPE_VERSION: AtomicU32 = AtomicU32::new(1);

const MANAGED_DICT_FLAGS: PyTypeFlags =
PyTypeFlags::from_slice(&[PyTypeFlags::HAS_DICT, PyTypeFlags::MANAGED_DICT]);

const MANAGED_DICT_INLINE_FLAGS: PyTypeFlags = PyTypeFlags::from_slice(&[
PyTypeFlags::HAS_DICT,
PyTypeFlags::MANAGED_DICT,
PyTypeFlags::INLINE_VALUES,
]);

const WEAKREF_FLAGS: PyTypeFlags =
PyTypeFlags::from_slice(&[PyTypeFlags::HAS_WEAKREF, PyTypeFlags::MANAGED_WEAKREF]);

// Method cache (type_cache / MCACHE): direct-mapped cache keyed by
// (tp_version_tag, interned_name_ptr).
//
Expand Down Expand Up @@ -782,15 +794,15 @@ impl PyType {
name: &str,
bases: Vec<PyRef<Self>>,
attrs: PyAttributes,
mut slots: PyTypeSlots,
slots: PyTypeSlots,
metaclass: PyRef<Self>,
ctx: &Context,
) -> Result<PyRef<Self>, String> {
// TODO: ensure clean slot name
// assert_eq!(slots.name.borrow(), "");

// Set HEAPTYPE flag for heap-allocated types
slots.flags |= PyTypeFlags::HEAPTYPE;
slots.flags.insert(PyTypeFlags::HEAPTYPE);

let name_utf8 = ctx.new_utf8_str(name);
let name = name_utf8.clone().into_wtf8();
Expand Down Expand Up @@ -842,52 +854,43 @@ impl PyType {
/// Inherit SEQUENCE and MAPPING flags from base classes
/// Check all bases in order and inherit the first SEQUENCE or MAPPING flag found
fn inherit_patma_flags(slots: &mut PyTypeSlots, bases: &[PyRef<Self>]) {
const COLLECTION_FLAGS: PyTypeFlags = PyTypeFlags::from_bits_truncate(
PyTypeFlags::SEQUENCE.bits() | PyTypeFlags::MAPPING.bits(),
);

// If flags are already set, don't override
if slots.flags.intersects(COLLECTION_FLAGS) {
if !slots.flags.load().is_disjoint(&PyTypeFlags::COLLECTION) {
return;
}

// Check each base in order and inherit the first collection flag found
for base in bases {
let base_flags = base.slots.flags.load() & COLLECTION_FLAGS;
let base_flags = base.slots.flags.load() & PyTypeFlags::COLLECTION;
if !base_flags.is_empty() {
slots.flags |= base_flags;
return;
}
}
}

pub fn has_patma_collection_flag(&self, flag: PyTypeFlags) -> bool {
debug_assert!(matches!(flag, PyTypeFlags::SEQUENCE | PyTypeFlags::MAPPING));
const COLLECTION_FLAGS: PyTypeFlags = PyTypeFlags::from_bits_truncate(
PyTypeFlags::SEQUENCE.bits() | PyTypeFlags::MAPPING.bits(),
);
let slot_flags = self.slots.flags.load() & COLLECTION_FLAGS;
slot_flags.contains(flag)
pub fn has_patma_collection_flag(&self, flag: u8) -> bool {
debug_assert!(flag == PyTypeFlags::SEQUENCE || flag == PyTypeFlags::MAPPING);
self.slots.flags.has_feature(flag)
}

pub fn set_is_abstract(&self, is_abstract: bool) {
if is_abstract {
self.slots.flags.set(PyTypeFlags::IS_ABSTRACT);
self.slots.flags.insert(PyTypeFlags::IS_ABSTRACT);
} else {
self.slots.flags.remove(PyTypeFlags::IS_ABSTRACT);
}
self.modified();
}

pub fn set_abc_collection_flags_recursive(&self, flags: PyTypeFlags) {
const COLLECTION_FLAGS: PyTypeFlags = PyTypeFlags::from_bits_truncate(
PyTypeFlags::SEQUENCE.bits() | PyTypeFlags::MAPPING.bits(),
);
let flags = flags & COLLECTION_FLAGS;
let flags = flags & PyTypeFlags::COLLECTION;
if flags.is_empty() {
return;
}
self.slots.flags.replace_masked(COLLECTION_FLAGS, flags);
self.slots
.flags
.replace_masked(PyTypeFlags::COLLECTION, flags);
self.modified();
for weak_ref in self.subclasses.read().iter() {
if let Some(subclass) = weak_ref.upgrade()
Expand All @@ -906,10 +909,6 @@ impl PyType {
bases: &[PyRef<Self>],
ctx: &Context,
) -> Result<(), String> {
const COLLECTION_FLAGS: PyTypeFlags = PyTypeFlags::from_bits_truncate(
PyTypeFlags::SEQUENCE.bits() | PyTypeFlags::MAPPING.bits(),
);

// Always validate this class's own __abc_tpflags__ even when slot
// flags were already inherited, otherwise a child setting both
// Py_TPFLAGS_SEQUENCE and Py_TPFLAGS_MAPPING would slip through.
Expand All @@ -919,21 +918,21 @@ impl PyType {
{
let flags_val = int_obj.as_bigint().to_i64().unwrap_or(0);
let abc_flags = PyTypeFlags::from_bits_truncate(flags_val as u64);
let masked = abc_flags & COLLECTION_FLAGS;
if masked == COLLECTION_FLAGS {
let masked = abc_flags & PyTypeFlags::COLLECTION;
if masked == PyTypeFlags::COLLECTION {
return Err(
"__abc_tpflags__ cannot be both Py_TPFLAGS_SEQUENCE and Py_TPFLAGS_MAPPING"
.to_owned(),
);
}
slots.flags.remove(COLLECTION_FLAGS);
slots.flags.remove_masked(PyTypeFlags::COLLECTION);
slots.flags |= masked;
return Ok(());
}

// No __abc_tpflags__ on this class. Inheritance already happened in
// inherit_patma_flags, using base order and including ABC markers.
if slots.flags.intersects(COLLECTION_FLAGS) {
if !slots.flags.load().is_disjoint(&PyTypeFlags::COLLECTION) {
return Ok(());
}

Expand All @@ -945,14 +944,14 @@ impl PyType {
{
let flags_val = int_obj.as_bigint().to_i64().unwrap_or(0);
let abc_flags = PyTypeFlags::from_bits_truncate(flags_val as u64);
let masked = abc_flags & COLLECTION_FLAGS;
if masked == COLLECTION_FLAGS {
let masked = abc_flags & PyTypeFlags::COLLECTION;
if masked == PyTypeFlags::COLLECTION {
return Err(
"__abc_tpflags__ cannot be both Py_TPFLAGS_SEQUENCE and Py_TPFLAGS_MAPPING"
.to_owned(),
);
}
slots.flags.remove(COLLECTION_FLAGS);
slots.flags.remove_masked(PyTypeFlags::COLLECTION);
slots.flags |= masked;
return Ok(());
}
Expand Down Expand Up @@ -985,22 +984,22 @@ impl PyType {
.iter()
.any(|b| b.slots.flags.has_feature(PyTypeFlags::HAS_DICT))
{
slots.flags |= PyTypeFlags::HAS_DICT;
slots.flags.insert(PyTypeFlags::HAS_DICT);
}
if bases
.as_slice()
.iter()
.any(|b| b.slots.flags.has_feature(PyTypeFlags::MANAGED_DICT))
{
slots.flags |= PyTypeFlags::MANAGED_DICT;
slots.flags.insert(PyTypeFlags::MANAGED_DICT);
}

if bases
.as_slice()
.iter()
.any(|b| b.slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF))
{
slots.flags |= PyTypeFlags::HAS_WEAKREF | PyTypeFlags::MANAGED_WEAKREF;
slots.flags |= WEAKREF_FLAGS;
}

// Inherit SEQUENCE and MAPPING flags from base classes
Expand All @@ -1015,7 +1014,7 @@ impl PyType {

// Normalize: any type with HAS_WEAKREF gets MANAGED_WEAKREF
if slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF) {
slots.flags |= PyTypeFlags::MANAGED_WEAKREF;
slots.flags.insert(PyTypeFlags::MANAGED_WEAKREF);
}

if let Some(qualname) = attrs.get(identifier!(ctx, __qualname__))
Expand Down Expand Up @@ -1066,10 +1065,10 @@ impl PyType {
metaclass: PyRef<Self>,
) -> Result<PyRef<Self>, String> {
if base.slots.flags.has_feature(PyTypeFlags::HAS_DICT) {
slots.flags |= PyTypeFlags::HAS_DICT
slots.flags.insert(PyTypeFlags::HAS_DICT);
}
if base.slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF) {
slots.flags |= PyTypeFlags::HAS_WEAKREF | PyTypeFlags::MANAGED_WEAKREF
slots.flags |= WEAKREF_FLAGS;
}

// Inherit SEQUENCE and MAPPING flags from base class
Expand All @@ -1082,7 +1081,7 @@ impl PyType {

// Normalize: any type with HAS_WEAKREF gets MANAGED_WEAKREF
if slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF) {
slots.flags |= PyTypeFlags::MANAGED_WEAKREF;
slots.flags.insert(PyTypeFlags::MANAGED_WEAKREF);
}

let bases =
Expand Down Expand Up @@ -1197,7 +1196,7 @@ impl PyType {
}

fn set_new(slots: &PyTypeSlots, base: Option<&Py<Self>>) {
if slots.flags.contains(PyTypeFlags::DISALLOW_INSTANTIATION) {
if slots.flags.has_feature(PyTypeFlags::DISALLOW_INSTANTIATION) {
slots.new.store(None)
} else if slots.new.load().is_none() {
slots.new.store(base.and_then(|base| base.slots.new.load()))
Expand Down Expand Up @@ -2048,7 +2047,7 @@ impl Constructor for PyType {
let heaptype_member_count = heaptype_slots.as_ref().map_or(0, |x| x.as_slice().len());
let member_count: usize = base_member_count + heaptype_member_count;

let mut flags = PyTypeFlags::heap_type_flags();
let mut flags = PyTypeFlags::HEAP_TYPE;

// Check if we may add dict
// We can only add a dict if the primary base class doesn't already have one
Expand All @@ -2059,12 +2058,13 @@ impl Constructor for PyType {
// 1. __slots__ is not defined AND base doesn't have dict, OR
// 2. __dict__ is in __slots__
if (heaptype_slots.is_none() && may_add_dict) || add_dict {
flags |= PyTypeFlags::HAS_DICT | PyTypeFlags::MANAGED_DICT;
// type_ready_managed_dict: fixed-size managed-dict types
// get an inline values array after the object.
if base.slots.itemsize == 0 {
flags |= PyTypeFlags::INLINE_VALUES;
}
flags |= if base.slots.itemsize == 0 {
MANAGED_DICT_INLINE_FLAGS
} else {
MANAGED_DICT_FLAGS
};
}

// Add HAS_WEAKREF if:
Expand All @@ -2074,12 +2074,12 @@ impl Constructor for PyType {
let may_add_weakref =
base.slots.itemsize == 0 && !base.slots.flags.has_feature(PyTypeFlags::HAS_WEAKREF);
if (heaptype_slots.is_none() && may_add_weakref) || add_weakref {
flags |= PyTypeFlags::HAS_WEAKREF | PyTypeFlags::MANAGED_WEAKREF;
flags |= WEAKREF_FLAGS;
}

let (slots, heaptype_ext) = {
let slots = PyTypeSlots {
flags: crate::types::PyAtomicTypeFlags::new(flags),
flags: crate::types::AtomicPyTypeFlags::from_plain(flags),
member_count,
itemsize: base.slots.itemsize,
..PyTypeSlots::heap_default()
Expand Down Expand Up @@ -3302,8 +3302,8 @@ fn get_builtin_base_with_dict(typ: &Py<PyType>, vm: &VirtualMachine) -> Option<P
return Some(t);
}
// We check HAS_DICT flag (equivalent to tp_dictoffset != 0) and HEAPTYPE
if t.slots.flags.contains(PyTypeFlags::HAS_DICT)
&& !t.slots.flags.contains(PyTypeFlags::HEAPTYPE)
if t.slots.flags.has_feature(PyTypeFlags::HAS_DICT)
&& !t.slots.flags.has_feature(PyTypeFlags::HEAPTYPE)
{
return Some(t);
}
Expand Down
Loading
Loading