Skip to content

Commit 7ffef8d

Browse files
corona10kumaraditya303serhiy-storchaka
authored
[3.13] gh-132070: Use _PyObject_IsUniquelyReferenced in unicodeobject (gh-133039) (gh-133126)
* gh-132070: Use _PyObject_IsUniquelyReferenced in unicodeobject (gh-133039) --------- (cherry picked from commit 75cbb8d) Co-authored-by: Donghee Na <[email protected]> Co-authored-by: Kumar Aditya <[email protected]> Co-authored-by: Serhiy Storchaka <[email protected]> * Add _PyObject_IsUniquelyReferenced --------- Co-authored-by: Kumar Aditya <[email protected]> Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 64dcbb0 commit 7ffef8d

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

Include/internal/pycore_object.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,23 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
165165
extern void _Py_SetImmortal(PyObject *op);
166166
extern void _Py_SetImmortalUntracked(PyObject *op);
167167

168+
// Checks if an object has a single, unique reference. If the caller holds a
169+
// unique reference, it may be able to safely modify the object in-place.
170+
static inline int
171+
_PyObject_IsUniquelyReferenced(PyObject *ob)
172+
{
173+
#if !defined(Py_GIL_DISABLED)
174+
return Py_REFCNT(ob) == 1;
175+
#else
176+
// NOTE: the entire ob_ref_shared field must be zero, including flags, to
177+
// ensure that other threads cannot concurrently create new references to
178+
// this object.
179+
return (_Py_IsOwnedByCurrentThread(ob) &&
180+
_Py_atomic_load_uint32_relaxed(&ob->ob_ref_local) == 1 &&
181+
_Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared) == 0);
182+
#endif
183+
}
184+
168185
// Makes an immortal object mortal again with the specified refcnt. Should only
169186
// be used during runtime finalization.
170187
static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt)

Objects/unicodeobject.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,21 @@ unicode_fill_invalid(PyObject *unicode, Py_ssize_t old_length)
11211121
}
11221122
#endif
11231123

1124+
static PyObject*
1125+
resize_copy(PyObject *unicode, Py_ssize_t length)
1126+
{
1127+
Py_ssize_t copy_length;
1128+
PyObject *copy;
1129+
1130+
copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode));
1131+
if (copy == NULL)
1132+
return NULL;
1133+
1134+
copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode));
1135+
_PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length);
1136+
return copy;
1137+
}
1138+
11241139
static PyObject*
11251140
resize_compact(PyObject *unicode, Py_ssize_t length)
11261141
{
@@ -1132,7 +1147,14 @@ resize_compact(PyObject *unicode, Py_ssize_t length)
11321147
Py_ssize_t old_length = _PyUnicode_LENGTH(unicode);
11331148
#endif
11341149

1135-
assert(unicode_modifiable(unicode));
1150+
if (!unicode_modifiable(unicode)) {
1151+
PyObject *copy = resize_copy(unicode, length);
1152+
if (copy == NULL) {
1153+
return NULL;
1154+
}
1155+
Py_DECREF(unicode);
1156+
return copy;
1157+
}
11361158
assert(PyUnicode_IS_COMPACT(unicode));
11371159

11381160
char_size = PyUnicode_KIND(unicode);
@@ -1232,21 +1254,6 @@ resize_inplace(PyObject *unicode, Py_ssize_t length)
12321254
return 0;
12331255
}
12341256

1235-
static PyObject*
1236-
resize_copy(PyObject *unicode, Py_ssize_t length)
1237-
{
1238-
Py_ssize_t copy_length;
1239-
PyObject *copy;
1240-
1241-
copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode));
1242-
if (copy == NULL)
1243-
return NULL;
1244-
1245-
copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode));
1246-
_PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length);
1247-
return copy;
1248-
}
1249-
12501257
static const char*
12511258
unicode_kind_name(PyObject *unicode)
12521259
{
@@ -1836,7 +1843,7 @@ static int
18361843
unicode_modifiable(PyObject *unicode)
18371844
{
18381845
assert(_PyUnicode_CHECK(unicode));
1839-
if (Py_REFCNT(unicode) != 1)
1846+
if (!_PyObject_IsUniquelyReferenced(unicode))
18401847
return 0;
18411848
if (PyUnicode_HASH(unicode) != -1)
18421849
return 0;
@@ -14025,7 +14032,7 @@ _PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type)
1402514032
assert(PyUnicode_IS_ASCII(result));
1402614033

1402714034
/* To modify the string in-place, there can only be one reference. */
14028-
if (Py_REFCNT(result) != 1) {
14035+
if (!_PyObject_IsUniquelyReferenced(result)) {
1402914036
Py_DECREF(result);
1403014037
PyErr_BadInternalCall();
1403114038
return NULL;

0 commit comments

Comments
 (0)