mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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:
parent
713df2c534
commit
7559f5fda9
25 changed files with 982 additions and 898 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)), \
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
773
Python/generated_cases.c.h
generated
773
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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} =", ";"):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue