Skip to content

Commit ef2fa40

Browse files
committed
Add static inline _Py_NewReferenceInline() function
1 parent 5bfab66 commit ef2fa40

7 files changed

Lines changed: 86 additions & 47 deletions

File tree

‎Include/internal/pycore_freelist.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern "C" {
1313
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED()
1414
#include "pycore_pystate.h" // _PyThreadState_GET
1515
#include "pycore_stats.h" // OBJECT_STAT_INC
16+
#include "pycore_object.h" // _Py_NewReferenceInline()
1617

1718
static inline struct _Py_freelists *
1819
_Py_freelists_GET(void)
@@ -89,7 +90,7 @@ _PyFreeList_Pop(struct _Py_freelist *fl)
8990
PyObject *op = _PyFreeList_PopNoStats(fl);
9091
if (op != NULL) {
9192
OBJECT_STAT_INC(from_freelist);
92-
_Py_NewReference(op);
93+
_Py_NewReferenceInline(op);
9394
}
9495
return op;
9596
}

‎Include/internal/pycore_object.h‎

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ extern "C" {
1919
#include <stdbool.h> // bool
2020

2121

22+
#ifdef Py_TRACE_REFS
23+
extern void _Py_AddToAllObjects(PyObject *op);
24+
extern void _Py_PrintReferences(PyInterpreterState *, FILE *);
25+
extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *);
26+
#endif
27+
28+
2229
// This value is added to `ob_ref_shared` for objects that use deferred
2330
// reference counting so that they are not immediately deallocated when the
2431
// non-deferred reference count drops to zero.
@@ -468,6 +475,52 @@ static inline void Py_DECREF_MORTAL_SPECIALIZED(PyObject *op, destructor destruc
468475
# define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF(op)
469476
#endif
470477

478+
static inline void
479+
_Py_NewReferenceNoTotalInline(PyObject *op)
480+
{
481+
// Skip the immortal object check in Py_SET_REFCNT; always set refcnt to 1
482+
#if !defined(Py_GIL_DISABLED)
483+
// With GIL
484+
#if SIZEOF_VOID_P > 4
485+
op->ob_refcnt_full = 1;
486+
assert(op->ob_refcnt == 1);
487+
assert(op->ob_flags == 0);
488+
#else
489+
op->ob_refcnt = 1;
490+
#endif
491+
#else
492+
// Free Threading
493+
op->ob_flags = 0;
494+
op->ob_mutex = (PyMutex){ 0 };
495+
#ifdef _Py_THREAD_SANITIZER
496+
_Py_atomic_store_uintptr_relaxed(&op->ob_tid, _Py_ThreadId());
497+
_Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, 0);
498+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, 1);
499+
_Py_atomic_store_ssize_relaxed(&op->ob_ref_shared, 0);
500+
#else
501+
op->ob_tid = _Py_ThreadId();
502+
op->ob_gc_bits = 0;
503+
op->ob_ref_local = 1;
504+
op->ob_ref_shared = 0;
505+
#endif
506+
#endif
507+
508+
#ifdef Py_TRACE_REFS
509+
_Py_AddToAllObjects(op);
510+
#endif
511+
512+
_PyReftracerTrack(op, PyRefTracer_CREATE);
513+
}
514+
515+
static inline void
516+
_Py_NewReferenceInline(PyObject *op)
517+
{
518+
#ifdef Py_REF_DEBUG
519+
_Py_IncRefTotal(_PyThreadState_GET());
520+
#endif
521+
_Py_NewReferenceNoTotalInline(op);
522+
}
523+
471524
/* Inline functions trading binary compatibility for speed:
472525
_PyObject_Init() is the fast version of PyObject_Init(), and
473526
_PyObject_InitVar() is the fast version of PyObject_InitVar().
@@ -480,7 +533,7 @@ _PyObject_Init(PyObject *op, PyTypeObject *typeobj)
480533
Py_SET_TYPE(op, typeobj);
481534
assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || _Py_IsImmortal(typeobj));
482535
_Py_INCREF_TYPE(typeobj);
483-
_Py_NewReference(op);
536+
_Py_NewReferenceInline(op);
484537
}
485538

486539
static inline void
@@ -764,12 +817,6 @@ extern void _Py_FinalizeRefTotal(_PyRuntimeState *);
764817
extern void _PyDebug_PrintTotalRefs(void);
765818
#endif
766819

767-
#ifdef Py_TRACE_REFS
768-
extern void _Py_AddToAllObjects(PyObject *op);
769-
extern void _Py_PrintReferences(PyInterpreterState *, FILE *);
770-
extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *);
771-
#endif
772-
773820

774821
/* Return the *address* of the object's weaklist. The address may be
775822
* dereferenced to get the current head of the weaklist. This is useful

‎Modules/_testcapimodule.c‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,29 @@ uptime_bsd(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args))
28892889
#endif
28902890

28912891

2892+
static PyObject *
2893+
bench_writer(PyObject *self, PyObject *args)
2894+
{
2895+
Py_ssize_t size, loops;
2896+
if (!PyArg_ParseTuple(args, "nn", &size, &loops)) {
2897+
return NULL;
2898+
}
2899+
2900+
PyTime_t t1, t2;
2901+
(void)PyTime_PerfCounterRaw(&t1);
2902+
for (Py_ssize_t i=0; i < loops; i++) {
2903+
PyObject *bytes = PyBytes_FromString("abc");
2904+
if (bytes == NULL) {
2905+
return NULL;
2906+
}
2907+
Py_DECREF(bytes);
2908+
}
2909+
(void)PyTime_PerfCounterRaw(&t2);
2910+
2911+
return PyFloat_FromDouble(PyTime_AsSecondsDouble(t2 - t1));
2912+
}
2913+
2914+
28922915
static PyMethodDef TestMethods[] = {
28932916
{"set_errno", set_errno, METH_VARARGS},
28942917
{"test_config", test_config, METH_NOARGS},
@@ -2988,6 +3011,7 @@ static PyMethodDef TestMethods[] = {
29883011
#ifdef HAVE_SYSCTLBYNAME
29893012
{"uptime_bsd", uptime_bsd, METH_NOARGS},
29903013
#endif
3014+
{"bench_writer", bench_writer, METH_VARARGS},
29913015
{NULL, NULL} /* sentinel */
29923016
};
29933017

