diff --git a/Include/refcount.h b/Include/refcount.h index 204e06cfacd7b0..b9769d80929ee0 100644 --- a/Include/refcount.h +++ b/Include/refcount.h @@ -142,11 +142,24 @@ static inline Py_ALWAYS_INLINE int _Py_IsImmutable(PyObject *op) } #define _Py_IsImmutable(op) _Py_IsImmutable(_PyObject_CAST(op)) -// Artifact[Implementation]: The definition of the `Py_CHECKWRITE` macro +#ifndef Py_LIMITED_API +// Cold path for Py_CHECKWRITE: called when the object is immutable. +// Returns 1 if the object is still writable (ImmModule or finalizing). +PyAPI_FUNC(int) _Py_CheckWriteImmutable(PyObject *op); + // Check whether an object is writeable. -// This check will always succeed during runtime finalization. -#define Py_CHECKWRITE(op) ((op) && (!_Py_IsImmutable(op) || _PyImmModule_Check(op) || Py_IsFinalizing())) +// The fast path just checks the immutable flag; the ImmModule and +// finalizing checks are pushed into a cold out-of-line function. +static inline int Py_CHECKWRITE(PyObject *op) +{ + if (_Py_IsImmutable(op)) { + return _Py_CheckWriteImmutable(op); + } + return 1; +} +#define Py_CHECKWRITE(op) Py_CHECKWRITE(_PyObject_CAST(op)) #define Py_REQUIREWRITE(op, msg) {if (Py_CHECKWRITE(op)) { _PyObject_ASSERT_FAILED_MSG(op, msg); }} +#endif // !Py_LIMITED_API static inline Py_ALWAYS_INLINE void _Py_CLEAR_IMMUTABLE(PyObject *op) { diff --git a/Python/immutability.c b/Python/immutability.c index c4feb45d0511c7..1f443ed11d3a4c 100644 --- a/Python/immutability.c +++ b/Python/immutability.c @@ -1846,6 +1846,15 @@ int _PyImmutability_CanViewAsImmutable(PyObject *obj) return 1; } +// Cold path for Py_CHECKWRITE: the object is known to be immutable. +// Returns 1 (writable) if the object's type is _PyImmModule_Type or +// the runtime is finalizing. +int +_Py_CheckWriteImmutable(PyObject *op) +{ + return _PyImmModule_Check(op) || Py_IsFinalizing(); +} + // Perform a decref on an immutable object // returns true if the object should be deallocated. int _Py_DecRef_Immutable(PyObject *op) diff --git a/Python/pystate.c b/Python/pystate.c index 90ea2571941a56..32825515a063c1 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1386,7 +1386,7 @@ PyModuleObject* _PyInterpreterState_GetModuleState(PyObject *mod) { if (modules_mod == mod) { // The modules in `sys.modules` is this frozen mod but there is // no mutable state in `sys.mut_modules`, probably because it was - // unimported? Either way: + // unimported? Either way: // Remove `mod` from `sys.modules` and trigger a reimport. if (PyDict_DelItem(modules, self->md_name) < 0) { Py_DECREF(modules_mod);