@@ -453,8 +453,14 @@ static PyDictKeysObject empty_keys_struct = {
453
453
};
454
454
455
455
456
- static PyDictValues empty_values_struct = { 0 , { NULL }};
457
- #define empty_values (&empty_values_struct)
456
+ struct {
457
+ uint8_t prefix [sizeof (PyObject * )];
458
+ PyDictValues values ;
459
+ } empty_values_struct = {
460
+ { [sizeof (PyObject * )-1 ] = sizeof (PyObject * ) },
461
+ {{NULL }}
462
+ };
463
+ #define empty_values (&empty_values_struct.values)
458
464
459
465
#define Py_EMPTY_KEYS &empty_keys_struct
460
466
@@ -470,9 +476,9 @@ static PyDictValues empty_values_struct = { 0, { NULL }};
470
476
static inline int
471
477
get_index_from_order (PyDictObject * mp , Py_ssize_t i )
472
478
{
473
- assert (mp -> ma_used <= 16 );
474
- int shift = ( int )( mp -> ma_used - 1 - i ) * 4 ;
475
- return (int )( mp -> ma_values -> mv_order >> shift ) & 15 ;
479
+ assert (mp -> ma_used <= SHARED_KEYS_MAX_SIZE );
480
+ assert ( i < ((( char * ) mp -> ma_values )[ -2 ])) ;
481
+ return (( char * ) mp -> ma_values )[ -3 - i ] ;
476
482
}
477
483
478
484
int
@@ -636,11 +642,25 @@ free_keys_object(PyDictKeysObject *keys)
636
642
static inline PyDictValues *
637
643
new_values (Py_ssize_t size )
638
644
{
639
- Py_ssize_t n = sizeof (PyDictValues ) + sizeof (PyObject * ) * (size - 1 );
640
- return (PyDictValues * )PyMem_Malloc (n );
645
+ assert (size > 0 );
646
+ size_t prefix_size = _Py_SIZE_ROUND_UP (size + 2 , sizeof (PyObject * ));
647
+ assert (prefix_size < 256 );
648
+ size_t n = prefix_size + size * sizeof (PyObject * );
649
+ uint8_t * mem = PyMem_Malloc (n );
650
+ if (mem == NULL ) {
651
+ return NULL ;
652
+ }
653
+ assert (prefix_size % sizeof (PyObject * ) == 0 );
654
+ mem [prefix_size - 1 ] = (uint8_t )prefix_size ;
655
+ return (PyDictValues * )(mem + prefix_size );
641
656
}
642
657
643
- #define free_values (values ) PyMem_Free(values)
658
+ static inline void
659
+ free_values (PyDictValues * values )
660
+ {
661
+ int prefix_size = ((uint8_t * )values )[-1 ];
662
+ PyMem_Free (((char * )values )- prefix_size );
663
+ }
644
664
645
665
/* Consumes a reference to the keys object */
646
666
static PyObject *
@@ -699,7 +719,7 @@ new_dict_with_shared_keys(PyDictKeysObject *keys)
699
719
dictkeys_decref (keys );
700
720
return PyErr_NoMemory ();
701
721
}
702
- values -> mv_order = 0 ;
722
+ (( char * ) values )[ -2 ] = 0 ;
703
723
for (i = 0 ; i < size ; i ++ ) {
704
724
values -> values [i ] = NULL ;
705
725
}
@@ -1017,7 +1037,7 @@ insertion_resize(PyDictObject *mp)
1017
1037
return dictresize (mp , calculate_log2_keysize (GROWTH_RATE (mp )));
1018
1038
}
1019
1039
1020
- static int
1040
+ static Py_ssize_t
1021
1041
insert_into_dictkeys (PyDictKeysObject * keys , PyObject * name )
1022
1042
{
1023
1043
assert (PyUnicode_CheckExact (name ));
@@ -1048,7 +1068,7 @@ insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
1048
1068
keys -> dk_nentries ++ ;
1049
1069
}
1050
1070
assert (ix < SHARED_KEYS_MAX_SIZE );
1051
- return ( int ) ix ;
1071
+ return ix ;
1052
1072
}
1053
1073
1054
1074
/*
@@ -1093,9 +1113,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
1093
1113
ep -> me_hash = hash ;
1094
1114
if (mp -> ma_values ) {
1095
1115
Py_ssize_t index = mp -> ma_keys -> dk_nentries ;
1096
- assert (index < SHARED_KEYS_MAX_SIZE );
1097
- assert ((mp -> ma_values -> mv_order >> 60 ) == 0 );
1098
- mp -> ma_values -> mv_order = ((mp -> ma_values -> mv_order )<<4 ) | index ;
1116
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , index );
1099
1117
assert (mp -> ma_values -> values [index ] == NULL );
1100
1118
mp -> ma_values -> values [index ] = value ;
1101
1119
}
@@ -1115,7 +1133,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
1115
1133
if (_PyDict_HasSplitTable (mp )) {
1116
1134
mp -> ma_values -> values [ix ] = value ;
1117
1135
if (old_value == NULL ) {
1118
- mp -> ma_values -> mv_order = (mp -> ma_values -> mv_order << 4 ) | ix ;
1136
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix ) ;
1119
1137
mp -> ma_used ++ ;
1120
1138
}
1121
1139
}
@@ -1598,19 +1616,20 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
1598
1616
return insertdict (mp , key , hash , value );
1599
1617
}
1600
1618
1601
- static uint64_t
1602
- delete_index_from_order (uint64_t order , Py_ssize_t ix )
1603
- { /* Update order */
1604
- for (int i = 0 ;; i += 4 ) {
1605
- assert (i < 64 );
1606
- if (((order >> i ) & 15 ) == (uint64_t )ix ) {
1607
- /* Remove 4 bits at ith position */
1608
- uint64_t high = ((order >>i )>>4 )<<i ;
1609
- uint64_t low = order & ((((uint64_t )1 )<<i )- 1 );
1610
- return high | low ;
1611
- }
1619
+ static void
1620
+ delete_index_from_values (PyDictValues * values , Py_ssize_t ix )
1621
+ {
1622
+ uint8_t * size_ptr = ((uint8_t * )values )- 2 ;
1623
+ int size = * size_ptr ;
1624
+ int i ;
1625
+ for (i = 1 ; size_ptr [- i ] != ix ; i ++ ) {
1626
+ assert (i <= size );
1612
1627
}
1613
- Py_UNREACHABLE ();
1628
+ assert (i <= size );
1629
+ for (; i < size ; i ++ ) {
1630
+ size_ptr [- i ] = size_ptr [- i - 1 ];
1631
+ }
1632
+ * size_ptr = size - 1 ;
1614
1633
}
1615
1634
1616
1635
static int
@@ -1631,8 +1650,7 @@ delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
1631
1650
mp -> ma_values -> values [ix ] = NULL ;
1632
1651
assert (ix < SHARED_KEYS_MAX_SIZE );
1633
1652
/* Update order */
1634
- mp -> ma_values -> mv_order =
1635
- delete_index_from_order (mp -> ma_values -> mv_order , ix );
1653
+ delete_index_from_values (mp -> ma_values , ix );
1636
1654
ASSERT_CONSISTENT (mp );
1637
1655
}
1638
1656
else {
@@ -2729,7 +2747,8 @@ PyDict_Copy(PyObject *o)
2729
2747
free_values (newvalues );
2730
2748
return NULL ;
2731
2749
}
2732
- newvalues -> mv_order = mp -> ma_values -> mv_order ;
2750
+ size_t prefix_size = ((uint8_t * )newvalues )[-1 ];
2751
+ memcpy (((char * )newvalues )- prefix_size , ((char * )mp -> ma_values )- prefix_size , prefix_size - 1 );
2733
2752
split_copy -> ma_values = newvalues ;
2734
2753
split_copy -> ma_keys = mp -> ma_keys ;
2735
2754
split_copy -> ma_used = mp -> ma_used ;
@@ -3031,11 +3050,11 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
3031
3050
ep -> me_key = key ;
3032
3051
ep -> me_hash = hash ;
3033
3052
if (_PyDict_HasSplitTable (mp )) {
3034
- int index = (int )mp -> ma_keys -> dk_nentries ;
3053
+ Py_ssize_t index = (int )mp -> ma_keys -> dk_nentries ;
3035
3054
assert (index < SHARED_KEYS_MAX_SIZE );
3036
3055
assert (mp -> ma_values -> values [index ] == NULL );
3037
3056
mp -> ma_values -> values [index ] = value ;
3038
- mp -> ma_values -> mv_order = (mp -> ma_values -> mv_order << 4 ) | index ;
3057
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , index ) ;
3039
3058
}
3040
3059
else {
3041
3060
ep -> me_value = value ;
@@ -3053,7 +3072,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
3053
3072
Py_INCREF (value );
3054
3073
MAINTAIN_TRACKING (mp , key , value );
3055
3074
mp -> ma_values -> values [ix ] = value ;
3056
- mp -> ma_values -> mv_order = (mp -> ma_values -> mv_order << 4 ) | ix ;
3075
+ _PyDictValues_AddToInsertionOrder (mp -> ma_values , ix ) ;
3057
3076
mp -> ma_used ++ ;
3058
3077
mp -> ma_version_tag = DICT_NEXT_VERSION ();
3059
3078
}
@@ -4941,7 +4960,7 @@ dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
4941
4960
PyDictKeysObject *
4942
4961
_PyDict_NewKeysForClass (void )
4943
4962
{
4944
- PyDictKeysObject * keys = new_keys_object (5 ); /* log2(32) */
4963
+ PyDictKeysObject * keys = new_keys_object (NEXT_LOG2_SHARED_KEYS_MAX_SIZE );
4945
4964
if (keys == NULL ) {
4946
4965
PyErr_Clear ();
4947
4966
}
@@ -4974,7 +4993,8 @@ init_inline_values(PyObject *obj, PyTypeObject *tp)
4974
4993
PyErr_NoMemory ();
4975
4994
return -1 ;
4976
4995
}
4977
- values -> mv_order = 0 ;
4996
+ assert (((uint8_t * )values )[-1 ] >= size + 2 );
4997
+ ((uint8_t * )values )[-2 ] = 0 ;
4978
4998
for (int i = 0 ; i < size ; i ++ ) {
4979
4999
values -> values [i ] = NULL ;
4980
5000
}
@@ -5047,14 +5067,14 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
5047
5067
assert (keys != NULL );
5048
5068
assert (values != NULL );
5049
5069
assert (Py_TYPE (obj )-> tp_flags & Py_TPFLAGS_MANAGED_DICT );
5050
- int ix = insert_into_dictkeys (keys , name );
5070
+ Py_ssize_t ix = insert_into_dictkeys (keys , name );
5051
5071
if (ix == DKIX_EMPTY ) {
5052
5072
if (value == NULL ) {
5053
5073
PyErr_SetObject (PyExc_AttributeError , name );
5054
5074
return -1 ;
5055
5075
}
5056
5076
#ifdef Py_STATS
5057
- if (shared_keys_usable_size (keys ) > 14 ) {
5077
+ if (shared_keys_usable_size (keys ) == SHARED_KEYS_MAX_SIZE ) {
5058
5078
OBJECT_STAT_INC (dict_materialized_too_big );
5059
5079
}
5060
5080
else {
@@ -5077,11 +5097,11 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
5077
5097
PyErr_SetObject (PyExc_AttributeError , name );
5078
5098
return -1 ;
5079
5099
}
5080
- values -> mv_order = (values -> mv_order << 4 ) | ix ;
5100
+ _PyDictValues_AddToInsertionOrder (values , ix ) ;
5081
5101
}
5082
5102
else {
5083
5103
if (value == NULL ) {
5084
- values -> mv_order = delete_index_from_order (values -> mv_order , ix );
5104
+ delete_index_from_values (values , ix );
5085
5105
}
5086
5106
Py_DECREF (old_value );
5087
5107
}
0 commit comments