‎Objects/bytesobject.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3438,7 +3438,7 @@ bytes_resize_inplace(PyObject **pv, Py_ssize_t newsize)
34383438

34393439
*pv = result;
34403440
v = result;
3441-
_Py_NewReferenceNoTotal(v);
3441+
_Py_NewReferenceNoTotalInline(v);
34423442
PyBytesObject *sv = (PyBytesObject *)v;
34433443
Py_SET_SIZE(sv, newsize);
34443444
sv->ob_sval[newsize] = '\0';

‎Objects/object.c‎

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,52 +2738,19 @@ _PyTypes_FiniTypes(PyInterpreterState *interp)
27382738
}
27392739

27402740

2741-
static inline void
2742-
new_reference(PyObject *op)
2743-
{
2744-
// Skip the immortal object check in Py_SET_REFCNT; always set refcnt to 1
2745-
#if !defined(Py_GIL_DISABLED)
2746-
#if SIZEOF_VOID_P > 4
2747-
op->ob_refcnt_full = 1;
2748-
assert(op->ob_refcnt == 1);
2749-
assert(op->ob_flags == 0);
2750-
#else
2751-
op->ob_refcnt = 1;
2752-
#endif
2753-
#else
2754-
op->ob_flags = 0;
2755-
op->ob_mutex = (PyMutex){ 0 };
2756-
#ifdef _Py_THREAD_SANITIZER
2757-
_Py_atomic_store_uintptr_relaxed(&op->ob_tid, _Py_ThreadId());
2758-
_Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, 0);
2759-
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, 1);
2760-
_Py_atomic_store_ssize_relaxed(&op->ob_ref_shared, 0);
2761-
#else
2762-
op->ob_tid = _Py_ThreadId();
2763-
op->ob_gc_bits = 0;
2764-
op->ob_ref_local = 1;
2765-
op->ob_ref_shared = 0;
2766-
#endif
2767-
#endif
2768-
#ifdef Py_TRACE_REFS
2769-
_Py_AddToAllObjects(op);
2770-
#endif
2771-
_PyReftracerTrack(op, PyRefTracer_CREATE);
2772-
}
2773-
27742741
void
27752742
_Py_NewReference(PyObject *op)
27762743
{
27772744
#ifdef Py_REF_DEBUG
27782745
_Py_IncRefTotal(_PyThreadState_GET());
27792746
#endif
2780-
new_reference(op);
2747+
_Py_NewReferenceNoTotalInline(op);
27812748
}
27822749

27832750
void
27842751
_Py_NewReferenceNoTotal(PyObject *op)
27852752
{
2786-
new_reference(op);
2753+
_Py_NewReferenceNoTotalInline(op);
27872754
}
27882755

27892756
void

‎Objects/tupleobject.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
10691069
PyObject_GC_Del(v);
10701070
return -1;
10711071
}
1072-
_Py_NewReferenceNoTotal((PyObject *) sv);
1072+
_Py_NewReferenceNoTotalInline((PyObject *) sv);
10731073
/* Zero out items added by growing */
10741074
if (newsize > oldsize)
10751075
memset(&sv->ob_item[oldsize], 0,

‎Objects/unicodeobject.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,12 +1124,12 @@ _PyUnicode_ResizeCompact(PyObject *unicode, Py_ssize_t length)
11241124

11251125
new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size);
11261126
if (new_unicode == NULL) {
1127-
_Py_NewReferenceNoTotal(unicode);
1127+
_Py_NewReferenceNoTotalInline(unicode);
11281128
PyErr_NoMemory();
11291129
return NULL;
11301130
}
11311131
unicode = new_unicode;
1132-
_Py_NewReferenceNoTotal(unicode);
1132+
_Py_NewReferenceNoTotalInline(unicode);
11331133

11341134
_PyUnicode_LENGTH(unicode) = length;
11351135
#ifdef Py_DEBUG

0 commit comments

Comments
 (0)