From 8e3b9f92835654943bb59d9658bb52e1b0f40a22 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 27 Oct 2020 00:00:03 +0100 Subject: [PATCH] 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. --- Include/internal/pycore_interp.h | 7 +++-- Include/internal/pycore_long.h | 43 ++++++++++++++++++++++++++++++ Makefile.pre.in | 1 + Objects/longobject.c | 37 ++++++++++--------------- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ 6 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 Include/internal/pycore_long.h diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 538aa5a653f..eee369a44bf 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -163,6 +163,11 @@ struct _Py_exc_state { #define _PY_NSMALLPOSINTS 257 #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. struct _is { @@ -233,14 +238,12 @@ struct _is { PyObject *audit_hooks; -#if _PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS > 0 /* Small integers are preallocated in this array so that they can be shared. The integers that are preallocated are those in the range -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (not inclusive). */ PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; -#endif struct _Py_bytes_state bytes; struct _Py_unicode_state unicode; struct _Py_float_state float_state; diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h new file mode 100644 index 00000000000..ec95786531c --- /dev/null +++ b/Include/internal/pycore_long.h @@ -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 */ diff --git a/Makefile.pre.in b/Makefile.pre.in index fe226ce45d8..31f61f3d5b8 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1117,6 +1117,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_initconfig.h \ $(srcdir)/Include/internal/pycore_interp.h \ $(srcdir)/Include/internal/pycore_list.h \ + $(srcdir)/Include/internal/pycore_long.h \ $(srcdir)/Include/internal/pycore_object.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \ $(srcdir)/Include/internal/pycore_pyerrors.h \ diff --git a/Objects/longobject.c b/Objects/longobject.c index 92514d4154e..ae63eba1345 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_bitutils.h" // _Py_popcount32() #include "pycore_interp.h" // _PY_NSMALLPOSINTS +#include "pycore_long.h" // __PyLong_GetSmallInt_internal() #include "pycore_object.h" // _PyObject_InitVar() #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "longintrepr.h" @@ -19,8 +20,8 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -#define NSMALLPOSINTS _PY_NSMALLPOSINTS #define NSMALLNEGINTS _PY_NSMALLNEGINTS +#define NSMALLPOSINTS _PY_NSMALLPOSINTS _Py_IDENTIFIER(little); _Py_IDENTIFIER(big); @@ -34,7 +35,6 @@ _Py_IDENTIFIER(big); PyObject *_PyLong_Zero = NULL; PyObject *_PyLong_One = NULL; -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) @@ -42,8 +42,7 @@ static PyObject * get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); - PyInterpreterState *interp = _PyInterpreterState_GET(); - PyObject *v = (PyObject*)interp->small_ints[ival + NSMALLNEGINTS]; + PyObject *v = __PyLong_GetSmallInt_internal(ival); Py_INCREF(v); return v; } @@ -60,12 +59,6 @@ maybe_small_long(PyLongObject *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 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) { return -1; } - Py_INCREF(_PyLong_Zero); - *pdiv = (PyLongObject*)_PyLong_Zero; + PyObject *zero = _PyLong_GetZero(); + Py_INCREF(zero); + *pdiv = (PyLongObject*)zero; return 0; } if (size_b == 1) { @@ -3669,7 +3663,7 @@ l_divmod(PyLongObject *v, PyLongObject *w, Py_DECREF(div); return -1; } - temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_One); + temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_GetOne()); if (temp == NULL) { Py_DECREF(mod); Py_DECREF(div); @@ -4078,7 +4072,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) Py_DECREF(c); 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. */ Py_DECREF(a); Py_DECREF(b); @@ -4313,7 +4307,7 @@ long_invert(PyLongObject *v) PyLongObject *x; if (Py_ABS(Py_SIZE(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) return NULL; _PyLong_Negate(&x); @@ -5105,7 +5099,8 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) /* compare twice the remainder with the divisor, to see 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) goto error; 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)) { /* fix up quotient */ if (quo_is_neg) - temp = long_sub(quo, (PyLongObject *)_PyLong_One); + temp = long_sub(quo, (PyLongObject *)one); else - temp = long_add(quo, (PyLongObject *)_PyLong_One); + temp = long_add(quo, (PyLongObject *)one); Py_DECREF(quo); quo = (PyLongObject *)temp; if (quo == NULL) @@ -5406,7 +5401,7 @@ int_as_integer_ratio_impl(PyObject *self) if (numerator == NULL) { return NULL; } - ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One); + ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_GetOne()); Py_DECREF(numerator); return ratio_tuple; } @@ -5712,7 +5707,6 @@ PyLong_GetInfo(void) int _PyLong_Init(PyThreadState *tstate) { -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { sdigit ival = (sdigit)i - NSMALLNEGINTS; int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); @@ -5727,7 +5721,6 @@ _PyLong_Init(PyThreadState *tstate) tstate->interp->small_ints[i] = v; } -#endif if (_Py_IsMainInterpreter(tstate)) { _PyLong_Zero = PyLong_FromLong(0); @@ -5759,9 +5752,7 @@ _PyLong_Fini(PyThreadState *tstate) Py_CLEAR(_PyLong_Zero); } -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { Py_CLEAR(tstate->interp->small_ints[i]); } -#endif } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 600f33b2c6e..18edba855d6 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -185,6 +185,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 75b91d8ed87..281bce1c5f4 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -537,6 +537,9 @@ Include\internal + + Include\internal + Include\internal