bpo-42161: Add _PyLong_GetZero() and _PyLong_GetOne() (GH-22993)

Add _PyLong_GetZero() and _PyLong_GetOne() functions and a new
internal pycore_long.h header file.

Python cannot be built without small integer singletons anymore.
This commit is contained in:
Victor Stinner 2020-10-27 00:00:03 +01:00 committed by GitHub
parent bca7014032
commit 8e3b9f9283
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 25 deletions

View File

@ -163,6 +163,11 @@ struct _Py_exc_state {
#define _PY_NSMALLPOSINTS 257 #define _PY_NSMALLPOSINTS 257
#define _PY_NSMALLNEGINTS 5 #define _PY_NSMALLNEGINTS 5
// _PyLong_GetZero() and _PyLong_GetOne() must always be available
#if _PY_NSMALLPOSINTS < 2
# error "_PY_NSMALLPOSINTS must be greater than 1"
#endif
// The PyInterpreterState typedef is in Include/pystate.h. // The PyInterpreterState typedef is in Include/pystate.h.
struct _is { struct _is {
@ -233,14 +238,12 @@ struct _is {
PyObject *audit_hooks; PyObject *audit_hooks;
#if _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS > 0
/* Small integers are preallocated in this array so that they /* Small integers are preallocated in this array so that they
can be shared. can be shared.
The integers that are preallocated are those in the range The integers that are preallocated are those in the range
-_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive). -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive).
*/ */
PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
#endif
struct _Py_bytes_state bytes; struct _Py_bytes_state bytes;
struct _Py_unicode_state unicode; struct _Py_unicode_state unicode;
struct _Py_float_state float_state; struct _Py_float_state float_state;

View File

@ -0,0 +1,43 @@
#ifndef Py_INTERNAL_LONG_H
#define Py_INTERNAL_LONG_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif
#include "pycore_interp.h" // PyInterpreterState.small_ints
#include "pycore_pystate.h" // _PyThreadState_GET()
// Don't call this function but _PyLong_GetZero() and _PyLong_GetOne()
static inline PyObject* __PyLong_GetSmallInt_internal(int value)
{
PyThreadState *tstate = _PyThreadState_GET();
#ifdef Py_DEBUG
_Py_EnsureTstateNotNULL(tstate);
#endif
assert(-_PY_NSMALLNEGINTS <= value && value < _PY_NSMALLPOSINTS);
size_t index = _PY_NSMALLNEGINTS + value;
PyObject *obj = (PyObject*)tstate->interp->small_ints[index];
// _PyLong_GetZero() and _PyLong_GetOne() must not be called
// before _PyLong_Init() nor after _PyLong_Fini()
assert(obj != NULL);
return obj;
}
// Return a borrowed reference to the zero singleton.
// The function cannot return NULL.
static inline PyObject* _PyLong_GetZero(void)
{ return __PyLong_GetSmallInt_internal(0); }
// Return a borrowed reference to the one singleton.
// The function cannot return NULL.
static inline PyObject* _PyLong_GetOne(void)
{ return __PyLong_GetSmallInt_internal(1); }
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_LONG_H */

View File

@ -1117,6 +1117,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_initconfig.h \ $(srcdir)/Include/internal/pycore_initconfig.h \
$(srcdir)/Include/internal/pycore_interp.h \ $(srcdir)/Include/internal/pycore_interp.h \
$(srcdir)/Include/internal/pycore_list.h \ $(srcdir)/Include/internal/pycore_list.h \
$(srcdir)/Include/internal/pycore_long.h \
$(srcdir)/Include/internal/pycore_object.h \ $(srcdir)/Include/internal/pycore_object.h \
$(srcdir)/Include/internal/pycore_pathconfig.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \
$(srcdir)/Include/internal/pycore_pyerrors.h \ $(srcdir)/Include/internal/pycore_pyerrors.h \

View File

@ -5,6 +5,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_bitutils.h" // _Py_popcount32() #include "pycore_bitutils.h" // _Py_popcount32()
#include "pycore_interp.h" // _PY_NSMALLPOSINTS #include "pycore_interp.h" // _PY_NSMALLPOSINTS
#include "pycore_long.h" // __PyLong_GetSmallInt_internal()
#include "pycore_object.h" // _PyObject_InitVar() #include "pycore_object.h" // _PyObject_InitVar()
#include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_pystate.h" // _Py_IsMainInterpreter()
#include "longintrepr.h" #include "longintrepr.h"
@ -19,8 +20,8 @@ class int "PyObject *" "&PyLong_Type"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/
#define NSMALLPOSINTS _PY_NSMALLPOSINTS
#define NSMALLNEGINTS _PY_NSMALLNEGINTS #define NSMALLNEGINTS _PY_NSMALLNEGINTS
#define NSMALLPOSINTS _PY_NSMALLPOSINTS
_Py_IDENTIFIER(little); _Py_IDENTIFIER(little);
_Py_IDENTIFIER(big); _Py_IDENTIFIER(big);
@ -34,7 +35,6 @@ _Py_IDENTIFIER(big);
PyObject *_PyLong_Zero = NULL; PyObject *_PyLong_Zero = NULL;
PyObject *_PyLong_One = NULL; PyObject *_PyLong_One = NULL;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
#define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS)
@ -42,8 +42,7 @@ static PyObject *
get_small_int(sdigit ival) get_small_int(sdigit ival)
{ {
assert(IS_SMALL_INT(ival)); assert(IS_SMALL_INT(ival));
PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *v = __PyLong_GetSmallInt_internal(ival);
PyObject *v = (PyObject*)interp->small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v); Py_INCREF(v);
return v; return v;
} }
@ -60,12 +59,6 @@ maybe_small_long(PyLongObject *v)
} }
return v; return v;
} }
#else
#define IS_SMALL_INT(ival) 0
#define IS_SMALL_UINT(ival) 0
#define get_small_int(ival) (Py_UNREACHABLE(), NULL)
#define maybe_small_long(val) (val)
#endif
/* If a freshly-allocated int is already shared, it must /* If a freshly-allocated int is already shared, it must
be a small integer, so negating it must go to PyLong_FromLong */ be a small integer, so negating it must go to PyLong_FromLong */
@ -2559,8 +2552,9 @@ long_divrem(PyLongObject *a, PyLongObject *b,
if (*prem == NULL) { if (*prem == NULL) {
return -1; return -1;
} }
Py_INCREF(_PyLong_Zero); PyObject *zero = _PyLong_GetZero();
*pdiv = (PyLongObject*)_PyLong_Zero; Py_INCREF(zero);
*pdiv = (PyLongObject*)zero;
return 0; return 0;
} }
if (size_b == 1) { if (size_b == 1) {
@ -3669,7 +3663,7 @@ l_divmod(PyLongObject *v, PyLongObject *w,
Py_DECREF(div); Py_DECREF(div);
return -1; return -1;
} }
temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_One); temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_GetOne());
if (temp == NULL) { if (temp == NULL) {
Py_DECREF(mod); Py_DECREF(mod);
Py_DECREF(div); Py_DECREF(div);
@ -4078,7 +4072,7 @@ long_invmod(PyLongObject *a, PyLongObject *n)
Py_DECREF(c); Py_DECREF(c);
Py_DECREF(n); Py_DECREF(n);
if (long_compare(a, (PyLongObject *)_PyLong_One)) { if (long_compare(a, (PyLongObject *)_PyLong_GetOne())) {
/* a != 1; we don't have an inverse. */ /* a != 1; we don't have an inverse. */
Py_DECREF(a); Py_DECREF(a);
Py_DECREF(b); Py_DECREF(b);
@ -4313,7 +4307,7 @@ long_invert(PyLongObject *v)
PyLongObject *x; PyLongObject *x;
if (Py_ABS(Py_SIZE(v)) <=1) if (Py_ABS(Py_SIZE(v)) <=1)
return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); return PyLong_FromLong(-(MEDIUM_VALUE(v)+1));
x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_One); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne());
if (x == NULL) if (x == NULL)
return NULL; return NULL;
_PyLong_Negate(&x); _PyLong_Negate(&x);
@ -5105,7 +5099,8 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b)
/* compare twice the remainder with the divisor, to see /* compare twice the remainder with the divisor, to see
if we need to adjust the quotient and remainder */ if we need to adjust the quotient and remainder */
twice_rem = long_lshift((PyObject *)rem, _PyLong_One); PyObject *one = _PyLong_GetOne(); // borrowed reference
twice_rem = long_lshift((PyObject *)rem, one);
if (twice_rem == NULL) if (twice_rem == NULL)
goto error; goto error;
if (quo_is_neg) { if (quo_is_neg) {
@ -5122,9 +5117,9 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b)
if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) {
/* fix up quotient */ /* fix up quotient */
if (quo_is_neg) if (quo_is_neg)
temp = long_sub(quo, (PyLongObject *)_PyLong_One); temp = long_sub(quo, (PyLongObject *)one);
else else
temp = long_add(quo, (PyLongObject *)_PyLong_One); temp = long_add(quo, (PyLongObject *)one);
Py_DECREF(quo); Py_DECREF(quo);
quo = (PyLongObject *)temp; quo = (PyLongObject *)temp;
if (quo == NULL) if (quo == NULL)
@ -5406,7 +5401,7 @@ int_as_integer_ratio_impl(PyObject *self)
if (numerator == NULL) { if (numerator == NULL) {
return NULL; return NULL;
} }
ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One); ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_GetOne());
Py_DECREF(numerator); Py_DECREF(numerator);
return ratio_tuple; return ratio_tuple;
} }
@ -5712,7 +5707,6 @@ PyLong_GetInfo(void)
int int
_PyLong_Init(PyThreadState *tstate) _PyLong_Init(PyThreadState *tstate)
{ {
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
sdigit ival = (sdigit)i - NSMALLNEGINTS; sdigit ival = (sdigit)i - NSMALLNEGINTS;
int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1);
@ -5727,7 +5721,6 @@ _PyLong_Init(PyThreadState *tstate)
tstate->interp->small_ints[i] = v; tstate->interp->small_ints[i] = v;
} }
#endif
if (_Py_IsMainInterpreter(tstate)) { if (_Py_IsMainInterpreter(tstate)) {
_PyLong_Zero = PyLong_FromLong(0); _PyLong_Zero = PyLong_FromLong(0);
@ -5759,9 +5752,7 @@ _PyLong_Fini(PyThreadState *tstate)
Py_CLEAR(_PyLong_Zero); Py_CLEAR(_PyLong_Zero);
} }
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
Py_CLEAR(tstate->interp->small_ints[i]); Py_CLEAR(tstate->interp->small_ints[i]);
} }
#endif
} }

View File

@ -185,6 +185,7 @@
<ClInclude Include="..\Include\internal\pycore_initconfig.h" /> <ClInclude Include="..\Include\internal\pycore_initconfig.h" />
<ClInclude Include="..\Include\internal\pycore_interp.h" /> <ClInclude Include="..\Include\internal\pycore_interp.h" />
<ClInclude Include="..\Include\internal\pycore_list.h" /> <ClInclude Include="..\Include\internal\pycore_list.h" />
<ClInclude Include="..\Include\internal\pycore_long.h" />
<ClInclude Include="..\Include\internal\pycore_object.h" /> <ClInclude Include="..\Include\internal\pycore_object.h" />
<ClInclude Include="..\Include\internal\pycore_pathconfig.h" /> <ClInclude Include="..\Include\internal\pycore_pathconfig.h" />
<ClInclude Include="..\Include\internal\pycore_pyerrors.h" /> <ClInclude Include="..\Include\internal\pycore_pyerrors.h" />

View File

@ -537,6 +537,9 @@
<ClInclude Include="..\Include\internal\pycore_list.h"> <ClInclude Include="..\Include\internal\pycore_list.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Include\internal\pycore_long.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_object.h"> <ClInclude Include="..\Include\internal\pycore_object.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>