@@ -3120,6 +3120,18 @@ clear_embedded_values(PyDictValues *values, Py_ssize_t nentries)
31203120 }
31213121}
31223122
3123+ // This function is used in both `PyDict_Clear`
3124+ // and `PyDict_AsFrozenDictAndClear`, place all the common parts here.
3125+ static void
3126+ clear_common (PyDictObject * mp )
3127+ {
3128+ /* Empty the dict... */
3129+ _PyDict_NotifyEvent (PyDict_EVENT_CLEARED , mp , NULL , NULL );
3130+ // We don't inc ref empty keys because they're immortal
3131+ ensure_shared_on_resize (mp );
3132+ STORE_USED (mp , 0 );
3133+ }
3134+
31233135static void
31243136clear_lock_held (PyObject * op )
31253137{
@@ -3138,11 +3150,7 @@ clear_lock_held(PyObject *op)
31383150 if (oldkeys == Py_EMPTY_KEYS ) {
31393151 return ;
31403152 }
3141- /* Empty the dict... */
3142- _PyDict_NotifyEvent (PyDict_EVENT_CLEARED , mp , NULL , NULL );
3143- // We don't inc ref empty keys because they're immortal
3144- ensure_shared_on_resize (mp );
3145- STORE_USED (mp , 0 );
3153+ clear_common (mp );
31463154 if (oldvalues == NULL ) {
31473155 set_keys (mp , Py_EMPTY_KEYS );
31483156 assert (oldkeys -> dk_refcnt == 1 );
@@ -8521,6 +8529,50 @@ frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
85218529 return d ;
85228530}
85238531
8532+ static void
8533+ transfer_keys_and_values_lock_held (PyObject * res , PyObject * dict )
8534+ {
8535+
8536+ PyDictObject * new = (PyDictObject * )res ;
8537+ PyDictObject * old = (PyDictObject * )dict ;
8538+ // Fast path: do nothing on an empty dict:
8539+ if (old -> ma_keys == Py_EMPTY_KEYS ) {
8540+ return ;
8541+ }
8542+
8543+ // Transfer keys and values from dict to res:
8544+ STORE_USED (new , old -> ma_used );
8545+ set_keys (new , old -> ma_keys );
8546+ set_values (new , old -> ma_values );
8547+ ASSERT_CONSISTENT (new );
8548+
8549+ // Now, clear the old dict keys and values, but do not decref them:
8550+ clear_common ((PyDictObject * )dict );
8551+ set_keys (old , Py_EMPTY_KEYS );
8552+ set_values (old , NULL );
8553+ ASSERT_CONSISTENT (dict );
8554+ }
8555+
8556+ PyObject *
8557+ PyDict_AsFrozenDictAndClear (PyObject * dict )
8558+ {
8559+ assert (dict != NULL );
8560+ assert (PyDict_CheckExact (dict ));
8561+ assert (can_modify_dict ((PyDictObject * )dict ));
8562+ PyObject * res = frozendict_new_untracked (& PyFrozenDict_Type );
8563+ if (res == NULL ) {
8564+ return NULL ;
8565+ }
8566+
8567+ Py_BEGIN_CRITICAL_SECTION (dict );
8568+ transfer_keys_and_values_lock_held (res , dict );
8569+ Py_END_CRITICAL_SECTION ();
8570+
8571+ _PyObject_GC_TRACK (res );
8572+ assert (_PyFrozenDictObject_CAST (res )-> ma_hash == -1 );
8573+ return res ;
8574+ }
8575+
85248576
85258577PyObject *
85268578PyFrozenDict_New (PyObject * iterable )
0 commit comments