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