Extend work on revision 52962:  Eliminate redundant calls to PyObject_Hash().
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 901e333..1cb3ee6 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -803,6 +803,34 @@
 	return 1;
 }
 
+/* Internal version of PyDict_Next that returns a hash value in addition to the key and value.*/
+int
+_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue, long *phash)
+{
+	register Py_ssize_t i;
+	register Py_ssize_t mask;
+	register dictentry *ep;
+
+	if (!PyDict_Check(op))
+		return 0;
+	i = *ppos;
+	if (i < 0)
+		return 0;
+	ep = ((dictobject *)op)->ma_table;
+	mask = ((dictobject *)op)->ma_mask;
+	while (i <= mask && ep[i].me_value == NULL)
+		i++;
+	*ppos = i+1;
+	if (i > mask)
+		return 0;
+        *phash = (long)(ep[i].me_hash);
+	if (pkey)
+		*pkey = ep[i].me_key;
+	if (pvalue)
+		*pvalue = ep[i].me_value;
+	return 1;
+}
+
 /* Methods */
 
 static void
@@ -1987,6 +2015,17 @@
 	return ep == NULL ? -1 : (ep->me_value != NULL);
 }
 
+/* Internal version of PyDict_Contains used when the hash value is already known */
+int
+_PyDict_Contains(PyObject *op, PyObject *key, long hash)
+{
+	dictobject *mp = (dictobject *)op;
+	dictentry *ep;
+
+	ep = (mp->ma_lookup)(mp, key, hash);
+	return ep == NULL ? -1 : (ep->me_value != NULL);
+}
+
 /* Hack to implement "key in dict" */
 static PySequenceMethods dict_as_sequence = {
 	0,			/* sq_length */
diff --git a/Objects/setobject.c b/Objects/setobject.c
index fc9d823..1f06cee 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -918,8 +918,14 @@
 	if (PyDict_CheckExact(other)) {
 		PyObject *value;
 		Py_ssize_t pos = 0;
-		while (PyDict_Next(other, &pos, &key, &value)) {
-			if (set_add_key(so, key) == -1)
+		long hash;
+
+		while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
+			setentry an_entry;
+
+			an_entry.hash = hash;
+			an_entry.key = key;
+			if (set_add_entry(so, &an_entry) == -1)
 				return -1;
 		}
 		return 0;
@@ -1382,7 +1388,7 @@
 			setentry entrycopy;
 			entrycopy.hash = entry->hash;
 			entrycopy.key = entry->key;
-			if (!PyDict_Contains(other, entry->key)) {
+			if (!_PyDict_Contains(other, entry->key, entry->hash)) {
 				if (set_add_entry((PySetObject *)result, &entrycopy) == -1) {
 					Py_DECREF(result);
 					return NULL;
@@ -1453,12 +1459,10 @@
 	if (PyDict_CheckExact(other)) {
 		PyObject *value;
 		int rv;
-		while (PyDict_Next(other, &pos, &key, &value)) {
+		long hash;
+		while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
 			setentry an_entry;
-			long hash = PyObject_Hash(key);
 
-			if (hash == -1)
-				return NULL;
 			an_entry.hash = hash;
 			an_entry.key = key;
 			rv = set_discard_entry(so, &an_entry);