GH-101291: Rearrange the size bits in PyLongObject (GH-102464)

* Eliminate all remaining uses of Py_SIZE and Py_SET_SIZE on PyLongObject, adding asserts.

* Change layout of size/sign bits in longobject to support future addition of immortal ints and tagged medium ints.

* Add functions to hide some internals of long object, and for setting sign and digit count.

* Replace uses of IS_MEDIUM_VALUE macro with _PyLong_IsCompact().
This commit is contained in:
Mark Shannon 2023-03-22 14:49:51 +00:00 committed by GitHub
parent 713df2c534
commit 7559f5fda9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 982 additions and 898 deletions

View file

@ -80,7 +80,7 @@ typedef long stwodigits; /* signed variant of twodigits */
*/ */
typedef struct _PyLongValue { typedef struct _PyLongValue {
Py_ssize_t ob_size; /* Number of items in variable part */ uintptr_t lv_tag; /* Number of digits, sign and flags */
digit ob_digit[1]; digit ob_digit[1];
} _PyLongValue; } _PyLongValue;
@ -94,6 +94,10 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t);
/* Return a copy of src. */ /* Return a copy of src. */
PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src);
PyAPI_FUNC(PyLongObject *)
_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -82,8 +82,6 @@ PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right);
PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right);
PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right);
int _PyLong_AssignValue(PyObject **target, Py_ssize_t value);
/* Used by Python/mystrtoul.c, _PyBytes_FromHex(), /* Used by Python/mystrtoul.c, _PyBytes_FromHex(),
_PyBytes_DecodeEscape(), etc. */ _PyBytes_DecodeEscape(), etc. */
PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];
@ -110,25 +108,155 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter(
int base, int base,
int alternate); int alternate);
/* Return 1 if the argument is positive single digit int */ /* Long value tag bits:
* 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1.
* 2: Reserved for immortality bit
* 3+ Unsigned digit count
*/
#define SIGN_MASK 3
#define SIGN_ZERO 1
#define SIGN_NEGATIVE 2
#define NON_SIZE_BITS 3
/* All *compact" values are guaranteed to fit into
* a Py_ssize_t with at least one bit to spare.
* In other words, for 64 bit machines, compact
* will be signed 63 (or fewer) bit values
*/
/* Return 1 if the argument is compact int */
static inline int static inline int
_PyLong_IsPositiveSingleDigit(PyObject* sub) { _PyLong_IsNonNegativeCompact(const PyLongObject* op) {
/* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. assert(PyLong_Check(op));
return op->long_value.lv_tag <= (1 << NON_SIZE_BITS);
We perform a fast check using a single comparison by casting from int
to uint which casts negative numbers to large positive numbers.
For details see Section 14.2 "Bounds Checking" in the Agner Fog
optimization manual found at:
https://www.agner.org/optimize/optimizing_cpp.pdf
The function is not affected by -fwrapv, -fno-wrapv and -ftrapv
compiler options of GCC and clang
*/
assert(PyLong_CheckExact(sub));
Py_ssize_t signed_size = Py_SIZE(sub);
return ((size_t)signed_size) <= 1;
} }
static inline int
_PyLong_IsCompact(const PyLongObject* op) {
assert(PyLong_Check(op));
return op->long_value.lv_tag < (2 << NON_SIZE_BITS);
}
static inline int
_PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) {
assert(PyLong_Check(a));
assert(PyLong_Check(b));
return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS);
}
/* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`.
*
* "Compact" values have at least one bit to spare,
* so that addition and subtraction can be performed on the values
* without risk of overflow.
*/
static inline Py_ssize_t
_PyLong_CompactValue(const PyLongObject *op)
{
assert(PyLong_Check(op));
assert(_PyLong_IsCompact(op));
Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK);
return sign * (Py_ssize_t)op->long_value.ob_digit[0];
}
static inline bool
_PyLong_IsZero(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
}
static inline bool
_PyLong_IsNegative(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE;
}
static inline bool
_PyLong_IsPositive(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == 0;
}
static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
assert(PyLong_Check(op));
return op->long_value.lv_tag >> NON_SIZE_BITS;
}
/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */
static inline Py_ssize_t
_PyLong_SignedDigitCount(const PyLongObject *op)
{
assert(PyLong_Check(op));
Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK);
return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS);
}
static inline int
_PyLong_CompactSign(const PyLongObject *op)
{
assert(PyLong_Check(op));
assert(_PyLong_IsCompact(op));
return 1 - (op->long_value.lv_tag & SIGN_MASK);
}
static inline int
_PyLong_NonCompactSign(const PyLongObject *op)
{
assert(PyLong_Check(op));
assert(!_PyLong_IsCompact(op));
return 1 - (op->long_value.lv_tag & SIGN_MASK);
}
/* Do a and b have the same sign? */
static inline int
_PyLong_SameSign(const PyLongObject *a, const PyLongObject *b)
{
return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK);
}
#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS))
static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
{
assert(size >= 0);
assert(-1 <= sign && sign <= 1);
assert(sign != 0 || size == 0);
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size);
}
static inline void
_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size)
{
assert(size >= 0);
op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK);
}
#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1)
static inline void
_PyLong_FlipSign(PyLongObject *op) {
unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK);
op->long_value.lv_tag &= NON_SIZE_MASK;
op->long_value.lv_tag |= flipped_sign;
}
#define _PyLong_DIGIT_INIT(val) \
{ \
.ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \
.long_value = { \
.lv_tag = TAG_FROM_SIGN_AND_SIZE( \
(val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \
(val) == 0 ? 0 : 1), \
{ ((val) >= 0 ? (val) : -(val)) }, \
} \
}
#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0)
#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -137,8 +137,9 @@ static inline void
_PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)
{ {
assert(op != NULL); assert(op != NULL);
Py_SET_SIZE(op, size); assert(typeobj != &PyLong_Type);
_PyObject_Init((PyObject *)op, typeobj); _PyObject_Init((PyObject *)op, typeobj);
Py_SET_SIZE(op, size);
} }

