diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index f5ccbb704e8bb8..6ab7a5bf5fe2f1 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -61,6 +61,12 @@ typedef long stwodigits; /* signed variant of twodigits */ #define PyLong_BASE ((digit)1 << PyLong_SHIFT) #define PyLong_MASK ((digit)(PyLong_BASE - 1)) +#define PyLong_IS_LONG_MASK ((digit)1 << 31) +#define PyLong_IS_NEGATIVE_MASK ((digit)1 << 30) +#define PyLong_FLAGS_MASK (PyLong_IS_LONG_MASK | PyLong_IS_NEGATIVE_MASK) +#define PyLong_LONG_HEADER_DIGITS (2) + +// MGDTODO: Update this docstring /* Long integer representation. The absolute value of a number is equal to SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) @@ -79,14 +85,9 @@ typedef long stwodigits; /* signed variant of twodigits */ aware that ints abuse ob_size's sign bit. */ -typedef struct _PyLongValue { - uintptr_t lv_tag; /* Number of digits, sign and flags */ - digit ob_digit[1]; -} _PyLongValue; - struct _longobject { PyObject_HEAD - _PyLongValue long_value; + digit ob_digit[1]; }; PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); @@ -100,17 +101,10 @@ PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( digit *digits); -/* Inline some internals for speed. These should be in pycore_long.h - * if user code didn't need them inlined. */ - -#define _PyLong_SIGN_MASK 3 -#define _PyLong_NON_SIZE_BITS 3 - - static inline int _PyLong_IsCompact(const PyLongObject* op) { assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); - return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); + return !(op->ob_digit[0] & PyLong_IS_LONG_MASK); } #define PyUnstable_Long_IsCompact _PyLong_IsCompact @@ -120,8 +114,7 @@ _PyLong_CompactValue(const PyLongObject *op) { assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); - Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); - return sign * (Py_ssize_t)op->long_value.ob_digit[0]; + return ((op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) ? -1 : 1) * ((Py_ssize_t)op->ob_digit[0] & PyLong_MASK); } #define PyUnstable_Long_CompactValue _PyLong_CompactValue diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index ec27df9e416c58..a29ebc754678b2 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -12,6 +12,12 @@ extern "C" { #include "pycore_global_objects.h"// _PY_NSMALLNEGINTS #include "pycore_runtime.h" // _PyRuntime +// MGDTODO: Put this in the right place +#define PyLong_IS_LONG_MASK ((digit)1 << 31) +#define PyLong_IS_NEGATIVE_MASK ((digit)1 << 30) +#define PyLong_FLAGS_MASK (PyLong_IS_LONG_MASK | PyLong_IS_NEGATIVE_MASK) +#define PyLong_LONG_HEADER_DIGITS (2) + /* * Default int base conversion size limitation: Denial of Service prevention. * @@ -168,14 +174,10 @@ PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *); PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *); /* 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 + * 31: Is long? Is the representation that stores more than one digit? + * 30: Is negative */ -#define SIGN_MASK 3 -#define SIGN_ZERO 1 -#define SIGN_NEGATIVE 2 -#define NON_SIZE_BITS 3 +// MGDTODO: Copy defines here? /* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined * in Include/cpython/longobject.h, since they need to be inline. @@ -185,24 +187,21 @@ PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *); * without risk of overflow. * * The inline functions need tag bits. - * For readability, rather than do `#define SIGN_MASK _PyLong_SIGN_MASK` + * For readability, rather than do `#define NON_SIZE_BITS _PyLong_NON_SIZE_BITS` * we define them to the numbers in both places and then assert that * they're the same. */ -static_assert(SIGN_MASK == _PyLong_SIGN_MASK, "SIGN_MASK does not match _PyLong_SIGN_MASK"); -static_assert(NON_SIZE_BITS == _PyLong_NON_SIZE_BITS, "NON_SIZE_BITS does not match _PyLong_NON_SIZE_BITS"); +// MGDTODO: Restore the new equivalents here /* 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 + * a uint32_t with at least one bit to spare. */ /* Return 1 if the argument is compact int */ static inline int _PyLong_IsNonNegativeCompact(const PyLongObject* op) { assert(PyLong_Check(op)); - return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); + return (op->ob_digit[0] & PyLong_FLAGS_MASK) == (digit)0; } @@ -210,41 +209,47 @@ 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); + return ((a->ob_digit[0] | b->ob_digit[0]) & PyLong_IS_LONG_MASK) == 0; } static inline bool _PyLong_IsZero(const PyLongObject *op) { - return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO; + return op->ob_digit[0] == 0; } static inline bool _PyLong_IsNegative(const PyLongObject *op) { - return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE; + return op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK; } static inline bool _PyLong_IsPositive(const PyLongObject *op) { - return (op->long_value.lv_tag & SIGN_MASK) == 0; + assert(PyLong_Check(op)); + // MGDTODO: Optimize + + return (op->ob_digit[0] & ~PyLong_IS_LONG_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; + // assert(PyLong_Check(op)); + if (_PyLong_IsCompact(op)) { + return _PyLong_IsZero(op) ? 0 : 1; + } else { + return (Py_ssize_t)op->ob_digit[1] | (Py_ssize_t)(op->ob_digit[0] & PyLong_MASK) << 32; + } } -/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */ -static inline Py_ssize_t -_PyLong_SignedDigitCount(const PyLongObject *op) +static inline int +_PyLong_NonCompactSign(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); + assert(!_PyLong_IsCompact(op)); + return (op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) ? -1 : 1; } static inline int @@ -252,25 +257,52 @@ _PyLong_CompactSign(const PyLongObject *op) { assert(PyLong_Check(op)); assert(_PyLong_IsCompact(op)); - return 1 - (op->long_value.lv_tag & SIGN_MASK); + if (op->ob_digit[0] == 0) { + return 0; + } + return (op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) ? -1 : 1; } -static inline int -_PyLong_NonCompactSign(const PyLongObject *op) +/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */ +static inline Py_ssize_t +_PyLong_SignedDigitCount(const PyLongObject *op) { assert(PyLong_Check(op)); - assert(!_PyLong_IsCompact(op)); - return 1 - (op->long_value.lv_tag & SIGN_MASK); + if (op->ob_digit[0] == 0) { + return 0; + } else if (_PyLong_IsCompact(op)) { + return (op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) ? -1 : 1; + } else { + return (Py_ssize_t)_PyLong_DigitCount(op) * _PyLong_NonCompactSign(op); + } } /* 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); + if (a->ob_digit[0] == 0 && b->ob_digit[0] == 0) { + return 1; + } + return !((a->ob_digit[0] ^ b->ob_digit[0]) & PyLong_IS_NEGATIVE_MASK); } -#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) +static inline void +_PyLong_SetSign(PyLongObject *op, int sign) +{ + assert(-1 <= sign && sign <= 1); + switch (sign) { + case 0: + op->ob_digit[0] = 0; + break; + case 1: + op->ob_digit[0] |= ~PyLong_IS_NEGATIVE_MASK; + break; + case -1: + op->ob_digit[0] |= PyLong_IS_NEGATIVE_MASK; + break; + } +} static inline void _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) @@ -278,39 +310,67 @@ _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); + if (size == 0) { + assert(sign == 0); + op->ob_digit[0] = 0; + } else if (size == 1) { + // assert(op->ob_digit[0] != 0); + op->ob_digit[0] = ( + ((sign == -1) ? PyLong_IS_NEGATIVE_MASK : 0) | + (op->ob_digit[PyLong_LONG_HEADER_DIGITS] & PyLong_MASK) + ); + } else { + // assert(op->ob_digit[0] & PyLong_IS_LONG_MASK); + // assert(_PyLong_DigitCount(op) >= size); + op->ob_digit[0] = ( + PyLong_IS_LONG_MASK | + ((sign == -1) ? PyLong_IS_NEGATIVE_MASK : 0) | + (size >> 32) + ); + op->ob_digit[1] = (size & 0xffffffff); + } } 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); + assert(!_PyLong_IsCompact(op)); + if (size == 0) { + op->ob_digit[0] = 0; + } else if (size == 1) { + assert(op->ob_digit[0] != 0); + op->ob_digit[0] = ( + (op->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) | + (op->ob_digit[PyLong_LONG_HEADER_DIGITS] & PyLong_MASK) + ); + } else { + assert(op->ob_digit[0] & PyLong_IS_LONG_MASK); + assert(_PyLong_DigitCount(op) >= size); + op->ob_digit[0] = ( + (op->ob_digit[0] & PyLong_FLAGS_MASK) | + size >> 32 + ); + op->ob_digit[1] = (size & 0xffffffff); + } } -#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; + op->ob_digit[0] ^= PyLong_IS_NEGATIVE_MASK; } +// MGDTODO: These objects will be 4 bytes larger than needed. + #define _PyLong_DIGIT_INIT(val) \ { \ .ob_base = _PyObject_HEAD_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)) }, \ + .ob_digit = { \ + (((val) < 0) ? PyLong_IS_NEGATIVE_MASK : 0) | \ + (((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 } #endif diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 8b93f8e2cbcf0b..be0a9a93c8d09a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -2299,17 +2299,17 @@ dec_from_long(PyTypeObject *type, PyObject *v, uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; if (_PyLong_IsCompact(l)) { - _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); + _dec_settriple(dec, sign, l->ob_digit[0] & PyLong_MASK, 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; } size_t len = _PyLong_DigitCount(l); #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->ob_digit + 2, len, sign, PyLong_BASE, ctx, status); #elif PYLONG_BITS_IN_DIGIT == 15 - mpd_qimport_u16(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, + mpd_qimport_u16(MPD(dec), l->ob_digit + 2, len, sign, PyLong_BASE, ctx, status); #else #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" diff --git a/Objects/boolobject.c b/Objects/boolobject.c index fb48dcbeca7850..244cfbe79b72de 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -171,7 +171,7 @@ bool_dealloc(PyObject *boolean) PyTypeObject PyBool_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "bool", - offsetof(struct _longobject, long_value.ob_digit), /* tp_basicsize */ + offsetof(struct _longobject, ob_digit) + sizeof(digit), /* tp_basicsize */ // MGDTODO: Too big? sizeof(digit), /* tp_itemsize */ bool_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ @@ -214,14 +214,10 @@ PyTypeObject PyBool_Type = { struct _longobject _Py_FalseStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { .lv_tag = _PyLong_FALSE_TAG, - { 0 } - } + .ob_digit = { 0 }, }; struct _longobject _Py_TrueStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { .lv_tag = _PyLong_TRUE_TAG, - { 1 } - } + .ob_digit = { 1 }, }; diff --git a/Objects/longobject.c b/Objects/longobject.c index fae70dd13bb18a..9d7b342c2ea3ce 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -31,6 +31,80 @@ class int "PyObject *" "&PyLong_Type" /* If defined, use algorithms from the _pylong.py module */ #define WITH_PYLONG_MODULE 1 +// MGDTODO: Remove me +static inline void +print_long( PyLongObject *a) { + if (_PyLong_IsCompact(a)) { + printf("Compact: N%d %d ", _PyLong_IsNegative(a), a->ob_digit[0] & PyLong_MASK); + } else { + printf("Long: N%d D%ld ", _PyLong_IsNegative(a), _PyLong_DigitCount(a)); + for (size_t i = 0; i < _PyLong_DigitCount(a); ++i) { + printf("%d ", a->ob_digit[PyLong_LONG_HEADER_DIGITS + i] & PyLong_MASK); + } + } +} + +static inline digit* +get_digit_offset( PyLongObject *v) +{ + return v->ob_digit + ((v->ob_digit[0] & PyLong_IS_LONG_MASK) >> 30); +} + +static inline digit +extract_digit( digit *d) +{ + return *d & PyLong_MASK; +} + +static inline void +store_digit(digit *d, digit val) +{ + *d = (*d & PyLong_FLAGS_MASK) | (val & PyLong_MASK); +} + + +static inline digit +get_digit( PyLongObject *v, size_t i) +{ + return extract_digit(get_digit_offset(v) + i); +} + +static inline void +set_digit(PyLongObject *v, size_t i, digit val) +{ + store_digit(get_digit_offset(v) + i, val); +} + +static inline void +copy_digits(PyLongObject *a, size_t a_offset, PyLongObject *b, size_t b_offset, int ndigits) +{ + assert(ndigits >= 1); + + if (_PyLong_IsCompact(a)) { + assert(a_offset == 0); + assert(ndigits == 1); + if (_PyLong_IsCompact(b)) { + assert(b_offset == 0); + store_digit(a->ob_digit, b->ob_digit[0]); + } else { + store_digit(a->ob_digit, b->ob_digit[PyLong_LONG_HEADER_DIGITS + b_offset]); + } + } else { + if (_PyLong_IsCompact(b)) { + assert(b_offset == 0); + assert(ndigits == 1); + store_digit(a->ob_digit + PyLong_LONG_HEADER_DIGITS + a_offset, b->ob_digit[0]); + } else { + // MGDTODO: Asserts + memcpy( + &a->ob_digit[PyLong_LONG_HEADER_DIGITS + a_offset], + &b->ob_digit[PyLong_LONG_HEADER_DIGITS + b_offset], + sizeof(digit) * ndigits + ); + } + } +} + static inline void _Py_DECREF_INT(PyLongObject *op) { @@ -50,7 +124,9 @@ static PyObject * get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); - return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival]; + PyObject *res = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival]; + assert(_PyLong_CompactValue((PyLongObject *)res) == ival); + return res; } static PyLongObject * @@ -114,17 +190,19 @@ maybe_small_long(PyLongObject *v) static PyLongObject * long_normalize(PyLongObject *v) { - Py_ssize_t j = _PyLong_DigitCount(v); - Py_ssize_t i = j; + if (!_PyLong_IsCompact(v)) { + Py_ssize_t j = _PyLong_DigitCount(v); + Py_ssize_t i = j; - while (i > 0 && v->long_value.ob_digit[i-1] == 0) - --i; - if (i != j) { - if (i == 0) { - _PyLong_SetSignAndDigitCount(v, 0, 0); - } - else { - _PyLong_SetDigitCount(v, i); + while (i > 0 && (v->ob_digit[i+1] & PyLong_MASK) == 0) + --i; + if (i != j) { + if (i == 0) { + _PyLong_SetSignAndDigitCount(v, 0, 0); + } + else { + _PyLong_SetDigitCount(v, i); + } } } return v; @@ -133,8 +211,9 @@ long_normalize(PyLongObject *v) /* Allocate a new int object with size digits. Return NULL and set exception if we run out of memory. */ +// MGDTODO: This calculation doesn't make sense #define MAX_LONG_DIGITS \ - ((PY_SSIZE_T_MAX - offsetof(PyLongObject, long_value.ob_digit))/sizeof(digit)) + ((PY_SSIZE_T_MAX - offsetof(PyLongObject, ob_digit))/sizeof(digit)) PyLongObject * _PyLong_New(Py_ssize_t size) @@ -149,23 +228,56 @@ _PyLong_New(Py_ssize_t size) /* Fast operations for single digit integers (including zero) * assume that there is always at least one digit present. */ Py_ssize_t ndigits = size ? size : 1; - /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + - sizeof(digit)*size. Previous incarnations of this code used - sizeof() instead of the offsetof, but this risks being - incorrect in the presence of padding between the header - and the digits. */ - result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + - ndigits*sizeof(digit)); - if (!result) { + if (ndigits == 1) { + // MGDTODO: This is extra long, because packing is weird + result = PyObject_Malloc(offsetof(PyLongObject, ob_digit) + sizeof(digit)); + if (!result) { + PyErr_NoMemory(); + return NULL; + } + _PyObject_Init((PyObject*)result, &PyLong_Type); + result->ob_digit[0] = 0; + return result; + } else { + /* Number of bytes needed is: offsetof(PyLongObject, long_value.digits) + + sizeof(digit)*size. Previous incarnations of this code used + sizeof() instead of the offsetof, but this risks being + incorrect in the presence of padding between the header + and the digits. */ + result = PyObject_Malloc(offsetof(PyLongObject, ob_digit) + + (ndigits + PyLong_LONG_HEADER_DIGITS)*sizeof(digit)); + if (!result) { + PyErr_NoMemory(); + return NULL; + } + _PyObject_Init((PyObject*)result, &PyLong_Type); + result->ob_digit[0] = PyLong_IS_LONG_MASK; + _PyLong_SetSignAndDigitCount(result, size != 0, size); + // MGDTODO: memset? + for (int i = 0; i < size; ++i) { + result->ob_digit[i + PyLong_LONG_HEADER_DIGITS] = 0; + } + return result; + } +} + +static PyObject * +_PyLong_FromMedium(sdigit x) +{ + assert(!IS_SMALL_INT(x)); + assert(is_medium_int(x)); + /* We could use a freelist here */ + PyLongObject *v = PyObject_Malloc(offsetof(PyLongObject, ob_digit) + sizeof(digit)); + if (v == NULL) { PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndDigitCount(result, size != 0, size); - _PyObject_Init((PyObject*)result, &PyLong_Type); - /* The digit has to be initialized explicitly to avoid - * use-of-uninitialized-value. */ - result->long_value.ob_digit[0] = 0; - return result; + v->ob_digit[0] = ( + ((x < 0) ? PyLong_IS_NEGATIVE_MASK : 0) | + (((x < 0) ? -x : x) & PyLong_MASK) + ); + _PyObject_Init((PyObject*)v, &PyLong_Type); + return (PyObject*)v; } PyLongObject * @@ -180,8 +292,15 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); - memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); + if (_PyLong_IsCompact(result)) { + result->ob_digit[0] = ( + (negative ? PyLong_IS_NEGATIVE_MASK : 0) | + (digits[0] & PyLong_MASK) + ); + } else { + _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); + memcpy(&result->ob_digit[PyLong_LONG_HEADER_DIGITS], digits, digit_count * sizeof(digit)); + } return result; } @@ -195,27 +314,19 @@ _PyLong_Copy(PyLongObject *src) if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } + PyLongObject *result = _PyLong_New(1); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + // MGDTODO: Optimization + result->ob_digit[0] = src->ob_digit[0]; + return (PyObject *)result; } - Py_ssize_t size = _PyLong_DigitCount(src); - return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); -} -static PyObject * -_PyLong_FromMedium(sdigit x) -{ - assert(!IS_SMALL_INT(x)); - assert(is_medium_int(x)); - /* We could use a freelist here */ - PyLongObject *v = PyObject_Malloc(sizeof(PyLongObject)); - if (v == NULL) { - PyErr_NoMemory(); - return NULL; - } - digit abs_x = x < 0 ? -x : x; - _PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1); - _PyObject_Init((PyObject*)v, &PyLong_Type); - v->long_value.ob_digit[0] = abs_x; - return (PyObject*)v; + Py_ssize_t size = _PyLong_DigitCount(src); + // MGDTODO: Maybe just memcpy in all cases? + return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, &src->ob_digit[2]); } static PyObject * @@ -245,7 +356,8 @@ _PyLong_FromLarge(stwodigits ival) } PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { - digit *p = v->long_value.ob_digit; + assert(!_PyLong_IsCompact(v)); + digit *p = v->ob_digit + PyLong_LONG_HEADER_DIGITS; _PyLong_SetSignAndDigitCount(v, sign, ndigits); t = abs_ival; while (t) { @@ -318,7 +430,8 @@ PyLong_FromLong(long ival) /* Construct output value. */ v = _PyLong_New(ndigits); if (v != NULL) { - digit *p = v->long_value.ob_digit; + assert(!_PyLong_IsCompact(v)); + digit *p = v->ob_digit + PyLong_LONG_HEADER_DIGITS; _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { @@ -341,11 +454,14 @@ PyLong_FromLong(long ival) ++ndigits; \ t >>= PyLong_SHIFT; \ } \ + if (ndigits == 1) { \ + return _PyLong_FromMedium(ival); \ + } \ PyLongObject *v = _PyLong_New(ndigits); \ if (v == NULL) { \ return NULL; \ } \ - digit *p = v->long_value.ob_digit; \ + digit *p = v->ob_digit + PyLong_LONG_HEADER_DIGITS; \ while ((ival)) { \ *p++ = (digit)((ival) & PyLong_MASK); \ (ival) >>= PyLong_SHIFT; \ @@ -418,13 +534,20 @@ PyLong_FromDouble(double dval) frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */ assert(expo > 0); ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */ + if (ndig == 1) { + frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1); + return _PyLong_FromMedium(frac); + } + v = _PyLong_New(ndig); if (v == NULL) return NULL; + assert(!_PyLong_IsCompact(v)); + // MGDTODO: Special handling when ndig == 1? frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1); for (i = ndig; --i >= 0; ) { digit bits = (digit)frac; - v->long_value.ob_digit[i] = bits; + v->ob_digit[i + PyLong_LONG_HEADER_DIGITS] = bits; frac = frac - (double)bits; frac = ldexp(frac, PyLong_SHIFT); } @@ -498,9 +621,10 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); x = 0; + assert(!_PyLong_IsCompact(v)); while (--i >= 0) { prev = x; - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; goto exit; @@ -590,7 +714,7 @@ PyLong_AsSsize_t(PyObject *vv) { x = 0; while (--i >= 0) { prev = x; - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; if ((x >> PyLong_SHIFT) != prev) goto overflow; } @@ -647,11 +771,12 @@ PyLong_AsUnsignedLong(PyObject *vv) "can't convert negative value to unsigned int"); return (unsigned long) -1; } + assert(!_PyLong_IsCompact(v)); i = _PyLong_DigitCount(v); x = 0; while (--i >= 0) { prev = x; - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; if ((x >> PyLong_SHIFT) != prev) { goto overflow; } @@ -692,11 +817,12 @@ PyLong_AsSize_t(PyObject *vv) "can't convert negative value to size_t"); return (size_t) -1; } + assert(!_PyLong_IsCompact(v)); i = _PyLong_DigitCount(v); x = 0; while (--i >= 0) { prev = x; - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; if ((x >> PyLong_SHIFT) != prev) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C size_t"); @@ -728,7 +854,7 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) int sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; } return x * sign; } @@ -764,10 +890,10 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - if (_PyLong_IsCompact(v)) { - return _PyLong_CompactSign(v); + if (v->ob_digit[0] == 0) { + return 0; } - return _PyLong_NonCompactSign(v); + return (v->ob_digit[0] & PyLong_IS_NEGATIVE_MASK) ? -1 : 1; } static int @@ -791,9 +917,9 @@ _PyLong_NumBits(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); ndigits = _PyLong_DigitCount(v); - assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); + assert(_PyLong_IsCompact(v) || v->ob_digit[ndigits - 1 + PyLong_LONG_HEADER_DIGITS] != 0); if (ndigits > 0) { - digit msd = v->long_value.ob_digit[ndigits - 1]; + digit msd = get_digit(v, ndigits - 1); if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT) goto Overflow; result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; @@ -902,7 +1028,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, if (accumbits >= PyLong_SHIFT) { /* There's enough to fill a Python digit. */ assert(idigit < ndigits); - v->long_value.ob_digit[idigit] = (digit)(accum & PyLong_MASK); + set_digit(v, idigit, (digit)(accum & PyLong_MASK)); ++idigit; accum >>= PyLong_SHIFT; accumbits -= PyLong_SHIFT; @@ -912,7 +1038,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, assert(accumbits < PyLong_SHIFT); if (accumbits) { assert(idigit < ndigits); - v->long_value.ob_digit[idigit] = (digit)accum; + set_digit(v, idigit, (digit)accum); ++idigit; } } @@ -968,13 +1094,14 @@ _PyLong_AsByteArray(PyLongObject* v, It's crucial that every Python digit except for the MSD contribute exactly PyLong_SHIFT bits to the total, so first assert that the int is normalized. */ - assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); + assert(_PyLong_IsCompact(v) || v->ob_digit[ndigits - 1 + PyLong_LONG_HEADER_DIGITS] != 0); j = 0; accum = 0; accumbits = 0; carry = do_twos_comp ? 1 : 0; for (i = 0; i < ndigits; ++i) { - digit thisdigit = v->long_value.ob_digit[i]; + // MGDTODO: Efficiency -- avoid repeatedly calling get_digit (also, maybe an abstraction to get digit) + digit thisdigit = get_digit(v, i); if (do_twos_comp) { thisdigit = (thisdigit ^ PyLong_MASK) + carry; carry = thisdigit >> PyLong_SHIFT; @@ -1145,7 +1272,8 @@ PyLong_FromLongLong(long long ival) /* Construct output value. */ v = _PyLong_New(ndigits); if (v != NULL) { - digit *p = v->long_value.ob_digit; + assert(!_PyLong_IsCompact(v)); + digit *p = v->ob_digit + PyLong_LONG_HEADER_DIGITS; _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { @@ -1170,7 +1298,9 @@ PyLong_FromSsize_t(Py_ssize_t ival) if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } - + if (is_medium_int(ival)) { + return _PyLong_FromMedium((sdigit)ival); + } if (ival < 0) { /* avoid signed overflow when ival = SIZE_T_MIN */ abs_ival = (size_t)(-1-ival)+1; @@ -1188,7 +1318,8 @@ PyLong_FromSsize_t(Py_ssize_t ival) } v = _PyLong_New(ndigits); if (v != NULL) { - digit *p = v->long_value.ob_digit; + assert(!_PyLong_IsCompact(v)); + digit *p = v->ob_digit + PyLong_LONG_HEADER_DIGITS; _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); t = abs_ival; while (t) { @@ -1303,7 +1434,7 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) sign = _PyLong_NonCompactSign(v); x = 0; while (--i >= 0) { - x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) | v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; } return x * sign; } @@ -1377,7 +1508,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) x = 0; while (--i >= 0) { prev = x; - x = (x << PyLong_SHIFT) + v->long_value.ob_digit[i]; + x = (x << PyLong_SHIFT) + v->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; res = -1; @@ -1545,14 +1676,14 @@ v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) assert(m >= n); for (i = 0; i < n; ++i) { - borrow = x[i] - y[i] - borrow; - x[i] = borrow & PyLong_MASK; + borrow = extract_digit(x + i) - extract_digit(y + i) - borrow; + store_digit(x + i, borrow); borrow >>= PyLong_SHIFT; borrow &= 1; /* keep only 1 sign bit */ } for (; borrow && i < m; ++i) { - borrow = x[i] - borrow; - x[i] = borrow & PyLong_MASK; + borrow = extract_digit(x + i) - borrow; + store_digit(x + i, borrow); borrow >>= PyLong_SHIFT; borrow &= 1; } @@ -1570,8 +1701,8 @@ v_lshift(digit *z, digit *a, Py_ssize_t m, int d) assert(0 <= d && d < PyLong_SHIFT); for (i=0; i < m; i++) { - twodigits acc = (twodigits)a[i] << d | carry; - z[i] = (digit)acc & PyLong_MASK; + twodigits acc = (twodigits)extract_digit(a + i) << d | carry; + store_digit(z + i, (digit)acc); carry = (digit)(acc >> PyLong_SHIFT); } return carry; @@ -1589,9 +1720,9 @@ v_rshift(digit *z, digit *a, Py_ssize_t m, int d) assert(0 <= d && d < PyLong_SHIFT); for (i=m; i-- > 0;) { - twodigits acc = (twodigits)carry << PyLong_SHIFT | a[i]; + twodigits acc = (twodigits)carry << PyLong_SHIFT | extract_digit(a + i); carry = (digit)acc & mask; - z[i] = (digit)(acc >> d); + store_digit(z + i, (digit)(acc >> d)); } return carry; } @@ -1625,11 +1756,11 @@ inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) assert(n > 0 && n <= PyLong_MASK); while (--size >= 0) { twodigits dividend; - dividend = ((twodigits)remainder << PyLong_SHIFT) | pin[size]; + dividend = ((twodigits)remainder << PyLong_SHIFT) | (pin[size] & PyLong_MASK); digit quotient; quotient = (digit)(dividend / n); remainder = dividend % n; - pout[size] = quotient; + store_digit(pout + size, quotient); } return remainder; } @@ -1649,7 +1780,7 @@ divrem1(PyLongObject *a, digit n, digit *prem) z = _PyLong_New(size); if (z == NULL) return NULL; - *prem = inplace_divrem1(z->long_value.ob_digit, a->long_value.ob_digit, size, n); + *prem = inplace_divrem1(get_digit_offset(z), get_digit_offset(a), size, n); return long_normalize(z); } @@ -1663,7 +1794,7 @@ inplace_rem1(digit *pin, Py_ssize_t size, digit n) assert(n > 0 && n <= PyLong_MASK); while (--size >= 0) - rem = ((rem << PyLong_SHIFT) | pin[size]) % n; + rem = ((rem << PyLong_SHIFT) | extract_digit(pin + size)) % n; return (digit)rem; } @@ -1678,7 +1809,7 @@ rem1(PyLongObject *a, digit n) assert(n > 0 && n <= PyLong_MASK); return (PyLongObject *)PyLong_FromLong( - (long)inplace_rem1(a->long_value.ob_digit, size, n) + (long)inplace_rem1(get_digit_offset(a), size, n) ); } @@ -1828,19 +1959,19 @@ long_to_decimal_string_internal(PyObject *aa, /* convert array of base _PyLong_BASE digits in pin to an array of base _PyLong_DECIMAL_BASE digits in pout, following Knuth (TAOCP, Volume 2 (3rd edn), section 4.4, Method 1b). */ - pin = a->long_value.ob_digit; - pout = scratch->long_value.ob_digit; + pin = get_digit_offset(a); + pout = get_digit_offset(scratch); size = 0; for (i = size_a; --i >= 0; ) { digit hi = pin[i]; for (j = 0; j < size; j++) { - twodigits z = (twodigits)pout[j] << PyLong_SHIFT | hi; + twodigits z = (twodigits)extract_digit(pout + j) << PyLong_SHIFT | hi; hi = (digit)(z / _PyLong_DECIMAL_BASE); - pout[j] = (digit)(z - (twodigits)hi * - _PyLong_DECIMAL_BASE); + store_digit(pout + j, (digit)(z - (twodigits)hi * _PyLong_DECIMAL_BASE)); } while (hi) { - pout[size++] = hi % _PyLong_DECIMAL_BASE; + + set_digit(scratch, size++, hi % _PyLong_DECIMAL_BASE); hi /= _PyLong_DECIMAL_BASE; } /* check for keyboard interrupt */ @@ -1852,12 +1983,12 @@ long_to_decimal_string_internal(PyObject *aa, /* pout should have at least one digit, so that the case when a = 0 works correctly */ if (size == 0) - pout[size++] = 0; + store_digit(pout + size++, 0); /* calculate exact length of output string, and allocate */ strlen = negative + 1 + (size - 1) * _PyLong_DECIMAL_SHIFT; tenpow = 10; - rem = pout[size-1]; + rem = extract_digit(pout + size - 1); while (rem >= tenpow) { tenpow *= 10; strlen++; @@ -1901,14 +2032,14 @@ long_to_decimal_string_internal(PyObject *aa, /* pout[0] through pout[size-2] contribute exactly \ _PyLong_DECIMAL_SHIFT digits each */ \ for (i=0; i < size - 1; i++) { \ - rem = pout[i]; \ + rem = extract_digit(pout + i); \ for (j = 0; j < _PyLong_DECIMAL_SHIFT; j++) { \ *--p = '0' + rem % 10; \ rem /= 10; \ } \ } \ /* pout[size-1]: always produce at least one decimal digit */ \ - rem = pout[i]; \ + rem = extract_digit(pout + i); \ do { \ *--p = '0' + rem % 10; \ rem /= 10; \ @@ -2034,7 +2165,7 @@ long_format_binary(PyObject *aa, int base, int alternate, return -1; } size_a_in_bits = (size_a - 1) * PyLong_SHIFT + - bit_length_digit(a->long_value.ob_digit[size_a - 1]); + bit_length_digit(get_digit(a, size_a - 1)); /* Allow 1 character for a '-' sign. */ sz = negative + (size_a_in_bits + (bits - 1)) / bits; } @@ -2070,8 +2201,9 @@ long_format_binary(PyObject *aa, int base, int alternate, twodigits accum = 0; \ int accumbits = 0; /* # of bits in accum */ \ Py_ssize_t i; \ + digit *ap = get_digit_offset(a); \ for (i = 0; i < size_a; ++i) { \ - accum |= (twodigits)a->long_value.ob_digit[i] << accumbits; \ + accum |= (twodigits)extract_digit(ap++) << accumbits; \ accumbits += PyLong_SHIFT; \ assert(accumbits >= bits); \ do { \ @@ -2242,7 +2374,7 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int PyLongObject *z; twodigits accum; int bits_in_accum; - digit *pdigit; + digit *pdigit, *offset; assert(base >= 2 && base <= 32 && (base & (base - 1)) == 0); n = base; @@ -2269,7 +2401,7 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int */ accum = 0; bits_in_accum = 0; - pdigit = z->long_value.ob_digit; + pdigit = offset = get_digit_offset(z); p = end; while (--p >= start) { int k; @@ -2281,8 +2413,8 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int accum |= (twodigits)k << bits_in_accum; bits_in_accum += bits_per_char; if (bits_in_accum >= PyLong_SHIFT) { - *pdigit++ = (digit)(accum & PyLong_MASK); - assert(pdigit - z->long_value.ob_digit <= n); + store_digit(pdigit++, (digit)accum); + assert(pdigit - get_digit_offset(z) <= n); accum >>= PyLong_SHIFT; bits_in_accum -= PyLong_SHIFT; assert(bits_in_accum < PyLong_SHIFT); @@ -2290,11 +2422,11 @@ long_from_binary_base(const char *start, const char *end, Py_ssize_t digits, int } if (bits_in_accum) { assert(bits_in_accum <= PyLong_SHIFT); - *pdigit++ = (digit)accum; - assert(pdigit - z->long_value.ob_digit <= n); + store_digit(pdigit++, (digit)accum); + assert(pdigit - get_digit_offset(z) <= n); } - while (pdigit - z->long_value.ob_digit < n) - *pdigit++ = 0; + while (pdigit - offset < n) + store_digit(pdigit++, 0); *res = z; return 0; } @@ -2475,7 +2607,8 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* Uncomment next line to test exceedingly rare copy code */ /* size_z = 1; */ assert(size_z > 0); - z = _PyLong_New(size_z); + /* Always be sure to allocate a "long" */ + z = _PyLong_New(size_z < 2 ? 2 : size_z); if (z == NULL) { *res = NULL; return 0; @@ -2519,18 +2652,18 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, } /* Multiply z by convmult, and add c. */ - pz = z->long_value.ob_digit; + pz = get_digit_offset(z); pzstop = pz + _PyLong_DigitCount(z); for (; pz < pzstop; ++pz) { - c += (twodigits)*pz * convmult; - *pz = (digit)(c & PyLong_MASK); + c += (twodigits)extract_digit(pz) * convmult; + store_digit(pz, c); c >>= PyLong_SHIFT; } /* carry off the current end? */ if (c) { assert(c < PyLong_BASE); if (_PyLong_DigitCount(z) < size_z) { - *pz = (digit)c; + store_digit(pz, (digit)c); assert(!_PyLong_IsNegative(z)); _PyLong_SetSignAndDigitCount(z, 1, _PyLong_DigitCount(z) + 1); } @@ -2539,16 +2672,16 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* Extremely rare. Get more space. */ assert(_PyLong_DigitCount(z) == size_z); tmp = _PyLong_New(size_z + 1); + assert(!_PyLong_IsCompact(tmp)); + assert(!_PyLong_IsCompact(z)); if (tmp == NULL) { Py_DECREF(z); *res = NULL; return 0; } - memcpy(tmp->long_value.ob_digit, - z->long_value.ob_digit, - sizeof(digit) * size_z); + copy_digits(tmp, 0, z, 0, size_z); Py_SETREF(z, tmp); - z->long_value.ob_digit[size_z] = (digit)c; + set_digit(z, size_z, (digit)c); ++size_z; } } @@ -2850,7 +2983,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, } if (size_a < size_b || (size_a == size_b && - a->long_value.ob_digit[size_a-1] < b->long_value.ob_digit[size_b-1])) { + get_digit(a, size_a - 1) < get_digit(b, size_b - 1))) { /* |a| < |b|. */ *prem = (PyLongObject *)long_long((PyObject *)a); if (*prem == NULL) { @@ -2861,7 +2994,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, } if (size_b == 1) { digit rem = 0; - z = divrem1(a, b->long_value.ob_digit[0], &rem); + z = divrem1(a, get_digit(b, 0), &rem); if (z == NULL) return -1; *prem = (PyLongObject *) PyLong_FromLong((long)rem); @@ -2913,13 +3046,13 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) } if (size_a < size_b || (size_a == size_b && - a->long_value.ob_digit[size_a-1] < b->long_value.ob_digit[size_b-1])) { + get_digit(a, size_a - 1) < get_digit(b, size_b - 1))) { /* |a| < |b|. */ *prem = (PyLongObject *)long_long((PyObject *)a); return -(*prem == NULL); } if (size_b == 1) { - *prem = rem1(a, b->long_value.ob_digit[0]); + *prem = rem1(a, get_digit(b, 0)); if (*prem == NULL) return -1; } @@ -2979,12 +3112,12 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) /* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2. shift v1 left by the same amount. Results go into w and v. */ - d = PyLong_SHIFT - bit_length_digit(w1->long_value.ob_digit[size_w-1]); - carry = v_lshift(w->long_value.ob_digit, w1->long_value.ob_digit, size_w, d); + d = PyLong_SHIFT - bit_length_digit(get_digit(w1, size_w-1)); + carry = v_lshift(get_digit_offset(w), get_digit_offset(w1), size_w, d); assert(carry == 0); - carry = v_lshift(v->long_value.ob_digit, v1->long_value.ob_digit, size_v, d); - if (carry != 0 || v->long_value.ob_digit[size_v-1] >= w->long_value.ob_digit[size_w-1]) { - v->long_value.ob_digit[size_v] = carry; + carry = v_lshift(get_digit_offset(v), get_digit_offset(v1), size_v, d); + if (carry != 0 || get_digit_offset(v)[size_v-1] >= get_digit_offset(w)[size_w-1]) { + set_digit(v, size_v, carry); size_v++; } @@ -2999,12 +3132,12 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) *prem = NULL; return NULL; } - v0 = v->long_value.ob_digit; - w0 = w->long_value.ob_digit; + v0 = get_digit_offset(v); + w0 = get_digit_offset(w); wm1 = w0[size_w-1]; wm2 = w0[size_w-2]; - for (vk = v0+k, ak = a->long_value.ob_digit + k; vk-- > v0;) { - /* inner loop: divide vk[0:size_w+1] by w0[0:size_w], giving + for (vk = v0+k, ak = get_digit_offset(a) + k; vk-- > v0;) { + /* inner loop: divide vk[0:size_w+1] by w0[0:size_w], giving single-digit quotient q, remainder in vk[0:size_w]. */ SIGCHECK({ @@ -3018,7 +3151,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) /* estimate quotient digit q; may overestimate by 1 (rare) */ vtop = vk[size_w]; assert(vtop <= wm1); - vv = ((twodigits)vtop << PyLong_SHIFT) | vk[size_w-1]; + vv = ((twodigits)vtop << PyLong_SHIFT) | extract_digit(vk + size_w-1); /* The code used to compute the remainder via * r = (digit)(vv - (twodigits)wm1 * q); * and compilers generally generated code to do the * and -. @@ -3029,7 +3162,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) q = (digit)(vv / wm1); r = (digit)(vv % wm1); while ((twodigits)wm2 * q > (((twodigits)r << PyLong_SHIFT) - | vk[size_w-2])) { + | extract_digit(vk + size_w-2))) { --q; r += wm1; if (r >= PyLong_BASE) @@ -3042,9 +3175,9 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) for (i = 0; i < size_w; ++i) { /* invariants: -PyLong_BASE <= -q <= zhi <= 0; -PyLong_BASE * q <= z < PyLong_BASE */ - z = (sdigit)vk[i] + zhi - + z = (sdigit)extract_digit(vk + i) + zhi - (stwodigits)q * (stwodigits)w0[i]; - vk[i] = (digit)z & PyLong_MASK; + store_digit(vk + i, (digit)z); zhi = (sdigit)Py_ARITHMETIC_RIGHT_SHIFT(stwodigits, z, PyLong_SHIFT); } @@ -3054,8 +3187,8 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) if ((sdigit)vtop + zhi < 0) { carry = 0; for (i = 0; i < size_w; ++i) { - carry += vk[i] + w0[i]; - vk[i] = carry & PyLong_MASK; + carry += extract_digit(vk + i) + extract_digit(w0 + i); + store_digit(vk + i, carry); carry >>= PyLong_SHIFT; } --q; @@ -3063,7 +3196,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) /* store quotient digit */ assert(q < PyLong_BASE); - *--ak = q; + store_digit(--ak, q); } /* unshift remainder; we reuse w to store the result */ @@ -3108,7 +3241,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) *e = 0; return 0.0; } - a_bits = bit_length_digit(a->long_value.ob_digit[a_size-1]); + a_bits = bit_length_digit(get_digit(a, a_size - 1)); /* The following is an overflow-free version of the check "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */ if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 && @@ -3146,7 +3279,8 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) shift_digits = (DBL_MANT_DIG + 2 - a_bits) / PyLong_SHIFT; shift_bits = (DBL_MANT_DIG + 2 - a_bits) % PyLong_SHIFT; x_size = shift_digits; - rem = v_lshift(x_digits + x_size, a->long_value.ob_digit, a_size, + assert(!_PyLong_IsCompact(a)); + rem = v_lshift(x_digits + x_size, get_digit_offset(a), a_size, (int)shift_bits); x_size += a_size; x_digits[x_size++] = rem; @@ -3154,7 +3288,8 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) else { shift_digits = (a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT; shift_bits = (a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT; - rem = v_rshift(x_digits, a->long_value.ob_digit + shift_digits, + assert(!_PyLong_IsCompact(a)); + rem = v_rshift(x_digits, get_digit_offset(a) + shift_digits, a_size - shift_digits, (int)shift_bits); x_size = a_size - shift_digits; /* For correct rounding below, we need the least significant @@ -3164,8 +3299,9 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) if (rem) x_digits[0] |= 1; else + // MGDTODO: Optimize loop while (shift_digits > 0) - if (a->long_value.ob_digit[--shift_digits]) { + if (get_digit(a, --shift_digits)) { x_digits[0] |= 1; break; } @@ -3247,8 +3383,9 @@ long_compare(PyLongObject *a, PyLongObject *b) if (sign == 0) { Py_ssize_t i = _PyLong_DigitCount(a); sdigit diff = 0; + // MGDTODO: Optimize loop while (--i >= 0) { - diff = (sdigit) a->long_value.ob_digit[i] - (sdigit) b->long_value.ob_digit[i]; + diff = (sdigit) get_digit(a, i) - (sdigit) get_digit(b, i); if (diff) { break; } @@ -3336,7 +3473,8 @@ long_hash(PyLongObject *v) _PyHASH_MODULUS. */ x = ((x << PyLong_SHIFT) & _PyHASH_MODULUS) | (x >> (_PyHASH_BITS - PyLong_SHIFT)); - x += v->long_value.ob_digit[i]; + // MGDTODO: Optimize loop + x += get_digit(v, i); if (x >= _PyHASH_MODULUS) x -= _PyHASH_MODULUS; } @@ -3368,16 +3506,16 @@ x_add(PyLongObject *a, PyLongObject *b) if (z == NULL) return NULL; for (i = 0; i < size_b; ++i) { - carry += a->long_value.ob_digit[i] + b->long_value.ob_digit[i]; - z->long_value.ob_digit[i] = carry & PyLong_MASK; + carry += get_digit(a, i) + get_digit(b, i); + set_digit(z, i, carry); carry >>= PyLong_SHIFT; } for (; i < size_a; ++i) { - carry += a->long_value.ob_digit[i]; - z->long_value.ob_digit[i] = carry & PyLong_MASK; + carry += get_digit(a, i); + set_digit(z, i, carry); carry >>= PyLong_SHIFT; } - z->long_value.ob_digit[i] = carry; + set_digit(z, i, carry); return long_normalize(z); } @@ -3403,11 +3541,12 @@ x_sub(PyLongObject *a, PyLongObject *b) else if (size_a == size_b) { /* Find highest digit where a and b differ: */ i = size_a; - while (--i >= 0 && a->long_value.ob_digit[i] == b->long_value.ob_digit[i]) + // MGDTODO: Optimize loop + while (--i >= 0 && get_digit(a, i) == get_digit(b, i)) ; if (i < 0) return (PyLongObject *)PyLong_FromLong(0); - if (a->long_value.ob_digit[i] < b->long_value.ob_digit[i]) { + if (get_digit(a, i) < get_digit(b, i)) { sign = -1; { PyLongObject *temp = a; a = b; b = temp; } } @@ -3416,17 +3555,18 @@ x_sub(PyLongObject *a, PyLongObject *b) z = _PyLong_New(size_a); if (z == NULL) return NULL; + // MGDTODO: Optimize loop for (i = 0; i < size_b; ++i) { /* The following assumes unsigned arithmetic works module 2**N for some N>PyLong_SHIFT. */ - borrow = a->long_value.ob_digit[i] - b->long_value.ob_digit[i] - borrow; - z->long_value.ob_digit[i] = borrow & PyLong_MASK; + borrow = get_digit(a, i) - get_digit(b, i) - borrow; + set_digit(z, i, borrow); borrow >>= PyLong_SHIFT; borrow &= 1; /* Keep only one sign bit */ } for (; i < size_a; ++i) { - borrow = a->long_value.ob_digit[i] - borrow; - z->long_value.ob_digit[i] = borrow & PyLong_MASK; + borrow = get_digit(a, i) - borrow; + set_digit(z, i, borrow); borrow >>= PyLong_SHIFT; borrow &= 1; /* Keep only one sign bit */ } @@ -3521,13 +3661,14 @@ x_mul(PyLongObject *a, PyLongObject *b) PyLongObject *z; Py_ssize_t size_a = _PyLong_DigitCount(a); Py_ssize_t size_b = _PyLong_DigitCount(b); - Py_ssize_t i; + Py_ssize_t i, j; z = _PyLong_New(size_a + size_b); if (z == NULL) return NULL; + assert(!_PyLong_IsCompact(z)); - memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); + memset(z->ob_digit + PyLong_LONG_HEADER_DIGITS, 0, _PyLong_DigitCount(z) * sizeof(digit)); if (a == b) { /* Efficient squaring per HAC, Algorithm 14.16: * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf @@ -3535,12 +3676,13 @@ x_mul(PyLongObject *a, PyLongObject *b) * via exploiting that each entry in the multiplication * pyramid appears twice (except for the size_a squares). */ - digit *paend = a->long_value.ob_digit + size_a; + assert(!_PyLong_IsCompact(a)); + digit *paend = a->ob_digit + size_a + PyLong_LONG_HEADER_DIGITS; for (i = 0; i < size_a; ++i) { twodigits carry; - twodigits f = a->long_value.ob_digit[i]; - digit *pz = z->long_value.ob_digit + (i << 1); - digit *pa = a->long_value.ob_digit + i + 1; + twodigits f = a->ob_digit[i + PyLong_LONG_HEADER_DIGITS]; + digit *pz = z->ob_digit + (i << 1) + PyLong_LONG_HEADER_DIGITS; + digit *pa = a->ob_digit + i + 1 + PyLong_LONG_HEADER_DIGITS; SIGCHECK({ Py_DECREF(z); @@ -3589,24 +3731,22 @@ x_mul(PyLongObject *a, PyLongObject *b) else { /* a is not the same as b -- gradeschool int mult */ for (i = 0; i < size_a; ++i) { twodigits carry = 0; - twodigits f = a->long_value.ob_digit[i]; - digit *pz = z->long_value.ob_digit + i; - digit *pb = b->long_value.ob_digit; - digit *pbend = b->long_value.ob_digit + size_b; + twodigits f = get_digit(a, i); SIGCHECK({ Py_DECREF(z); return NULL; }); - while (pb < pbend) { - carry += *pz + *pb++ * f; - *pz++ = (digit)(carry & PyLong_MASK); + // MGDTODO: Optimize loop + for (j = 0; j < size_b; ++j) { + carry += get_digit(z, i + j) + get_digit(b, j) * f; + set_digit(z, i + j, (digit)carry); carry >>= PyLong_SHIFT; assert(carry <= PyLong_MASK); } if (carry) - *pz += (digit)(carry & PyLong_MASK); + set_digit(z, i+j, (digit)carry); assert((carry >> PyLong_SHIFT) == 0); } } @@ -3640,8 +3780,8 @@ kmul_split(PyLongObject *n, return -1; } - memcpy(lo->long_value.ob_digit, n->long_value.ob_digit, size_lo * sizeof(digit)); - memcpy(hi->long_value.ob_digit, n->long_value.ob_digit + size_lo, size_hi * sizeof(digit)); + copy_digits(lo, 0, n, 0, size_lo); + copy_digits(hi, 0, n, size_lo, size_hi); *high = long_normalize(hi); *low = long_normalize(lo); @@ -3737,22 +3877,24 @@ k_mul(PyLongObject *a, PyLongObject *b) /* 1. Allocate result space. */ ret = _PyLong_New(asize + bsize); if (ret == NULL) goto fail; + assert(!_PyLong_IsCompact(ret)); #ifdef Py_DEBUG /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit)); + memset(ret->ob_digit + PyLong_LONG_HEADER_DIGITS, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit)); #endif /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; + assert(!_PyLong_IsCompact(t1)); assert(!_PyLong_IsNegative(t1)); assert(2*shift + _PyLong_DigitCount(t1) <= _PyLong_DigitCount(ret)); - memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, + memcpy(ret->ob_digit + 2*shift + PyLong_LONG_HEADER_DIGITS, t1->ob_digit + PyLong_LONG_HEADER_DIGITS, _PyLong_DigitCount(t1) * sizeof(digit)); /* Zero-out the digits higher than the ah*bh copy. */ i = _PyLong_DigitCount(ret) - 2*shift - _PyLong_DigitCount(t1); if (i) - memset(ret->long_value.ob_digit + 2*shift + _PyLong_DigitCount(t1), 0, + memset(ret->ob_digit + 2*shift + _PyLong_DigitCount(t1) + PyLong_LONG_HEADER_DIGITS, 0, i * sizeof(digit)); /* 3. t2 <- al*bl, and copy into the low digits. */ @@ -3762,21 +3904,21 @@ k_mul(PyLongObject *a, PyLongObject *b) } assert(!_PyLong_IsNegative(t2)); assert(_PyLong_DigitCount(t2) <= 2*shift); /* no overlap with high digits */ - memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_DigitCount(t2) * sizeof(digit)); + copy_digits(ret, 0, t2, 0, _PyLong_DigitCount(t2)); /* Zero out remaining digits. */ i = 2*shift - _PyLong_DigitCount(t2); /* number of uninitialized digits */ if (i) - memset(ret->long_value.ob_digit + _PyLong_DigitCount(t2), 0, i * sizeof(digit)); + memset(ret->ob_digit + _PyLong_DigitCount(t2) + PyLong_LONG_HEADER_DIGITS, 0, i * sizeof(digit)); /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first * because it's fresher in cache. */ i = _PyLong_DigitCount(ret) - shift; /* # digits after shift */ - (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_DigitCount(t2)); + v_isub(get_digit_offset(ret) + shift, i, get_digit_offset(t2), _PyLong_DigitCount(t2)); _Py_DECREF_INT(t2); - (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_DigitCount(t1)); + (void)v_isub(get_digit_offset(ret) + shift, i, get_digit_offset(t1), _PyLong_DigitCount(t1)); _Py_DECREF_INT(t1); /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ @@ -3801,11 +3943,11 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; assert(!_PyLong_IsNegative(t3)); - + assert(!_PyLong_IsCompact(t3)); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function. */ - (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_DigitCount(t3)); + (void)v_iadd(get_digit_offset(ret) + shift, i, get_digit_offset(t3), _PyLong_DigitCount(t3)); _Py_DECREF_INT(t3); return long_normalize(ret); @@ -3881,6 +4023,9 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) PyLongObject *ret; PyLongObject *bslice = NULL; + assert(!_PyLong_IsCompact(a)); + assert(!_PyLong_IsCompact(b)); + assert(asize > KARATSUBA_CUTOFF); assert(2 * asize <= bsize); @@ -3888,12 +4033,14 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) ret = _PyLong_New(asize + bsize); if (ret == NULL) return NULL; - memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); + assert(!_PyLong_IsCompact(ret)); + memset(ret->ob_digit + PyLong_LONG_HEADER_DIGITS, 0, _PyLong_DigitCount(ret) * sizeof(digit)); /* Successive slices of b are copied into bslice. */ bslice = _PyLong_New(asize); if (bslice == NULL) goto fail; + assert(!_PyLong_IsCompact(bslice)); nbdone = 0; while (bsize > 0) { @@ -3901,7 +4048,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) const Py_ssize_t nbtouse = Py_MIN(bsize, asize); /* Multiply the next slice of b by a. */ - memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, + memcpy(bslice->ob_digit + PyLong_LONG_HEADER_DIGITS, b->ob_digit + nbdone + PyLong_LONG_HEADER_DIGITS, nbtouse * sizeof(digit)); assert(nbtouse >= 0); _PyLong_SetSignAndDigitCount(bslice, 1, nbtouse); @@ -3909,9 +4056,10 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) if (product == NULL) goto fail; + assert(!_PyLong_IsCompact(product)); /* Add into result. */ - (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_DigitCount(ret) - nbdone, - product->long_value.ob_digit, _PyLong_DigitCount(product)); + (void)v_iadd(ret->ob_digit + nbdone + PyLong_LONG_HEADER_DIGITS, _PyLong_DigitCount(ret) - nbdone, + product->ob_digit + PyLong_LONG_HEADER_DIGITS, _PyLong_DigitCount(product)); _Py_DECREF_INT(product); bsize -= nbtouse; @@ -3959,8 +4107,8 @@ long_mul(PyLongObject *a, PyLongObject *b) static PyObject * fast_mod(PyLongObject *a, PyLongObject *b) { - sdigit left = a->long_value.ob_digit[0]; - sdigit right = b->long_value.ob_digit[0]; + sdigit left = get_digit(a, 0); + sdigit right = get_digit(b, 0); sdigit mod; assert(_PyLong_DigitCount(a) == 1); @@ -3981,8 +4129,8 @@ fast_mod(PyLongObject *a, PyLongObject *b) static PyObject * fast_floor_div(PyLongObject *a, PyLongObject *b) { - sdigit left = a->long_value.ob_digit[0]; - sdigit right = b->long_value.ob_digit[0]; + sdigit left = get_digit(a, 0); + sdigit right = get_digit(b, 0); sdigit div; assert(_PyLong_DigitCount(a) == 1); @@ -4303,18 +4451,20 @@ long_true_divide(PyObject *v, PyObject *w) the x87 FPU set to 64-bit precision. */ a_is_small = a_size <= MANT_DIG_DIGITS || (a_size == MANT_DIG_DIGITS+1 && - a->long_value.ob_digit[MANT_DIG_DIGITS] >> MANT_DIG_BITS == 0); + a->ob_digit[MANT_DIG_DIGITS + PyLong_LONG_HEADER_DIGITS] >> MANT_DIG_BITS == 0); b_is_small = b_size <= MANT_DIG_DIGITS || (b_size == MANT_DIG_DIGITS+1 && - b->long_value.ob_digit[MANT_DIG_DIGITS] >> MANT_DIG_BITS == 0); + b->ob_digit[MANT_DIG_DIGITS + PyLong_LONG_HEADER_DIGITS] >> MANT_DIG_BITS == 0); if (a_is_small && b_is_small) { double da, db; - da = a->long_value.ob_digit[--a_size]; + da = get_digit(a, --a_size); + // MGDTODO: Optimize loop while (a_size > 0) - da = da * PyLong_BASE + a->long_value.ob_digit[--a_size]; - db = b->long_value.ob_digit[--b_size]; + da = da * PyLong_BASE + get_digit(a, --a_size); + db = get_digit(b, --b_size); + // MGDTODO: Optimize loop while (b_size > 0) - db = db * PyLong_BASE + b->long_value.ob_digit[--b_size]; + db = db * PyLong_BASE + get_digit(b, --b_size); result = da / db; goto success; } @@ -4328,8 +4478,8 @@ long_true_divide(PyObject *v, PyObject *w) /* Extreme underflow */ goto underflow_or_zero; /* Next line is now safe from overflowing a Py_ssize_t */ - diff = diff * PyLong_SHIFT + bit_length_digit(a->long_value.ob_digit[a_size - 1]) - - bit_length_digit(b->long_value.ob_digit[b_size - 1]); + diff = diff * PyLong_SHIFT + bit_length_digit(get_digit(a, a_size - 1)) - + bit_length_digit(get_digit(b, b_size - 1)); /* Now diff = a_bits - b_bits. */ if (diff > DBL_MAX_EXP) goto overflow; @@ -4357,11 +4507,12 @@ long_true_divide(PyObject *v, PyObject *w) x = _PyLong_New(a_size + shift_digits + 1); if (x == NULL) goto error; + // MGDTODO: Optimize loop for (i = 0; i < shift_digits; i++) - x->long_value.ob_digit[i] = 0; - rem = v_lshift(x->long_value.ob_digit + shift_digits, a->long_value.ob_digit, + set_digit(x, i, 0); + rem = v_lshift(get_digit_offset(x) + shift_digits, get_digit_offset(a), a_size, -shift % PyLong_SHIFT); - x->long_value.ob_digit[a_size + shift_digits] = rem; + set_digit(x, a_size + shift_digits, rem); } else { Py_ssize_t shift_digits = shift / PyLong_SHIFT; @@ -4371,13 +4522,15 @@ long_true_divide(PyObject *v, PyObject *w) x = _PyLong_New(a_size - shift_digits); if (x == NULL) goto error; - rem = v_rshift(x->long_value.ob_digit, a->long_value.ob_digit + shift_digits, + assert(!_PyLong_IsCompact(x)); + assert(!_PyLong_IsCompact(a)); + rem = v_rshift(get_digit_offset(x), get_digit_offset(a) + shift_digits, a_size - shift_digits, shift % PyLong_SHIFT); /* set inexact if any of the bits shifted out is nonzero */ if (rem) inexact = 1; while (!inexact && shift_digits > 0) - if (a->long_value.ob_digit[--shift_digits]) + if (a->ob_digit[--shift_digits + PyLong_LONG_HEADER_DIGITS]) inexact = 1; } long_normalize(x); @@ -4386,8 +4539,9 @@ long_true_divide(PyObject *v, PyObject *w) /* x //= b. If the remainder is nonzero, set inexact. We own the only reference to x, so it's safe to modify it in-place. */ if (b_size == 1) { - digit rem = inplace_divrem1(x->long_value.ob_digit, x->long_value.ob_digit, x_size, - b->long_value.ob_digit[0]); + assert(!_PyLong_IsCompact(x)); + digit rem = inplace_divrem1(get_digit_offset(x), get_digit_offset(x), x_size, + get_digit(b, 0)); long_normalize(x); if (rem) inexact = 1; @@ -4404,7 +4558,7 @@ long_true_divide(PyObject *v, PyObject *w) } x_size = _PyLong_DigitCount(x); assert(x_size > 0); /* result of division is never zero */ - x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->long_value.ob_digit[x_size-1]); + x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(get_digit(x, x_size - 1)); /* The number of extra bits that have to be rounded away. */ extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG; @@ -4412,15 +4566,15 @@ long_true_divide(PyObject *v, PyObject *w) /* Round by directly modifying the low digit of x. */ mask = (digit)1 << (extra_bits - 1); - low = x->long_value.ob_digit[0] | inexact; + low = get_digit(x, 0) | inexact; if ((low & mask) && (low & (3U*mask-1U))) low += mask; - x->long_value.ob_digit[0] = low & ~(2U*mask-1U); + set_digit(x, 0, low & ~(2U*mask-1U)); /* Convert x to a double dx; the conversion is exact. */ - dx = x->long_value.ob_digit[--x_size]; + dx = get_digit(x, --x_size); while (x_size > 0) - dx = dx * PyLong_BASE + x->long_value.ob_digit[--x_size]; + dx = dx * PyLong_BASE + get_digit(x, --x_size); Py_DECREF(x); /* Check whether ldexp result will overflow a double. */ @@ -4641,7 +4795,8 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if (_PyLong_IsNonNegativeCompact(c) && (c->long_value.ob_digit[0] == 1)) { + // MGDTODO: Add "IsOne" + if (c->ob_digit[0] == 1) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } @@ -4717,7 +4872,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) } while(0) i = _PyLong_SignedDigitCount(b); - digit bi = i ? b->long_value.ob_digit[i-1] : 0; + digit bi = i ? get_digit(b, i-1) : 0; digit bit; if (i <= 1 && bi <= 3) { /* aim for minimal overhead */ @@ -4763,7 +4918,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) if (--i < 0) { break; } - bi = b->long_value.ob_digit[i]; + bi = get_digit(b, i); bit = (digit)1 << (PyLong_SHIFT-1); } } @@ -4809,7 +4964,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) } while(0) for (i = _PyLong_SignedDigitCount(b) - 1; i >= 0; --i) { - const digit bi = b->long_value.ob_digit[i]; + const digit bi = get_digit(b, i); for (j = PyLong_SHIFT - 1; j >= 0; --j) { const int bit = (bi >> j) & 1; pending = (pending << 1) | bit; @@ -4980,7 +5135,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) } hishift = PyLong_SHIFT - remshift; - accum = a->long_value.ob_digit[wordshift]; + accum = get_digit(a, wordshift); if (a_negative) { /* For a positive integer a and nonnegative shift, we have: @@ -4993,23 +5148,23 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - _PyLong_SetSignAndDigitCount(z, -1, newsize); + _PyLong_SetSign(z, -1); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { - sticky |= a->long_value.ob_digit[j]; + sticky |= get_digit(a, j); } accum += (PyLong_MASK >> hishift) + (digit)(sticky != 0); } accum >>= remshift; for (Py_ssize_t i = 0, j = wordshift + 1; j < size_a; i++, j++) { - accum += (twodigits)a->long_value.ob_digit[j] << hishift; - z->long_value.ob_digit[i] = (digit)(accum & PyLong_MASK); + accum += (twodigits)get_digit(a, j) << hishift; + set_digit(z, i, (digit)(accum & PyLong_MASK)); accum >>= PyLong_SHIFT; } assert(accum <= PyLong_MASK); - z->long_value.ob_digit[newsize - 1] = (digit)accum; + set_digit(z, newsize - 1, (digit)accum); z = maybe_small_long(long_normalize(z)); return (PyObject *)z; @@ -5076,16 +5231,17 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) assert(Py_REFCNT(z) == 1); _PyLong_FlipSign(z); } + // MGDTODO: Optimize loop for (i = 0; i < wordshift; i++) - z->long_value.ob_digit[i] = 0; + set_digit(z, i, 0); accum = 0; for (j = 0; j < oldsize; i++, j++) { - accum |= (twodigits)a->long_value.ob_digit[j] << remshift; - z->long_value.ob_digit[i] = (digit)(accum & PyLong_MASK); + accum |= (twodigits)get_digit(a, j) << remshift; + set_digit(z, i, (digit)(accum & PyLong_MASK)); accum >>= PyLong_SHIFT; } if (remshift) - z->long_value.ob_digit[newsize-1] = (digit)accum; + set_digit(z, newsize-1, (digit)accum); else assert(!accum); z = long_normalize(z); @@ -5138,8 +5294,9 @@ v_complement(digit *z, digit *a, Py_ssize_t m) Py_ssize_t i; digit carry = 1; for (i = 0; i < m; ++i) { - carry += a[i] ^ PyLong_MASK; - z[i] = carry & PyLong_MASK; + // MGDTODO: Is this XOR still necessary? + carry += extract_digit(a + 1) ^ PyLong_MASK; + store_digit(z + i, carry); carry >>= PyLong_SHIFT; } assert(carry == 0); @@ -5168,7 +5325,7 @@ long_bitwise(PyLongObject *a, z = _PyLong_New(size_a); if (z == NULL) return NULL; - v_complement(z->long_value.ob_digit, a->long_value.ob_digit, size_a); + v_complement(get_digit_offset(z), get_digit_offset(a), size_a); a = z; } else @@ -5184,7 +5341,7 @@ long_bitwise(PyLongObject *a, Py_DECREF(a); return NULL; } - v_complement(z->long_value.ob_digit, b->long_value.ob_digit, size_b); + v_complement(get_digit_offset(z), get_digit_offset(b), size_b); b = z; } else @@ -5234,33 +5391,34 @@ long_bitwise(PyLongObject *a, switch(op) { case '&': for (i = 0; i < size_b; ++i) - z->long_value.ob_digit[i] = a->long_value.ob_digit[i] & b->long_value.ob_digit[i]; + set_digit(z, i, get_digit(a, i) & get_digit(b, i)); break; case '|': for (i = 0; i < size_b; ++i) - z->long_value.ob_digit[i] = a->long_value.ob_digit[i] | b->long_value.ob_digit[i]; + set_digit(z, i, get_digit(a, i) | get_digit(b, i)); break; case '^': for (i = 0; i < size_b; ++i) - z->long_value.ob_digit[i] = a->long_value.ob_digit[i] ^ b->long_value.ob_digit[i]; + set_digit(z, i, get_digit(a, i) ^ get_digit(b, i)); break; default: Py_UNREACHABLE(); } /* Copy any remaining digits of a, inverting if necessary. */ - if (op == '^' && negb) + if (op == '^' && negb) { for (; i < size_z; ++i) - z->long_value.ob_digit[i] = a->long_value.ob_digit[i] ^ PyLong_MASK; - else if (i < size_z) - memcpy(&z->long_value.ob_digit[i], &a->long_value.ob_digit[i], - (size_z-i)*sizeof(digit)); + set_digit(z, i, get_digit(a, i) ^ PyLong_MASK); + } + else if (i < size_z) { + copy_digits(z, i, a, i, size_z - i); + } /* Complement result if negative. */ if (negz) { _PyLong_FlipSign(z); - z->long_value.ob_digit[size_z] = PyLong_MASK; - v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); + set_digit(z, size_z, PyLong_MASK); + v_complement(get_digit_offset(z), get_digit_offset(z), size_z+1); } Py_DECREF(a); @@ -5353,7 +5511,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) alloc_b = _PyLong_DigitCount(b); /* reduce until a fits into 2 digits */ while ((size_a = _PyLong_DigitCount(a)) > 2) { - nbits = bit_length_digit(a->long_value.ob_digit[size_a-1]); + nbits = bit_length_digit(get_digit(a, size_a-1)); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ size_b = _PyLong_DigitCount(b); @@ -5370,13 +5528,13 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) Py_XDECREF(d); return (PyObject *)r; } - x = (((twodigits)a->long_value.ob_digit[size_a-1] << (2*PyLong_SHIFT-nbits)) | - ((twodigits)a->long_value.ob_digit[size_a-2] << (PyLong_SHIFT-nbits)) | - (a->long_value.ob_digit[size_a-3] >> nbits)); + x = (((twodigits)get_digit(a, size_a-1) << (2*PyLong_SHIFT-nbits)) | + ((twodigits)get_digit(a, size_a-2) << (PyLong_SHIFT-nbits)) | + (get_digit(a, size_a-3) >> nbits)); - y = ((size_b >= size_a - 2 ? b->long_value.ob_digit[size_a-3] >> nbits : 0) | - (size_b >= size_a - 1 ? (twodigits)b->long_value.ob_digit[size_a-2] << (PyLong_SHIFT-nbits) : 0) | - (size_b >= size_a ? (twodigits)b->long_value.ob_digit[size_a-1] << (2*PyLong_SHIFT-nbits) : 0)); + y = ((size_b >= size_a - 2 ? get_digit(b, size_a-3) >> nbits : 0) | + (size_b >= size_a - 1 ? (twodigits)get_digit(b, size_a-2) << (PyLong_SHIFT-nbits) : 0) | + (size_b >= size_a ? (twodigits)get_digit(b, size_a-1) << (2*PyLong_SHIFT-nbits) : 0)); /* inner loop of Lehmer's algorithm; A, B, C, D never grow larger than PyLong_MASK during the algorithm. */ @@ -5441,29 +5599,29 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) if (d == NULL) goto error; } - a_end = a->long_value.ob_digit + size_a; - b_end = b->long_value.ob_digit + size_b; + a_end = get_digit_offset(a) + size_a; + b_end = get_digit_offset(b) + size_b; /* compute new a and new b in parallel */ - a_digit = a->long_value.ob_digit; - b_digit = b->long_value.ob_digit; - c_digit = c->long_value.ob_digit; - d_digit = d->long_value.ob_digit; + a_digit = get_digit_offset(a); + b_digit = get_digit_offset(b); + c_digit = get_digit_offset(c); + d_digit = get_digit_offset(d); c_carry = 0; d_carry = 0; while (b_digit < b_end) { - c_carry += (A * *a_digit) - (B * *b_digit); - d_carry += (D * *b_digit++) - (C * *a_digit++); - *c_digit++ = (digit)(c_carry & PyLong_MASK); - *d_digit++ = (digit)(d_carry & PyLong_MASK); + c_carry += (A * extract_digit(a_digit)) - (B * extract_digit(b_digit)); + d_carry += (D * extract_digit(b_digit++)) - (C * extract_digit(a_digit++)); + store_digit(c_digit++, (digit)c_carry); + store_digit(d_digit++, (digit)d_carry); c_carry >>= PyLong_SHIFT; d_carry >>= PyLong_SHIFT; } while (a_digit < a_end) { - c_carry += A * *a_digit; - d_carry -= C * *a_digit++; - *c_digit++ = (digit)(c_carry & PyLong_MASK); - *d_digit++ = (digit)(d_carry & PyLong_MASK); + c_carry += A * extract_digit(a_digit); + d_carry -= C * extract_digit(a_digit++); + store_digit(c_digit++, (digit)c_carry); + store_digit(d_digit++, (digit)d_carry); c_carry >>= PyLong_SHIFT; d_carry >>= PyLong_SHIFT; } @@ -5598,7 +5756,7 @@ static PyObject * long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) { PyLongObject *tmp, *newobj; - Py_ssize_t i, n; + Py_ssize_t n; assert(PyType_IsSubtype(type, &PyLong_Type)); tmp = (PyLongObject *)long_new_impl(&PyLong_Type, x, obase); @@ -5617,9 +5775,10 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) return NULL; } assert(PyLong_Check(newobj)); - newobj->long_value.lv_tag = tmp->long_value.lv_tag; - for (i = 0; i < n; i++) { - newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; + if (_PyLong_IsCompact(tmp)) { + newobj->ob_digit[0] = tmp->ob_digit[0]; + } else { + memcpy(newobj->ob_digit, tmp->ob_digit, (n + PyLong_LONG_HEADER_DIGITS) * sizeof(digit)); } Py_DECREF(tmp); return (PyObject *)newobj; @@ -5731,7 +5890,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) cmp = long_compare((PyLongObject *)twice_rem, (PyLongObject *)b); Py_DECREF(twice_rem); - quo_is_odd = (quo->long_value.ob_digit[0] & 1) != 0; + quo_is_odd = (get_digit(quo, 0) & 1) != 0; if ((_PyLong_IsNegative((PyLongObject *)b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) @@ -5883,7 +6042,7 @@ int_bit_length_impl(PyObject *self) if (ndigits == 0) return PyLong_FromLong(0); - msd = ((PyLongObject *)self)->long_value.ob_digit[ndigits-1]; + msd = get_digit((PyLongObject *)self, ndigits-1); msd_bits = bit_length_digit(msd); if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) @@ -5955,8 +6114,9 @@ int_bit_count_impl(PyObject *self) from the first PY_SSIZE_T_MAX/PyLong_SHIFT digits can't overflow a Py_ssize_t. */ Py_ssize_t ndigits_fast = Py_MIN(ndigits, PY_SSIZE_T_MAX/PyLong_SHIFT); + // MGDTODO: Optimize loop for (Py_ssize_t i = 0; i < ndigits_fast; i++) { - bit_count += popcount_digit(z->long_value.ob_digit[i]); + bit_count += popcount_digit(get_digit(z, i)); } PyObject *result = PyLong_FromSsize_t(bit_count); @@ -5966,7 +6126,8 @@ int_bit_count_impl(PyObject *self) /* Use Python integers if bit_count would overflow. */ for (Py_ssize_t i = ndigits_fast; i < ndigits; i++) { - PyObject *x = PyLong_FromLong(popcount_digit(z->long_value.ob_digit[i])); + // MGDTODO: Optimize loop + PyObject *x = PyLong_FromLong(popcount_digit(get_digit(z, i))); if (x == NULL) { goto error; } @@ -6274,7 +6435,7 @@ static PyNumberMethods long_as_number = { PyTypeObject PyLong_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "int", /* tp_name */ - offsetof(PyLongObject, long_value.ob_digit), /* tp_basicsize */ + offsetof(PyLongObject, ob_digit) + sizeof(digit), /* tp_basicsize */ sizeof(digit), /* tp_itemsize */ long_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index aa00e04ad5e11b..b0bc319270262d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4767,6 +4767,10 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) OBJECT_STAT_INC_COND(type_cache_misses, !is_dunder_name(name)); OBJECT_STAT_INC_COND(type_cache_dunder_misses, is_dunder_name(name)); + if (PyErr_Occurred()) { + PyErr_Print(); + } + /* We may end up clearing live exceptions below, so make sure it's ours. */ assert(!PyErr_Occurred()); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2075c195df3d38..60369f31e6d637 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -599,7 +599,7 @@ dummy_func( // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list)); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); @@ -613,7 +613,7 @@ dummy_func( DEOPT_IF(!PyLong_CheckExact(sub)); DEOPT_IF(!PyUnicode_CheckExact(str)); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index); // Specialize for reading an ASCII character from any string: Py_UCS4 c = PyUnicode_READ_CHAR(str, index); @@ -630,7 +630,7 @@ dummy_func( // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple)); STAT_INC(BINARY_SUBSCR, hit); res = PyTuple_GET_ITEM(tuple, index); @@ -718,7 +718,7 @@ dummy_func( // Ensure nonnegative, zero-or-one-digit ints. DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list)); STAT_INC(STORE_SUBSCR, hit); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 547be6f13237dd..10f40707e4e099 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -449,7 +449,7 @@ // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); @@ -471,7 +471,7 @@ DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyUnicode_CheckExact(str), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index, BINARY_SUBSCR); // Specialize for reading an ASCII character from any string: Py_UCS4 c = PyUnicode_READ_CHAR(str, index); @@ -496,7 +496,7 @@ // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyTuple_GET_ITEM(tuple, index); @@ -582,7 +582,7 @@ // Ensure nonnegative, zero-or-one-digit ints. 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)->ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0ac99e759deb12..4b455372da139b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -504,7 +504,7 @@ // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); @@ -529,7 +529,7 @@ DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyUnicode_CheckExact(str), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(PyUnicode_GET_LENGTH(str) <= index, BINARY_SUBSCR); // Specialize for reading an ASCII character from any string: Py_UCS4 c = PyUnicode_READ_CHAR(str, index); @@ -557,7 +557,7 @@ // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyTuple_GET_ITEM(tuple, index); @@ -5369,7 +5369,7 @@ // Ensure nonnegative, zero-or-one-digit ints. 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)->ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); diff --git a/Python/marshal.c b/Python/marshal.c index 8940582c7f5328..12af3dcf784285 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -21,6 +21,38 @@ module marshal #include "clinic/marshal.c.h" +// MGDTODO: Put in a shared location + +static inline digit* +get_digit_offset(PyLongObject *v) +{ + return v->ob_digit + ((v->ob_digit[0] & PyLong_IS_LONG_MASK) >> 30); +} + +static inline digit +extract_digit(const digit *d) +{ + return *d & PyLong_MASK; +} + +static inline void +store_digit(digit *d, digit val) +{ + *d = (*d & PyLong_FLAGS_MASK) | (val & PyLong_MASK); +} + +static inline digit +get_digit(const PyLongObject *v, size_t i) +{ + return extract_digit(get_digit_offset(v) + i); +} + +static inline void +set_digit(PyLongObject *v, size_t i, digit val) +{ + store_digit(get_digit_offset(v) + i, val); +} + /* High water mark to determine when the marshalled object is dangerously deep * and risks coring the interpreter. When the object stack gets this deep, * raise an exception instead of continuing. @@ -237,10 +269,12 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) return; } + // MGDTODO: More efficient form for compact + /* set l to number of base PyLong_MARSHAL_BASE digits */ n = _PyLong_DigitCount(ob); l = (n-1) * PyLong_MARSHAL_RATIO; - d = ob->long_value.ob_digit[n-1]; + d = get_digit(ob, n-1); assert(d != 0); /* a PyLong is always normalized */ do { d >>= PyLong_MARSHAL_SHIFT; @@ -254,14 +288,14 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); for (i=0; i < n-1; i++) { - d = ob->long_value.ob_digit[i]; + d = get_digit(ob, i); for (j=0; j < PyLong_MARSHAL_RATIO; j++) { w_short(d & PyLong_MARSHAL_MASK, p); d >>= PyLong_MARSHAL_SHIFT; } assert (d == 0); } - d = ob->long_value.ob_digit[n-1]; + d = get_digit(ob, n-1); do { w_short(d & PyLong_MARSHAL_MASK, p); d >>= PyLong_MARSHAL_SHIFT; @@ -859,7 +893,7 @@ r_PyLong(RFILE *p) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; } - ob->long_value.ob_digit[i] = d; + set_digit(ob, i, d); } d = 0; @@ -879,7 +913,7 @@ r_PyLong(RFILE *p) assert(!PyErr_Occurred()); /* top digit should be nonzero, else the resulting PyLong won't be normalized */ - ob->long_value.ob_digit[size-1] = d; + set_digit(ob, size-1, d); return (PyObject *)ob; bad_digit: Py_DECREF(ob); diff --git a/Python/specialize.c b/Python/specialize.c index ba704cbbb464d7..5e72f597020c7e 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1563,7 +1563,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub) - && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) + && ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; goto success;