Skip to content

Commit e0886e2

Browse files
committed
type lock
1 parent 328de2e commit e0886e2

File tree

8 files changed

+304
-182
lines changed

8 files changed

+304
-182
lines changed

crates/vm/src/builtins/type.rs

Lines changed: 276 additions & 142 deletions
Large diffs are not rendered by default.

crates/vm/src/frame.rs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7316,10 +7316,7 @@ impl ExecutingFrame<'_> {
73167316
.load()
73177317
.is_some_and(|f| f as usize == PyBaseObject::getattro as *const () as usize);
73187318
if !is_default_getattro {
7319-
let mut type_version = cls.tp_version_tag.load(Acquire);
7320-
if type_version == 0 {
7321-
type_version = cls.assign_version_tag();
7322-
}
7319+
let type_version = cls.version_for_specialization(_vm);
73237320
if type_version != 0
73247321
&& !oparg.is_method()
73257322
&& !self.specialization_eval_frame_active(_vm)
@@ -7357,10 +7354,7 @@ impl ExecutingFrame<'_> {
73577354
}
73587355

73597356
// Get or assign type version
7360-
let mut type_version = cls.tp_version_tag.load(Acquire);
7361-
if type_version == 0 {
7362-
type_version = cls.assign_version_tag();
7363-
}
7357+
let type_version = cls.version_for_specialization(_vm);
73647358
if type_version == 0 {
73657359
// Version counter overflow — backoff to avoid re-attempting every execution
73667360
unsafe {
@@ -7580,10 +7574,7 @@ impl ExecutingFrame<'_> {
75807574
let owner_type = obj.downcast_ref::<PyType>().unwrap();
75817575

75827576
// Get or assign type version for the type object itself
7583-
let mut type_version = owner_type.tp_version_tag.load(Acquire);
7584-
if type_version == 0 {
7585-
type_version = owner_type.assign_version_tag();
7586-
}
7577+
let type_version = owner_type.version_for_specialization(_vm);
75877578
if type_version == 0 {
75887579
unsafe {
75897580
self.code.instructions.write_adaptive_counter(
@@ -7618,10 +7609,7 @@ impl ExecutingFrame<'_> {
76187609
}
76197610
let mut metaclass_version = 0;
76207611
if !mcl.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
7621-
metaclass_version = mcl.tp_version_tag.load(Acquire);
7622-
if metaclass_version == 0 {
7623-
metaclass_version = mcl.assign_version_tag();
7624-
}
7612+
metaclass_version = mcl.version_for_specialization(_vm);
76257613
if metaclass_version == 0 {
76267614
unsafe {
76277615
self.code.instructions.write_adaptive_counter(
@@ -7808,16 +7796,14 @@ impl ExecutingFrame<'_> {
78087796
Some(Instruction::BinaryOpSubscrListSlice)
78097797
} else {
78107798
let cls = a.class();
7799+
let (getitem, type_version) =
7800+
cls.lookup_ref_and_version_interned(identifier!(vm, __getitem__), vm);
78117801
if cls.slots.flags.has_feature(PyTypeFlags::HEAPTYPE)
78127802
&& !self.specialization_eval_frame_active(vm)
7813-
&& let Some(_getitem) = cls.get_attr(identifier!(vm, __getitem__))
7803+
&& let Some(_getitem) = getitem
78147804
&& let Some(func) = _getitem.downcast_ref_if_exact::<PyFunction>(vm)
78157805
&& func.can_specialize_call(2)
78167806
{
7817-
let mut type_version = cls.tp_version_tag.load(Acquire);
7818-
if type_version == 0 {
7819-
type_version = cls.assign_version_tag();
7820-
}
78217807
if type_version != 0 {
78227808
if cls.cache_getitem_for_specialization(
78237809
func.to_owned(),
@@ -8356,11 +8342,8 @@ impl ExecutingFrame<'_> {
83568342
&& cls_new_fn as usize == obj_new_fn as usize
83578343
&& cls_alloc_fn as usize == obj_alloc_fn as usize
83588344
{
8359-
let init = cls.get_attr(identifier!(vm, __init__));
8360-
let mut version = cls.tp_version_tag.load(Acquire);
8361-
if version == 0 {
8362-
version = cls.assign_version_tag();
8363-
}
8345+
let (init, version) =
8346+
cls.lookup_ref_and_version_interned(identifier!(vm, __init__), vm);
83648347
if version == 0 {
83658348
unsafe {
83668349
self.code.instructions.write_adaptive_counter(
@@ -8680,10 +8663,7 @@ impl ExecutingFrame<'_> {
86808663
&& cls.slots.as_sequence.length.load().is_none()
86818664
{
86828665
// Cache type version for ToBoolAlwaysTrue guard
8683-
let mut type_version = cls.tp_version_tag.load(Acquire);
8684-
if type_version == 0 {
8685-
type_version = cls.assign_version_tag();
8686-
}
8666+
let type_version = cls.version_for_specialization(vm);
86878667
if type_version != 0 {
86888668
unsafe {
86898669
self.code
@@ -9021,10 +9001,7 @@ impl ExecutingFrame<'_> {
90219001
}
90229002

90239003
// Get or assign type version
9024-
let mut type_version = cls.tp_version_tag.load(Acquire);
9025-
if type_version == 0 {
9026-
type_version = cls.assign_version_tag();
9027-
}
9004+
let type_version = cls.version_for_specialization(vm);
90289005
if type_version == 0 {
90299006
unsafe {
90309007
self.code.instructions.write_adaptive_counter(

crates/vm/src/stdlib/_ctypes/base.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,10 +2554,11 @@ fn make_fields(
25542554
}
25552555

25562556
let new_descr = super::PyCField::new_from_field(fdescr, index, offset);
2557-
cls.set_attr(
2557+
cls.as_object().set_attr(
25582558
vm.ctx.intern_str(fname.as_wtf8()),
25592559
new_descr.to_pyobject(vm),
2560-
);
2560+
vm,
2561+
)?;
25612562
}
25622563

25632564
Ok(())
@@ -2596,10 +2597,11 @@ pub(super) fn make_anon_fields(cls: &Py<PyType>, vm: &VirtualMachine) -> PyResul
25962597

25972598
let mut new_descr = super::PyCField::new_from_field(descr, 0, 0);
25982599
new_descr.set_anonymous(true);
2599-
cls.set_attr(
2600+
cls.as_object().set_attr(
26002601
vm.ctx.intern_str(fname.as_wtf8()),
26012602
new_descr.to_pyobject(vm),
2602-
);
2603+
vm,
2604+
)?;
26032605

26042606
make_fields(cls, descr, descr.index, descr.offset, vm)?;
26052607
}

crates/vm/src/stdlib/_ctypes/structure.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,11 @@ impl PyCStructType {
498498
};
499499

500500
// Set the CField as a class attribute
501-
cls.set_attr(vm.ctx.intern_str(name.clone()), c_field.to_pyobject(vm));
501+
cls.as_object().set_attr(
502+
vm.ctx.intern_str(name.clone()),
503+
c_field.to_pyobject(vm),
504+
vm,
505+
)?;
502506

503507
// Update tracking - don't advance offset for packed bitfields
504508
if field_advances_offset {

crates/vm/src/stdlib/_ctypes/union.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ impl PyCUnionType {
312312
PyCField::new(name.clone(), field_type_ref, 0, size as isize, index)
313313
};
314314

315-
cls.set_attr(vm.ctx.intern_str(name), c_field.to_pyobject(vm));
315+
cls.as_object()
316+
.set_attr(vm.ctx.intern_str(name), c_field.to_pyobject(vm), vm)?;
316317
}
317318

318319
// Calculate total_align and aligned_size

crates/vm/src/stdlib/posix.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ pub mod module {
840840
reinit_mutex_after_fork(&vm.state.atexit_funcs);
841841
reinit_mutex_after_fork(&vm.state.global_trace_func);
842842
reinit_mutex_after_fork(&vm.state.global_profile_func);
843+
reinit_mutex_after_fork(&vm.state.type_mutex);
843844
reinit_mutex_after_fork(&vm.state.monitoring);
844845

845846
// PyGlobalState parking_lot::Mutex locks

crates/vm/src/vm/interpreter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ where
115115
switch_interval: AtomicCell::new(0.005),
116116
global_trace_func: PyMutex::default(),
117117
global_profile_func: PyMutex::default(),
118+
type_mutex: PyMutex::default(),
118119
#[cfg(feature = "threading")]
119120
main_thread_ident: AtomicCell::new(0),
120121
#[cfg(feature = "threading")]

crates/vm/src/vm/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@ pub struct PyGlobalState {
599599
pub global_trace_func: PyMutex<Option<PyObjectRef>>,
600600
/// Global profile function for all threads (set by sys._setprofileallthreads)
601601
pub global_profile_func: PyMutex<Option<PyObjectRef>>,
602+
/// Global type mutation/versioning mutex for CPython-style FT type operations.
603+
pub type_mutex: PyMutex<()>,
602604
/// Main thread identifier (pthread_self on Unix)
603605
#[cfg(feature = "threading")]
604606
pub main_thread_ident: AtomicCell<u64>,

0 commit comments

Comments
 (0)