GH-101291: Refactor the `PyLongObject` struct into object header and PyLongValue struct. (GH-101292)

This commit is contained in:
Mark Shannon 2023-01-30 10:03:04 +00:00 committed by GitHub
parent f5a3d91b6c
commit c1b1f51cd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 226 additions and 217 deletions

View File

@ -79,9 +79,14 @@ typedef long stwodigits; /* signed variant of twodigits */
aware that ints abuse ob_size's sign bit. aware that ints abuse ob_size's sign bit.
*/ */
struct _longobject { typedef struct _PyLongValue {
PyObject_VAR_HEAD Py_ssize_t ob_size; /* Number of items in variable part */
digit ob_digit[1]; digit ob_digit[1];
} _PyLongValue;
struct _longobject {
PyObject_HEAD
_PyLongValue long_value;
}; };
PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t);

View File

@ -149,9 +149,11 @@ extern "C" {
#define _PyLong_DIGIT_INIT(val) \ #define _PyLong_DIGIT_INIT(val) \
{ \ { \
_PyVarObject_IMMORTAL_INIT(&PyLong_Type, \ .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \
((val) == 0 ? 0 : ((val) > 0 ? 1 : -1))), \ .long_value = { \
.ob_digit = { ((val) >= 0 ? (val) : -(val)) }, \ ((val) == 0 ? 0 : ((val) > 0 ? 1 : -1)), \
{ ((val) >= 0 ? (val) : -(val)) }, \
} \
} }
#define _PyBytes_SIMPLE_INIT(CH, LEN) \ #define _PyBytes_SIMPLE_INIT(CH, LEN) \

View File

@ -0,0 +1,2 @@
Refactor the ``PyLongObject`` struct into a normal Python object header and
a ``PyLongValue`` struct.

View File

@ -2171,16 +2171,16 @@ dec_from_long(PyTypeObject *type, PyObject *v,
} }
if (len == 1) { if (len == 1) {
_dec_settriple(dec, sign, *l->ob_digit, 0); _dec_settriple(dec, sign, *l->long_value.ob_digit, 0);
mpd_qfinalize(MPD(dec), ctx, status); mpd_qfinalize(MPD(dec), ctx, status);
return dec; return dec;
} }
#if PYLONG_BITS_IN_DIGIT == 30 #if PYLONG_BITS_IN_DIGIT == 30
mpd_qimport_u32(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE,
ctx, status); ctx, status);
#elif PYLONG_BITS_IN_DIGIT == 15 #elif PYLONG_BITS_IN_DIGIT == 15
mpd_qimport_u16(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, mpd_qimport_u16(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE,
ctx, status); ctx, status);
#else #else
#error "PYLONG_BITS_IN_DIGIT should be 15 or 30" #error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
@ -3543,11 +3543,11 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
return NULL; return NULL;
} }
memcpy(pylong->ob_digit, ob_digit, n * sizeof(digit)); memcpy(pylong->long_value.ob_digit, ob_digit, n * sizeof(digit));
mpd_free(ob_digit); mpd_free(ob_digit);
i = n; i = n;
while ((i > 0) && (pylong->ob_digit[i-1] == 0)) { while ((i > 0) && (pylong->long_value.ob_digit[i-1] == 0)) {
i--; i--;
} }

View File

@ -195,11 +195,11 @@ PyTypeObject PyBool_Type = {
/* The objects representing bool values False and True */ /* The objects representing bool values False and True */
struct _longobject _Py_FalseStruct = { struct _longobject _Py_FalseStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 0) PyObject_HEAD_INIT(&PyBool_Type)
{ 0 } { 0, { 0 } }
}; };
struct _longobject _Py_TrueStruct = { struct _longobject _Py_TrueStruct = {
PyVarObject_HEAD_INIT(&PyBool_Type, 1) PyObject_HEAD_INIT(&PyBool_Type)
{ 1 } { 1, { 1 } }
}; };

View File

@ -2155,8 +2155,8 @@ unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms)
vl = (PyLongObject*)v; vl = (PyLongObject*)v;
wl = (PyLongObject*)w; wl = (PyLongObject*)w;
v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->ob_digit[0]; v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->long_value.ob_digit[0];
w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->ob_digit[0]; w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->long_value.ob_digit[0];
if (Py_SIZE(vl) < 0) if (Py_SIZE(vl) < 0)
v0 = -v0; v0 = -v0;

File diff suppressed because it is too large Load Diff

View File

