@@ -240,10 +240,6 @@ w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
240
240
#define PyLong_MARSHAL_SHIFT 15
241
241
#define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT)
242
242
#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)
247
243
248
244
#define W_TYPE (t , p ) do { \
249
245
w_byte((t) | flag, (p)); \
@@ -252,47 +248,101 @@ w_short_pstring(const void *s, Py_ssize_t n, WFILE *p)
252
248
static PyObject *
253
249
_PyMarshal_WriteObjectToString (PyObject * x , int version , int allow_code );
254
250
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
+
255
289
static void
256
290
w_PyLong (const PyLongObject * ob , char flag , WFILE * p )
257
291
{
258
- Py_ssize_t i , j , n , l ;
259
- digit d ;
260
-
261
292
W_TYPE (TYPE_LONG , p );
262
293
if (_PyLong_IsZero (ob )) {
263
294
w_long ((long )0 , p );
264
295
return ;
265
296
}
266
297
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
+ PyLongExport long_export ;
299
+
300
+ if (PyLong_Export ((PyObject * )ob , & long_export ) < 0 ) {
277
301
p -> depth -- ;
278
302
p -> error = WFERR_UNMARSHALLABLE ;
279
303
return ;
280
304
}
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
+ uint64_t abs_value = Py_ABS (long_export .value );
308
+ uint64_t d = abs_value ;
309
+ long l = 0 ;
282
310
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 {
286
319
w_short (d & PyLong_MARSHAL_MASK , p );
287
320
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 );
290
344
}
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 );
296
346
}
297
347
298
348
static void
@@ -875,17 +925,60 @@ r_long64(RFILE *p)
875
925
1 /* signed */ );
876
926
}
877
927
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
+
878
978
static PyObject *
879
979
r_PyLong (RFILE * p )
880
980
{
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 );
889
982
if (n == -1 && PyErr_Occurred ()) {
890
983
return NULL ;
891
984
}
@@ -895,51 +988,40 @@ r_PyLong(RFILE *p)
895
988
return NULL ;
896
989
}
897
990
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 ;
903
993
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 );
905
996
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 ;
915
1010
}
916
1011
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 );
930
1016
}
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 ;
941
1023
}
942
- return NULL ;
1024
+ return PyLongWriter_Finish ( writer ) ;
943
1025
}
944
1026
945
1027
static double
0 commit comments