@@ -1214,7 +1214,7 @@ After resizing a table is always combined,
12141214but can be resplit by make_keys_shared().
12151215*/
12161216static int
1217- dictresize (PyDictObject * mp , Py_ssize_t minused )
1217+ dictresize (PyDictObject * mp , Py_ssize_t minsize )
12181218{
12191219 Py_ssize_t newsize , numentries ;
12201220 PyDictKeysObject * oldkeys ;
@@ -1223,7 +1223,7 @@ dictresize(PyDictObject *mp, Py_ssize_t minused)
12231223
12241224 /* Find the smallest table size > minused. */
12251225 for (newsize = PyDict_MINSIZE ;
1226- newsize <= minused && newsize > 0 ;
1226+ newsize < minsize && newsize > 0 ;
12271227 newsize <<= 1 )
12281228 ;
12291229 if (newsize <= 0 ) {
@@ -1244,6 +1244,8 @@ dictresize(PyDictObject *mp, Py_ssize_t minused)
12441244 mp -> ma_keys = oldkeys ;
12451245 return -1 ;
12461246 }
1247+ // New table must be large enough.
1248+ assert (mp -> ma_keys -> dk_usable >= mp -> ma_used );
12471249 if (oldkeys -> dk_lookup == lookdict )
12481250 mp -> ma_keys -> dk_lookup = lookdict ;
12491251
@@ -4270,10 +4272,25 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
42704272 CACHED_KEYS (tp ) = NULL ;
42714273 DK_DECREF (cached );
42724274 }
4273- } else {
4275+ }
4276+ else {
4277+ int was_shared = cached == ((PyDictObject * )dict )-> ma_keys ;
42744278 res = PyDict_SetItem (dict , key , value );
4275- if (cached != ((PyDictObject * )dict )-> ma_keys ) {
4276- /* Either update tp->ht_cached_keys or delete it */
4279+ if (was_shared && cached != ((PyDictObject * )dict )-> ma_keys ) {
4280+ /* PyDict_SetItem() may call dictresize and convert split table
4281+ * into combined table. In such case, convert it to split
4282+ * table again and update type's shared key only when this is
4283+ * the only dict sharing key with the type.
4284+ *
4285+ * This is to allow using shared key in class like this:
4286+ *
4287+ * class C:
4288+ * def __init__(self):
4289+ * # one dict resize happens
4290+ * self.a, self.b, self.c = 1, 2, 3
4291+ * self.d, self.e, self.f = 4, 5, 6
4292+ * a = C()
4293+ */
42774294 if (cached -> dk_refcnt == 1 ) {
42784295 CACHED_KEYS (tp ) = make_keys_shared (dict );
42794296 }
0 commit comments