This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eelizondo
Recipients Mark.Shannon, carljm, corona10, dino.viehland, eelizondo, gregory.p.smith, nascheme, pablogsal, pitrou, shihai1991, steve.dower, tim.peters, vstinner
Date 2020-04-16.19:13:30
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <>
> I'm somewhat puzzled how a version that does no more work and has no jumps is slower.

Oh I think I know why there's some confusion. I've updated the PR from the initial version (which is probably the one that you saw). The branching does 
less work in Py_INCREF and Py_DECREF for all instances marked with the immortal bit by exiting early.

In the latest change, I added the immortal bit to a bunch of "known" immortal objects by. For instance:
* All static types (i.e: PyType_Type, etc.)
* All small ints (-5 to 256)
* The following Singletons: PyTrue, PyFalse, PyNone
* And the heap after the runtime is initialized (in pymain_main)

Example 1)
PyObject _Py_NoneStruct = {
  1, &_PyNone_Type
#endif  /* Py_IMMORTAL_OBJECTS */

Example 2)
static int
pymain_main(_PyArgv *args)
    PyStatus status = pymain_init(args);
    if (_PyStatus_IS_EXIT(status)) {
        return status.exitcode;
    if (_PyStatus_EXCEPTION(status)) {

    /* Most of the objects alive at this point will stay alive throughout the
     * lifecycle of the runtime. Immortalize to avoid the GC and refcnt costs */
#endif  /* Py_IMMORTAL_OBJECTS */
    return Py_RunMain();

Therefore, you are now making Py_INCREF and Py_DECREF cheaper for things like  `Py_RETURN_NONE` and a bunch of other instances.

Let me know if that explains it! I could also send you patch of the branch-less version so you can compare them.

> but making the object header immutable prevents changes like

Why would it prevent it? These changes are not mutually exclusive, you can still have an immortal bit by:
1) Using a bit from `gc_bits`. Currently you only need 2 bits for the GC. Even with a `short` you'll have space for the immortal bit.
2) Using a bit from the ob_refcnt. Separately, using this allows us to experiment with a branch-less and test-less code by using saturated adds. For example:

/* Branch-less incref with saturated add */
#define PY_REFCNT_MAX ((int)(((int)-1)>>1))
#define _Py_INCREF(op) ({
    __asm__ (
        "addl $0x1, %[refcnt]"
        "cmovol  %[refcnt_max], %[refcnt]"
        : [refcnt] "+r" (((PyObject *)op)->ob_refcnt)
        : [refcnt_max] "r" (PY_REFCNT_MAX)
Date User Action Args
2020-04-16 19:13:30eelizondosetrecipients: + eelizondo, tim.peters, nascheme, gregory.p.smith, pitrou, vstinner, carljm, dino.viehland, Mark.Shannon, steve.dower, corona10, pablogsal, shihai1991
2020-04-16 19:13:30eelizondosetmessageid: <>
2020-04-16 19:13:30eelizondolinkissue40255 messages
2020-04-16 19:13:30eelizondocreate