Skip to content

gh-135832: implement Py_DECREF specializations for Py_GIL_DISABLED build #135833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

alex-semenyuk
Copy link
Contributor

@alex-semenyuk alex-semenyuk commented Jun 23, 2025

Comment on lines 316 to 317
static inline void
_Py_DECREF_NO_DEALLOC(PyObject *op)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this function is used anymore.

@@ -272,17 +272,93 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
}

#else
// TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build

static inline void
_Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is barely used now, but there's a similar function PyStackRef_CLOSE_SPECIALIZED.

There are two possible reasons to implement this as something that's not just Py_DECREF:

  1. Performance, but it's not really clear that it's going to be any faster
  2. To avoid _Py_Dealloc so that you can enable this assertion

    cpython/Objects/object.c

    Lines 3166 to 3170 in 6227662

    #if !defined(Py_GIL_DISABLED) && !defined(Py_STACKREF_DEBUG)
    /* This assertion doesn't hold for the free-threading build, as
    * PyStackRef_CLOSE_SPECIALIZED is not implemented */
    assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
    #endif
    , but that means you can't call _Py_MergeZeroLocalRefcount because that internally may call _Py_Dealloc

I think (2) would be difficult to achieve because of _Py_brc_queue_object.

&op->ob_ref_shared,
&shared,
new_shared)) {
if (new_shared == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can only safely deallocate if the reference count is zero and it's merged (i.e., new_shared is _Py_REF_MERGED)

Comment on lines +298 to +299
Py_ssize_t new_shared = shared - (1 << _Py_REF_SHARED_SHIFT);
if (_Py_atomic_compare_exchange_ssize(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing important parts of _Py_DecRefShared: if the shared reference count becomes negative, the object must be queued so that the owning thread merges the two reference count fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants