gh-115754: Add Py_GetConstant() function (#116883)

Add Py_GetConstant() and Py_GetConstantBorrowed() functions.

In the limited C API version 3.13, getting Py_None, Py_False,
Py_True, Py_Ellipsis and Py_NotImplemented singletons is now
implemented as function calls at the stable ABI level to hide
implementation details. Getting these constants still return borrowed
references.

Add _testlimitedcapi/object.c and test_capi/test_object.py to test
Py_GetConstant() and Py_GetConstantBorrowed() functions.
This commit is contained in:
Victor Stinner 2024-03-21 17:07:00 +01:00 committed by GitHub
parent 5a76d1be8e
commit 8bea6c411d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 312 additions and 6 deletions

View file

@ -14,6 +14,7 @@
#include "pycore_memoryobject.h" // _PyManagedBuffer_Type
#include "pycore_namespace.h" // _PyNamespace_Type
#include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_optimizer.h" // _PyUOpExecutor_Type, _PyUOpOptimizer_Type, ...
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
@ -2991,3 +2992,53 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
{
Py_SET_REFCNT(ob, refcnt);
}
static PyObject* constants[] = {
&_Py_NoneStruct, // Py_CONSTANT_NONE
(PyObject*)(&_Py_FalseStruct), // Py_CONSTANT_FALSE
(PyObject*)(&_Py_TrueStruct), // Py_CONSTANT_TRUE
&_Py_EllipsisObject, // Py_CONSTANT_ELLIPSIS
&_Py_NotImplementedStruct, // Py_CONSTANT_NOT_IMPLEMENTED
NULL, // Py_CONSTANT_ZERO
NULL, // Py_CONSTANT_ONE
NULL, // Py_CONSTANT_EMPTY_STR
NULL, // Py_CONSTANT_EMPTY_BYTES
NULL, // Py_CONSTANT_EMPTY_TUPLE
};
void
_Py_GetConstant_Init(void)
{
constants[Py_CONSTANT_ZERO] = _PyLong_GetZero();
constants[Py_CONSTANT_ONE] = _PyLong_GetOne();
constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_New(0, 0);
constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize(NULL, 0);
constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0);
#ifndef NDEBUG
for (size_t i=0; i < Py_ARRAY_LENGTH(constants); i++) {
assert(constants[i] != NULL);
assert(_Py_IsImmortal(constants[i]));
}
#endif
}
PyObject*
Py_GetConstant(unsigned int constant_id)
{
if (constant_id < Py_ARRAY_LENGTH(constants)) {
return constants[constant_id];
}
else {
PyErr_BadInternalCall();
return NULL;
}
}
PyObject*
Py_GetConstantBorrowed(unsigned int constant_id)
{
// All constants are immortal
return Py_GetConstant(constant_id);
}