Skip to content

Commit 226011b

Browse files
authored
gh-139165: Make Py_SIZE, Py_IS_TYPE,Py_ SET_SIZE regular functions in stable ABI (GH-139166)
* Make Py_{SIZE,IS_TYPE,SET_SIZE} regular functions in stable ABI Group them together with Py_TYPE & Py_SET_TYPE to cut down on repetitive preprocessor macros. Format repetitive definitions in object.c more concisely. Py_SET_TYPE is still left out of the Limited API.
1 parent e6174ee commit 226011b

File tree

7 files changed

+90
-59
lines changed

7 files changed

+90
-59
lines changed

Doc/data/stable_abi.dat

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/object.h

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ struct _object {
140140
# endif
141141
};
142142
#else
143-
Py_ssize_t ob_refcnt;
143+
Py_ssize_t ob_refcnt; // part of stable ABI; do not change
144144
#endif
145145
_Py_ALIGNED_DEF(_PyObject_MIN_ALIGNMENT, char) _aligner;
146146
};
147147

148-
PyTypeObject *ob_type;
148+
PyTypeObject *ob_type; // part of stable ABI; do not change
149149
};
150150
#else
151151
// Objects that are not owned by any thread use a thread id (tid) of zero.
@@ -173,7 +173,7 @@ struct _object {
173173
#ifndef _Py_OPAQUE_PYOBJECT
174174
struct PyVarObject {
175175
PyObject ob_base;
176-
Py_ssize_t ob_size; /* Number of items in variable part */
176+
Py_ssize_t ob_size; // Number of items in variable part. Part of stable ABI
177177
};
178178
#endif
179179
typedef struct PyVarObject PyVarObject;
@@ -265,56 +265,72 @@ _Py_IsOwnedByCurrentThread(PyObject *ob)
265265
}
266266
#endif
267267

268-
// Py_TYPE() implementation for the stable ABI
268+
PyAPI_DATA(PyTypeObject) PyLong_Type;
269+
PyAPI_DATA(PyTypeObject) PyBool_Type;
270+
271+
/* Definitions for the stable ABI */
272+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 14)
269273
PyAPI_FUNC(PyTypeObject*) Py_TYPE(PyObject *ob);
274+
#endif
275+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
276+
PyAPI_FUNC(Py_ssize_t) Py_SIZE(PyObject *ob);
277+
PyAPI_FUNC(int) Py_IS_TYPE(PyObject *ob, PyTypeObject *type);
278+
PyAPI_FUNC(void) Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size);
279+
#endif
280+
281+
#ifndef _Py_OPAQUE_PYOBJECT
270282

271-
#if defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030e0000
272-
// Stable ABI implements Py_TYPE() as a function call
273-
// on limited C API version 3.14 and newer.
283+
static inline void
284+
Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
285+
{
286+
ob->ob_type = type;
287+
}
288+
289+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 11)
290+
// Non-limited API & limited API 3.11 & below: use static inline functions and
291+
// use _PyObject_CAST so that users don't need their own casts
292+
# define Py_TYPE(ob) _Py_TYPE_impl(_PyObject_CAST(ob))
293+
# define Py_SIZE(ob) _Py_SIZE_impl(_PyObject_CAST(ob))
294+
# define Py_IS_TYPE(ob, type) _Py_IS_TYPE_impl(_PyObject_CAST(ob), (type))
295+
# define Py_SET_SIZE(ob, size) _Py_SET_SIZE_impl(_PyVarObject_CAST(ob), (size))
296+
# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type)
297+
#elif Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 15)
298+
// Limited API 3.11-3.14: use static inline functions, without casts
299+
# define Py_SIZE(ob) _Py_SIZE_impl(ob)
300+
# define Py_IS_TYPE(ob, type) _Py_IS_TYPE_impl((ob), (type))
301+
# define Py_SET_SIZE(ob, size) _Py_SET_SIZE_impl((ob), (size))
302+
# if Py_LIMITED_API+0 < _Py_PACK_VERSION(3, 14)
303+
// Py_TYPE() is static inline only on Limited API 3.13 and below
304+
# define Py_TYPE(ob) _Py_TYPE_impl(ob)
305+
# endif
274306
#else
275-
static inline PyTypeObject* _Py_TYPE(PyObject *ob)
276-
{
277-
return ob->ob_type;
278-
}
279-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
280-
# define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST(ob))
281-
#else
282-
# define Py_TYPE(ob) _Py_TYPE(ob)
283-
#endif
307+
// Limited API 3.15+: use function calls
284308
#endif
285309

286-
PyAPI_DATA(PyTypeObject) PyLong_Type;
287-
PyAPI_DATA(PyTypeObject) PyBool_Type;
310+
static inline
311+
PyTypeObject* _Py_TYPE_impl(PyObject *ob)
312+
{
313+
return ob->ob_type;
314+
}
288315