View file

@ -8,6 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define" # error "this header requires Py_BUILD_CORE define"
#endif #endif
#include "pycore_long.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_parser.h" #include "pycore_parser.h"
#include "pycore_pymem_init.h" #include "pycore_pymem_init.h"
@ -130,15 +131,6 @@ extern PyTypeObject _PyExc_MemoryError;
// global objects // global objects
#define _PyLong_DIGIT_INIT(val) \
{ \
.ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \
.long_value = { \
((val) == 0 ? 0 : ((val) > 0 ? 1 : -1)), \
{ ((val) >= 0 ? (val) : -(val)) }, \
} \
}
#define _PyBytes_SIMPLE_INIT(CH, LEN) \ #define _PyBytes_SIMPLE_INIT(CH, LEN) \
{ \ { \
_PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \ _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \

View file

@ -138,8 +138,13 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) {
# define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob))
#endif #endif
PyAPI_DATA(PyTypeObject) PyLong_Type;
PyAPI_DATA(PyTypeObject) PyBool_Type;
// bpo-39573: The Py_SET_SIZE() function must be used to set an object size. // bpo-39573: The Py_SET_SIZE() function must be used to set an object size.
static inline Py_ssize_t Py_SIZE(PyObject *ob) { static inline Py_ssize_t Py_SIZE(PyObject *ob) {
assert(ob->ob_type != &PyLong_Type);
assert(ob->ob_type != &PyBool_Type);
PyVarObject *var_ob = _PyVarObject_CAST(ob); PyVarObject *var_ob = _PyVarObject_CAST(ob);
return var_ob->ob_size; return var_ob->ob_size;
} }
@ -171,8 +176,9 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
# define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type)
#endif #endif
static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
assert(ob->ob_base.ob_type != &PyLong_Type);
assert(ob->ob_base.ob_type != &PyBool_Type);
ob->ob_size = size; ob->ob_size = size;
} }
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000

View file

@ -0,0 +1,7 @@
Rearrage bits in first field (after header) of PyLongObject.
* Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers.
* Bit 2 reserved (probably for the immortal bit)
* Bits 3+ the unsigned size.
This makes a few operations slightly more efficient, and will enable a more
compact and faster 2s-complement representation of most ints in future.

View file

