https://github.com/python/cpython/commit/7ffef8d07bba6c1c8551cafc3f0cb58c9102f909 commit: 7ffef8d07bba6c1c8551cafc3f0cb58c9102f909 branch: 3.13 author: Donghee Na <donghee...@python.org> committer: corona10 <donghee.n...@gmail.com> date: 2025-04-29T14:26:44+09:00 summary:
[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 75cbb8d89e7e92ccaba5c615c72459f241dca8b1) Co-authored-by: Donghee Na <donghee...@python.org> Co-authored-by: Kumar Aditya <kumaradi...@python.org> Co-authored-by: Serhiy Storchaka <storch...@gmail.com> * Add _PyObject_IsUniquelyReferenced --------- Co-authored-by: Kumar Aditya <kumaradi...@python.org> Co-authored-by: Serhiy Storchaka <storch...@gmail.com> files: M Include/internal/pycore_object.h M Objects/unicodeobject.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 07b5a95ae1a037..bed8b9b171ba02 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -165,6 +165,23 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) extern void _Py_SetImmortal(PyObject *op); extern void _Py_SetImmortalUntracked(PyObject *op); +// Checks if an object has a single, unique reference. If the caller holds a +// unique reference, it may be able to safely modify the object in-place. +static inline int +_PyObject_IsUniquelyReferenced(PyObject *ob) +{ +#if !defined(Py_GIL_DISABLED) + return Py_REFCNT(ob) == 1; +#else + // NOTE: the entire ob_ref_shared field must be zero, including flags, to + // ensure that other threads cannot concurrently create new references to + // this object. + return (_Py_IsOwnedByCurrentThread(ob) && + _Py_atomic_load_uint32_relaxed(&ob->ob_ref_local) == 1 && + _Py_atomic_load_ssize_relaxed(&ob->ob_ref_shared) == 0); +#endif +} + // Makes an immortal object mortal again with the specified refcnt. Should only // be used during runtime finalization. static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index a00125345b2dd5..27e66b2a7ca18c 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1121,6 +1121,21 @@ unicode_fill_invalid(PyObject *unicode, Py_ssize_t old_length) } #endif +static PyObject* +resize_copy(PyObject *unicode, Py_ssize_t length) +{ + Py_ssize_t copy_length; + PyObject *copy; + + copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode)); + if (copy == NULL) + return NULL; + + copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode)); + _PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length); + return copy; +} + static PyObject* resize_compact(PyObject *unicode, Py_ssize_t length) { @@ -1132,7 +1147,14 @@ resize_compact(PyObject *unicode, Py_ssize_t length) Py_ssize_t old_length = _PyUnicode_LENGTH(unicode); #endif - assert(unicode_modifiable(unicode)); + if (!unicode_modifiable(unicode)) { + PyObject *copy = resize_copy(unicode, length); + if (copy == NULL) { + return NULL; + } + Py_DECREF(unicode); + return copy; + } assert(PyUnicode_IS_COMPACT(unicode)); char_size = PyUnicode_KIND(unicode); @@ -1232,21 +1254,6 @@ resize_inplace(PyObject *unicode, Py_ssize_t length) return 0; } -static PyObject* -resize_copy(PyObject *unicode, Py_ssize_t length) -{ - Py_ssize_t copy_length; - PyObject *copy; - - copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode)); - if (copy == NULL) - return NULL; - - copy_length = Py_MIN(length, PyUnicode_GET_LENGTH(unicode)); - _PyUnicode_FastCopyCharacters(copy, 0, unicode, 0, copy_length); - return copy; -} - static const char* unicode_kind_name(PyObject *unicode) { @@ -1836,7 +1843,7 @@ static int unicode_modifiable(PyObject *unicode) { assert(_PyUnicode_CHECK(unicode)); - if (Py_REFCNT(unicode) != 1) + if (!_PyObject_IsUniquelyReferenced(unicode)) return 0; if (PyUnicode_HASH(unicode) != -1) return 0; @@ -14025,7 +14032,7 @@ _PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type) assert(PyUnicode_IS_ASCII(result)); /* To modify the string in-place, there can only be one reference. */ - if (Py_REFCNT(result) != 1) { + if (!_PyObject_IsUniquelyReferenced(result)) { Py_DECREF(result); PyErr_BadInternalCall(); return NULL; _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com