Skip to content

Commit 05a824f

Browse files
authored
GH-84436: Skip refcounting for known immortals (GH-107605)
1 parent ec0a0d2 commit 05a824f

19 files changed

+52
-65
lines changed

Include/internal/pycore_long.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,19 @@ extern void _PyLong_FiniTypes(PyInterpreterState *interp);
6464
# error "_PY_NSMALLPOSINTS must be greater than or equal to 257"
6565
#endif
6666

67-
// Return a borrowed reference to the zero singleton.
67+
// Return a reference to the immortal zero singleton.
6868
// The function cannot return NULL.
6969
static inline PyObject* _PyLong_GetZero(void)
7070
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS]; }
7171

72-
// Return a borrowed reference to the one singleton.
72+
// Return a reference to the immortal one singleton.
7373
// The function cannot return NULL.
7474
static inline PyObject* _PyLong_GetOne(void)
7575
{ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+1]; }
7676

7777
static inline PyObject* _PyLong_FromUnsignedChar(unsigned char i)
7878
{
79-
return Py_NewRef((PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+i]);
79+
return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS+i];
8080
}
8181

8282
extern PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Skip reference count modifications for many known immortal objects.

Modules/_asynciomodule.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,8 @@ FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored))
13981398
default:
13991399
assert (0);
14001400
}
1401-
return Py_XNewRef(ret);
1401+
assert(_Py_IsImmortal(ret));
1402+
return ret;
14021403
}
14031404

14041405
static PyObject *

Modules/_io/textio.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
234234
{
235235

236236
if (errors == NULL) {
237-
errors = Py_NewRef(&_Py_ID(strict));
237+
errors = &_Py_ID(strict);
238238
}
239239
else {
240240
errors = Py_NewRef(errors);
@@ -1138,7 +1138,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
11381138

11391139
if (encoding == NULL && _PyRuntime.preconfig.utf8_mode) {
11401140
_Py_DECLARE_STR(utf_8, "utf-8");
1141-
self->encoding = Py_NewRef(&_Py_STR(utf_8));
1141+
self->encoding = &_Py_STR(utf_8);
11421142
}
11431143
else if (encoding == NULL || (strcmp(encoding, "locale") == 0)) {
11441144
self->encoding = _Py_GetLocaleEncodingObject();
@@ -2267,7 +2267,7 @@ _textiowrapper_readline(textio *self, Py_ssize_t limit)
22672267
Py_CLEAR(chunks);
22682268
}
22692269
if (line == NULL) {
2270-
line = Py_NewRef(&_Py_STR(empty));
2270+
line = &_Py_STR(empty);
22712271
}
22722272

22732273
return line;

Modules/_json.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1277,13 +1277,13 @@ _encoded_const(PyObject *obj)
12771277
{
12781278
/* Return the JSON string representation of None, True, False */
12791279
if (obj == Py_None) {
1280-
return Py_NewRef(&_Py_ID(null));
1280+
return &_Py_ID(null);
12811281
}
12821282
else if (obj == Py_True) {
1283-
return Py_NewRef(&_Py_ID(true));
1283+
return &_Py_ID(true);
12841284
}
12851285
else if (obj == Py_False) {
1286-
return Py_NewRef(&_Py_ID(false));
1286+
return &_Py_ID(false);
12871287
}
12881288
else {
12891289
PyErr_SetString(PyExc_ValueError, "not a const");

Modules/_pickle.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -2029,8 +2029,7 @@ whichmodule(PyObject *global, PyObject *dotted_path)
20292029
}
20302030

20312031
/* If no module is found, use __main__. */
2032-
module_name = &_Py_ID(__main__);
2033-
return Py_NewRef(module_name);
2032+
return &_Py_ID(__main__);
20342033
}
20352034

20362035
/* fast_save_enter() and fast_save_leave() are guards against recursive

Objects/boolobject.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
static PyObject *
1414
bool_repr(PyObject *self)
1515
{
16-
PyObject *res = self == Py_True ? &_Py_ID(True) : &_Py_ID(False);
17-
return Py_NewRef(res);
16+
return self == Py_True ? &_Py_ID(True) : &_Py_ID(False);
1817
}
1918

2019
/* Function to return a bool from a C long */

Objects/bytesobject.c

+12-15
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,12 @@ Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer,
4141
#define EMPTY (&_Py_SINGLETON(bytes_empty))
4242

4343

44-
// Return a borrowed reference to the empty bytes string singleton.
44+
// Return a reference to the immortal empty bytes string singleton.
4545
static inline PyObject* bytes_get_empty(void)
4646
{
47-
return &EMPTY->ob_base.ob_base;
48-
}
49-
50-
51-
// Return a strong reference to the empty bytes string singleton.
52-
static inline PyObject* bytes_new_empty(void)
53-
{
54-
return Py_NewRef(EMPTY);
47+
PyObject *empty = &EMPTY->ob_base.ob_base;
48+
assert(_Py_IsImmortal(empty));
49+
return empty;
5550
}
5651

5752

@@ -84,7 +79,7 @@ _PyBytes_FromSize(Py_ssize_t size, int use_calloc)
8479
assert(size >= 0);
8580

8681
if (size == 0) {
87-
return bytes_new_empty();
82+
return bytes_get_empty();
8883
}
8984

9085
if ((size_t)size > (size_t)PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
@@ -123,10 +118,11 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
123118
}
124119
if (size == 1 && str != NULL) {
125120
op = CHARACTER(*str & 255);
126-
return Py_NewRef(op);
121+
assert(_Py_IsImmortal(op));
122+
return (PyObject *)op;
127123
}
128124
if (size == 0) {
129-
return bytes_new_empty();
125+
return bytes_get_empty();
130126
}
131127

132128
op = (PyBytesObject *)_PyBytes_FromSize(size, 0);
@@ -154,11 +150,12 @@ PyBytes_FromString(const char *str)
154150
}
155151

156152
if (size == 0) {
157-
return bytes_new_empty();
153+
return bytes_get_empty();
158154
}
159155
else if (size == 1) {
160156
op = CHARACTER(*str & 255);
161-
return Py_NewRef(op);
157+
assert(_Py_IsImmortal(op));
158+
return (PyObject *)op;
162159
}
163160

164161
/* Inline PyObject_NewVar */
@@ -3065,7 +3062,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
30653062
goto error;
30663063
}
30673064
if (newsize == 0) {
3068-
*pv = bytes_new_empty();
3065+
*pv = bytes_get_empty();
30693066
Py_DECREF(v);
30703067
return 0;
30713068
}

