Refactored the update_slot() code a bit to be hopefully slightly more
efficient:

- recurse down subclasses only once rather than for each affected
  slot;

- short-circuit recursing down subclasses when a subclass has its own
  definition of the name that caused the update_slot() calls in the
  first place;

- inline collect_ptrs().
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 901d026..363c562 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3764,54 +3764,56 @@
 	return (void **)ptr;
 }
 
-staticforward int recurse_down_subclasses(PyTypeObject *type, slotdef *p);
+staticforward int recurse_down_subclasses(PyTypeObject *type,
+					  slotdef **pp, PyObject *name);
 
 static int
-update_one_slot(PyTypeObject *type, slotdef *p0)
+update_these_slots(PyTypeObject *type, slotdef **pp0, PyObject *name)
 {
-	slotdef *p = p0;
-	PyObject *descr;
-	PyWrapperDescrObject *d;
-	void *generic = NULL, *specific = NULL;
-	int use_generic = 0;
-	int offset;
-	void **ptr;
+	slotdef **pp;
 
-	offset = p->offset;
-	ptr = slotptr(type, offset);
-	if (ptr == NULL)
-		return recurse_down_subclasses(type, p);
-	do {
-		descr = _PyType_Lookup(type, p->name_strobj);
-		if (descr == NULL)
+	for (pp = pp0; *pp; pp++) {
+		slotdef *p = *pp;
+		PyObject *descr;
+		PyWrapperDescrObject *d;
+		void *generic = NULL, *specific = NULL;
+		int use_generic = 0;
+		int offset = p->offset;
+		void **ptr = slotptr(type, offset);
+		if (ptr == NULL)
 			continue;
-		generic = p->function;
-		if (descr->ob_type == &PyWrapperDescr_Type) {
-			d = (PyWrapperDescrObject *)descr;
-			if (d->d_base->wrapper == p->wrapper &&
-			    PyType_IsSubtype(type, d->d_type)) {
-				if (specific == NULL ||
-				    specific == d->d_wrapped)
-					specific = d->d_wrapped;
-				else
-					use_generic = 1;
+		do {
+			descr = _PyType_Lookup(type, p->name_strobj);
+			if (descr == NULL)
+				continue;
+			generic = p->function;
+			if (descr->ob_type == &PyWrapperDescr_Type) {
+				d = (PyWrapperDescrObject *)descr;
+				if (d->d_base->wrapper == p->wrapper &&
+				    PyType_IsSubtype(type, d->d_type)) {
+					if (specific == NULL ||
+					    specific == d->d_wrapped)
+						specific = d->d_wrapped;
+					else
+						use_generic = 1;
+				}
 			}
-		}
+			else
+				use_generic = 1;
+		} while ((++p)->offset == offset);
+		if (specific && !use_generic)
+			*ptr = specific;
 		else
-			use_generic = 1;
-	} while ((++p)->offset == offset);
-	if (specific && !use_generic)
-		*ptr = specific;
-	else
-		*ptr = generic;
-	return recurse_down_subclasses(type, p0);
+			*ptr = generic;
+	}
+	return recurse_down_subclasses(type, pp0, name);
 }
 
 static int
-recurse_down_subclasses(PyTypeObject *type, slotdef *p)
+recurse_down_subclasses(PyTypeObject *type, slotdef **pp, PyObject *name)
 {
 	PyTypeObject *subclass;
-	PyObject *ref, *subclasses;
+	PyObject *ref, *subclasses, *dict;
 	int i, n;
 
 	subclasses = type->tp_subclasses;
@@ -3826,7 +3828,12 @@
 		if (subclass == NULL)
 			continue;
 		assert(PyType_Check(subclass));
-		if (update_one_slot(subclass, p) < 0)
+		/* Avoid recursing down into unaffected classes */
+		dict = subclass->tp_dict;
+		if (dict != NULL && PyDict_Check(dict) &&
+		    PyDict_GetItem(dict, name) != NULL)
+			continue;
+		if (update_these_slots(subclass, pp, name) < 0)
 			return -1;
 	}
 	return 0;
@@ -3856,39 +3863,35 @@
 		if (!p->name_strobj)
 			Py_FatalError("XXX ouch");
 	}
-	qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef), slotdef_cmp);
+	qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),
+	      slotdef_cmp);
 	initialized = 1;
 }
 
-static void
-collect_ptrs(PyObject *name, slotdef *ptrs[])
-{
-	slotdef *p;
-
-	init_slotdefs();
-	for (p = slotdefs; p->name; p++) {
-		if (name == p->name_strobj)
-			*ptrs++ = p;
-	}
-	*ptrs = NULL;
-}
-
 static int
 update_slot(PyTypeObject *type, PyObject *name)
 {
 	slotdef *ptrs[10];
 	slotdef *p;
 	slotdef **pp;
+	int offset;
 
-	collect_ptrs(name, ptrs);
+	init_slotdefs();
+	pp = ptrs;
+	for (p = slotdefs; p->name; p++) {
+		/* XXX assume name is interned! */
+		if (p->name_strobj == name)
+			*pp++ = p;
+	}
+	*pp = NULL;
 	for (pp = ptrs; *pp; pp++) {
 		p = *pp;
-		while (p > slotdefs && p->offset == (p-1)->offset)
+		offset = p->offset;
+		while (p > slotdefs && (p-1)->offset == offset)
 			--p;
-		if (update_one_slot(type, p) < 0)
-			return -1;
+		*pp = p;
 	}
-	return 0;
+	return update_these_slots(type, ptrs, name);
 }
 
 static void
@@ -3921,7 +3924,8 @@
 		do {
 			descr = NULL;
 			for (i = 0; i < n; i++) {
-				base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);
+				base = (PyTypeObject *)
+					PyTuple_GET_ITEM(mro, i);
 				assert(PyType_Check(base));
 				descr = PyDict_GetItem(
 					base->tp_dict, p->name_strobj);