@@ -240,10 +240,6 @@ w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
240240#define PyLong_MARSHAL_SHIFT 15
241241#define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT)
242242#define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1)
243- #if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0
244- #error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT"
245- #endif
246- #define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT)
247243
248244#define W_TYPE (t , p ) do { \
249245 w_byte((t) | flag, (p)); \
@@ -252,47 +248,101 @@ w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
252248static PyObject *
253249_PyMarshal_WriteObjectToString (PyObject * x , int version , int allow_code );
254250
251+ #define _r_digits (bs ) \
252+ static void \
253+ _r_digits##bs(const uint##bs##_t *digits, Py_ssize_t n, uint8_t negative, \
254+ Py_ssize_t marshal_ratio, WFILE *p) \
255+ { \
256+ /* set l to number of base PyLong_MARSHAL_BASE digits */ \
257+ Py_ssize_t l = (n - 1 )* marshal_ratio ; \
258+ uint ##bs ##_t d = digits [n - 1 ]; \
259+ \
260+ assert (d != 0 ); /* a PyLong is always normalized */ \
261+ do { \
262+ d >>= PyLong_MARSHAL_SHIFT ; \
263+ l ++ ; \
264+ } while (d != 0 ); \
265+ if (l > SIZE32_MAX ) { \
266+ p -> depth -- ; \
267+ p -> error = WFERR_UNMARSHALLABLE ; \
268+ return ; \
269+ } \
270+ w_long ((long )(negative ? - l : l ), p ); \
271+ \
272+ for (Py_ssize_t i = 0 ; i < n - 1 ; i ++ ) { \
273+ d = digits [i ]; \
274+ for (Py_ssize_t j = 0 ; j < marshal_ratio ; j ++ ) { \
275+ w_short (d & PyLong_MARSHAL_MASK , p ); \
276+ d >>= PyLong_MARSHAL_SHIFT ; \
277+ } \
278+ assert (d == 0 ); \
279+ } \
280+ d = digits [n - 1 ]; \
281+ do { \
282+ w_short (d & PyLong_MARSHAL_MASK , p ); \
283+ d >>= PyLong_MARSHAL_SHIFT ; \
284+ } while (d != 0 ); \
285+ }
286+ _r_digits (16 )
287+ _r_digits (32 )
288+
255289static void
256290w_PyLong (const PyLongObject * ob , char flag , WFILE * p )
257291{
258- Py_ssize_t i , j , n , l ;
259- digit d ;
260-
261292 W_TYPE (TYPE_LONG , p );
262293 if (_PyLong_IsZero (ob )) {
263294 w_long ((long )0 , p );
264295 return ;
265296 }
266297
267- /* set l to number of base PyLong_MARSHAL_BASE digits */
268- n = _PyLong_DigitCount (ob );
269- l = (n - 1 ) * PyLong_MARSHAL_RATIO ;
270- d = ob -> long_value .ob_digit [n - 1 ];
271- assert (d != 0 ); /* a PyLong is always normalized */
272- do {
273- d >>= PyLong_MARSHAL_SHIFT ;
274- l ++ ;
275- } while (d != 0 );
276- if (l > SIZE32_MAX ) {
298+ static PyLongExport long_export ;
299+
300+ if (PyLong_Export ((PyObject * )ob , & long_export ) < 0 ) {
277301 p -> depth -- ;
278302 p -> error = WFERR_UNMARSHALLABLE ;
279303 return ;
280304 }
281- w_long ((long )(_PyLong_IsNegative (ob ) ? - l : l ), p );
305+ if (!long_export .digits ) {
306+ int8_t sign = long_export .value < 0 ? -1 : 1 ;
307+ int64_t abs_value = Py_ABS (long_export .value );
308+ int64_t d = abs_value ;
309+ long l = 0 ;
282310
283- for (i = 0 ; i < n - 1 ; i ++ ) {
284- d = ob -> long_value .ob_digit [i ];
285- for (j = 0 ; j < PyLong_MARSHAL_RATIO ; j ++ ) {
311+ /* set l to number of base PyLong_MARSHAL_BASE digits */
312+ do {
313+ d >>= PyLong_MARSHAL_SHIFT ;
314+ l += sign ;
315+ } while (d );
316+ w_long (l , p );
317+ d = abs_value ;
318+ do {
286319 w_short (d & PyLong_MARSHAL_MASK , p );
287320 d >>= PyLong_MARSHAL_SHIFT ;
288- }
289- assert (d == 0 );
321+ } while (d );
322+ return ;
323+ }
324+
325+ const PyLongLayout * layout = PyLong_GetNativeLayout ();
326+ Py_ssize_t marshal_ratio = layout -> bits_per_digit /PyLong_MARSHAL_SHIFT ;
327+
328+ /* must be a multiple of PyLong_MARSHAL_SHIFT */
329+ assert (layout -> bits_per_digit % PyLong_MARSHAL_SHIFT == 0 );
330+
331+ /* other assumptions on PyLongObject internals */
332+ assert (layout -> bits_per_digit <= 32 );
333+ assert (layout -> digits_order == -1 );
334+ assert (layout -> digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1 ));
335+ assert (layout -> digit_size == 2 || layout -> digit_size == 4 );
336+
337+ if (layout -> digit_size == 4 ) {
338+ _r_digits32 (long_export .digits , long_export .ndigits ,
339+ long_export .negative , marshal_ratio , p );
340+ }
341+ else {
342+ _r_digits16 (long_export .digits , long_export .ndigits ,
343+ long_export .negative , marshal_ratio , p );
290344 }
291- d = ob -> long_value .ob_digit [n - 1 ];
292- do {
293- w_short (d & PyLong_MARSHAL_MASK , p );
294- d >>= PyLong_MARSHAL_SHIFT ;
295- } while (d != 0 );
345+ PyLong_FreeExport (& long_export );
296346}
297347
298348static void
@@ -875,17 +925,60 @@ r_long64(RFILE *p)
875925 1 /* signed */ );
876926}
877927
928+ #define _w_digits (bs ) \
929+ static int \
930+ _w_digits##bs(uint##bs##_t *digits, Py_ssize_t size, \
931+ Py_ssize_t marshal_ratio, \
932+ int shorts_in_top_digit, RFILE *p) \
933+ { \
934+ int md; \
935+ uint##bs##_t d; \
936+ \
937+ for (Py_ssize_t i = 0; i < size - 1; i++) { \
938+ d = 0; \
939+ for (Py_ssize_t j = 0; j < marshal_ratio; j++) { \
940+ md = r_short(p); \
941+ if (md < 0 || md > PyLong_MARSHAL_BASE) { \
942+ goto bad_digit; \
943+ } \
944+ d += (uint##bs##_t)md << j*PyLong_MARSHAL_SHIFT; \
945+ } \
946+ digits[i] = d; \
947+ } \
948+ \
949+ d = 0; \
950+ for (Py_ssize_t j = 0; j < shorts_in_top_digit; j++) { \
951+ md = r_short(p); \
952+ if (md < 0 || md > PyLong_MARSHAL_BASE) { \
953+ goto bad_digit; \
954+ } \
955+ /* topmost marshal digit should be nonzero */ \
956+ if (md == 0 && j == shorts_in_top_digit - 1 ) { \
957+ PyErr_SetString (PyExc_ValueError , \
958+ "bad marshal data (unnormalized long data)" ); \
959+ return -1 ; \
960+ } \
961+ d += (uint ##bs ##_t)md << j*PyLong_MARSHAL_SHIFT; \
962+ } \
963+ assert(!PyErr_Occurred()); \
964+ /* top digit should be nonzero, else the resulting PyLong won't be \
965+ normalized */ \
966+ digits [size - 1 ] = d ; \
967+ return 0 ; \
968+ bad_digit : \
969+ if (!PyErr_Occurred ()) { \
970+ PyErr_SetString (PyExc_ValueError , \
971+ "bad marshal data (digit out of range in long)" ); \
972+ } \
973+ return -1 ; \
974+ }
975+ _w_digits (32 )
976+ _w_digits (16 )
977+
878978static PyObject *
879979r_PyLong (RFILE * p )
880980{
881- PyLongObject * ob ;
882- long n , size , i ;
883- int j , md , shorts_in_top_digit ;
884- digit d ;
885-
886- n = r_long (p );
887- if (n == 0 )
888- return (PyObject * )_PyLong_New (0 );
981+ long n = r_long (p );
889982 if (n == -1 && PyErr_Occurred ()) {
890983 return NULL ;
891984 }
@@ -895,51 +988,40 @@ r_PyLong(RFILE *p)
895988 return NULL ;
896989 }
897990
898- size = 1 + (Py_ABS (n ) - 1 ) / PyLong_MARSHAL_RATIO ;
899- shorts_in_top_digit = 1 + (Py_ABS (n ) - 1 ) % PyLong_MARSHAL_RATIO ;
900- ob = _PyLong_New (size );
901- if (ob == NULL )
902- return NULL ;
991+ const PyLongLayout * layout = PyLong_GetNativeLayout ();
992+ Py_ssize_t marshal_ratio = layout -> bits_per_digit /PyLong_MARSHAL_SHIFT ;
903993
904- _PyLong_SetSignAndDigitCount (ob , n < 0 ? -1 : 1 , size );
994+ /* must be a multiple of PyLong_MARSHAL_SHIFT */
995+ assert (layout -> bits_per_digit % PyLong_MARSHAL_SHIFT == 0 );
905996
906- for (i = 0 ; i < size - 1 ; i ++ ) {
907- d = 0 ;
908- for (j = 0 ; j < PyLong_MARSHAL_RATIO ; j ++ ) {
909- md = r_short (p );
910- if (md < 0 || md > PyLong_MARSHAL_BASE )
911- goto bad_digit ;
912- d += (digit )md << j * PyLong_MARSHAL_SHIFT ;
913- }
914- ob -> long_value .ob_digit [i ] = d ;
997+ /* other assumptions on PyLongObject internals */
998+ assert (layout -> bits_per_digit <= 32 );
999+ assert (layout -> digits_order == -1 );
1000+ assert (layout -> digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1 ));
1001+ assert (layout -> digit_size == 2 || layout -> digit_size == 4 );
1002+
1003+ Py_ssize_t size = 1 + (Py_ABS (n ) - 1 ) / marshal_ratio ;
1004+ int shorts_in_top_digit = 1 + (Py_ABS (n ) - 1 ) % marshal_ratio ;
1005+ void * digits ;
1006+ PyLongWriter * writer = PyLongWriter_Create (n < 0 , size , & digits );
1007+
1008+ if (writer == NULL ) {
1009+ return NULL ;
9151010 }
9161011
917- d = 0 ;
918- for (j = 0 ; j < shorts_in_top_digit ; j ++ ) {
919- md = r_short (p );
920- if (md < 0 || md > PyLong_MARSHAL_BASE )
921- goto bad_digit ;
922- /* topmost marshal digit should be nonzero */
923- if (md == 0 && j == shorts_in_top_digit - 1 ) {
924- Py_DECREF (ob );
925- PyErr_SetString (PyExc_ValueError ,
926- "bad marshal data (unnormalized long data)" );
927- return NULL ;
928- }
929- d += (digit )md << j * PyLong_MARSHAL_SHIFT ;
1012+ int ret ;
1013+
1014+ if (layout -> digit_size == 4 ) {
1015+ ret = _w_digits32 (digits , size , marshal_ratio , shorts_in_top_digit , p );
9301016 }
931- assert (!PyErr_Occurred ());
932- /* top digit should be nonzero, else the resulting PyLong won't be
933- normalized */
934- ob -> long_value .ob_digit [size - 1 ] = d ;
935- return (PyObject * )ob ;
936- bad_digit :
937- Py_DECREF (ob );
938- if (!PyErr_Occurred ()) {
939- PyErr_SetString (PyExc_ValueError ,
940- "bad marshal data (digit out of range in long)" );
1017+ else {
1018+ ret = _w_digits16 (digits , size , marshal_ratio , shorts_in_top_digit , p );
1019+ }
1020+ if (ret < 0 ) {
1021+ PyLongWriter_Discard (writer );
1022+ return NULL ;
9411023 }
942- return NULL ;
1024+ return PyLongWriter_Finish ( writer ) ;
9431025}
9441026
9451027static double
0 commit comments