@@ -88,6 +88,7 @@ typedef struct {
88
88
_Py_hashtable_t * hashtable ;
89
89
int last_index ;
90
90
int version ;
91
+ int stable ;
91
92
} WFILE ;
92
93
93
94
#define w_byte (c , p ) do { \
@@ -282,29 +283,61 @@ w_ref(PyObject *v, char *flag, WFILE *p)
282
283
}
283
284
284
285
entry = _Py_HASHTABLE_GET_ENTRY (p -> hashtable , v );
285
- if (entry == NULL ) {
286
- return 0 ;
287
- }
288
286
289
- _Py_HASHTABLE_ENTRY_READ_DATA (p -> hashtable , entry , w );
290
- // w >= 0: index written by previous w_ref()
291
- // w < 0 : refcnt counted by w_count_refs()
292
- if (w == -1 ) {
293
- // This object is used only once.
294
- return 0 ;
295
- }
287
+ if (p -> stable ) {
288
+ if (entry == NULL ) {
289
+ return 0 ;
290
+ }
296
291
297
- if (w >= 0 ) {
298
- /* we don't store "long" indices in the dict */
299
- assert (0 <= w && w <= 0x7fffffff );
300
- w_byte (TYPE_REF , p );
301
- w_long (w , p );
292
+ _Py_HASHTABLE_ENTRY_READ_DATA (p -> hashtable , entry , w );
293
+ // w >= 0: index written by previous w_ref()
294
+ // w < 0 : refcnt counted by w_count_refs()
295
+ if (w == -1 ) {
296
+ // This object is used only once.
297
+ return 0 ;
298
+ }
299
+
300
+ if (w >= 0 ) {
301
+ /* we don't store "long" indices in the dict */
302
+ assert (0 <= w && w <= 0x7fffffff );
303
+ w_byte (TYPE_REF , p );
304
+ w_long (w , p );
305
+ return 1 ;
306
+ } else {
307
+ w = p -> last_index ++ ;
308
+ _Py_HASHTABLE_ENTRY_WRITE_DATA (p -> hashtable , entry , w );
309
+ * flag |= FLAG_REF ;
310
+ return 0 ;
311
+ }
312
+ }
313
+ else {
314
+ if (entry != NULL ) {
315
+ /* write the reference index to the stream */
316
+ _Py_HASHTABLE_ENTRY_READ_DATA (p -> hashtable , entry , w );
317
+ /* we don't store "long" indices in the dict */
318
+ assert (0 <= w && w <= 0x7fffffff );
319
+ w_byte (TYPE_REF , p );
320
+ w_long (w , p );
321
+ return 1 ;
322
+ } else {
323
+ size_t s = p -> hashtable -> entries ;
324
+ /* we don't support long indices */
325
+ if (s >= 0x7fffffff ) {
326
+ PyErr_SetString (PyExc_ValueError , "too many objects" );
327
+ goto err ;
328
+ }
329
+ w = (int )s ;
330
+ Py_INCREF (v );
331
+ if (_Py_HASHTABLE_SET (p -> hashtable , v , w ) < 0 ) {
332
+ Py_DECREF (v );
333
+ goto err ;
334
+ }
335
+ * flag |= FLAG_REF ;
336
+ return 0 ;
337
+ }
338
+ err :
339
+ p -> error = WFERR_UNMARSHALLABLE ;
302
340
return 1 ;
303
- } else {
304
- w = p -> last_index ++ ;
305
- _Py_HASHTABLE_ENTRY_WRITE_DATA (p -> hashtable , entry , w );
306
- * flag |= FLAG_REF ;
307
- return 0 ;
308
341
}
309
342
}
310
343
@@ -711,7 +744,10 @@ w_init_refs(WFILE *wf, int version, PyObject *x)
711
744
}
712
745
wf -> last_index = 0 ;
713
746
714
- return w_count_refs (x , wf );
747
+ if (wf -> stable ) {
748
+ return w_count_refs (x , wf );
749
+ }
750
+ return 0 ;
715
751
}
716
752
717
753
static int
@@ -1725,19 +1761,17 @@ PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len)
1725
1761
return result ;
1726
1762
}
1727
1763
1728
- PyObject *
1729
- PyMarshal_WriteObjectToString (PyObject * x , int version )
1764
+ static PyObject *
1765
+ marshal_to_string (PyObject * x , int version , int stable )
1730
1766
{
1731
- WFILE wf ;
1767
+ WFILE wf = {. stable = stable , . version = version } ;
1732
1768
1733
- memset (& wf , 0 , sizeof (wf ));
1734
1769
wf .str = PyBytes_FromStringAndSize ((char * )NULL , 50 );
1735
1770
if (wf .str == NULL )
1736
1771
return NULL ;
1737
1772
wf .ptr = wf .buf = PyBytes_AS_STRING ((PyBytesObject * )wf .str );
1738
1773
wf .end = wf .ptr + PyBytes_Size (wf .str );
1739
1774
wf .error = WFERR_OK ;
1740
- wf .version = version ;
1741
1775
if (w_init_refs (& wf , version , x )) {
1742
1776
Py_DECREF (wf .str );
1743
1777
return NULL ;
@@ -1768,6 +1802,12 @@ PyMarshal_WriteObjectToString(PyObject *x, int version)
1768
1802
return wf .str ;
1769
1803
}
1770
1804
1805
+ PyObject *
1806
+ PyMarshal_WriteObjectToString (PyObject * x , int version )
1807
+ {
1808
+ return marshal_to_string (x , version , 0 );
1809
+ }
1810
+
1771
1811
/* And an interface for Python programs... */
1772
1812
/*[clinic input]
1773
1813
marshal.dump
@@ -1778,6 +1818,8 @@ marshal.dump
1778
1818
Must be a writeable binary file.
1779
1819
version: int(c_default="Py_MARSHAL_VERSION") = version
1780
1820
Indicates the data format that dump should use.
1821
+ stable: bool = False
1822
+ Generate stable output as possible.
1781
1823
/
1782
1824
1783
1825
Write the value on the open file.
@@ -1789,15 +1831,15 @@ to the file. The object will not be properly read back by load().
1789
1831
1790
1832
static PyObject *
1791
1833
marshal_dump_impl (PyObject * module , PyObject * value , PyObject * file ,
1792
- int version )
1793
- /*[clinic end generated code: output=aaee62c7028a7cb2 input=6c7a3c23c6fef556 ]*/
1834
+ int version , int stable )
1835
+ /*[clinic end generated code: output=b472bdb1b466baa1 input=89780da6b9530e4b ]*/
1794
1836
{
1795
1837
/* XXX Quick hack -- need to do this differently */
1796
1838
PyObject * s ;
1797
1839
PyObject * res ;
1798
1840
_Py_IDENTIFIER (write );
1799
1841
1800
- s = PyMarshal_WriteObjectToString (value , version );
1842
+ s = marshal_to_string (value , version , stable );
1801
1843
if (s == NULL )
1802
1844
return NULL ;
1803
1845
res = _PyObject_CallMethodIdObjArgs (file , & PyId_write , s , NULL );
@@ -1871,6 +1913,8 @@ marshal.dumps
1871
1913
Must be a supported type.
1872
1914
version: int(c_default="Py_MARSHAL_VERSION") = version
1873
1915
Indicates the data format that dumps should use.
1916
+ stable: bool = False
1917
+ Generate stable output as possible.
1874
1918
/
1875
1919
1876
1920
Return the bytes object that would be written to a file by dump(value, file).
@@ -1880,10 +1924,11 @@ unsupported type.
1880
1924
[clinic start generated code]*/
1881
1925
1882
1926
static PyObject *
1883
- marshal_dumps_impl (PyObject * module , PyObject * value , int version )
1884
- /*[clinic end generated code: output=9c200f98d7256cad input=a2139ea8608e9b27]*/
1927
+ marshal_dumps_impl (PyObject * module , PyObject * value , int version ,
1928
+ int stable )
1929
+ /*[clinic end generated code: output=87276039e6c75faf input=afce1546a470f153]*/
1885
1930
{
1886
- return PyMarshal_WriteObjectToString (value , version );
1931
+ return marshal_to_string (value , version , stable );
1887
1932
}
1888
1933
1889
1934
/*[clinic input]
0 commit comments