Handing threading race resolving methods.

- Don't prune the extension registry as that can lead to failures when two
  threads are racing.
- If adding the method fails, check and see if it already is bound to decide
  the return result. Deals with threading races binding the methods.
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 9660f1e..58a10fd 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -3152,8 +3152,17 @@
   if (result.impToAdd) {
     const char *encoding =
         GPBMessageEncodingForSelector(result.encodingSelector, YES);
-    BOOL methodAdded = class_addMethod(descriptor.messageClass, sel,
-                                       result.impToAdd, encoding);
+    Class msgClass = descriptor.messageClass;
+    BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
+    // class_addMethod() is documented as also failing if the method was already
+    // added; so we check if the method is already there and return success so
+    // the method dispatch will still happen.  Why would it already be added?
+    // Two threads could cause the same method to be bound at the same time,
+    // but only one will actually bind it; the other still needs to return true
+    // so things will dispatch.
+    if (!methodAdded) {
+      methodAdded = GPBClassHasSel(msgClass, sel);
+    }
     return methodAdded;
   }
   return [super resolveInstanceMethod:sel];
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m
index 4570716..585d205 100644
--- a/objectivec/GPBRootObject.m
+++ b/objectivec/GPBRootObject.m
@@ -184,11 +184,10 @@
   dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
                           DISPATCH_TIME_FOREVER);
   id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
-  if (extension) {
-    // The method is getting wired in to the class, so no need to keep it in
-    // the dictionary.
-    CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
-  }
+  // We can't remove the key from the dictionary here (as an optimization),
+  // two threads could have gone into +resolveClassMethod: for the same method,
+  // and ended up here; there's no way to ensure both return YES without letting
+  // both try to wire in the method.
   dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
   return extension;
 }
@@ -212,9 +211,17 @@
 #pragma unused(obj)
       return extension;
     });
-    if (class_addMethod(metaClass, sel, imp, encoding)) {
-      return YES;
+    BOOL methodAdded = class_addMethod(metaClass, sel, imp, encoding);
+    // class_addMethod() is documented as also failing if the method was already
+    // added; so we check if the method is already there and return success so
+    // the method dispatch will still happen.  Why would it already be added?
+    // Two threads could cause the same method to be bound at the same time,
+    // but only one will actually bind it; the other still needs to return true
+    // so things will dispatch.
+    if (!methodAdded) {
+      methodAdded = GPBClassHasSel(metaClass, sel);
     }
+    return methodAdded;
   }
   return NO;
 }
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 1843478..5029ec7 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -1893,6 +1893,25 @@
 
 #pragma clang diagnostic pop
 
+BOOL GPBClassHasSel(Class aClass, SEL sel) {
+  // NOTE: We have to use class_copyMethodList, all other runtime method
+  // lookups actually also resolve the method implementation and this
+  // is called from within those methods.
+
+  BOOL result = NO;
+  unsigned int methodCount = 0;
+  Method *methodList = class_copyMethodList(aClass, &methodCount);
+  for (unsigned int i = 0; i < methodCount; ++i) {
+    SEL methodSelector = method_getName(methodList[i]);
+    if (methodSelector == sel) {
+      result = YES;
+      break;
+    }
+  }
+  free(methodList);
+  return result;
+}
+
 #pragma mark - GPBMessageSignatureProtocol
 
 // A series of selectors that are used solely to get @encoding values
diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h
index 274351b..16859d4 100644
--- a/objectivec/GPBUtilities_PackagePrivate.h
+++ b/objectivec/GPBUtilities_PackagePrivate.h
@@ -345,4 +345,6 @@
 + (id)getClassValue;
 @end
 
+BOOL GPBClassHasSel(Class aClass, SEL sel);
+
 CF_EXTERN_C_END