mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
Issue #4258: Make it possible to use 30-bit digits for PyLongs:
- new configure option --enable-big-digits - new structseq sys.int_info giving information about the internal format By default, 30-bit digits are enabled on 64-bit machines but disabled on 32-bit machines.
This commit is contained in:
parent
e7f45b8e59
commit
bd7926478d
15 changed files with 865 additions and 68 deletions
146
Python/marshal.c
146
Python/marshal.c
|
@ -11,6 +11,8 @@
|
|||
#include "code.h"
|
||||
#include "marshal.h"
|
||||
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
/* 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.
|
||||
|
@ -122,6 +124,56 @@ w_long64(long x, WFILE *p)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* We assume that Python longs are stored internally in base some power of
|
||||
2**15; for the sake of portability we'll always read and write them in base
|
||||
exactly 2**15. */
|
||||
|
||||
#define PyLong_MARSHAL_SHIFT 15
|
||||
#define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT)
|
||||
#define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1)
|
||||
#if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0
|
||||
#error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT"
|
||||
#endif
|
||||
#define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT)
|
||||
|
||||
static void
|
||||
w_PyLong(const PyLongObject *ob, WFILE *p)
|
||||
{
|
||||
Py_ssize_t i, j, n, l;
|
||||
digit d;
|
||||
|
||||
w_byte(TYPE_LONG, p);
|
||||
if (Py_SIZE(ob) == 0) {
|
||||
w_long((long)0, p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set l to number of base PyLong_MARSHAL_BASE digits */
|
||||
n = ABS(Py_SIZE(ob));
|
||||
l = (n-1) * PyLong_MARSHAL_RATIO;
|
||||
d = ob->ob_digit[n-1];
|
||||
assert(d != 0); /* a PyLong is always normalized */
|
||||
do {
|
||||
d >>= PyLong_MARSHAL_SHIFT;
|
||||
l++;
|
||||
} while (d != 0);
|
||||
w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p);
|
||||
|
||||
for (i=0; i < n-1; i++) {
|
||||
d = ob->ob_digit[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->ob_digit[n-1];
|
||||
do {
|
||||
w_short(d & PyLong_MARSHAL_MASK, p);
|
||||
d >>= PyLong_MARSHAL_SHIFT;
|
||||
} while (d != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
w_object(PyObject *v, WFILE *p)
|
||||
{
|
||||
|
@ -155,14 +207,8 @@ w_object(PyObject *v, WFILE *p)
|
|||
if ((x == -1) && PyErr_Occurred()) {
|
||||
PyLongObject *ob = (PyLongObject *)v;
|
||||
PyErr_Clear();
|
||||
w_byte(TYPE_LONG, p);
|
||||
n = Py_SIZE(ob);
|
||||
w_long((long)n, p);
|
||||
if (n < 0)
|
||||
n = -n;
|
||||
for (i = 0; i < n; i++)
|
||||
w_short(ob->ob_digit[i], p);
|
||||
}
|
||||
w_PyLong(ob, p);
|
||||
}
|
||||
else {
|
||||
#if SIZEOF_LONG > 4
|
||||
long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31);
|
||||
|
@ -480,6 +526,56 @@ r_long64(RFILE *p)
|
|||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
r_PyLong(RFILE *p)
|
||||
{
|
||||
PyLongObject *ob;
|
||||
int size, i, j, md;
|
||||
long n;
|
||||
digit d;
|
||||
|
||||
n = r_long(p);
|
||||
if (n == 0)
|
||||
return (PyObject *)_PyLong_New(0);
|
||||
if (n < -INT_MAX || n > INT_MAX) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"bad marshal data (long size out of range)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = 1 + (ABS(n)-1) / PyLong_MARSHAL_RATIO;
|
||||
ob = _PyLong_New(size);
|
||||
if (ob == NULL)
|
||||
return NULL;
|
||||
Py_SIZE(ob) = n > 0 ? size : -size;
|
||||
|
||||
for (i = 0; i < size-1; i++) {
|
||||
d = 0;
|
||||
for (j=0; j < PyLong_MARSHAL_RATIO; j++) {
|
||||
md = r_short(p);
|
||||
if (md < 0 || md > PyLong_MARSHAL_BASE)
|
||||
goto bad_digit;
|
||||
d += (digit)md << j*PyLong_MARSHAL_SHIFT;
|
||||
}
|
||||
ob->ob_digit[i] = d;
|
||||
}
|
||||
d = 0;
|
||||
for (j=0; j < (ABS(n)-1)%PyLong_MARSHAL_RATIO + 1; j++) {
|
||||
md = r_short(p);
|
||||
if (md < 0 || md > PyLong_MARSHAL_BASE)
|
||||
goto bad_digit;
|
||||
d += (digit)md << j*PyLong_MARSHAL_SHIFT;
|
||||
}
|
||||
ob->ob_digit[size-1] = d;
|
||||
return (PyObject *)ob;
|
||||
bad_digit:
|
||||
Py_DECREF(ob);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"bad marshal data (digit out of range in long)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
r_object(RFILE *p)
|
||||
{
|
||||
|
@ -544,38 +640,8 @@ r_object(RFILE *p)
|
|||
break;
|
||||
|
||||
case TYPE_LONG:
|
||||
{
|
||||
int size;
|
||||
PyLongObject *ob;
|
||||
n = r_long(p);
|
||||
if (n < -INT_MAX || n > INT_MAX) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"bad marshal data (long size out of range)");
|
||||
retval = NULL;
|
||||
break;
|
||||
}
|
||||
size = n<0 ? -n : n;
|
||||
ob = _PyLong_New(size);
|
||||
if (ob == NULL) {
|
||||
retval = NULL;
|
||||
break;
|
||||
}
|
||||
Py_SIZE(ob) = n;
|
||||
for (i = 0; i < size; i++) {
|
||||
int digit = r_short(p);
|
||||
if (digit < 0) {
|
||||
Py_DECREF(ob);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"bad marshal data (negative digit in long)");
|
||||
ob = NULL;
|
||||
break;
|
||||
}
|
||||
if (ob != NULL)
|
||||
ob->ob_digit[i] = digit;
|
||||
}
|
||||
retval = (PyObject *)ob;
|
||||
break;
|
||||
}
|
||||
retval = r_PyLong(p);
|
||||
break;
|
||||
|
||||
case TYPE_FLOAT:
|
||||
{
|
||||
|
|
|
@ -1012,6 +1012,7 @@ PyDoc_STR(
|
|||
Static objects:\n\
|
||||
\n\
|
||||
float_info -- a dict with information about the float implementation.\n\
|
||||
int_info -- a struct sequence with information about the int implementation.\n\
|
||||
maxsize -- the largest supported length of containers.\n\
|
||||
maxunicode -- the largest supported character\n\
|
||||
builtin_module_names -- tuple of module names built into this interpreter\n\
|
||||
|
@ -1375,6 +1376,8 @@ _PySys_Init(void)
|
|||
PyLong_FromSsize_t(PY_SSIZE_T_MAX));
|
||||
SET_SYS_FROM_STRING("float_info",
|
||||
PyFloat_GetInfo());
|
||||
SET_SYS_FROM_STRING("int_info",
|
||||
PyLong_GetInfo());
|
||||
SET_SYS_FROM_STRING("maxunicode",
|
||||
PyLong_FromLong(PyUnicode_GetMax()));
|
||||
SET_SYS_FROM_STRING("builtin_module_names",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue