Skip to content

Commit c894014

Browse files
committed
type lock
1 parent 4107217 commit c894014

8 files changed

Lines changed: 304 additions & 182 deletions

File tree

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
@@ -7453,10 +7453,7 @@ impl ExecutingFrame<'_> {
74537453
.load()
74547454
.is_some_and(|f| f as usize == PyBaseObject::getattro as *const () as usize);
74557455
if !is_default_getattro {
7456-
let mut type_version = cls.tp_version_tag.load(Acquire);
7457-
if type_version == 0 {
7458-
type_version = cls.assign_version_tag();
7459-
}
7456+
let type_version = cls.version_for_specialization(_vm);
74607457
if type_version != 0
74617458
&& !oparg.is_method()
74627459
&& !self.specialization_eval_frame_active(_vm)
@@ -7494,10 +7491,7 @@ impl ExecutingFrame<'_> {
74947491
}
74957492

74967493
// Get or assign type version
7497-
let mut type_version = cls.tp_version_tag.load(Acquire);
7498-
if type_version == 0 {
7499-
type_version = cls.assign_version_tag();
7500-
}
7494+
let type_version = cls.version_for_specialization(_vm);
75017495
if type_version == 0 {
75027496
// Version counter overflow — backoff to avoid re-attempting every execution
75037497
unsafe {
@@ -7717,10 +7711,7 @@ impl ExecutingFrame<'_> {
77177711
let owner_type = obj.downcast_ref::<PyType>().unwrap();
77187712

77197713
// Get or assign type version for the type object itself
7720-
let mut type_version = owner_type.tp_version_tag.load(Acquire);
7721-
if type_version == 0 {
7722-
type_version = owner_type.assign_version_tag();
7723-
}
7714+
let type_version = owner_type.version_for_specialization(_vm);
77247715
if type_version == 0 {
77257716
unsafe {
77267717
self.code.instructions.write_adaptive_counter(
@@ -7755,10 +7746,7 @@ impl ExecutingFrame<'_> {
77557746
}
77567747
let mut metaclass_version = 0;
77577748
if !mcl.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
7758-
metaclass_version = mcl.tp_version_tag.load(Acquire);
7759-
if metaclass_version == 0 {
7760-
metaclass_version = mcl.assign_version_tag();
7761-
}
7749+
metaclass_version = mcl.version_for_specialization(_vm);
77627750
if metaclass_version == 0 {
77637751
unsafe {
77647752
self.code.instructions.write_adaptive_counter(
@@ -7945,16 +7933,14 @@ impl ExecutingFrame<'_> {
79457933
Some(Instruction::BinaryOpSubscrListSlice)
79467934
} else {
79477935
let cls = a.class();
7936+
let (getitem, type_version) =
7937+
cls.lookup_ref_and_version_interned(identifier!(vm, __getitem__), vm);
79487938
if cls.slots.flags.has_feature(PyTypeFlags::HEAPTYPE)
79497939
&& !self.specialization_eval_frame_active(vm)
7950-
&& let Some(_getitem) = cls.get_attr(identifier!(vm, __getitem__))
7940+
&& let Some(_getitem) = getitem
79517941
&& let Some(func) = _getitem.downcast_ref_if_exact::<PyFunction>(vm)
79527942
&& func.can_specialize_call(2)
79537943
{
7954-
let mut type_version = cls.tp_version_tag.load(Acquire);
7955-
if type_version == 0 {
7956-
type_version = cls.assign_version_tag();
7957-
}
79587944
if type_version != 0 {
79597945
if cls.cache_getitem_for_specialization(
79607946
func.to_owned(),
@@ -8493,11 +8479,8 @@ impl ExecutingFrame<'_> {
84938479
&& cls_new_fn as usize == obj_new_fn as usize
84948480
&& cls_alloc_fn as usize == obj_alloc_fn as usize
84958481
{
8496-
let init = cls.get_attr(identifier!(vm, __init__));
8497-
let mut version = cls.tp_version_tag.load(Acquire);
8498-
if version == 0 {
8499-
version = cls.assign_version_tag();
8500-
}
8482+
let (init, version) =
8483+
cls.lookup_ref_and_version_interned(identifier!(vm, __init__), vm);
85018484
if version == 0 {
85028485
unsafe {
85038486
self.code.instructions.write_adaptive_counter(
@@ -8817,10 +8800,7 @@ impl ExecutingFrame<'_> {
88178800
&& cls.slots.as_sequence.length.load().is_none()
88188801
{
88198802
// Cache type version for ToBoolAlwaysTrue guard
8820-
let mut type_version = cls.tp_version_tag.load(Acquire);
8821-
if type_version == 0 {
8822-
type_version = cls.assign_version_tag();
8823-
}
8803+
let type_version = cls.version_for_specialization(vm);
88248804
if type_version != 0 {
88258805
unsafe {
88268806
self.code
@@ -9158,10 +9138,7 @@ impl ExecutingFrame<'_> {
91589138
}
91599139

91609140
// Get or assign type version
9161-
let mut type_version = cls.tp_version_tag.load(Acquire);
9162-
if type_version == 0 {
9163-
type_version = cls.assign_version_tag();
9164-
}
9141+
let type_version = cls.version_for_specialization(vm);
91659142
if type_version == 0 {
91669143
unsafe {
91679144
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
@@ -119,6 +119,7 @@ where
119119
switch_interval: AtomicCell::new(0.005),
120120
global_trace_func: PyMutex::default(),
121121
global_profile_func: PyMutex::default(),
122+
type_mutex: PyMutex::default(),
122123
#[cfg(feature = "threading")]
123124
main_thread_ident: AtomicCell::new(0),
124125
#[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)