Objects/funcobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -831,8 +831,8 @@ func_clear(PyFunctionObject *op)
831831
// However, name and qualname could be str subclasses, so they
832832
// could have reference cycles. The solution is to replace them
833833
// with a genuinely immutable string.
834-
Py_SETREF(op->func_name, Py_NewRef(&_Py_STR(empty)));
835-
Py_SETREF(op->func_qualname, Py_NewRef(&_Py_STR(empty)));
834+
Py_SETREF(op->func_name, &_Py_STR(empty));
835+
Py_SETREF(op->func_qualname, &_Py_STR(empty));
836836
return 0;
837837
}
838838

Objects/longobject.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits)
174174
{
175175
assert(digit_count >= 0);
176176
if (digit_count == 0) {
177-
return (PyLongObject *)Py_NewRef(_PyLong_GetZero());
177+
return (PyLongObject *)_PyLong_GetZero();
178178
}
179179
PyLongObject *result = _PyLong_New(digit_count);
180180
if (result == NULL) {
@@ -2857,8 +2857,7 @@ long_divrem(PyLongObject *a, PyLongObject *b,
28572857
if (*prem == NULL) {
28582858
return -1;
28592859
}
2860-
PyObject *zero = _PyLong_GetZero();
2861-
*pdiv = (PyLongObject*)Py_NewRef(zero);
2860+
*pdiv = (PyLongObject*)_PyLong_GetZero();
28622861
return 0;
28632862
}
28642863
if (size_b == 1) {

Objects/rangeobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
106106
if (!stop) {
107107
return NULL;
108108
}
109-
start = Py_NewRef(_PyLong_GetZero());
110-
step = Py_NewRef(_PyLong_GetOne());
109+
start = _PyLong_GetZero();
110+
step = _PyLong_GetOne();
111111
break;
112112
case 0:
113113
PyErr_SetString(PyExc_TypeError,

Objects/sliceobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
415415

416416
/* Convert step to an integer; raise for zero step. */
417417
if (self->step == Py_None) {
418-
step = Py_NewRef(_PyLong_GetOne());
418+
step = _PyLong_GetOne();
419419
step_is_negative = 0;
420420
}
421421
else {
@@ -443,7 +443,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
443443
goto error;
444444
}
445445
else {
446-
lower = Py_NewRef(_PyLong_GetZero());
446+
lower = _PyLong_GetZero();
447447
upper = Py_NewRef(length);
448448
}
449449

Objects/tupleobject.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ tuple_alloc(Py_ssize_t size)
6262
static inline PyObject *
6363
tuple_get_empty(void)
6464
{
65-
return Py_NewRef(&_Py_SINGLETON(tuple_empty));
65+
return (PyObject *)&_Py_SINGLETON(tuple_empty);
6666
}
6767

6868
PyObject *

Objects/typeobject.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ type_module(PyTypeObject *type, void *context)
10851085
PyUnicode_InternInPlace(&mod);
10861086
}
10871087
else {
1088-
mod = Py_NewRef(&_Py_ID(builtins));
1088+
mod = &_Py_ID(builtins);
10891089
}
10901090
}
10911091
return mod;

Objects/unicodeobject.c

+12-21
Original file line numberDiff line numberDiff line change
@@ -211,21 +211,13 @@ static int unicode_is_singleton(PyObject *unicode);
211211
#endif
212212

213213

214-
// Return a borrowed reference to the empty string singleton.
214+
// Return a reference to the immortal empty string singleton.
215215
static inline PyObject* unicode_get_empty(void)
216216
{
217217
_Py_DECLARE_STR(empty, "");
218218
return &_Py_STR(empty);
219219
}
220220

221-
222-
// Return a strong reference to the empty string singleton.
223-
static inline PyObject* unicode_new_empty(void)
224-
{
225-
PyObject *empty = unicode_get_empty();
226-
return Py_NewRef(empty);
227-
}
228-
229221
/* This dictionary holds all interned unicode strings. Note that references
230222
to strings in this dictionary are *not* counted in the string's ob_refcnt.
231223
When the interned string reaches a refcnt of 0 the string deallocation
@@ -310,7 +302,7 @@ clear_interned_dict(PyInterpreterState *interp)
310302

311303
#define _Py_RETURN_UNICODE_EMPTY() \
312304
do { \
313-
return unicode_new_empty(); \
305+
return unicode_get_empty(); \
314306
} while (0)
315307

316308
static inline void
@@ -650,7 +642,6 @@ unicode_result(PyObject *unicode)
650642
PyObject *empty = unicode_get_empty();
651643
if (unicode != empty) {
652644
Py_DECREF(unicode);
653-
Py_INCREF(empty);
654645
}
655646
return empty;
656647
}
@@ -662,7 +653,6 @@ unicode_result(PyObject *unicode)
662653
Py_UCS1 ch = data[0];
663654
PyObject *latin1_char = LATIN1(ch);
664655
if (unicode != latin1_char) {
665-
Py_INCREF(latin1_char);
666656
Py_DECREF(unicode);
667657
}
668658
return latin1_char;
@@ -1199,7 +1189,7 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar)
11991189
{
12001190
/* Optimization for empty strings */
12011191
if (size == 0) {
1202-
return unicode_new_empty();
1192+
return unicode_get_empty();
12031193
}
12041194

12051195
PyObject *obj;
@@ -1669,7 +1659,7 @@ unicode_resize(PyObject **p_unicode, Py_ssize_t length)
16691659
return 0;
16701660

16711661
if (length == 0) {
1672-
PyObject *empty = unicode_new_empty();
1662+
PyObject *empty = unicode_get_empty();
16731663
Py_SETREF(*p_unicode, empty);
16741664
return 0;
16751665
}
@@ -1764,7 +1754,9 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index,
17641754
static PyObject*
17651755
get_latin1_char(Py_UCS1 ch)
17661756
{
1767-
return Py_NewRef(LATIN1(ch));
1757+
PyObject *o = LATIN1(ch);
1758+
assert(_Py_IsImmortal(o));
1759+
return o;
17681760
}
17691761

17701762
static PyObject*
@@ -1891,7 +1883,7 @@ PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size)
18911883
"NULL string with positive size with NULL passed to PyUnicode_FromStringAndSize");
18921884
return NULL;
18931885
}
1894-
return unicode_new_empty();
1886+
return unicode_get_empty();
18951887
}
18961888

