Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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;
Expand Down
43 changes: 43 additions & 0 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
@@ -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 */
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
37 changes: 14 additions & 23 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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);
Expand All @@ -34,16 +35,14 @@ _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)

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;
}
Expand All @@ -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 */
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -5727,7 +5721,6 @@ _PyLong_Init(PyThreadState *tstate)

tstate->interp->small_ints[i] = v;
}
#endif

if (_Py_IsMainInterpreter(tstate)) {
_PyLong_Zero = PyLong_FromLong(0);
Expand Down Expand Up @@ -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
}
1 change: 1 addition & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
<ClInclude Include="..\Include\internal\pycore_initconfig.h" />
<ClInclude Include="..\Include\internal\pycore_interp.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_pathconfig.h" />
<ClInclude Include="..\Include\internal\pycore_pyerrors.h" />
Expand Down
3 changes: 3 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,9 @@
<ClInclude Include="..\Include\internal\pycore_list.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_long.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_object.h">
<Filter>Include\internal</Filter>
</ClInclude>
Expand Down