diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-03-18 20:06:12 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-03-18 20:06:12 (GMT) |
commit | bd7926478de92a2a0ef4440e1a9ae61b706a80d2 (patch) | |
tree | f92ef0133e96195e1875cc74b046474aeb7be155 /Python/marshal.c | |
parent | e7f45b8e5948d7367c3754b0506b082d1296138f (diff) | |
download | cpython-bd7926478de92a2a0ef4440e1a9ae61b706a80d2.zip cpython-bd7926478de92a2a0ef4440e1a9ae61b706a80d2.tar.gz cpython-bd7926478de92a2a0ef4440e1a9ae61b706a80d2.tar.bz2 |
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.
Diffstat (limited to 'Python/marshal.c')
-rw-r--r-- | Python/marshal.c | 146 |
1 files changed, 106 insertions, 40 deletions
diff --git a/Python/marshal.c b/Python/marshal.c index 8fe34d4..e5e5ce4 100644 --- a/Python/marshal.c +++ b/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); @@ -481,6 +527,56 @@ r_long64(RFILE *p) } 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) { /* NULL is a valid return value, it does not necessarily means that @@ -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: { |