18971889
PyObject *
@@ -10261,7 +10253,7 @@ replace(PyObject *self, PyObject *str1,
1026110253
}
1026210254
new_size = slen + n * (len2 - len1);
1026310255
if (new_size == 0) {
10264-
u = unicode_new_empty();
10256+
u = unicode_get_empty();
1026510257
goto done;
1026610258
}
1026710259
if (new_size > (PY_SSIZE_T_MAX / rkind)) {
@@ -14505,7 +14497,7 @@ unicode_new_impl(PyTypeObject *type, PyObject *x, const char *encoding,
1450514497
{
1450614498
PyObject *unicode;
1450714499
if (x == NULL) {
14508-
unicode = unicode_new_empty();
14500+
unicode = unicode_get_empty();
1450914501
}
1451014502
else if (encoding == NULL && errors == NULL) {
1451114503
unicode = PyObject_Str(x);
@@ -14994,8 +14986,7 @@ unicode_ascii_iter_next(unicodeiterobject *it)
1499414986
Py_UCS1 chr = (Py_UCS1)PyUnicode_READ(PyUnicode_1BYTE_KIND,
1499514987
data, it->it_index);
1499614988
it->it_index++;
14997-
PyObject *item = (PyObject*)&_Py_SINGLETON(strings).ascii[chr];
14998-
return Py_NewRef(item);
14989+
return (PyObject*)&_Py_SINGLETON(strings).ascii[chr];
1499914990
}
1500014991
it->it_seq = NULL;
1500114992
Py_DECREF(seq);
@@ -15025,7 +15016,7 @@ unicodeiter_reduce(unicodeiterobject *it, PyObject *Py_UNUSED(ignored))
1502515016
if (it->it_seq != NULL) {
1502615017
return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
1502715018
} else {
15028-
PyObject *u = unicode_new_empty();
15019+
PyObject *u = unicode_get_empty();
1502915020
if (u == NULL) {
1503015021
Py_XDECREF(iter);
1503115022
return NULL;

Python/ceval.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
12651265
if (co->co_flags & CO_VARARGS) {
12661266
PyObject *u = NULL;
12671267
if (argcount == n) {
1268-
u = Py_NewRef(&_Py_SINGLETON(tuple_empty));
1268+
u = (PyObject *)&_Py_SINGLETON(tuple_empty);
12691269
}
12701270
else {
12711271
assert(args != NULL);

Python/context.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ PyTypeObject _PyContextTokenMissing_Type = {
12671267
static PyObject *
12681268
get_token_missing(void)
12691269
{
1270-
return Py_NewRef(&_Py_SINGLETON(context_token_missing));
1270+
return (PyObject *)&_Py_SINGLETON(context_token_missing);
12711271
}
12721272

12731273

Python/fileutils.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ _Py_device_encoding(int fd)
105105
#else
106106
if (_PyRuntime.preconfig.utf8_mode) {
107107
_Py_DECLARE_STR(utf_8, "utf-8");
108-
return Py_NewRef(&_Py_STR(utf_8));
108+
return &_Py_STR(utf_8);
109109
}
110110
return _Py_GetLocaleEncodingObject();
111111
#endif

0 commit comments

Comments
 (0)