@@ -11,7 +11,7 @@ extern "C" {
11
11
12
12
#include "pycore_freelist.h" // _PyFreeListState
13
13
#include "pycore_identifier.h" // _Py_Identifier
14
- #include "pycore_object.h" // PyDictOrValues
14
+ #include "pycore_object.h" // PyManagedDictPointer
15
15
16
16
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
17
17
extern PyObject * _PyDict_GetItemWithError (PyObject * dp , PyObject * key );
@@ -181,6 +181,10 @@ struct _dictkeysobject {
181
181
* [-1] = prefix size. [-2] = used size. size[-2-n...] = insertion order.
182
182
*/
183
183
struct _dictvalues {
184
+ uint8_t capacity ;
185
+ uint8_t size ;
186
+ uint8_t embedded ;
187
+ uint8_t valid ;
184
188
PyObject * values [1 ];
185
189
};
186
190
@@ -196,6 +200,7 @@ static inline void* _DK_ENTRIES(PyDictKeysObject *dk) {
196
200
size_t index = (size_t )1 << dk -> dk_log2_index_bytes ;
197
201
return (& indices [index ]);
198
202
}
203
+
199
204
static inline PyDictKeyEntry * DK_ENTRIES (PyDictKeysObject * dk ) {
200
205
assert (dk -> dk_kind == DICT_KEYS_GENERAL );
201
206
return (PyDictKeyEntry * )_DK_ENTRIES (dk );
@@ -211,9 +216,6 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) {
211
216
#define DICT_WATCHER_MASK ((1 << DICT_MAX_WATCHERS) - 1)
212
217
#define DICT_WATCHER_AND_MODIFICATION_MASK ((1 << (DICT_MAX_WATCHERS + DICT_WATCHED_MUTATION_BITS)) - 1)
213
218
214
- #define DICT_VALUES_SIZE (values ) ((uint8_t *)values)[-1]
215
- #define DICT_VALUES_USED_SIZE (values ) ((uint8_t *)values)[-2]
216
-
217
219
#ifdef Py_GIL_DISABLED
218
220
#define DICT_NEXT_VERSION (INTERP ) \
219
221
(_Py_atomic_add_uint64(&(INTERP)->dict_state.global_version, DICT_VERSION_INCREMENT) + DICT_VERSION_INCREMENT)
@@ -246,25 +248,63 @@ _PyDict_NotifyEvent(PyInterpreterState *interp,
246
248
return DICT_NEXT_VERSION (interp ) | (mp -> ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK );
247
249
}
248
250
249
- extern PyObject * _PyObject_MakeDictFromInstanceAttributes (PyObject * obj , PyDictValues * values );
250
- PyAPI_FUNC ( bool ) _PyObject_MakeInstanceAttributesFromDict ( PyObject * obj , PyDictOrValues * dorv );
251
+ extern PyDictObject * _PyObject_MakeDictFromInstanceAttributes (PyObject * obj );
252
+
251
253
PyAPI_FUNC (PyObject * )_PyDict_FromItems (
252
254
PyObject * const * keys , Py_ssize_t keys_offset ,
253
255
PyObject * const * values , Py_ssize_t values_offset ,
254
256
Py_ssize_t length );
255
257
258
+ static inline uint8_t *
259
+ get_insertion_order_array (PyDictValues * values )
260
+ {
261
+ return (uint8_t * )& values -> values [values -> capacity ];
262
+ }
263
+
256
264
static inline void
257
265
_PyDictValues_AddToInsertionOrder (PyDictValues * values , Py_ssize_t ix )
258
266
{
259
267
assert (ix < SHARED_KEYS_MAX_SIZE );
260
- uint8_t * size_ptr = ((uint8_t * )values )- 2 ;
261
- int size = * size_ptr ;
262
- assert (size + 2 < DICT_VALUES_SIZE (values ));
263
- size ++ ;
264
- size_ptr [- size ] = (uint8_t )ix ;
265
- * size_ptr = size ;
268
+ int size = values -> size ;
269
+ uint8_t * array = get_insertion_order_array (values );
270
+ assert (size < values -> capacity );
271
+ assert (((uint8_t )ix ) == ix );
272
+ array [size ] = (uint8_t )ix ;
273
+ values -> size = size + 1 ;
274
+ }
275
+
276
+ static inline size_t
277
+ shared_keys_usable_size (PyDictKeysObject * keys )
278
+ {
279
+ #ifdef Py_GIL_DISABLED
280
+ // dk_usable will decrease for each instance that is created and each
281
+ // value that is added. dk_nentries will increase for each value that
282
+ // is added. We want to always return the right value or larger.
283
+ // We therefore increase dk_nentries first and we decrease dk_usable
284
+ // second, and conversely here we read dk_usable first and dk_entries
285
+ // second (to avoid the case where we read entries before the increment
286
+ // and read usable after the decrement)
287
+ return (size_t )(_Py_atomic_load_ssize_acquire (& keys -> dk_usable ) +
288
+ _Py_atomic_load_ssize_acquire (& keys -> dk_nentries ));
289
+ #else
290
+ return (size_t )keys -> dk_nentries + (size_t )keys -> dk_usable ;
291
+ #endif
266
292
}
267
293
294
+ static inline size_t
295
+ _PyInlineValuesSize (PyTypeObject * tp )
296
+ {
297
+ PyDictKeysObject * keys = ((PyHeapTypeObject * )tp )-> ht_cached_keys ;
298
+ assert (keys != NULL );
299
+ size_t size = shared_keys_usable_size (keys );
300
+ size_t prefix_size = _Py_SIZE_ROUND_UP (size , sizeof (PyObject * ));
301
+ assert (prefix_size < 256 );
302
+ return prefix_size + (size + 1 ) * sizeof (PyObject * );
303
+ }
304
+
305
+ int
306
+ _PyDict_DetachFromObject (PyDictObject * dict , PyObject * obj );
307
+
268
308
#ifdef __cplusplus
269
309
}
270
310
#endif
0 commit comments