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:
Mark Dickinson 2009-03-18 20:06:12 +00:00
parent e7f45b8e59
commit bd7926478d
15 changed files with 865 additions and 68 deletions

View file

@ -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:
{

View file

@ -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",