289-
#ifndef _Py_OPAQUE_PYOBJECT
290316
// bpo-39573: The Py_SET_SIZE() function must be used to set an object size.
291-
static inline Py_ssize_t Py_SIZE(PyObject *ob) {
317+
static inline Py_ssize_t
318+
_Py_SIZE_impl(PyObject *ob)
319+
{
292320
assert(Py_TYPE(ob) != &PyLong_Type);
293321
assert(Py_TYPE(ob) != &PyBool_Type);
294322
return _PyVarObject_CAST(ob)->ob_size;
295323
}
296-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
297-
# define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob))
298-
#endif
299-
#endif // !defined(_Py_OPAQUE_PYOBJECT)
300324

301-
static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
325+
static inline int
326+
_Py_IS_TYPE_impl(PyObject *ob, PyTypeObject *type)
327+
{
302328
return Py_TYPE(ob) == type;
303329
}
304-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
305-
# define Py_IS_TYPE(ob, type) Py_IS_TYPE(_PyObject_CAST(ob), (type))
306-
#endif
307330

308-
309-
#ifndef _Py_OPAQUE_PYOBJECT
310-
static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
311-
ob->ob_type = type;
312-
}
313-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
314-
# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type)
315-
#endif
316-
317-
static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
331+
static inline void
332+
_Py_SET_SIZE_impl(PyVarObject *ob, Py_ssize_t size)
333+
{
318334
assert(Py_TYPE(_PyObject_CAST(ob)) != &PyLong_Type);
319335
assert(Py_TYPE(_PyObject_CAST(ob)) != &PyBool_Type);
320336
#ifdef Py_GIL_DISABLED
@@ -323,9 +339,7 @@ static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
323339
ob->ob_size = size;
324340
#endif
325341
}
326-
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
327-
# define Py_SET_SIZE(ob, size) Py_SET_SIZE(_PyVarObject_CAST(ob), (size))
328-
#endif
342+
329343
#endif // !defined(_Py_OPAQUE_PYOBJECT)
330344

331345

Lib/test/test_stable_abi_ctypes.py

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Expose the functions :c:func:`Py_SIZE`, :c:func:`Py_IS_TYPE` and
2+
:c:func:`Py_SET_SIZE` in the Stable ABI.

Misc/stable_abi.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,8 +2524,10 @@
25242524
added = '3.13'
25252525

25262526
[function.Py_TYPE]
2527+
# Before 3.14, this was a macro that accessed the PyObject member
25272528
added = '3.14'
25282529
[function.Py_REFCNT]
2530+
# Before 3.14, this was a macro that accessed the PyObject member
25292531
added = '3.14'
25302532
[function.PyIter_NextItem]
25312533
added = '3.14'
@@ -2641,3 +2643,12 @@
26412643
added = '3.15'
26422644
[function.PyDict_SetDefaultRef]
26432645
added = '3.15'
2646+
[function.Py_SIZE]
2647+
# Before 3.15, this was a macro that accessed the PyObject member
2648+
added = '3.15'
2649+
[function.Py_IS_TYPE]
2650+
# Before 3.15, this was a macro that accessed the PyObject member
2651+
added = '3.15'
2652+
[function.Py_SET_SIZE]
2653+
# Before 3.15, this was a macro that accessed the PyObject member
2654+
added = '3.15'

Objects/object.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3361,24 +3361,6 @@ Py_GetConstantBorrowed(unsigned int constant_id)
33613361
return Py_GetConstant(constant_id);
33623362
}
33633363

3364-
3365-
// Py_TYPE() implementation for the stable ABI
3366-
#undef Py_TYPE
3367-
PyTypeObject*
3368-
Py_TYPE(PyObject *ob)
3369-
{
3370-
return _Py_TYPE(ob);
3371-
}
3372-
3373-
3374-
// Py_REFCNT() implementation for the stable ABI
3375-
#undef Py_REFCNT
3376-
Py_ssize_t
3377-
Py_REFCNT(PyObject *ob)
3378-
{
3379-
return _Py_REFCNT(ob);
3380-
}
3381-
33823364
int
33833365
PyUnstable_IsImmortal(PyObject *op)
33843366
{
@@ -3405,3 +3387,16 @@ _PyObject_VisitType(PyObject *op, visitproc visit, void *arg)
34053387
Py_VISIT(tp);
34063388
return 0;
34073389
}
3390+
3391+
// Implementations for the stable ABI
3392+
// Keep these at the end.
3393+
#undef Py_TYPE
3394+
#undef Py_REFCNT
3395+
#undef Py_SIZE
3396+
#undef Py_IS_TYPE
3397+
#undef Py_SET_SIZE
3398+
PyTypeObject* Py_TYPE(PyObject *ob) { return _Py_TYPE_impl(ob); }
3399+
Py_ssize_t Py_REFCNT(PyObject *ob) { return _Py_REFCNT(ob); }
3400+
Py_ssize_t Py_SIZE(PyObject *o) { return _Py_SIZE_impl(o); }
3401+
int Py_IS_TYPE(PyObject *o, PyTypeObject *t) { return _Py_IS_TYPE_impl(o, t); }
3402+
void Py_SET_SIZE(PyVarObject *o, Py_ssize_t s) { _Py_SET_SIZE_impl(o, s); }

PC/python3dll.c

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)