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.
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 @@
 }
 #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 @@
 		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 @@
 }
 
 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 @@
 		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:
 		{