@ -30,6 +30,7 @@
#endif #endif
#include <Python.h> #include <Python.h>
#include "pycore_long.h" // _PyLong_IsZero()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "complexobject.h" #include "complexobject.h"
#include "mpdecimal.h" #include "mpdecimal.h"
@ -2146,35 +2147,25 @@ dec_from_long(PyTypeObject *type, PyObject *v,
{ {
PyObject *dec; PyObject *dec;
PyLongObject *l = (PyLongObject *)v; PyLongObject *l = (PyLongObject *)v;
Py_ssize_t ob_size;
size_t len;
uint8_t sign;
dec = PyDecType_New(type); dec = PyDecType_New(type);
if (dec == NULL) { if (dec == NULL) {
return NULL; return NULL;
} }
ob_size = Py_SIZE(l); if (_PyLong_IsZero(l)) {
if (ob_size == 0) {
_dec_settriple(dec, MPD_POS, 0, 0); _dec_settriple(dec, MPD_POS, 0, 0);
return dec; return dec;
} }
if (ob_size < 0) { uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS;
len = -ob_size;
sign = MPD_NEG;
}
else {
len = ob_size;
sign = MPD_POS;
}
if (len == 1) { if (_PyLong_IsCompact(l)) {
_dec_settriple(dec, sign, *l->long_value.ob_digit, 0); _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0);
mpd_qfinalize(MPD(dec), ctx, status); mpd_qfinalize(MPD(dec), ctx, status);
return dec; return dec;
} }
size_t len = _PyLong_DigitCount(l);
#if PYLONG_BITS_IN_DIGIT == 30 #if PYLONG_BITS_IN_DIGIT == 30
mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE,
@ -3482,7 +3473,6 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
PyLongObject *pylong; PyLongObject *pylong;
digit *ob_digit; digit *ob_digit;
size_t n; size_t n;
Py_ssize_t i;
mpd_t *x; mpd_t *x;
mpd_context_t workctx; mpd_context_t workctx;
uint32_t status = 0; uint32_t status = 0;
@ -3536,26 +3526,9 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
} }
assert(n > 0); assert(n > 0);
pylong = _PyLong_New(n); assert(!mpd_iszero(x));
if (pylong == NULL) { pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit);
mpd_free(ob_digit);
mpd_del(x);
return NULL;
}
memcpy(pylong->long_value.ob_digit, ob_digit, n * sizeof(digit));
mpd_free(ob_digit); mpd_free(ob_digit);
i = n;
while ((i > 0) && (pylong->long_value.ob_digit[i-1] == 0)) {
i--;
}
Py_SET_SIZE(pylong, i);
if (mpd_isnegative(x) && !mpd_iszero(x)) {
Py_SET_SIZE(pylong, -i);
}
mpd_del(x); mpd_del(x);
return (PyObject *) pylong; return (PyObject *) pylong;
} }

View file

