X Tutup
Skip to content

Commit c487b6d

Browse files
committed
Align call-init frame flow and spec cache atomic ordering
1 parent fc4728b commit c487b6d

File tree

3 files changed

+48
-21
lines changed

3 files changed

+48
-21
lines changed

crates/vm/src/builtins/type.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,9 @@ impl PyType {
914914
if self.tp_version_tag.load(Ordering::Acquire) != tp_version {
915915
return None;
916916
}
917-
ext.specialization_cache.init.to_owned()
917+
ext.specialization_cache
918+
.init
919+
.to_owned_ordering(Ordering::Acquire)
918920
}
919921

920922
/// Cache __getitem__ for BINARY_OP_SUBSCR_GETITEM specialization.
@@ -940,7 +942,7 @@ impl PyType {
940942
ext.specialization_cache.swap_getitem(Some(getitem));
941943
ext.specialization_cache
942944
.getitem_version
943-
.store(func_version, Ordering::Release);
945+
.store(func_version, Ordering::Relaxed);
944946
true
945947
}
946948

@@ -950,16 +952,13 @@ impl PyType {
950952
let cached_version = ext
951953
.specialization_cache
952954
.getitem_version
953-
.load(Ordering::Acquire);
955+
.load(Ordering::Relaxed);
954956
if cached_version == 0 {
955957
return None;
956958
}
957-
if self.tp_version_tag.load(Ordering::Acquire) == 0 {
958-
return None;
959-
}
960959
ext.specialization_cache
961960
.getitem
962-
.to_owned()
961+
.to_owned_ordering(Ordering::Acquire)
963962
.map(|getitem| (getitem, cached_version))
964963
}
965964

crates/vm/src/frame.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4723,6 +4723,12 @@ impl ExecutingFrame<'_> {
47234723
) {
47244724
return self.execute_call_vectorcall(nargs, vm);
47254725
}
4726+
// CPython creates two frames for this opcode:
4727+
// `_Py_InitCleanup` trampoline + `__init__` frame.
4728+
// Guard recursion limit accordingly and fall back.
4729+
if self.specialization_call_recursion_guard_with_extra_frames(vm, 1) {
4730+
return self.execute_call_vectorcall(nargs, vm);
4731+
}
47264732
// Allocate object directly (tp_new == object.__new__, tp_alloc == generic).
47274733
let cls_ref = cls.to_owned();
47284734
let new_obj = cls_alloc(cls_ref, 0, vm)?;
@@ -4736,10 +4742,9 @@ impl ExecutingFrame<'_> {
47364742
all_args.push(new_obj.clone());
47374743
all_args.extend(pos_args);
47384744

4739-
let init_callable: PyObjectRef = init_func.into();
4740-
let effective_nargs = all_args.len();
4741-
let init_result =
4742-
vectorcall_function(&init_callable, all_args, effective_nargs, None, vm)?;
4745+
// Match CPython's _CREATE_INIT_FRAME path shape: run init
4746+
// as exact-args Python function call.
4747+
let init_result = init_func.invoke_exact_args(all_args, vm)?;
47434748

47444749
// EXIT_INIT_CHECK: __init__ must return None
47454750
if !vm.is_none(&init_result) {
@@ -8690,7 +8695,19 @@ impl ExecutingFrame<'_> {
86908695

86918696
#[inline]
86928697
fn specialization_call_recursion_guard(&self, vm: &VirtualMachine) -> bool {
8693-
vm.current_recursion_depth().saturating_add(1) >= vm.recursion_limit.get()
8698+
self.specialization_call_recursion_guard_with_extra_frames(vm, 0)
8699+
}
8700+
8701+
#[inline]
8702+
fn specialization_call_recursion_guard_with_extra_frames(
8703+
&self,
8704+
vm: &VirtualMachine,
8705+
extra_frames: usize,
8706+
) -> bool {
8707+
vm.current_recursion_depth()
8708+
.saturating_add(1)
8709+
.saturating_add(extra_frames)
8710+
>= vm.recursion_limit.get()
86948711
}
86958712

86968713
#[inline]

crates/vm/src/object/ext.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,19 @@ impl<T: PyPayload> From<Option<PyRef<T>>> for PyAtomicRef<Option<T>> {
355355

356356
impl<T: PyPayload> PyAtomicRef<Option<T>> {
357357
pub fn deref(&self) -> Option<&Py<T>> {
358-
unsafe { self.inner.load(Ordering::Relaxed).cast::<Py<T>>().as_ref() }
358+
self.deref_ordering(Ordering::Relaxed)
359+
}
360+
361+
pub fn deref_ordering(&self, ordering: Ordering) -> Option<&Py<T>> {
362+
unsafe { self.inner.load(ordering).cast::<Py<T>>().as_ref() }
359363
}
360364

361365
pub fn to_owned(&self) -> Option<PyRef<T>> {
362-
self.deref().map(|x| x.to_owned())
366+
self.to_owned_ordering(Ordering::Relaxed)
367+
}
368+
369+
pub fn to_owned_ordering(&self, ordering: Ordering) -> Option<PyRef<T>> {
370+
self.deref_ordering(ordering).map(|x| x.to_owned())
363371
}
364372

365373
/// # Safety
@@ -441,16 +449,19 @@ impl From<Option<PyObjectRef>> for PyAtomicRef<Option<PyObject>> {
441449

442450
impl PyAtomicRef<Option<PyObject>> {
443451
pub fn deref(&self) -> Option<&PyObject> {
444-
unsafe {
445-
self.inner
446-
.load(Ordering::Relaxed)
447-
.cast::<PyObject>()
448-
.as_ref()
449-
}
452+
self.deref_ordering(Ordering::Relaxed)
453+
}
454+
455+
pub fn deref_ordering(&self, ordering: Ordering) -> Option<&PyObject> {
456+
unsafe { self.inner.load(ordering).cast::<PyObject>().as_ref() }
450457
}
451458

452459
pub fn to_owned(&self) -> Option<PyObjectRef> {
453-
self.deref().map(|x| x.to_owned())
460+
self.to_owned_ordering(Ordering::Relaxed)
461+
}
462+
463+
pub fn to_owned_ordering(&self, ordering: Ordering) -> Option<PyObjectRef> {
464+
self.deref_ordering(ordering).map(|x| x.to_owned())
454465
}
455466

456467
/// # Safety

0 commit comments

Comments
 (0)
X Tutup