@ -2507,10 +2507,10 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
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)) { switch (Py_SIZE(item)) {
case -1: b = -(sdigit) ((PyLongObject*)item)->ob_digit[0]; break; case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break;
// Note: the continue goes to the top of the "while" loop that iterates over the elements // Note: the continue goes to the top of the "while" loop that iterates over the elements
case 0: Py_DECREF(item); continue; case 0: Py_DECREF(item); continue;
case 1: b = ((PyLongObject*)item)->ob_digit[0]; break; case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break;
default: b = PyLong_AsLongAndOverflow(item, &overflow); break; default: b = PyLong_AsLongAndOverflow(item, &overflow); break;
} }
if (overflow == 0 && if (overflow == 0 &&

View File

@ -357,8 +357,8 @@ dummy_func(
// Deopt unless 0 <= sub < PyList_Size(list) // Deopt unless 0 <= sub < PyList_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->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);
res = PyList_GET_ITEM(list, index); res = PyList_GET_ITEM(list, index);
@ -375,8 +375,8 @@ dummy_func(
// Deopt unless 0 <= sub < PyTuple_Size(list) // Deopt unless 0 <= sub < PyTuple_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->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);
res = PyTuple_GET_ITEM(tuple, index); res = PyTuple_GET_ITEM(tuple, index);
@ -469,7 +469,7 @@ dummy_func(
// Ensure nonnegative, zero-or-one-digit ints. // Ensure nonnegative, zero-or-one-digit ints.
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR);
Py_ssize_t index = ((PyLongObject*)sub)->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);
STAT_INC(STORE_SUBSCR, hit); STAT_INC(STORE_SUBSCR, hit);
@ -1834,8 +1834,8 @@ dummy_func(
DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, 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(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1);
Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->ob_digit[0]; Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0];
Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->ob_digit[0]; Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0];
// 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);

View File

@ -484,8 +484,8 @@
// Deopt unless 0 <= sub < PyList_Size(list) // Deopt unless 0 <= sub < PyList_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->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);
res = PyList_GET_ITEM(list, index); res = PyList_GET_ITEM(list, index);
@ -509,8 +509,8 @@
// Deopt unless 0 <= sub < PyTuple_Size(list) // Deopt unless 0 <= sub < PyTuple_Size(list)
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR);
assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0);
Py_ssize_t index = ((PyLongObject*)sub)->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);
res = PyTuple_GET_ITEM(tuple, index); res = PyTuple_GET_ITEM(tuple, index);
@ -634,7 +634,7 @@
// Ensure nonnegative, zero-or-one-digit ints. // Ensure nonnegative, zero-or-one-digit ints.
DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR);
Py_ssize_t index = ((PyLongObject*)sub)->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);
STAT_INC(STORE_SUBSCR, hit); STAT_INC(STORE_SUBSCR, hit);
@ -2179,8 +2179,8 @@
DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, 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(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1);
Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->ob_digit[0]; Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0];
Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->ob_digit[0]; Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0];
// 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);

View File

@ -240,7 +240,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
/* 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 = Py_ABS(Py_SIZE(ob));
l = (n-1) * PyLong_MARSHAL_RATIO; l = (n-1) * PyLong_MARSHAL_RATIO;
d = ob->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 */
do { do {
d >>= PyLong_MARSHAL_SHIFT; d >>= PyLong_MARSHAL_SHIFT;
@ -254,14 +254,14 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p);
for (i=0; i < n-1; i++) { for (i=0; i < n-1; i++) {
d = ob->ob_digit[i]; d = ob->long_value.ob_digit[i];
for (j=0; j < PyLong_MARSHAL_RATIO; j++) { for (j=0; j < PyLong_MARSHAL_RATIO; j++) {
w_short(d & PyLong_MARSHAL_MASK, p); w_short(d & PyLong_MARSHAL_MASK, p);
d >>= PyLong_MARSHAL_SHIFT; d >>= PyLong_MARSHAL_SHIFT;
} }
assert (d == 0); assert (d == 0);
} }
d = ob->ob_digit[n-1]; d = ob->long_value.ob_digit[n-1];
do { do {
w_short(d & PyLong_MARSHAL_MASK, p); w_short(d & PyLong_MARSHAL_MASK, p);
d >>= PyLong_MARSHAL_SHIFT; d >>= PyLong_MARSHAL_SHIFT;
@ -853,7 +853,7 @@ r_PyLong(RFILE *p)
goto bad_digit; goto bad_digit;
d += (digit)md << j*PyLong_MARSHAL_SHIFT; d += (digit)md << j*PyLong_MARSHAL_SHIFT;
} }
ob->ob_digit[i] = d; ob->long_value.ob_digit[i] = d;
} }
d = 0; d = 0;
@ -880,7 +880,7 @@ r_PyLong(RFILE *p)
} }
/* top digit should be nonzero, else the resulting PyLong won't be /* top digit should be nonzero, else the resulting PyLong won't be
normalized */ normalized */
ob->ob_digit[size-1] = d; ob->long_value.ob_digit[size-1] = d;
return (PyObject *)ob; return (PyObject *)ob;
bad_digit: bad_digit:
Py_DECREF(ob); Py_DECREF(ob);

View File

@ -1411,7 +1411,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
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 ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
&& ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container)) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container))
{ {
_py_set_opcode(instr, STORE_SUBSCR_LIST_INT); _py_set_opcode(instr, STORE_SUBSCR_LIST_INT);
goto success; goto success;

View File

@ -901,7 +901,7 @@ class PyLongObjectPtr(PyObjectPtr):
if ob_size == 0: if ob_size == 0:
return 0 return 0
ob_digit = self.field('ob_digit') ob_digit = self.field('long_value')['ob_digit']
if gdb.lookup_type('digit').sizeof == 2: if gdb.lookup_type('digit').sizeof == 2:
SHIFT = 15 SHIFT = 15