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)
}
#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)
{
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);
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)
{
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;
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;