@ -347,7 +347,7 @@ test_pyobject_new(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
PyObject *obj; PyObject *obj;
PyTypeObject *type = &PyBaseObject_Type; PyTypeObject *type = &PyBaseObject_Type;
PyTypeObject *var_type = &PyLong_Type; PyTypeObject *var_type = &PyBytes_Type;
// PyObject_New() // PyObject_New()
obj = PyObject_New(PyObject, type); obj = PyObject_New(PyObject, type);

View file

@ -32,6 +32,8 @@ Copyright (C) 1994 Steen Lumholt.
# include "pycore_fileutils.h" // _Py_stat() # include "pycore_fileutils.h" // _Py_stat()
#endif #endif
#include "pycore_long.h"
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
#include <windows.h> #include <windows.h>
#endif #endif
@ -886,7 +888,8 @@ asBignumObj(PyObject *value)
const char *hexchars; const char *hexchars;
mp_int bigValue; mp_int bigValue;
neg = Py_SIZE(value) < 0; assert(PyLong_Check(value));
neg = _PyLong_IsNegative((PyLongObject *)value);
hexstr = _PyLong_Format(value, 16); hexstr = _PyLong_Format(value, 16);
if (hexstr == NULL) if (hexstr == NULL)
return NULL; return NULL;
@ -1950,7 +1953,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
int v; int v;
if (PyLong_Check(arg)) { /* int or bool */ if (PyLong_Check(arg)) { /* int or bool */
return PyBool_FromLong(Py_SIZE(arg) != 0); return PyBool_FromLong(!_PyLong_IsZero((PyLongObject *)arg));
} }
if (PyTclObject_Check(arg)) { if (PyTclObject_Check(arg)) {

View file

@ -836,7 +836,7 @@ long_lcm(PyObject *a, PyObject *b)
{ {
PyObject *g, *m, *f, *ab; PyObject *g, *m, *f, *ab;
if (Py_SIZE(a) == 0 || Py_SIZE(b) == 0) { if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) {
return PyLong_FromLong(0); return PyLong_FromLong(0);
} }
g = _PyLong_GCD(a, b); g = _PyLong_GCD(a, b);
@ -1726,13 +1726,13 @@ math_isqrt(PyObject *module, PyObject *n)
return NULL; return NULL;
} }
if (_PyLong_Sign(n) < 0) { if (_PyLong_IsNegative((PyLongObject *)n)) {
PyErr_SetString( PyErr_SetString(
PyExc_ValueError, PyExc_ValueError,
"isqrt() argument must be nonnegative"); "isqrt() argument must be nonnegative");
goto error; goto error;
} }
if (_PyLong_Sign(n) == 0) { if (_PyLong_IsZero((PyLongObject *)n)) {
Py_DECREF(n); Py_DECREF(n);
return PyLong_FromLong(0); return PyLong_FromLong(0);
} }
@ -2254,7 +2254,7 @@ loghelper(PyObject* arg, double (*func)(double))
Py_ssize_t e; Py_ssize_t e;
/* Negative or zero inputs give a ValueError. */ /* Negative or zero inputs give a ValueError. */
if (Py_SIZE(arg) <= 0) { if (!_PyLong_IsPositive((PyLongObject *)arg)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"math domain error"); "math domain error");
return NULL; return NULL;
@ -3716,12 +3716,12 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k)
} }
assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); assert(PyLong_CheckExact(n) && PyLong_CheckExact(k));
if (Py_SIZE(n) < 0) { if (_PyLong_IsNegative((PyLongObject *)n)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"n must be a non-negative integer"); "n must be a non-negative integer");
goto error; goto error;
} }
if (Py_SIZE(k) < 0) { if (_PyLong_IsNegative((PyLongObject *)k)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"k must be a non-negative integer"); "k must be a non-negative integer");
goto error; goto error;
@ -3808,12 +3808,12 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k)
} }
assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); assert(PyLong_CheckExact(n) && PyLong_CheckExact(k));
if (Py_SIZE(n) < 0) { if (_PyLong_IsNegative((PyLongObject *)n)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"n must be a non-negative integer"); "n must be a non-negative integer");
goto error; goto error;
} }
if (Py_SIZE(k) < 0) { if (_PyLong_IsNegative((PyLongObject *)k)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"k must be a non-negative integer"); "k must be a non-negative integer");
goto error; goto error;
@ -3845,7 +3845,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k)
if (temp == NULL) { if (temp == NULL) {
goto error; goto error;
} }
if (Py_SIZE(temp) < 0) { assert(PyLong_Check(temp));
if (_PyLong_IsNegative((PyLongObject *)temp)) {
Py_DECREF(temp); Py_DECREF(temp);
result = PyLong_FromLong(0); result = PyLong_FromLong(0);
goto done; goto done;

View file

@ -5,6 +5,7 @@
#include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
#include "pycore_object.h" // _Py_CheckSlotResult() #include "pycore_object.h" // _Py_CheckSlotResult()
#include "pycore_long.h" // _Py_IsNegative
#include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_unionobject.h" // _PyUnion_Check() #include "pycore_unionobject.h" // _PyUnion_Check()
@ -1483,7 +1484,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err)
/* Whether or not it is less than or equal to /* Whether or not it is less than or equal to
zero is determined by the sign of ob_size zero is determined by the sign of ob_size
*/ */
if (_PyLong_Sign(value) < 0) if (_PyLong_IsNegative((PyLongObject *)value))
result = PY_SSIZE_T_MIN; result = PY_SSIZE_T_MIN;
else else
result = PY_SSIZE_T_MAX; result = PY_SSIZE_T_MAX;

View file

@ -2,6 +2,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_object.h" // _Py_FatalRefcountError() #include "pycore_object.h" // _Py_FatalRefcountError()
#include "pycore_long.h" // FALSE_TAG TRUE_TAG
#include "pycore_runtime.h" // _Py_ID() #include "pycore_runtime.h" // _Py_ID()
#include <stddef.h> #include <stddef.h>
@ -198,10 +199,14 @@ PyTypeObject PyBool_Type = {
struct _longobject _Py_FalseStruct = { struct _longobject _Py_FalseStruct = {
PyObject_HEAD_INIT(&PyBool_Type) PyObject_HEAD_INIT(&PyBool_Type)
{ 0, { 0 } } { .lv_tag = _PyLong_FALSE_TAG,
{ 0 }
}
}; };
struct _longobject _Py_TrueStruct = { struct _longobject _Py_TrueStruct = {
PyObject_HEAD_INIT(&PyBool_Type) PyObject_HEAD_INIT(&PyBool_Type)
{ 1, { 1 } } { .lv_tag = _PyLong_TRUE_TAG,
{ 1 }
}
}; };

View file

@ -4,6 +4,7 @@
#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_interp.h" // PyInterpreterState.list #include "pycore_interp.h" // PyInterpreterState.list
#include "pycore_list.h" // struct _Py_list_state, _PyListIterObject #include "pycore_list.h" // struct _Py_list_state, _PyListIterObject
#include "pycore_long.h" // _PyLong_DigitCount
#include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_tuple.h" // _PyTuple_FromArray()
#include <stddef.h> #include <stddef.h>
@ -2144,24 +2145,21 @@ unsafe_latin_compare(PyObject *v, PyObject *w, MergeState *ms)
static int static int
unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms)
{ {
PyLongObject *vl, *wl; sdigit v0, w0; int res; PyLongObject *vl, *wl;
intptr_t v0, w0;
int res;
/* Modified from Objects/longobject.c:long_compare, assuming: */ /* Modified from Objects/longobject.c:long_compare, assuming: */
assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(v, &PyLong_Type));
assert(Py_IS_TYPE(w, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type));
assert(Py_ABS(Py_SIZE(v)) <= 1); assert(_PyLong_IsCompact((PyLongObject *)v));
assert(Py_ABS(Py_SIZE(w)) <= 1); assert(_PyLong_IsCompact((PyLongObject *)w));
vl = (PyLongObject*)v; vl = (PyLongObject*)v;
wl = (PyLongObject*)w; wl = (PyLongObject*)w;
v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->long_value.ob_digit[0]; v0 = _PyLong_CompactValue(vl);
w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->long_value.ob_digit[0]; w0 = _PyLong_CompactValue(wl);
if (Py_SIZE(vl) < 0)
v0 = -v0;
if (Py_SIZE(wl) < 0)
w0 = -w0;
res = v0 < w0; res = v0 < w0;
assert(res == PyObject_RichCompareBool(v, w, Py_LT)); assert(res == PyObject_RichCompareBool(v, w, Py_LT));
@ -2359,7 +2357,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
if (keys_are_all_same_type) { if (keys_are_all_same_type) {
if (key_type == &PyLong_Type && if (key_type == &PyLong_Type &&
ints_are_bounded && ints_are_bounded &&
Py_ABS(Py_SIZE(key)) > 1) { !_PyLong_IsCompact((PyLongObject *)key)) {
ints_are_bounded = 0; ints_are_bounded = 0;
} }

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,7 @@ validate_step(PyObject *step)
return PyLong_FromLong(1); return PyLong_FromLong(1);
step = PyNumber_Index(step); step = PyNumber_Index(step);
if (step && _PyLong_Sign(step) == 0) { if (step && _PyLong_IsZero((PyLongObject *)step)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"range() arg 3 must not be zero"); "range() arg 3 must not be zero");
Py_CLEAR(step); Py_CLEAR(step);

View file

@ -445,7 +445,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
if (start == NULL) if (start == NULL)
goto error; goto error;
if (_PyLong_Sign(start) < 0) { if (_PyLong_IsNegative((PyLongObject *)start)) {
/* start += length */ /* start += length */
PyObject *tmp = PyNumber_Add(start, length); PyObject *tmp = PyNumber_Add(start, length);
Py_SETREF(start, tmp); Py_SETREF(start, tmp);
@ -478,7 +478,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
if (stop == NULL) if (stop == NULL)
goto error; goto error;
if (_PyLong_Sign(stop) < 0) { if (_PyLong_IsNegative((PyLongObject *)stop)) {
/* stop += length */ /* stop += length */
PyObject *tmp = PyNumber_Add(stop, length); PyObject *tmp = PyNumber_Add(stop, length);
Py_SETREF(stop, tmp); Py_SETREF(stop, tmp);
@ -533,7 +533,7 @@ slice_indices(PySliceObject* self, PyObject* len)
if (length == NULL) if (length == NULL)
return NULL; return NULL;
if (_PyLong_Sign(length) < 0) { if (_PyLong_IsNegative((PyLongObject *)length)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"length should not be negative"); "length should not be negative");
Py_DECREF(length); Py_DECREF(length);

View file

@ -8,6 +8,7 @@
#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_moduleobject.h" // _PyModule_GetDef()
#include "pycore_object.h" // _PyType_HasFeature() #include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_long.h" // _PyLong_IsNegative()
#include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_typeobject.h" // struct type_cache #include "pycore_typeobject.h" // struct type_cache
@ -7865,7 +7866,7 @@ slot_sq_length(PyObject *self)
return -1; return -1;
assert(PyLong_Check(res)); assert(PyLong_Check(res));
if (Py_SIZE(res) < 0) { if (_PyLong_IsNegative((PyLongObject *)res)) {
Py_DECREF(res); Py_DECREF(res);
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"__len__() should return >= 0"); "__len__() should return >= 0");

View file

@ -2,6 +2,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_ast.h" // _PyAST_GetDocString()
#include "pycore_compile.h" // _PyASTOptimizeState #include "pycore_compile.h" // _PyASTOptimizeState
#include "pycore_long.h" // _PyLong
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_format.h" // F_LJUST #include "pycore_format.h" // F_LJUST
@ -152,7 +153,9 @@ check_complexity(PyObject *obj, Py_ssize_t limit)
static PyObject * static PyObject *
safe_multiply(PyObject *v, PyObject *w) safe_multiply(PyObject *v, PyObject *w)
{ {
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
) {
size_t vbits = _PyLong_NumBits(v); size_t vbits = _PyLong_NumBits(v);
size_t wbits = _PyLong_NumBits(w); size_t wbits = _PyLong_NumBits(w);
if (vbits == (size_t)-1 || wbits == (size_t)-1) { if (vbits == (size_t)-1 || wbits == (size_t)-1) {
@ -198,7 +201,9 @@ safe_multiply(PyObject *v, PyObject *w)
static PyObject * static PyObject *
safe_power(PyObject *v, PyObject *w) safe_power(PyObject *v, PyObject *w)
{ {
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) { if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w)
) {
size_t vbits = _PyLong_NumBits(v); size_t vbits = _PyLong_NumBits(v);
size_t wbits = PyLong_AsSize_t(w); size_t wbits = PyLong_AsSize_t(w);
if (vbits == (size_t)-1 || wbits == (size_t)-1) { if (vbits == (size_t)-1 || wbits == (size_t)-1) {
@ -215,7 +220,9 @@ safe_power(PyObject *v, PyObject *w)
static PyObject * static PyObject *
safe_lshift(PyObject *v, PyObject *w) safe_lshift(PyObject *v, PyObject *w)
{ {
if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
) {
size_t vbits = _PyLong_NumBits(v); size_t vbits = _PyLong_NumBits(v);
size_t wbits = PyLong_AsSize_t(w); size_t wbits = PyLong_AsSize_t(w);
if (vbits == (size_t)-1 || wbits == (size_t)-1) { if (vbits == (size_t)-1 || wbits == (size_t)-1) {

View file

@ -5,6 +5,7 @@
#include "pycore_ast.h" // _PyAST_Validate() #include "pycore_ast.h" // _PyAST_Validate()
#include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_compile.h" // _PyAST_Compile() #include "pycore_compile.h" // _PyAST_Compile()
#include "pycore_long.h" // _PyLong_CompactValue
#include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_object.h" // _Py_AddToAllObjects()
#include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pyerrors.h" // _PyErr_NoMemory()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()
@ -2491,7 +2492,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
*/ */
if (PyLong_CheckExact(result)) { if (PyLong_CheckExact(result)) {
int overflow; int overflow;
long i_result = PyLong_AsLongAndOverflow(result, &overflow); Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow);
/* If this already overflowed, don't even enter the loop. */ /* If this already overflowed, don't even enter the loop. */
if (overflow == 0) { if (overflow == 0) {
Py_SETREF(result, NULL); Py_SETREF(result, NULL);
@ -2505,15 +2506,14 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
return PyLong_FromLong(i_result); return PyLong_FromLong(i_result);
} }
if (PyLong_CheckExact(item) || PyBool_Check(item)) { if (PyLong_CheckExact(item) || PyBool_Check(item)) {
long b; Py_ssize_t b;
overflow = 0; overflow = 0;
/* Single digits are common, fast, and cannot overflow on unpacking. */ /* Single digits are common, fast, and cannot overflow on unpacking. */
switch (Py_SIZE(item)) { if (_PyLong_IsCompact((PyLongObject *)item)) {
case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break; b = _PyLong_CompactValue((PyLongObject *)item);
// Note: the continue goes to the top of the "while" loop that iterates over the elements }
case 0: Py_DECREF(item); continue; else {
case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break; b = PyLong_AsLongAndOverflow(item, &overflow);
default: b = PyLong_AsLongAndOverflow(item, &overflow); break;
} }
if (overflow == 0 && if (overflow == 0 &&
(i_result >= 0 ? (b <= LONG_MAX - i_result) (i_result >= 0 ? (b <= LONG_MAX - i_result)

View file

@ -345,8 +345,7 @@ dummy_func(
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
// Deopt unless 0 <= sub < PyList_Size(list) // Deopt unless 0 <= sub < PyList_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
STAT_INC(BINARY_SUBSCR, hit); STAT_INC(BINARY_SUBSCR, hit);
@ -363,8 +362,7 @@ dummy_func(
DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
// Deopt unless 0 <= sub < PyTuple_Size(list) // Deopt unless 0 <= sub < PyTuple_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
STAT_INC(BINARY_SUBSCR, hit); STAT_INC(BINARY_SUBSCR, hit);
@ -456,7 +454,7 @@ dummy_func(
DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
// Ensure nonnegative, zero-or-one-digit ints. // Ensure nonnegative, zero-or-one-digit ints.
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR);
Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0];
// Ensure index < len(list) // Ensure index < len(list)
DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR);
@ -1755,12 +1753,13 @@ dummy_func(
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH);
DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH);
DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH);
DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH);
STAT_INC(COMPARE_AND_BRANCH, hit); STAT_INC(COMPARE_AND_BRANCH, hit);
assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 &&
Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; _PyLong_DigitCount((PyLongObject *)right) <= 1);
Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left);
Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right);
// 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg
int sign_ish = COMPARISON_BIT(ileft, iright); int sign_ish = COMPARISON_BIT(ileft, iright);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_code.h" // _PyCode_New() #include "pycore_code.h" // _PyCode_New()
#include "pycore_long.h" // _PyLong_DigitCount
#include "pycore_hashtable.h" // _Py_hashtable_t #include "pycore_hashtable.h" // _Py_hashtable_t
#include "marshal.h" // Py_MARSHAL_VERSION #include "marshal.h" // Py_MARSHAL_VERSION
@ -232,13 +233,13 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
digit d; digit d;
W_TYPE(TYPE_LONG, p); W_TYPE(TYPE_LONG, p);
if (Py_SIZE(ob) == 0) { if (_PyLong_IsZero(ob)) {
w_long((long)0, p); w_long((long)0, p);
return; return;
} }
/* set l to number of base PyLong_MARSHAL_BASE digits */ /* set l to number of base PyLong_MARSHAL_BASE digits */
n = Py_ABS(Py_SIZE(ob)); n = _PyLong_DigitCount(ob);
l = (n-1) * PyLong_MARSHAL_RATIO; l = (n-1) * PyLong_MARSHAL_RATIO;
d = ob->long_value.ob_digit[n-1]; d = ob->long_value.ob_digit[n-1];
assert(d != 0); /* a PyLong is always normalized */ assert(d != 0); /* a PyLong is always normalized */
@ -251,7 +252,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
p->error = WFERR_UNMARSHALLABLE; p->error = WFERR_UNMARSHALLABLE;
return; return;
} }
w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p);
for (i=0; i < n-1; i++) { for (i=0; i < n-1; i++) {
d = ob->long_value.ob_digit[i]; d = ob->long_value.ob_digit[i];
@ -839,7 +840,7 @@ r_PyLong(RFILE *p)
if (ob == NULL) if (ob == NULL)
return NULL; return NULL;
Py_SET_SIZE(ob, n > 0 ? size : -size); _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size);
for (i = 0; i < size-1; i++) { for (i = 0; i < size-1; i++) {
d = 0; d = 0;

View file

@ -1308,7 +1308,7 @@ _Py_Specialize_BinarySubscr(
PyTypeObject *container_type = Py_TYPE(container); PyTypeObject *container_type = Py_TYPE(container);
if (container_type == &PyList_Type) { if (container_type == &PyList_Type) {
if (PyLong_CheckExact(sub)) { if (PyLong_CheckExact(sub)) {
if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
instr->op.code = BINARY_SUBSCR_LIST_INT; instr->op.code = BINARY_SUBSCR_LIST_INT;
goto success; goto success;
} }
@ -1321,7 +1321,7 @@ _Py_Specialize_BinarySubscr(
} }
if (container_type == &PyTuple_Type) { if (container_type == &PyTuple_Type) {
if (PyLong_CheckExact(sub)) { if (PyLong_CheckExact(sub)) {
if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) {
instr->op.code = BINARY_SUBSCR_TUPLE_INT; instr->op.code = BINARY_SUBSCR_TUPLE_INT;
goto success; goto success;
} }
@ -1389,7 +1389,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
PyTypeObject *container_type = Py_TYPE(container); PyTypeObject *container_type = Py_TYPE(container);
if (container_type == &PyList_Type) { if (container_type == &PyList_Type) {
if (PyLong_CheckExact(sub)) { if (PyLong_CheckExact(sub)) {
if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)
&& ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container))
{ {
instr->op.code = STORE_SUBSCR_LIST_INT; instr->op.code = STORE_SUBSCR_LIST_INT;
@ -2007,7 +2007,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst
goto success; goto success;
} }
if (PyLong_CheckExact(lhs)) { if (PyLong_CheckExact(lhs)) {
if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) { if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) {
instr->op.code = COMPARE_AND_BRANCH_INT; instr->op.code = COMPARE_AND_BRANCH_INT;
goto success; goto success;
} }

View file

@ -309,7 +309,7 @@ class Printer:
return f"& {name}._object.ob_base.ob_base" return f"& {name}._object.ob_base.ob_base"
def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None:
sign = -1 if i < 0 else 0 if i == 0 else +1 sign = (i > 0) - (i < 0)
i = abs(i) i = abs(i)
digits: list[int] = [] digits: list[int] = []
while i: while i:
@ -318,10 +318,12 @@ class Printer:
self.write("static") self.write("static")
with self.indent(): with self.indent():
with self.block("struct"): with self.block("struct"):
self.write("PyObject_VAR_HEAD") self.write("PyObject ob_base;")
self.write("uintptr_t lv_tag;")
self.write(f"digit ob_digit[{max(1, len(digits))}];") self.write(f"digit ob_digit[{max(1, len(digits))}];")
with self.block(f"{name} =", ";"): with self.block(f"{name} =", ";"):
self.object_var_head("PyLong_Type", sign*len(digits)) self.object_head("PyLong_Type")
self.write(f".lv_tag = TAG_FROM_SIGN_AND_SIZE({sign}, {len(digits)}),")
if digits: if digits:
ds = ", ".join(map(str, digits)) ds = ", ".join(map(str, digits))
self.write(f".ob_digit = {{ {ds} }},") self.write(f".ob_digit = {{ {ds} }},")
@ -345,7 +347,7 @@ class Printer:
self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"') self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"')
self.write("#endif") self.write("#endif")
# If neither clause applies, it won't compile # If neither clause applies, it won't compile
return f"& {name}.ob_base.ob_base" return f"& {name}.ob_base"
def generate_float(self, name: str, x: float) -> str: def generate_float(self, name: str, x: float) -> str:
with self.block(f"static PyFloatObject {name} =", ";"): with self.block(f"static PyFloatObject {name} =", ";"):

View file

@ -882,10 +882,16 @@ class PyLongObjectPtr(PyObjectPtr):
def proxyval(self, visited): def proxyval(self, visited):
''' '''
Python's Include/longobjrep.h has this declaration: Python's Include/longobjrep.h has this declaration:
struct _longobject {
PyObject_VAR_HEAD typedef struct _PyLongValue {
digit ob_digit[1]; uintptr_t lv_tag; /* Number of digits, sign and flags */
}; digit ob_digit[1];
} _PyLongValue;
struct _longobject {
PyObject_HEAD
_PyLongValue long_value;
};
with this description: with this description:
The absolute value of a number is equal to The absolute value of a number is equal to
@ -897,11 +903,13 @@ class PyLongObjectPtr(PyObjectPtr):
#define PyLong_SHIFT 30 #define PyLong_SHIFT 30
#define PyLong_SHIFT 15 #define PyLong_SHIFT 15
''' '''
ob_size = int(self.field('ob_size')) long_value = self.field('long_value')
if ob_size == 0: lv_tag = int(long_value['lv_tag'])
size = lv_tag >> 3
if size == 0:
return 0 return 0
ob_digit = self.field('long_value')['ob_digit'] ob_digit = long_value['ob_digit']
if gdb.lookup_type('digit').sizeof == 2: if gdb.lookup_type('digit').sizeof == 2:
SHIFT = 15 SHIFT = 15
@ -909,9 +917,9 @@ class PyLongObjectPtr(PyObjectPtr):
SHIFT = 30 SHIFT = 30
digits = [int(ob_digit[i]) * 2**(SHIFT*i) digits = [int(ob_digit[i]) * 2**(SHIFT*i)
for i in safe_range(abs(ob_size))] for i in safe_range(size)]
result = sum(digits) result = sum(digits)
if ob_size < 0: if (lv_tag & 3) == 2:
result = -result result = -result
return result return result