Objective C Second Alpha Drop

- Style fixups in the code.
- map<> serialization fixes and more tests.
- Autocreation of map<> fields (to match repeated fields).
- @@protoc_insertion_point(global_scope|imports).
- Fixup proto2 syntax extension support.
- Move all startup code to +initialize so it happen on class usage and not app startup.
- Have generated headers use forward declarations and move imports into generated code, reduces what is need at compile time to speed up compiled and avoid pointless rippling of rebuilds.
diff --git a/Makefile.am b/Makefile.am
index eecffa1..22a4274 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -198,9 +198,10 @@
   javanano/pom.xml
 
 objectivec_EXTRA_DIST=                                                       \
-  objectivec/DevTools/generate_descriptors_proto.sh                          \
+  objectivec/DevTools/check_version_stamps.sh                                \
   objectivec/DevTools/pddm.py                                                \
   objectivec/DevTools/pddm_tests.py                                          \
+  objectivec/generate_descriptors_proto.sh                                   \
   objectivec/google/protobuf/Descriptor.pbobjc.h                             \
   objectivec/google/protobuf/Descriptor.pbobjc.m                             \
   objectivec/google/protobuf/Duration.pbobjc.h                               \
@@ -227,7 +228,6 @@
   objectivec/GPBExtensionField_PackagePrivate.h                              \
   objectivec/GPBExtensionRegistry.h                                          \
   objectivec/GPBExtensionRegistry.m                                          \
-  objectivec/GPBExtensionRegistry_PackagePrivate.h                           \
   objectivec/GPBField.h                                                      \
   objectivec/GPBField.m                                                      \
   objectivec/GPBField_PackagePrivate.h                                       \
diff --git a/configure.ac b/configure.ac
index 0615cd8..8338c18 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
 AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
 case "$DIST_LANG" in
   "") DIST_LANG=all ;;
-  all | cpp | java | python | javanano | ruby) ;;
+  all | cpp | java | python | javanano | objectivec | ruby) ;;
   *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
 esac
 AC_SUBST(DIST_LANG)
diff --git a/objectivec/DevTools/check_version_stamps.sh b/objectivec/DevTools/check_version_stamps.sh
index 7fc4426..325b71d 100755
--- a/objectivec/DevTools/check_version_stamps.sh
+++ b/objectivec/DevTools/check_version_stamps.sh
@@ -29,7 +29,7 @@
 )
 
 if [[ -z "${PluginVersion}" ]] ; then
-    die "Failed to fine ${ConstantName} in the plugin source (${PluginSrc})."
+    die "Failed to find ${ConstantName} in the plugin source (${PluginSrc})."
 fi
 
 # Collect version from runtime sources.
@@ -41,7 +41,7 @@
 )
 
 if [[ -z "${RuntimeVersion}" ]] ; then
-    die "Failed to fine ${ConstantName} in the runtime source (${RuntimeSrc})."
+    die "Failed to find ${ConstantName} in the runtime source (${RuntimeSrc})."
 fi
 
 # Compare them.
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
new file mode 100755
index 0000000..57c4f43
--- /dev/null
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -0,0 +1,228 @@
+#!/bin/bash
+#
+# Helper to do build so you don't have to remember all the steps/args.
+
+
+set -eu
+
+# Some base locations.
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/../.."
+
+printUsage() {
+  NAME=$(basename "${0}")
+  cat << EOF
+usage: ${NAME} [OPTIONS]
+
+This script does the common build steps needed.
+
+OPTIONS:
+
+ General:
+
+   -h, --help
+         Show this message
+   -c, --clean
+         Issue a clean before the normal build.
+   -a, --autogen
+         Start by rerunning autogen & configure.
+   -r, --regenerate-descriptors
+         The descriptor.proto is checked in generated, cause it to regenerate.
+   -j #, --jobs #
+         Force the number of parallel jobs (useful for debugging build issues).
+   --skip-xcode
+         Skip the invoke of Xcode to test the runtime on both iOS and OS X.
+   --skip-xcode-ios
+         Skip the invoke of Xcode to test the runtime on iOS.
+   --skip-xcode-osx
+         Skip the invoke of Xcode to test the runtime on OS X.
+
+EOF
+}
+
+header() {
+  echo ""
+  echo "========================================================================"
+  echo "    ${@}"
+  echo "========================================================================"
+}
+
+# Thanks to libtool, builds can fail in odd ways and since it eats some output
+# it can be hard to spot, so force error output if make exits with a non zero.
+wrapped_make() {
+  set +e  # Don't stop if the command fails.
+  make $*
+  MAKE_EXIT_STATUS=$?
+  if [ ${MAKE_EXIT_STATUS} -ne 0 ]; then
+    echo "Error: 'make $*' exited with status ${MAKE_EXIT_STATUS}"
+    exit ${MAKE_EXIT_STATUS}
+  fi
+  set -e
+}
+
+NUM_MAKE_JOBS=$(/usr/sbin/sysctl -n hw.ncpu)
+if [[ "${NUM_MAKE_JOBS}" -lt 4 ]] ; then
+  NUM_MAKE_JOBS=4
+fi
+
+DO_AUTOGEN=no
+DO_CLEAN=no
+REGEN_CPP_DESCRIPTORS=no
+DO_XCODE_IOS_TESTS=yes
+DO_XCODE_OSX_TESTS=yes
+while [[ $# != 0 ]]; do
+  case "${1}" in
+    -h | --help )
+      printUsage
+      exit 0
+      ;;
+    -c | --clean )
+      DO_CLEAN=yes
+      ;;
+    -a | --autogen )
+      DO_AUTOGEN=yes
+      ;;
+    -r | --regenerate-cpp-descriptors )
+      REGEN_CPP_DESCRIPTORS=yes
+      ;;
+    -j | --jobs )
+      shift
+      NUM_MAKE_JOBS="${1}"
+      ;;
+    --skip-xcode )
+      DO_XCODE_IOS_TESTS=no
+      DO_XCODE_OSX_TESTS=no
+      ;;
+    --skip-xcode-ios )
+      DO_XCODE_IOS_TESTS=no
+      ;;
+    --skip-xcode-osx )
+      DO_XCODE_OSX_TESTS=no
+      ;;
+    -*)
+      echo "ERROR: Unknown option: ${1}" 1>&2
+      printUsage
+      exit 1
+      ;;
+    *)
+      echo "ERROR: Unknown argument: ${1}" 1>&2
+      printUsage
+      exit 1
+      ;;
+  esac
+  shift
+done
+
+# Into the proto dir.
+pushd "${ProtoRootDir}"
+
+# if no Makefile, force the autogen.
+if [[ ! -f Makefile ]] ; then
+  DO_AUTOGEN=yes
+fi
+
+if [[ "${DO_AUTOGEN}" == "yes" ]] ; then
+  header "Running autogen & configure"
+  ./autogen.sh
+  ./configure CXXFLAGS="-mmacosx-version-min=10.9 -Wnon-virtual-dtor -Woverloaded-virtual -Wunused-const-variable -Wunused-function"
+fi
+
+if [[ "${DO_CLEAN}" == "yes" ]] ; then
+  header "Cleaning"
+  wrapped_make clean
+  if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
+    XCODEBUILD_CLEAN_BASE_IOS=(
+      xcodebuild
+        -project objectivec/ProtocolBuffers_iOS.xcodeproj
+        -scheme ProtocolBuffers
+    )
+  "${XCODEBUILD_CLEAN_BASE_IOS[@]}" -configuration Debug clean
+  "${XCODEBUILD_CLEAN_BASE_IOS[@]}" -configuration Release clean
+  fi
+  if [[ "${DO_XCODE_OSX_TESTS}" == "yes" ]] ; then
+    XCODEBUILD_CLEAN_BASE_OSX=(
+      xcodebuild
+        -project objectivec/ProtocolBuffers_OSX.xcodeproj
+        -scheme ProtocolBuffers
+    )
+  "${XCODEBUILD_CLEAN_BASE_OSX[@]}" -configuration Debug clean
+  "${XCODEBUILD_CLEAN_BASE_OSX[@]}" -configuration Release clean
+  fi
+fi
+
+if [[ "${REGEN_CPP_DESCRIPTORS}" == "yes" ]] ; then
+  header "Regenerating the C++ descriptor sources."
+  ./generate_descriptor_proto.sh -j "${NUM_MAKE_JOBS}"
+fi
+
+header "Building"
+# Can't issue these together, when fully parallel, something sometimes chokes
+# at random.
+wrapped_make -j "${NUM_MAKE_JOBS}" all
+wrapped_make -j "${NUM_MAKE_JOBS}" check
+
+header "Ensuring the ObjC descriptors are current."
+# Find the newest input file (protos, compiler, and this script).
+# (these patterns catch some extra stuff, but better to over sample than under)
+readonly NewestInput=$(find \
+   src/google/protobuf/*.proto \
+   src/.libs src/*.la src/protoc \
+   objectivec/generate_descriptors_proto.sh \
+      -type f -print0 \
+      | xargs -0 stat -f "%m %N" \
+      | sort -n | tail -n1 | cut -f2- -d" ")
+# Find the oldest output file.
+readonly OldestOutput=$(find \
+      "${ProtoRootDir}/objectivec/google" \
+      -type f -print0 \
+      | xargs -0 stat -f "%m %N" \
+      | sort -n -r | tail -n1 | cut -f2- -d" ")
+# If the newest input is newer than the oldest output, regenerate.
+if [[ "${NewestInput}" -nt "${OldestOutput}" ]] ; then
+  echo ">> Newest input is newer than oldest output, regenerating."
+  objectivec/generate_descriptors_proto.sh -j "${NUM_MAKE_JOBS}"
+else
+  echo ">> Newest input is older than oldest output, no need to regenerating."
+fi
+
+header "Checking on the ObjC Runtime Code"
+objectivec/DevTools/pddm_tests.py
+if ! objectivec/DevTools/pddm.py --dry-run objectivec/*.[hm] objectivec/Tests/*.[hm] ; then
+  echo ""
+  echo "Update by running:"
+  echo "   objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]"
+  exit 1
+fi
+
+if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
+  XCODEBUILD_TEST_BASE_IOS=(
+    xcodebuild
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj
+      -scheme ProtocolBuffers
+      # Don't need to worry about form factors or retina/non retina;
+      # just pick a mix of OS Versions and 32/64 bit.
+      -destination "platform=iOS Simulator,name=iPhone 4s,OS=7.1" # 32bit
+      -destination "platform=iOS Simulator,name=iPhone 6,OS=8.3" # 64bit
+      -destination "platform=iOS Simulator,name=iPad 2,OS=7.1" # 32bit
+      -destination "platform=iOS Simulator,name=iPad Air,OS=8.3" # 64bit
+  )
+  header "Doing Xcode iOS build/tests - Debug"
+  "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Debug test
+  header "Doing Xcode iOS build/tests - Release"
+  "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Release test
+  # Don't leave the simulator in the developer's face.
+  killall "iOS Simulator"
+fi
+if [[ "${DO_XCODE_OSX_TESTS}" == "yes" ]] ; then
+  XCODEBUILD_TEST_BASE_OSX=(
+    xcodebuild
+      -project objectivec/ProtocolBuffers_OSX.xcodeproj
+      -scheme ProtocolBuffers
+      # Since the ObjC 2.0 Runtime is required, 32bit OS X isn't supported.
+      -destination "platform=OS X,arch=x86_64" # 64bit
+  )
+  header "Doing Xcode OS X build/tests - Debug"
+  "${XCODEBUILD_TEST_BASE_OSX[@]}" -configuration Debug test
+  header "Doing Xcode OS X build/tests - Release"
+  "${XCODEBUILD_TEST_BASE_OSX[@]}" -configuration Release test
+fi
diff --git a/objectivec/DevTools/generate_descriptors_proto.sh b/objectivec/DevTools/generate_descriptors_proto.sh
deleted file mode 100755
index 42502bf..0000000
--- a/objectivec/DevTools/generate_descriptors_proto.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-# This script will generate the common descriptors needed by the Objective C
-# runtime.
-
-# HINT:  Flags passed to generate_descriptor_proto.sh will be passed directly
-#   to make when building protoc.  This is particularly useful for passing
-#   -j4 to run 4 jobs simultaneously.
-
-set -eu
-
-readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
-readonly ProtoRootDir="${ScriptDir}/../.."
-readonly ProtoC="${ProtoRootDir}/src/protoc"
-
-pushd "${ProtoRootDir}" > /dev/null
-
-# Compiler build fails if config.h hasn't been made yet (even if configure/etc.
-# have been run, so get that made first).
-make $@ config.h
-
-# Make sure the compiler is current.
-cd src
-make $@ protoc
-
-# These really should only be run when the inputs or compiler are newer than
-# the outputs.
-
-# Needed by the runtime.
-./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/descriptor.proto
-
-# Well known types that the library provides helpers for.
-./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/timestamp.proto
-./protoc --objc_out="${ProtoRootDir}/objectivec" google/protobuf/duration.proto
-
-popd > /dev/null
diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m
index 6aa3df2..60b08ad 100644
--- a/objectivec/GPBArray.m
+++ b/objectivec/GPBArray.m
@@ -149,7 +149,9 @@
 
 //%PDDM-DEFINE ARRAY_IMMUTABLE_CORE(NAME, TYPE, ACCESSOR_NAME, FORMAT)
 //%- (void)dealloc {
-//%  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
 //%  free(_values);
 //%  [super dealloc];
 //%}
@@ -214,7 +216,7 @@
 //%  if (values == NULL || count == 0) return;
 //%MUTATION_HOOK_##HOOK_1()  NSUInteger initialCount = _count;
 //%  NSUInteger newCount = initialCount + count;
-//%MAYBE_GROW_TO_SET_COUNT(newCount);
+//%MAYBE_GROW_TO_SET_COUNT(newCount)
 //%  memcpy(&_values[initialCount], values, count * sizeof(TYPE));
 //%  if (_autocreator) {
 //%    GPBAutocreatedArrayModified(_autocreator, self);
@@ -225,7 +227,7 @@
 //%VALIDATE_RANGE(index, _count + 1)
 //%MUTATION_HOOK_##HOOK_2()  NSUInteger initialCount = _count;
 //%  NSUInteger newCount = initialCount + 1;
-//%MAYBE_GROW_TO_SET_COUNT(newCount);
+//%MAYBE_GROW_TO_SET_COUNT(newCount)
 //%  if (index != initialCount) {
 //%    memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(TYPE));
 //%  }
@@ -355,7 +357,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -442,7 +446,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(int32_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -460,7 +464,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
   }
@@ -598,7 +602,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -685,7 +691,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(uint32_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -703,7 +709,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint32_t));
   }
@@ -841,7 +847,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -928,7 +936,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(int64_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -946,7 +954,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int64_t));
   }
@@ -1084,7 +1092,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -1171,7 +1181,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(uint64_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -1189,7 +1199,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(uint64_t));
   }
@@ -1327,7 +1337,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -1414,7 +1426,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(float));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -1432,7 +1444,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(float));
   }
@@ -1570,7 +1582,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -1657,7 +1671,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(double));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -1675,7 +1689,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(double));
   }
@@ -1813,7 +1827,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -1900,7 +1916,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(BOOL));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -1918,7 +1934,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(BOOL));
   }
@@ -2083,7 +2099,9 @@
 // This block of code is generated, do not edit it directly.
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   free(_values);
   [super dealloc];
 }
@@ -2229,7 +2247,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(int32_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -2247,7 +2265,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
   }
@@ -2332,7 +2350,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   memcpy(&_values[initialCount], values, count * sizeof(int32_t));
   if (_autocreator) {
     GPBAutocreatedArrayModified(_autocreator, self);
@@ -2355,7 +2373,7 @@
   if (newCount > _capacity) {
     [self internalResizeToCapacity:CapacityFromCount(newCount)];
   }
-  _count = newCount;;
+  _count = newCount;
   if (index != initialCount) {
     memmove(&_values[index + 1], &_values[index], (initialCount - index) * sizeof(int32_t));
   }
@@ -2407,7 +2425,9 @@
 }
 
 - (void)dealloc {
-  NSAssert(!_autocreator, @"Autocreator must be cleared before release.");
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_array release];
   [super dealloc];
 }
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 530eb5c..3dd2de8 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -51,11 +51,11 @@
 // the Swift bridge will have one where the names line up to support short
 // names since they are scoped to the enum.
 // https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_11
-#define GPB_ENUM(X) enum X##_ : int32_t X; typedef NS_ENUM(int32_t, X##_)
-// GPB_ENUM_FWD_DECLARE is used for forward declaring enums ex:
+#define GPB_ENUM(X) NS_ENUM(int32_t, X)
+// GPB_ENUM_FWD_DECLARE is used for forward declaring enums, ex:
 //   GPB_ENUM_FWD_DECLARE(Foo_Enum)
 //   @property (nonatomic) Foo_Enum value;
-#define GPB_ENUM_FWD_DECLARE(_name) enum _name : int32_t
+#define GPB_ENUM_FWD_DECLARE(X) enum X : int32_t
 
 // Based upon CF_INLINE. Forces inlining in release.
 #if !defined(DEBUG)
diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h
index db39c26..e9b27e2 100644
--- a/objectivec/GPBCodedInputStream.h
+++ b/objectivec/GPBCodedInputStream.h
@@ -66,7 +66,9 @@
 - (void)readMessage:(GPBMessage *)message
     extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
 
-// Reads and discards a single field, given its tag value.
+// Reads and discards a single field, given its tag value. Returns NO if the
+// tag is an endgroup tag, in which case nothing is skipped.  Otherwise,
+// returns YES.
 - (BOOL)skipField:(int32_t)tag;
 
 // Reads and discards an entire message.  This will read either until EOF
@@ -74,8 +76,8 @@
 - (void)skipMessage;
 
 // Verifies that the last call to readTag() returned the given tag value.
-// This is used to verify that a nested group ended with the correct
-// end tag.
+// This is used to verify that a nested group ended with the correct end tag.
+// Throws NSParseErrorException if value does not match the last tag.
 - (void)checkLastTagWas:(int32_t)value;
 
 @end
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index d8c369c..97b46b3 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -56,7 +56,6 @@
 @property(nonatomic, readonly, strong) NSArray *fields;
 @property(nonatomic, readonly, strong) NSArray *oneofs;
 @property(nonatomic, readonly, strong) NSArray *enums;
-@property(nonatomic, readonly, strong) NSArray *extensions;
 @property(nonatomic, readonly) const GPBExtensionRange *extensionRanges;
 @property(nonatomic, readonly) NSUInteger extensionRangesCount;
 @property(nonatomic, readonly, assign) GPBFileDescriptor *file;
@@ -68,8 +67,6 @@
 - (GPBFieldDescriptor *)fieldWithName:(NSString *)name;
 - (GPBOneofDescriptor *)oneofWithName:(NSString *)name;
 - (GPBEnumDescriptor *)enumWithName:(NSString *)name;
-- (GPBFieldDescriptor *)extensionWithNumber:(uint32_t)fieldNumber;
-- (GPBFieldDescriptor *)extensionWithName:(NSString *)name;
 
 @end
 
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
index 6730d53..b955018 100644
--- a/objectivec/GPBDescriptor.m
+++ b/objectivec/GPBDescriptor.m
@@ -93,7 +93,6 @@
 @implementation GPBDescriptor {
   Class messageClass_;
   NSArray *enums_;
-  NSArray *extensions_;
   GPBFileDescriptor *file_;
   BOOL wireFormat_;
 }
@@ -102,7 +101,6 @@
 @synthesize fields = fields_;
 @synthesize oneofs = oneofs_;
 @synthesize enums = enums_;
-@synthesize extensions = extensions_;
 @synthesize extensionRanges = extensionRanges_;
 @synthesize extensionRangesCount = extensionRangesCount_;
 @synthesize file = file_;
@@ -161,13 +159,11 @@
     [enums addObject:enumDescriptor];
   }
 
-  // TODO(dmaclach): Add support for extensions
   GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
                                                      file:file
                                                    fields:fields
                                                    oneofs:oneofs
                                                     enums:enums
-                                               extensions:nil
                                           extensionRanges:ranges
                                      extensionRangesCount:rangeCount
                                               storageSize:storageSize
@@ -226,7 +222,6 @@
                        fields:(NSArray *)fields
                        oneofs:(NSArray *)oneofs
                         enums:(NSArray *)enums
-                   extensions:(NSArray *)extensions
               extensionRanges:(const GPBExtensionRange *)extensionRanges
          extensionRangesCount:(NSUInteger)extensionRangesCount
                   storageSize:(size_t)storageSize
@@ -237,7 +232,6 @@
     fields_ = [fields retain];
     oneofs_ = [oneofs retain];
     enums_ = [enums retain];
-    extensions_ = [extensions retain];
     extensionRanges_ = extensionRanges;
     extensionRangesCount_ = extensionRangesCount;
     storageSize_ = storageSize;
@@ -250,7 +244,6 @@
   [fields_ release];
   [oneofs_ release];
   [enums_ release];
-  [extensions_ release];
   [super dealloc];
 }
 
@@ -299,24 +292,6 @@
   return nil;
 }
 
-- (GPBFieldDescriptor *)extensionWithNumber:(uint32_t)fieldNumber {
-  for (GPBFieldDescriptor *descriptor in extensions_) {
-    if (GPBFieldNumber(descriptor) == fieldNumber) {
-      return descriptor;
-    }
-  }
-  return nil;
-}
-
-- (GPBFieldDescriptor *)extensionWithName:(NSString *)name {
-  for (GPBFieldDescriptor *descriptor in extensions_) {
-    if ([descriptor.name isEqual:name]) {
-      return descriptor;
-    }
-  }
-  return nil;
-}
-
 @end
 
 @implementation GPBFileDescriptor {
@@ -366,7 +341,7 @@
 }
 
 - (NSString *)name {
-  return [NSString stringWithUTF8String:oneofDescription_->name];
+  return @(oneofDescription_->name);
 }
 
 - (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
@@ -455,7 +430,8 @@
                                              freeWhenDone:NO];
         GPBExtensionRegistry *registry = [rootClass extensionRegistry];
         fieldOptions_ = [[GPBFieldOptions parseFromData:optionsData
-                                      extensionRegistry:registry] retain];
+                                      extensionRegistry:registry
+                                                  error:NULL] retain];
       }
     }
 
@@ -532,7 +508,7 @@
 }
 
 - (NSString *)name {
-  return [NSString stringWithUTF8String:description_->name];
+  return @(description_->name);
 }
 
 - (BOOL)isRequired {
@@ -809,7 +785,7 @@
 
   NSString *result = nil;
   // Naming adds an underscore between enum name and value name, skip that also.
-  NSString *shortName = [NSString stringWithUTF8String:valueDescriptor->name];
+  NSString *shortName = @(valueDescriptor->name);
 
   // See if it is in the map of special format handling.
   if (extraTextFormatInfo_) {
@@ -846,7 +822,7 @@
 }
 
 - (NSString *)singletonName {
-  return [NSString stringWithUTF8String:description_->singletonName];
+  return @(description_->singletonName);
 }
 
 - (const char *)singletonNameC {
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
index acb4fe7..b289a48 100644
--- a/objectivec/GPBDescriptor_PackagePrivate.h
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -186,7 +186,6 @@
                        fields:(NSArray *)fields
                        oneofs:(NSArray *)oneofs
                         enums:(NSArray *)enums
-                   extensions:(NSArray *)extensions
               extensionRanges:(const GPBExtensionRange *)ranges
          extensionRangesCount:(NSUInteger)rangeCount
                   storageSize:(size_t)storage
diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m
index de7347e..3769c69 100644
--- a/objectivec/GPBDictionary.m
+++ b/objectivec/GPBDictionary.m
@@ -45,8 +45,10 @@
 // directly.
 // ------------------------------------------------------------------
 
-#define kMapKeyFieldNumber 1
-#define kMapValueFieldNumber 2
+enum {
+  kMapKeyFieldNumber = 1,
+  kMapValueFieldNumber = 2,
+};
 
 static BOOL DictDefault_IsValidValue(int32_t value) {
   // Anything but the bad value marker is allowed.
@@ -55,58 +57,62 @@
 
 //%PDDM-DEFINE SERIALIZE_SUPPORT_2_TYPE(VALUE_NAME, VALUE_TYPE, GPBTYPE_NAME1, GPBTYPE_NAME2)
 //%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) {
-//%  NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2),
-//%            @"bad type: %d", wireType);
 //%  if (wireType == GPBType##GPBTYPE_NAME1) {
 //%    return GPBCompute##GPBTYPE_NAME1##Size(fieldNum, value);
-//%  } else {  // wireType == GPBType##GPBTYPE_NAME2
+//%  } else if (wireType == GPBType##GPBTYPE_NAME2) {
 //%    return GPBCompute##GPBTYPE_NAME2##Size(fieldNum, value);
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", wireType);
+//%    return 0;
 //%  }
 //%}
 //%
 //%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) {
-//%  NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2),
-//%            @"bad type: %d", wireType);
 //%  if (wireType == GPBType##GPBTYPE_NAME1) {
 //%    [stream write##GPBTYPE_NAME1##:fieldNum value:value];
-//%  } else {  // wireType == GPBType##GPBTYPE_NAME2
+//%  } else if (wireType == GPBType##GPBTYPE_NAME2) {
 //%    [stream write##GPBTYPE_NAME2##:fieldNum value:value];
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", wireType);
 //%  }
 //%}
 //%
 //%PDDM-DEFINE SERIALIZE_SUPPORT_3_TYPE(VALUE_NAME, VALUE_TYPE, GPBTYPE_NAME1, GPBTYPE_NAME2, GPBTYPE_NAME3)
 //%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) {
-//%  NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2) || (wireType == GPBType##GPBTYPE_NAME3),
-//%            @"bad type: %d", wireType);
 //%  if (wireType == GPBType##GPBTYPE_NAME1) {
 //%    return GPBCompute##GPBTYPE_NAME1##Size(fieldNum, value);
 //%  } else if (wireType == GPBType##GPBTYPE_NAME2) {
 //%    return GPBCompute##GPBTYPE_NAME2##Size(fieldNum, value);
-//%  } else {  // wireType == GPBType##GPBTYPE_NAME3
+//%  } else if (wireType == GPBType##GPBTYPE_NAME3) {
 //%    return GPBCompute##GPBTYPE_NAME3##Size(fieldNum, value);
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", wireType);
+//%    return 0;
 //%  }
 //%}
 //%
 //%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE value, uint32_t fieldNum, GPBType wireType) {
-//%  NSCAssert((wireType == GPBType##GPBTYPE_NAME1) || (wireType == GPBType##GPBTYPE_NAME2) || (wireType == GPBType##GPBTYPE_NAME3),
-//%            @"bad type: %d", wireType);
 //%  if (wireType == GPBType##GPBTYPE_NAME1) {
 //%    [stream write##GPBTYPE_NAME1##:fieldNum value:value];
 //%  } else if (wireType == GPBType##GPBTYPE_NAME2) {
 //%    [stream write##GPBTYPE_NAME2##:fieldNum value:value];
-//%  } else {  // wireType == GPBType##GPBTYPE_NAME3
+//%  } else if (wireType == GPBType##GPBTYPE_NAME3) {
 //%    [stream write##GPBTYPE_NAME3##:fieldNum value:value];
+//%  } else {
+//%    NSCAssert(NO, @"Unexpected type %d", wireType);
 //%  }
 //%}
 //%
 //%PDDM-DEFINE SIMPLE_SERIALIZE_SUPPORT(VALUE_NAME, VALUE_TYPE, VisP)
 //%GPB_INLINE size_t ComputeDict##VALUE_NAME##FieldSize(VALUE_TYPE VisP##value, uint32_t fieldNum, GPBType wireType) {
 //%  NSCAssert(wireType == GPBType##VALUE_NAME, @"bad type: %d", wireType);
+//%  #pragma unused(wireType)  // For when asserts are off in release.
 //%  return GPBCompute##VALUE_NAME##Size(fieldNum, value);
 //%}
 //%
 //%GPB_INLINE void WriteDict##VALUE_NAME##Field(GPBCodedOutputStream *stream, VALUE_TYPE VisP##value, uint32_t fieldNum, GPBType wireType) {
 //%  NSCAssert(wireType == GPBType##VALUE_NAME, @"bad type: %d", wireType);
+//%  #pragma unused(wireType)  // For when asserts are off in release.
 //%  [stream write##VALUE_NAME##:fieldNum value:value];
 //%}
 //%
@@ -125,171 +131,185 @@
 // This block of code is generated, do not edit it directly.
 
 GPB_INLINE size_t ComputeDictInt32FieldSize(int32_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeInt32) || (wireType == GPBTypeSInt32) || (wireType == GPBTypeSFixed32),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeInt32) {
     return GPBComputeInt32Size(fieldNum, value);
   } else if (wireType == GPBTypeSInt32) {
     return GPBComputeSInt32Size(fieldNum, value);
-  } else {  // wireType == GPBTypeSFixed32
+  } else if (wireType == GPBTypeSFixed32) {
     return GPBComputeSFixed32Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
+    return 0;
   }
 }
 
 GPB_INLINE void WriteDictInt32Field(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeInt32) || (wireType == GPBTypeSInt32) || (wireType == GPBTypeSFixed32),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeInt32) {
     [stream writeInt32:fieldNum value:value];
   } else if (wireType == GPBTypeSInt32) {
     [stream writeSInt32:fieldNum value:value];
-  } else {  // wireType == GPBTypeSFixed32
+  } else if (wireType == GPBTypeSFixed32) {
     [stream writeSFixed32:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
   }
 }
 
 GPB_INLINE size_t ComputeDictUInt32FieldSize(uint32_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeUInt32) || (wireType == GPBTypeFixed32),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeUInt32) {
     return GPBComputeUInt32Size(fieldNum, value);
-  } else {  // wireType == GPBTypeFixed32
+  } else if (wireType == GPBTypeFixed32) {
     return GPBComputeFixed32Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
+    return 0;
   }
 }
 
 GPB_INLINE void WriteDictUInt32Field(GPBCodedOutputStream *stream, uint32_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeUInt32) || (wireType == GPBTypeFixed32),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeUInt32) {
     [stream writeUInt32:fieldNum value:value];
-  } else {  // wireType == GPBTypeFixed32
+  } else if (wireType == GPBTypeFixed32) {
     [stream writeFixed32:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
   }
 }
 
 GPB_INLINE size_t ComputeDictInt64FieldSize(int64_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeInt64) || (wireType == GPBTypeSInt64) || (wireType == GPBTypeSFixed64),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeInt64) {
     return GPBComputeInt64Size(fieldNum, value);
   } else if (wireType == GPBTypeSInt64) {
     return GPBComputeSInt64Size(fieldNum, value);
-  } else {  // wireType == GPBTypeSFixed64
+  } else if (wireType == GPBTypeSFixed64) {
     return GPBComputeSFixed64Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
+    return 0;
   }
 }
 
 GPB_INLINE void WriteDictInt64Field(GPBCodedOutputStream *stream, int64_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeInt64) || (wireType == GPBTypeSInt64) || (wireType == GPBTypeSFixed64),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeInt64) {
     [stream writeInt64:fieldNum value:value];
   } else if (wireType == GPBTypeSInt64) {
     [stream writeSInt64:fieldNum value:value];
-  } else {  // wireType == GPBTypeSFixed64
+  } else if (wireType == GPBTypeSFixed64) {
     [stream writeSFixed64:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
   }
 }
 
 GPB_INLINE size_t ComputeDictUInt64FieldSize(uint64_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeUInt64) || (wireType == GPBTypeFixed64),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeUInt64) {
     return GPBComputeUInt64Size(fieldNum, value);
-  } else {  // wireType == GPBTypeFixed64
+  } else if (wireType == GPBTypeFixed64) {
     return GPBComputeFixed64Size(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
+    return 0;
   }
 }
 
 GPB_INLINE void WriteDictUInt64Field(GPBCodedOutputStream *stream, uint64_t value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeUInt64) || (wireType == GPBTypeFixed64),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeUInt64) {
     [stream writeUInt64:fieldNum value:value];
-  } else {  // wireType == GPBTypeFixed64
+  } else if (wireType == GPBTypeFixed64) {
     [stream writeFixed64:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
   }
 }
 
 GPB_INLINE size_t ComputeDictBoolFieldSize(BOOL value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeBool, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   return GPBComputeBoolSize(fieldNum, value);
 }
 
 GPB_INLINE void WriteDictBoolField(GPBCodedOutputStream *stream, BOOL value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeBool, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   [stream writeBool:fieldNum value:value];
 }
 
 GPB_INLINE size_t ComputeDictEnumFieldSize(int32_t value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeEnum, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   return GPBComputeEnumSize(fieldNum, value);
 }
 
 GPB_INLINE void WriteDictEnumField(GPBCodedOutputStream *stream, int32_t value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeEnum, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   [stream writeEnum:fieldNum value:value];
 }
 
 GPB_INLINE size_t ComputeDictFloatFieldSize(float value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeFloat, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   return GPBComputeFloatSize(fieldNum, value);
 }
 
 GPB_INLINE void WriteDictFloatField(GPBCodedOutputStream *stream, float value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeFloat, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   [stream writeFloat:fieldNum value:value];
 }
 
 GPB_INLINE size_t ComputeDictDoubleFieldSize(double value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeDouble, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   return GPBComputeDoubleSize(fieldNum, value);
 }
 
 GPB_INLINE void WriteDictDoubleField(GPBCodedOutputStream *stream, double value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeDouble, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   [stream writeDouble:fieldNum value:value];
 }
 
 GPB_INLINE size_t ComputeDictStringFieldSize(NSString *value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeString, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   return GPBComputeStringSize(fieldNum, value);
 }
 
 GPB_INLINE void WriteDictStringField(GPBCodedOutputStream *stream, NSString *value, uint32_t fieldNum, GPBType wireType) {
   NSCAssert(wireType == GPBTypeString, @"bad type: %d", wireType);
+  #pragma unused(wireType)  // For when asserts are off in release.
   [stream writeString:fieldNum value:value];
 }
 
 GPB_INLINE size_t ComputeDictObjectFieldSize(id value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeMessage) || (wireType == GPBTypeString) || (wireType == GPBTypeData),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeMessage) {
     return GPBComputeMessageSize(fieldNum, value);
   } else if (wireType == GPBTypeString) {
     return GPBComputeStringSize(fieldNum, value);
-  } else {  // wireType == GPBTypeData
+  } else if (wireType == GPBTypeData) {
     return GPBComputeDataSize(fieldNum, value);
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
+    return 0;
   }
 }
 
 GPB_INLINE void WriteDictObjectField(GPBCodedOutputStream *stream, id value, uint32_t fieldNum, GPBType wireType) {
-  NSCAssert((wireType == GPBTypeMessage) || (wireType == GPBTypeString) || (wireType == GPBTypeData),
-            @"bad type: %d", wireType);
   if (wireType == GPBTypeMessage) {
     [stream writeMessage:fieldNum value:value];
   } else if (wireType == GPBTypeString) {
     [stream writeString:fieldNum value:value];
-  } else {  // wireType == GPBTypeData
+  } else if (wireType == GPBTypeData) {
     [stream writeData:fieldNum value:value];
+  } else {
+    NSCAssert(NO, @"Unexpected type %d", wireType);
   }
 }
 
 //%PDDM-EXPAND-END SERIALIZE_SUPPORT_HELPERS()
 
 size_t GPBDictionaryComputeSizeInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) {
-  NSCAssert(field.mapKeyType == GPBTypeString, @"Unexpected key type");
   GPBType mapValueType = GPBGetFieldType(field);
   __block size_t result = 0;
   [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
@@ -319,7 +339,7 @@
 
     // Write the size and fields.
     [outputStream writeInt32NoTag:(int32_t)msgSize];
-    [outputStream writeString:kMapValueFieldNumber value:obj];
+    [outputStream writeString:kMapKeyFieldNumber value:key];
     WriteDictObjectField(outputStream, obj, kMapValueFieldNumber, mapValueType);
   }];
 }
@@ -327,6 +347,7 @@
 BOOL GPBDictionaryIsInitializedInternalHelper(NSDictionary *dict, GPBFieldDescriptor *field) {
   NSCAssert(field.mapKeyType == GPBTypeString, @"Unexpected key type");
   NSCAssert(GPBGetFieldType(field) == GPBTypeMessage, @"Unexpected value type");
+  #pragma unused(field)  // For when asserts are off in release.
   for (GPBMessage *msg in [dict objectEnumerator]) {
     if (!msg.initialized) {
       return NO;
@@ -488,8 +509,12 @@
     }
   }
 
-  if (GPBTypeIsObject(keyType)) [key.valueString release];
-  if (GPBTypeIsObject(valueType)) [value.valueString release];
+  if (GPBTypeIsObject(keyType)) {
+    [key.valueString release];
+  }
+  if (GPBTypeIsObject(valueType)) {
+    [value.valueString release];
+  }
 }
 
 //
@@ -751,6 +776,9 @@
 //%  }
 //%
 //%  [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
 //%}
 //%
 //%@end
@@ -758,6 +786,9 @@
 
 //%PDDM-DEFINE DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ACCESSOR_NAME)
 //%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
 //%  [_dictionary release];
 //%  [super dealloc];
 //%}
@@ -854,11 +885,17 @@
 //%- (void)add##ACCESSOR_NAME##EntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary {
 //%  if (otherDictionary) {
 //%    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
 //%  }
 //%}
 //%
 //%- (void)set##ACCESSOR_NAME##Value:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key {
 //%  [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
 //%}
 //%
 //%- (void)removeValueForKey:(KEY_TYPE##KisP$S##KisP)aKey {
@@ -930,7 +967,9 @@
 //%  return [self initWithValues:NULL forKeys:NULL count:0];
 //%}
 //%
-//%BOOL_DICT_DEALLOC##HELPER()- (instancetype)copyWithZone:(NSZone *)zone {
+//%BOOL_DICT_DEALLOC##HELPER()
+//%
+//%- (instancetype)copyWithZone:(NSZone *)zone {
 //%  return [[GPBBool##VALUE_NAME##Dictionary allocWithZone:zone] initWithDictionary:self];
 //%}
 //%
@@ -1158,7 +1197,14 @@
 //%  return self;
 //%}
 //%PDDM-DEFINE BOOL_DICT_DEALLOCPOD()
-// Empty
+//%#if !defined(NS_BLOCK_ASSERTIONS)
+//%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
+//%  [super dealloc];
+//%}
+//%#endif  // !defined(NS_BLOCK_ASSERTIONS)
 //%PDDM-DEFINE BOOL_DICT_W_HASPOD(IDX, REF)
 //%BOOL_DICT_HASPOD(IDX, REF)
 //%PDDM-DEFINE BOOL_DICT_HASPOD(IDX, REF)
@@ -1189,6 +1235,9 @@
 //%        _values[i] = otherDictionary->_values[i];
 //%      }
 //%    }
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
 //%  }
 //%}
 //%
@@ -1196,6 +1245,9 @@
 //%  int idx = (key ? 1 : 0);
 //%  _values[idx] = value;
 //%  _valueSet[idx] = YES;
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
 //%}
 //%
 //%- (void)removeValueForKey:(BOOL)aKey {
@@ -1333,12 +1385,13 @@
 //%}
 //%PDDM-DEFINE BOOL_DICT_DEALLOCOBJECT()
 //%- (void)dealloc {
+//%  NSAssert(!_autocreator,
+//%           @"%@: Autocreator must be cleared before release, autocreator: %@",
+//%           [self class], _autocreator);
 //%  [_values[0] release];
 //%  [_values[1] release];
 //%  [super dealloc];
 //%}
-//%
-//%
 //%PDDM-DEFINE BOOL_DICT_W_HASOBJECT(IDX, REF)
 //%(BOOL_DICT_HASOBJECT(IDX, REF))
 //%PDDM-DEFINE BOOL_DICT_HASOBJECT(IDX, REF)
@@ -1363,6 +1416,9 @@
 //%        _values[i] = [otherDictionary->_values[i] retain];
 //%      }
 //%    }
+//%    if (_autocreator) {
+//%      GPBAutocreatedDictionaryModified(_autocreator, self);
+//%    }
 //%  }
 //%}
 //%
@@ -1370,6 +1426,9 @@
 //%  int idx = (key ? 1 : 0);
 //%  [_values[idx] release];
 //%  _values[idx] = [value retain];
+//%  if (_autocreator) {
+//%    GPBAutocreatedDictionaryModified(_autocreator, self);
+//%  }
 //%}
 //%
 //%- (void)removeValueForKey:(BOOL)aKey {
@@ -1466,6 +1525,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -1570,11 +1632,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint32_t)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -1662,6 +1730,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -1766,11 +1837,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int32_t)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -1858,6 +1935,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -1962,11 +2042,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint64_t)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -2054,6 +2140,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -2158,11 +2247,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int64_t)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -2250,6 +2345,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -2354,11 +2452,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(BOOL)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -2446,6 +2550,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -2550,11 +2657,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(float)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -2642,6 +2755,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -2746,11 +2862,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(double)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -2866,6 +2988,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -3008,11 +3133,17 @@
 - (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setRawValue:(int32_t)value forKey:(uint32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -3031,6 +3162,9 @@
   }
 
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 @end
@@ -3110,6 +3244,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -3234,11 +3371,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(id)value forKey:(uint32_t)key {
   [_dictionary setObject:value forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint32_t)aKey {
@@ -3329,6 +3472,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -3433,11 +3579,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint32_t)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -3525,6 +3677,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -3629,11 +3784,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int32_t)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -3721,6 +3882,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -3825,11 +3989,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint64_t)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -3917,6 +4087,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -4021,11 +4194,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int64_t)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -4113,6 +4292,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -4217,11 +4399,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(BOOL)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -4309,6 +4497,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -4413,11 +4604,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(float)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -4505,6 +4702,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -4609,11 +4809,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(double)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -4729,6 +4935,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -4871,11 +5080,17 @@
 - (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setRawValue:(int32_t)value forKey:(int32_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -4894,6 +5109,9 @@
   }
 
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 @end
@@ -4973,6 +5191,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -5097,11 +5318,17 @@
 - (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(id)value forKey:(int32_t)key {
   [_dictionary setObject:value forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int32_t)aKey {
@@ -5192,6 +5419,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -5296,11 +5526,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint32_t)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -5388,6 +5624,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -5492,11 +5731,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int32_t)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -5584,6 +5829,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -5688,11 +5936,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint64_t)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -5780,6 +6034,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -5884,11 +6141,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int64_t)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -5976,6 +6239,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -6080,11 +6346,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(BOOL)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -6172,6 +6444,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -6276,11 +6551,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(float)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -6368,6 +6649,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -6472,11 +6756,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(double)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -6592,6 +6882,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -6734,11 +7027,17 @@
 - (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setRawValue:(int32_t)value forKey:(uint64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -6757,6 +7056,9 @@
   }
 
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 @end
@@ -6836,6 +7138,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -6960,11 +7265,17 @@
 - (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(id)value forKey:(uint64_t)key {
   [_dictionary setObject:value forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(uint64_t)aKey {
@@ -7055,6 +7366,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -7159,11 +7473,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint32_t)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -7251,6 +7571,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -7355,11 +7678,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int32_t)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -7447,6 +7776,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -7551,11 +7883,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint64_t)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -7643,6 +7981,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -7747,11 +8088,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int64_t)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -7839,6 +8186,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -7943,11 +8293,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(BOOL)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -8035,6 +8391,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -8139,11 +8498,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(float)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -8231,6 +8596,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -8335,11 +8703,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(double)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -8455,6 +8829,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -8597,11 +8974,17 @@
 - (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setRawValue:(int32_t)value forKey:(int64_t)key {
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -8620,6 +9003,9 @@
   }
 
   [_dictionary setObject:@(value) forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 @end
@@ -8699,6 +9085,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -8823,11 +9212,17 @@
 - (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(id)value forKey:(int64_t)key {
   [_dictionary setObject:value forKey:@(key)];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(int64_t)aKey {
@@ -8918,6 +9313,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -9022,11 +9420,17 @@
 - (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint32_t)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -9114,6 +9518,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -9218,11 +9625,17 @@
 - (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int32_t)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -9310,6 +9723,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -9414,11 +9830,17 @@
 - (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(uint64_t)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -9506,6 +9928,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -9610,11 +10035,17 @@
 - (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(int64_t)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -9702,6 +10133,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -9806,11 +10240,17 @@
 - (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(BOOL)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -9898,6 +10338,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -10002,11 +10445,17 @@
 - (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(float)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -10094,6 +10543,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -10198,11 +10650,17 @@
 - (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setValue:(double)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -10318,6 +10776,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_dictionary release];
   [super dealloc];
 }
@@ -10460,11 +10921,17 @@
 - (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary {
   if (otherDictionary) {
     [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
 - (void)setRawValue:(int32_t)value forKey:(NSString *)key {
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(NSString *)aKey {
@@ -10483,6 +10950,9 @@
   }
 
   [_dictionary setObject:@(value) forKey:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 @end
@@ -10572,6 +11042,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolUInt32Dictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -10695,6 +11174,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -10702,6 +11184,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -10797,6 +11282,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolInt32Dictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -10920,6 +11414,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -10927,6 +11424,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -11022,6 +11522,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolUInt64Dictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -11145,6 +11654,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -11152,6 +11664,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -11247,6 +11762,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolInt64Dictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -11370,6 +11894,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -11377,6 +11904,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -11472,6 +12002,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolBoolDictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -11595,6 +12134,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -11602,6 +12144,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -11697,6 +12242,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolFloatDictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -11820,6 +12374,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -11827,6 +12384,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -11922,6 +12482,15 @@
   return [self initWithValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolDoubleDictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -12045,6 +12614,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -12052,6 +12624,9 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -12143,6 +12718,9 @@
 }
 
 - (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
   [_values[0] release];
   [_values[1] release];
   [super dealloc];
@@ -12285,6 +12863,9 @@
         _values[i] = [otherDictionary->_values[i] retain];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -12292,6 +12873,9 @@
   int idx = (key ? 1 : 0);
   [_values[idx] release];
   _values[idx] = [value retain];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -12418,6 +13002,15 @@
   return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
 }
 
+#if !defined(NS_BLOCK_ASSERTIONS)
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [super dealloc];
+}
+#endif  // !defined(NS_BLOCK_ASSERTIONS)
+
 - (instancetype)copyWithZone:(NSZone *)zone {
   return [[GPBBoolEnumDictionary allocWithZone:zone] initWithDictionary:self];
 }
@@ -12595,6 +13188,9 @@
         _values[i] = otherDictionary->_values[i];
       }
     }
+    if (_autocreator) {
+      GPBAutocreatedDictionaryModified(_autocreator, self);
+    }
   }
 }
 
@@ -12607,12 +13203,18 @@
   int idx = (key ? 1 : 0);
   _values[idx] = value;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key {
   int idx = (key ? 1 : 0);
   _values[idx] = rawValue;
   _valueSet[idx] = YES;
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
 }
 
 - (void)removeValueForKey:(BOOL)aKey {
@@ -12625,3 +13227,110 @@
 }
 
 @end
+
+#pragma mark - NSDictionary Subclass
+
+@implementation GPBAutocreatedDictionary {
+  NSMutableDictionary *_dictionary;
+}
+
+- (void)dealloc {
+  NSAssert(!_autocreator,
+           @"%@: Autocreator must be cleared before release, autocreator: %@",
+           [self class], _autocreator);
+  [_dictionary release];
+  [super dealloc];
+}
+
+#pragma mark Required NSDictionary overrides
+
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const id<NSCopying> [])keys
+                          count:(NSUInteger)count {
+  self = [super init];
+  if (self) {
+    _dictionary = [[NSMutableDictionary alloc] initWithObjects:objects
+                                                       forKeys:keys
+                                                         count:count];
+  }
+  return self;
+}
+
+- (NSUInteger)count {
+  return [_dictionary count];
+}
+
+- (id)objectForKey:(id)aKey {
+  return [_dictionary objectForKey:aKey];
+}
+
+- (NSEnumerator *)keyEnumerator {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary keyEnumerator];
+}
+
+#pragma mark Required NSMutableDictionary overrides
+
+// Only need to call GPBAutocreatedDictionaryModified() when adding things
+// since we only autocreate empty dictionaries.
+
+- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  [_dictionary setObject:anObject forKey:aKey];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)removeObjectForKey:(id)aKey {
+  [_dictionary removeObjectForKey:aKey];
+}
+
+#pragma mark Extra things hooked
+
+- (id)copyWithZone:(NSZone *)zone {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary copyWithZone:zone];
+}
+
+- (id)mutableCopyWithZone:(NSZone *)zone {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  return [_dictionary mutableCopyWithZone:zone];
+}
+
+- (id)objectForKeyedSubscript:(id)key {
+  return [_dictionary objectForKeyedSubscript:key];
+}
+
+- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
+  if (_dictionary == nil) {
+    _dictionary = [[NSMutableDictionary alloc] init];
+  }
+  [_dictionary setObject:obj forKeyedSubscript:key];
+  if (_autocreator) {
+    GPBAutocreatedDictionaryModified(_autocreator, self);
+  }
+}
+
+- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key,
+                                                    id obj,
+                                                    BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsUsingBlock:block];
+}
+
+- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts
+                                usingBlock:(void (^)(id key,
+                                                     id obj,
+                                                     BOOL *stop))block {
+  [_dictionary enumerateKeysAndObjectsWithOptions:opts usingBlock:block];
+}
+
+@end
diff --git a/objectivec/GPBDictionary_PackagePrivate.h b/objectivec/GPBDictionary_PackagePrivate.h
index 54b37dd..9c3c591 100644
--- a/objectivec/GPBDictionary_PackagePrivate.h
+++ b/objectivec/GPBDictionary_PackagePrivate.h
@@ -37,6 +37,14 @@
 @class GPBExtensionRegistry;
 @class GPBFieldDescriptor;
 
+@protocol GPBDictionaryInternalsProtocol
+- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
+- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
+                         asField:(GPBFieldDescriptor *)field;
+- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
+- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@end
+
 //%PDDM-DEFINE DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(KEY_NAME)
 //%DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(KEY_NAME)
 //%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Object, Object)
@@ -51,12 +59,10 @@
 //%DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, Enum, Enum)
 
 //%PDDM-DEFINE DICTIONARY_PRIVATE_INTERFACES(KEY_NAME, VALUE_NAME, HELPER)
-//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary ()
-//%- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-//%- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-//%                         asField:(GPBFieldDescriptor *)field;
-//%- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-//%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary () <GPBDictionaryInternalsProtocol> {
+//% @package
+//%  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+//%}
 //%EXTRA_DICTIONARY_PRIVATE_INTERFACES_##HELPER()@end
 //%
 
@@ -76,79 +82,61 @@
 //%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt32)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBUInt32UInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32Int32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32UInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32Int64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32BoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32FloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32DoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt32EnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
 @end
 
-@interface GPBUInt32ObjectDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt32ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (BOOL)isInitialized;
 - (instancetype)deepCopyWithZone:(NSZone *)zone
     __attribute__((ns_returns_retained));
@@ -157,79 +145,61 @@
 //%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int32)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBInt32UInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32Int32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32UInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32Int64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32BoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32FloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32DoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt32EnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
 @end
 
-@interface GPBInt32ObjectDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt32ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (BOOL)isInitialized;
 - (instancetype)deepCopyWithZone:(NSZone *)zone
     __attribute__((ns_returns_retained));
@@ -238,79 +208,61 @@
 //%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(UInt64)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBUInt64UInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64Int32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64UInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64Int64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64BoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64FloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64DoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBUInt64EnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
 @end
 
-@interface GPBUInt64ObjectDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBUInt64ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (BOOL)isInitialized;
 - (instancetype)deepCopyWithZone:(NSZone *)zone
     __attribute__((ns_returns_retained));
@@ -319,79 +271,61 @@
 //%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Int64)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBInt64UInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64UInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64Int32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64Int32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64UInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64UInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64Int64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64Int64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64BoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64BoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64FloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64FloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64DoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64DoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBInt64EnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64EnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
 @end
 
-@interface GPBInt64ObjectDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBInt64ObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (BOOL)isInitialized;
 - (instancetype)deepCopyWithZone:(NSZone *)zone
     __attribute__((ns_returns_retained));
@@ -400,79 +334,61 @@
 //%PDDM-EXPAND DICTIONARY_PRIV_INTERFACES_FOR_POD_KEY(Bool)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBBoolUInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolUInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolUInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolUInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolBoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolBoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolFloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolFloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolDoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolDoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBBoolEnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolEnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
 @end
 
-@interface GPBBoolObjectDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBBoolObjectDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (BOOL)isInitialized;
 - (instancetype)deepCopyWithZone:(NSZone *)zone
     __attribute__((ns_returns_retained));
@@ -481,68 +397,52 @@
 //%PDDM-EXPAND DICTIONARY_POD_PRIV_INTERFACES_FOR_KEY(String)
 // This block of code is generated, do not edit it directly.
 
-@interface GPBStringUInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringUInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringInt32Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringInt32Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringUInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringUInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringInt64Dictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringInt64Dictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringBoolDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringBoolDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringFloatDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringFloatDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringDoubleDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringDoubleDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 @end
 
-@interface GPBStringEnumDictionary ()
-- (size_t)computeSerializedSizeAsField:(GPBFieldDescriptor *)field;
-- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)outputStream
-                         asField:(GPBFieldDescriptor *)field;
-- (void)setGPBValue:(GPBValue *)value forGPBValueKey:(GPBValue *)key;
-- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block;
+@interface GPBStringEnumDictionary () <GPBDictionaryInternalsProtocol> {
+ @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
 - (NSData *)serializedDataForUnknownValue:(int32_t)value
                                    forKey:(GPBValue *)key
                                   keyType:(GPBType)keyType;
@@ -550,6 +450,16 @@
 
 //%PDDM-EXPAND-END (6 expansions)
 
+#pragma mark - NSDictionary Subclass
+
+@interface GPBAutocreatedDictionary : NSMutableDictionary {
+  @package
+  GPB_UNSAFE_UNRETAINED GPBMessage *_autocreator;
+}
+@end
+
+#pragma mark - Helpers
+
 CF_EXTERN_C_BEGIN
 
 // Helper to compute size when an NSDictionary is used for the map instead
diff --git a/objectivec/GPBExtensionRegistry.h b/objectivec/GPBExtensionRegistry.h
index ce1f8fa..e382971 100644
--- a/objectivec/GPBExtensionRegistry.h
+++ b/objectivec/GPBExtensionRegistry.h
@@ -38,7 +38,24 @@
 // ExtensionRegistry in which you have registered any extensions that you want
 // to be able to parse.  Otherwise, those extensions will just be treated like
 // unknown fields.
-@interface GPBExtensionRegistry : NSObject
+//
+// The *Root classes provide +extensionRegistry for the extensions defined in a
+// given file *and* all files it imports.  You can also create a
+// GPBExtensionRegistry, and merge those registries to handle parsing extensions
+// defined from non overlapping files.
+//
+//    GPBExtensionRegistry *registry =
+//        [[[MyProtoFileRoot extensionRegistry] copy] autorelease];
+//    [registry addExtension:[OtherMessage neededExtension];  // Not in MyProtoFile
+//    NSError *parseError = nil;
+//    MyMessage *msg = [MyMessage parseData:data
+//                        extensionRegistry:registry
+//                                    error:&parseError];
+//
+@interface GPBExtensionRegistry : NSObject<NSCopying>
+
+- (void)addExtension:(GPBExtensionField *)extension;
+- (void)addExtensions:(GPBExtensionRegistry *)registry;
 
 - (GPBExtensionField *)getExtension:(GPBDescriptor *)containingType
                         fieldNumber:(NSInteger)fieldNumber;
diff --git a/objectivec/GPBExtensionRegistry.m b/objectivec/GPBExtensionRegistry.m
index a191dac..4f234f5 100644
--- a/objectivec/GPBExtensionRegistry.m
+++ b/objectivec/GPBExtensionRegistry.m
@@ -28,7 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#import "GPBExtensionRegistry_PackagePrivate.h"
+#import "GPBExtensionRegistry.h"
 
 #import "GPBBootstrap.h"
 #import "GPBDescriptor.h"
@@ -52,6 +52,14 @@
   [super dealloc];
 }
 
+- (instancetype)copyWithZone:(NSZone *)zone {
+  GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
+  if (result && mutableClassMap_.count) {
+    [result->mutableClassMap_ addEntriesFromDictionary:mutableClassMap_];
+  }
+  return result;
+}
+
 - (NSMutableDictionary *)extensionMapForContainingType:
         (GPBDescriptor *)containingType {
   NSMutableDictionary *extensionMap =
diff --git a/objectivec/GPBExtensionRegistry_PackagePrivate.h b/objectivec/GPBExtensionRegistry_PackagePrivate.h
deleted file mode 100644
index 968cb1f..0000000
--- a/objectivec/GPBExtensionRegistry_PackagePrivate.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#import <Foundation/Foundation.h>
-
-#import "GPBExtensionRegistry.h"
-
-@interface GPBExtensionRegistry ()
-
-- (void)addExtension:(GPBExtensionField *)extension;
-- (void)addExtensions:(GPBExtensionRegistry *)registry;
-
-@end
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index 2483f5d..1c6c091 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -28,15 +28,28 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#import "GPBRootObject.h"
+#import <Foundation/Foundation.h>
+
+#import "GPBBootstrap.h"
 
 @class GPBDescriptor;
 @class GPBCodedInputStream;
 @class GPBCodedOutputStream;
 @class GPBExtensionField;
+@class GPBExtensionRegistry;
 @class GPBFieldDescriptor;
 @class GPBUnknownFieldSet;
 
+CF_EXTERN_C_BEGIN
+
+// NSError domain used for errors.
+extern NSString *const GPBMessageErrorDomain;
+
+typedef NS_ENUM(NSInteger, GPBMessageErrorCode) {
+  GPBMessageErrorCodeMalformedData = -100,
+  GPBMessageErrorCodeMissingRequiredField = -101,
+};
+
 // In DEBUG ONLY, an NSException is thrown when a parsed message doesn't
 // contain required fields. This key allows you to retrieve the parsed message
 // from the exception's |userInfo| dictionary.
@@ -44,12 +57,14 @@
 extern NSString *const GPBExceptionMessageKey;
 #endif  // DEBUG
 
-// NOTE:
-// If you add a instance method/property to this class that may conflict with
-// methods declared in protos, you need to update objective_helpers.cc.
+CF_EXTERN_C_END
+
+@interface GPBMessage : NSObject<NSSecureCoding, NSCopying>
+
+// NOTE: If you add a instance method/property to this class that may conflict
+// with methods declared in protos, you need to update objective_helpers.cc.
 // The main cases are methods that take no arguments, or setFoo:/hasFoo: type
 // methods.
-@interface GPBMessage : GPBRootObject<NSCoding, NSCopying>
 
 @property(nonatomic, readonly) GPBUnknownFieldSet *unknownFields;
 
@@ -59,29 +74,38 @@
 // Returns an autoreleased instance.
 + (instancetype)message;
 
-// Create a message based on a variety of inputs.
-// In DEBUG ONLY
-// @throws NSInternalInconsistencyException The message is missing one or more
-//         required fields (i.e. -[isInitialized] returns false). Use
-//         GGPBExceptionMessageKey to retrieve the message from |userInfo|.
-+ (instancetype)parseFromData:(NSData *)data;
+// Create a message based on a variety of inputs.  If there is a data parse
+// error, nil is returned and if not NULL, errorPtr is filled in.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, the parse will fail (returning nil, filling in errorPtr).
++ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr;
 + (instancetype)parseFromData:(NSData *)data
-            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
+            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                        error:(NSError **)errorPtr;
 + (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
                         extensionRegistry:
-                            (GPBExtensionRegistry *)extensionRegistry;
+                            (GPBExtensionRegistry *)extensionRegistry
+                                    error:(NSError **)errorPtr;
 
-// Create a message based on delimited input.
+// Create a message based on delimited input.  If there is a data parse
+// error, nil is returned and if not NULL, errorPtr is filled in.
 + (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
                                  extensionRegistry:
-                                     (GPBExtensionRegistry *)extensionRegistry;
+                                     (GPBExtensionRegistry *)extensionRegistry
+                                             error:(NSError **)errorPtr;
 
-- (instancetype)initWithData:(NSData *)data;
+// If there is a data parse error, nil is returned and if not NULL, errorPtr is
+// filled in.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, the parse will fail (returning nil, filling in errorPtr).
+- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr;
 - (instancetype)initWithData:(NSData *)data
-           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
+           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                       error:(NSError **)errorPtr;
 - (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
                        extensionRegistry:
-                           (GPBExtensionRegistry *)extensionRegistry;
+                           (GPBExtensionRegistry *)extensionRegistry
+                                   error:(NSError **)errorPtr;
 
 // Serializes the message and writes it to output.
 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
@@ -93,11 +117,10 @@
 - (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
 
 // Serializes the message to an NSData. Note that this value is not cached, so
-// if you are using it repeatedly, cache it yourself.
-// In DEBUG ONLY:
-// @throws NSInternalInconsistencyException The message is missing one or more
-//         required fields (i.e. -[isInitialized] returns false). Use
-//         GPBExceptionMessageKey to retrieve the message from |userInfo|.
+// if you are using it repeatedly, cache it yourself. If there is an error
+// while generating the data, nil is returned.
+// NOTE: In DEBUG ONLY, the message is also checked for all required field,
+// if one is missing, nil will be returned.
 - (NSData *)data;
 
 // Same as -[data], except a delimiter is added to the start of the data
@@ -106,16 +129,16 @@
 
 // Returns the size of the object if it were serialized.
 // This is not a cached value. If you are following a pattern like this:
-// size_t size = [aMsg serializedSize];
-// NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
-// [foo writeSize:size];
-// [foo appendData:[aMsg data]];
+//   size_t size = [aMsg serializedSize];
+//   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+//   [foo writeSize:size];
+//   [foo appendData:[aMsg data]];
 // you would be better doing:
-// NSData *data = [aMsg data];
-// NSUInteger size = [aMsg length];
-// NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
-// [foo writeSize:size];
-// [foo appendData:data];
+//   NSData *data = [aMsg data];
+//   NSUInteger size = [aMsg length];
+//   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
+//   [foo writeSize:size];
+//   [foo appendData:data];
 - (size_t)serializedSize;
 
 // Return the descriptor for the message
@@ -123,8 +146,8 @@
 - (GPBDescriptor *)descriptor;
 
 // Extensions use boxed values (NSNumbers) for PODs, NSMutableArrays for
-// repeated. If the extension is a Message, just like fields, one will be
-// auto created for you and returned.
+// repeated. If the extension is a Message one will be auto created for you
+// and returned similar to fields.
 - (BOOL)hasExtension:(GPBExtensionField *)extension;
 - (id)getExtension:(GPBExtensionField *)extension;
 - (void)setExtension:(GPBExtensionField *)extension value:(id)value;
@@ -141,6 +164,7 @@
 
 // Parses a message of this type from the input and merges it with this
 // message.
+// NOTE: This will throw if there is an error parsing the data.
 - (void)mergeFromData:(NSData *)data
     extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
 
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 63ffc3b..bd3235f 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -39,15 +39,21 @@
 #import "GPBDescriptor_PackagePrivate.h"
 #import "GPBDictionary_PackagePrivate.h"
 #import "GPBExtensionField_PackagePrivate.h"
-#import "GPBExtensionRegistry_PackagePrivate.h"
+#import "GPBExtensionRegistry.h"
+#import "GPBRootObject_PackagePrivate.h"
 #import "GPBUnknownFieldSet_PackagePrivate.h"
 #import "GPBUtilities_PackagePrivate.h"
 
+NSString *const GPBMessageErrorDomain =
+    GPBNSStringifySymbol(GPBMessageErrorDomain);
+
 #ifdef DEBUG
 NSString *const GPBExceptionMessageKey =
     GPBNSStringifySymbol(GPBExceptionMessage);
 #endif  // DEBUG
 
+static NSString *const kGPBDataCoderKey = @"GPBData";
+
 //
 // PLEASE REMEMBER:
 //
@@ -78,13 +84,32 @@
                                         GPBFieldDescriptor *field,
                                         GPBFileSyntax syntax);
 static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
+static id CreateMapForField(GPBFieldDescriptor *field,
+                            GPBMessage *autocreator)
+    __attribute__((ns_returns_retained));
 static id GetOrCreateMapIvarWithField(GPBMessage *self,
                                       GPBFieldDescriptor *field,
                                       GPBFileSyntax syntax);
+static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
 static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap,
                                               NSZone *zone)
     __attribute__((ns_returns_retained));
 
+static NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
+  return [NSError errorWithDomain:GPBMessageErrorDomain
+                             code:code
+                         userInfo:userInfo];
+}
+
+static NSError *MessageErrorWithReason(NSInteger code, NSString *reason) {
+  NSDictionary *userInfo = nil;
+  if ([reason length]) {
+    userInfo = @{ @"Reason" : reason };
+  }
+  return MessageError(code, userInfo);
+}
+
+
 static void CheckExtension(GPBMessage *self, GPBExtensionField *extension) {
   if ([[self class] descriptor] != [extension containingType]) {
     [NSException
@@ -201,6 +226,303 @@
   return result;
 }
 
+static id CreateMapForField(GPBFieldDescriptor *field,
+                            GPBMessage *autocreator) {
+  id result;
+  GPBType keyType = field.mapKeyType;
+  GPBType valueType = GPBGetFieldType(field);
+  switch (keyType) {
+    case GPBTypeBool:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBBoolBoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBBoolUInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBBoolInt32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBBoolUInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBBoolInt64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBBoolFloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBBoolDoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBBoolEnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          result = [[GPBBoolObjectDictionary alloc] init];
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBTypeFixed32:
+    case GPBTypeUInt32:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBUInt32BoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBUInt32UInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBUInt32Int32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBUInt32UInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBUInt32Int64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBUInt32FloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBUInt32DoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBUInt32EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          result = [[GPBUInt32ObjectDictionary alloc] init];
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBTypeInt32:
+    case GPBTypeSFixed32:
+    case GPBTypeSInt32:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBInt32BoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBInt32UInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBInt32Int32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBInt32UInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBInt32Int64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBInt32FloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBInt32DoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBInt32EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          result = [[GPBInt32ObjectDictionary alloc] init];
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBTypeFixed64:
+    case GPBTypeUInt64:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBUInt64BoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBUInt64UInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBUInt64Int32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBUInt64UInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBUInt64Int64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBUInt64FloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBUInt64DoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBUInt64EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          result = [[GPBUInt64ObjectDictionary alloc] init];
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBTypeInt64:
+    case GPBTypeSFixed64:
+    case GPBTypeSInt64:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBInt64BoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBInt64UInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBInt64Int32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBInt64UInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBInt64Int64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBInt64FloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBInt64DoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBInt64EnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          result = [[GPBInt64ObjectDictionary alloc] init];
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+    case GPBTypeString:
+      switch (valueType) {
+        case GPBTypeBool:
+          result = [[GPBStringBoolDictionary alloc] init];
+          break;
+        case GPBTypeFixed32:
+        case GPBTypeUInt32:
+          result = [[GPBStringUInt32Dictionary alloc] init];
+          break;
+        case GPBTypeInt32:
+        case GPBTypeSFixed32:
+        case GPBTypeSInt32:
+          result = [[GPBStringInt32Dictionary alloc] init];
+          break;
+        case GPBTypeFixed64:
+        case GPBTypeUInt64:
+          result = [[GPBStringUInt64Dictionary alloc] init];
+          break;
+        case GPBTypeInt64:
+        case GPBTypeSFixed64:
+        case GPBTypeSInt64:
+          result = [[GPBStringInt64Dictionary alloc] init];
+          break;
+        case GPBTypeFloat:
+          result = [[GPBStringFloatDictionary alloc] init];
+          break;
+        case GPBTypeDouble:
+          result = [[GPBStringDoubleDictionary alloc] init];
+          break;
+        case GPBTypeEnum:
+          result = [[GPBStringEnumDictionary alloc]
+              initWithValidationFunction:field.enumDescriptor.enumVerifier];
+          break;
+        case GPBTypeData:
+        case GPBTypeMessage:
+        case GPBTypeString:
+          if (autocreator) {
+            result = [[GPBAutocreatedDictionary alloc] init];
+          } else {
+            result = [[NSMutableDictionary alloc] init];
+          }
+          break;
+        case GPBTypeGroup:
+          NSCAssert(NO, @"shouldn't happen");
+          return nil;
+      }
+      break;
+
+    case GPBTypeFloat:
+    case GPBTypeDouble:
+    case GPBTypeEnum:
+    case GPBTypeData:
+    case GPBTypeGroup:
+    case GPBTypeMessage:
+      NSCAssert(NO, @"shouldn't happen");
+      return nil;
+  }
+
+  if (autocreator) {
+    if ((keyType == GPBTypeString) && GPBTypeIsObject(valueType)) {
+      GPBAutocreatedDictionary *autoDict = result;
+      autoDict->_autocreator =  autocreator;
+    } else {
+      GPBInt32Int32Dictionary *gpbDict = result;
+      gpbDict->_autocreator = autocreator;
+    }
+  }
+
+  return result;
+}
 
 #if !defined(__clang_analyzer__)
 // These functions are blocked from the analyzer because the analyzer sees the
@@ -249,289 +571,31 @@
                                       GPBFileSyntax syntax) {
   id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!dict) {
-    GPBType keyType = field.mapKeyType;
-    GPBType valueType = GPBGetFieldType(field);
-    switch (keyType) {
-      case GPBTypeBool:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBBoolBoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBBoolUInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBBoolInt32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBBoolUInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBBoolInt64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBBoolFloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBBoolDoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBBoolEnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[GPBBoolObjectDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-      case GPBTypeFixed32:
-      case GPBTypeUInt32:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBUInt32BoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBUInt32UInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBUInt32Int32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBUInt32UInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBUInt32Int64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBUInt32FloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBUInt32DoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBUInt32EnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[GPBUInt32ObjectDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-      case GPBTypeInt32:
-      case GPBTypeSFixed32:
-      case GPBTypeSInt32:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBInt32BoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBInt32UInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBInt32Int32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBInt32UInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBInt32Int64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBInt32FloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBInt32DoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBInt32EnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[GPBInt32ObjectDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-      case GPBTypeFixed64:
-      case GPBTypeUInt64:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBUInt64BoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBUInt64UInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBUInt64Int32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBUInt64UInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBUInt64Int64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBUInt64FloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBUInt64DoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBUInt64EnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[GPBUInt64ObjectDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-      case GPBTypeInt64:
-      case GPBTypeSFixed64:
-      case GPBTypeSInt64:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBInt64BoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBInt64UInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBInt64Int32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBInt64UInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBInt64Int64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBInt64FloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBInt64DoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBInt64EnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[GPBInt64ObjectDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-      case GPBTypeString:
-        switch (valueType) {
-          case GPBTypeBool:
-            dict = [[GPBStringBoolDictionary alloc] init];
-            break;
-          case GPBTypeFixed32:
-          case GPBTypeUInt32:
-            dict = [[GPBStringUInt32Dictionary alloc] init];
-            break;
-          case GPBTypeInt32:
-          case GPBTypeSFixed32:
-          case GPBTypeSInt32:
-            dict = [[GPBStringInt32Dictionary alloc] init];
-            break;
-          case GPBTypeFixed64:
-          case GPBTypeUInt64:
-            dict = [[GPBStringUInt64Dictionary alloc] init];
-            break;
-          case GPBTypeInt64:
-          case GPBTypeSFixed64:
-          case GPBTypeSInt64:
-            dict = [[GPBStringInt64Dictionary alloc] init];
-            break;
-          case GPBTypeFloat:
-            dict = [[GPBStringFloatDictionary alloc] init];
-            break;
-          case GPBTypeDouble:
-            dict = [[GPBStringDoubleDictionary alloc] init];
-            break;
-          case GPBTypeEnum:
-            dict = [[GPBStringEnumDictionary alloc]
-                initWithValidationFunction:field.enumDescriptor.enumVerifier];
-            break;
-          case GPBTypeData:
-          case GPBTypeMessage:
-          case GPBTypeString:
-            dict = [[NSMutableDictionary alloc] init];
-            break;
-          case GPBTypeGroup:
-            NSCAssert(NO, @"shouldn't happen");
-            return nil;
-        }
-        break;
-
-      case GPBTypeFloat:
-      case GPBTypeDouble:
-      case GPBTypeEnum:
-      case GPBTypeData:
-      case GPBTypeGroup:
-      case GPBTypeMessage:
-        NSCAssert(NO, @"shouldn't happen");
-        return nil;
-    }
-
+    // No lock needed, this is called from places expecting to mutate
+    // so no threading protection is needed.
+    dict = CreateMapForField(field, nil);
     GPBSetRetainedObjectIvarWithFieldInternal(self, field, dict, syntax);
   }
   return dict;
 }
 
+// This is like GPBGetObjectIvarWithField(), but for maps, it should
+// only be used to wire the method into the class.
+static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
+  id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+  if (!dict) {
+    // Check again after getting the lock.
+    OSSpinLockLock(&self->readOnlyMutex_);
+    dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+    if (!dict) {
+      dict = CreateMapForField(field, self);
+      GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict);
+    }
+    OSSpinLockUnlock(&self->readOnlyMutex_);
+  }
+  return dict;
+}
+
 #endif  // !defined(__clang_analyzer__)
 
 GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass,
@@ -595,7 +659,30 @@
       }
     }
   }
-  NSCAssert(NO, @"Unknown array.");
+  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self);
+}
+
+void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) {
+  // When one of our autocreated dicts adds elements, make it visible.
+  GPBDescriptor *descriptor = [[self class] descriptor];
+  for (GPBFieldDescriptor *field in descriptor->fields_) {
+    if (field.fieldType == GPBFieldTypeMap) {
+      id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+      if (curDict == dictionary) {
+        if ((field.mapKeyType == GPBTypeString) &&
+            GPBFieldTypeIsObject(field)) {
+          GPBAutocreatedDictionary *autoDict = dictionary;
+          autoDict->_autocreator = nil;
+        } else {
+          GPBInt32Int32Dictionary *gpbDict = dictionary;
+          gpbDict->_autocreator = nil;
+        }
+        GPBBecomeVisibleToAutocreator(self);
+        return;
+      }
+    }
+  }
+  NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self);
 }
 
 void GPBClearMessageAutocreator(GPBMessage *self) {
@@ -617,7 +704,8 @@
            : [self->autocreator_->autocreatedExtensionMap_
                  objectForKey:self->autocreatorExtension_]);
   NSCAssert(autocreatorHas || autocreatorFieldValue != self,
-            @"Cannot clear autocreator because it still refers to self.");
+            @"Cannot clear autocreator because it still refers to self, self: %@.",
+            self);
 
 #endif  // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
 
@@ -636,26 +724,6 @@
   return self->unknownFields_;
 }
 
-#ifdef DEBUG
-static void DebugRaiseExceptionIfNotInitialized(GPBMessage *message) {
-  if (!message.initialized) {
-    NSString *reason =
-        [NSString stringWithFormat:@"Uninitialized Message %@", message];
-    NSDictionary *userInfo =
-        message ? @{GPBExceptionMessageKey : message} : nil;
-    NSException *exception =
-        [NSException exceptionWithName:NSInternalInconsistencyException
-                                reason:reason
-                              userInfo:userInfo];
-    [exception raise];
-  }
-}
-#else
-GPB_INLINE void DebugRaiseExceptionIfNotInitialized(GPBMessage *message) {
-#pragma unused(message)
-}
-#endif  // DEBUG
-
 @implementation GPBMessage
 
 + (void)initialize {
@@ -663,14 +731,20 @@
   if ([self class] == pbMessageClass) {
     // This is here to start up the "base" class descriptor.
     [self descriptor];
+    // Message shares extension method resolving with GPBRootObject so insure
+    // it is started up at the same time.
+    (void)[GPBRootObject class];
   } else if ([self superclass] == pbMessageClass) {
     // This is here to start up all the "message" subclasses. Just needs to be
     // done for the messages, not any of the subclasses.
     // This must be done in initialize to enforce thread safety of start up of
-    // the protocol buffer library. All of the extension registries must be
-    // created in either "+load" or "+initialize".
+    // the protocol buffer library.
+    // Note: The generated code for -descriptor calls
+    // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject
+    // subclass for the file.  That call chain is what ensures that *Root class
+    // is started up to support extension resolution off the message class
+    // (+resolveClassMethod: below) in a thread safe manner.
     [self descriptor];
-    [self extensionRegistry];
   }
 }
 
@@ -728,25 +802,63 @@
   return self;
 }
 
-- (instancetype)initWithData:(NSData *)data {
-  return [self initWithData:data extensionRegistry:nil];
+- (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr {
+  return [self initWithData:data extensionRegistry:nil error:errorPtr];
 }
 
 - (instancetype)initWithData:(NSData *)data
-           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+           extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                       error:(NSError **)errorPtr {
   if ((self = [self init])) {
-    [self mergeFromData:data extensionRegistry:extensionRegistry];
-    DebugRaiseExceptionIfNotInitialized(self);
+    @try {
+      [self mergeFromData:data extensionRegistry:extensionRegistry];
+    }
+    @catch (NSException *exception) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                           exception.reason);
+      }
+    }
+#ifdef DEBUG
+    if (self && !self.initialized) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+      }
+    }
+#endif
   }
   return self;
 }
 
 - (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
                        extensionRegistry:
-                           (GPBExtensionRegistry *)extensionRegistry {
+                           (GPBExtensionRegistry *)extensionRegistry
+                                   error:(NSError **)errorPtr {
   if ((self = [self init])) {
-    [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
-    DebugRaiseExceptionIfNotInitialized(self);
+    @try {
+      [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+    }
+    @catch (NSException *exception) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                           exception.reason);
+      }
+    }
+#ifdef DEBUG
+    if (self && !self.initialized) {
+      [self release];
+      self = nil;
+      if (errorPtr) {
+        *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+      }
+    }
+#endif
   }
   return self;
 }
@@ -900,6 +1012,20 @@
               gpbArray->_autocreator = nil;
             }
           }
+        } else {
+          if ((field.mapKeyType == GPBTypeString) &&
+              GPBFieldTypeIsObject(field)) {
+            GPBAutocreatedDictionary *autoDict = arrayOrMap;
+            if (autoDict->_autocreator == self) {
+              autoDict->_autocreator = nil;
+            }
+          } else {
+            // Type doesn't matter, it is a GPB*Dictionary.
+            GPBInt32Int32Dictionary *gpbDict = arrayOrMap;
+            if (gpbDict->_autocreator == self) {
+              gpbDict->_autocreator = nil;
+            }
+          }
         }
         [arrayOrMap release];
       }
@@ -960,7 +1086,8 @@
           }
         } else {
           NSAssert(field.isOptional,
-                   @"If not required or optional, what was it?");
+                   @"%@: Single message field %@ not required or optional?",
+                   [self class], field.name);
           if (GPBGetHasIvarField(self, field)) {
             GPBMessage *message = GPBGetMessageIvarWithField(self, field);
             if (!message.initialized) {
@@ -1025,11 +1152,27 @@
 }
 
 - (NSData *)data {
-  DebugRaiseExceptionIfNotInitialized(self);
+#ifdef DEBUG
+  if (!self.initialized) {
+    return nil;
+  }
+#endif
   NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]];
   GPBCodedOutputStream *stream =
       [[GPBCodedOutputStream alloc] initWithData:data];
-  [self writeToCodedOutputStream:stream];
+  @try {
+    [self writeToCodedOutputStream:stream];
+  }
+  @catch (NSException *exception) {
+    // This really shouldn't happen. The only way writeToCodedOutputStream:
+    // could throw is if something in the library has a bug and the
+    // serializedSize was wrong.
+#ifdef DEBUG
+    NSLog(@"%@: Internal exception while building message data: %@",
+          [self class], exception);
+#endif
+    data = nil;
+  }
   [stream release];
   return data;
 }
@@ -1041,7 +1184,19 @@
       [NSMutableData dataWithLength:(serializedSize + varintSize)];
   GPBCodedOutputStream *stream =
       [[GPBCodedOutputStream alloc] initWithData:data];
-  [self writeDelimitedToCodedOutputStream:stream];
+  @try {
+    [self writeDelimitedToCodedOutputStream:stream];
+  }
+  @catch (NSException *exception) {
+    // This really shouldn't happen.  The only way writeToCodedOutputStream:
+    // could throw is if something in the library has a bug and the
+    // serializedSize was wrong.
+#ifdef DEBUG
+    NSLog(@"%@: Internal exception while building message delimitedData: %@",
+          [self class], exception);
+#endif
+    data = nil;
+  }
   [stream release];
   return data;
 }
@@ -1717,32 +1872,55 @@
 
 #pragma mark - Parse From Data Support
 
-+ (instancetype)parseFromData:(NSData *)data {
-  return [self parseFromData:data extensionRegistry:nil];
++ (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr {
+  return [self parseFromData:data extensionRegistry:nil error:errorPtr];
 }
 
 + (instancetype)parseFromData:(NSData *)data
-            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+            extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                        error:(NSError **)errorPtr {
   return [[[self alloc] initWithData:data
-                   extensionRegistry:extensionRegistry] autorelease];
+                   extensionRegistry:extensionRegistry
+                               error:errorPtr] autorelease];
 }
 
 + (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
-                        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry {
+                        extensionRegistry:(GPBExtensionRegistry *)extensionRegistry
+                                    error:(NSError **)errorPtr {
   return
       [[[self alloc] initWithCodedInputStream:input
-                            extensionRegistry:extensionRegistry] autorelease];
+                            extensionRegistry:extensionRegistry
+                                        error:errorPtr] autorelease];
 }
 
 #pragma mark - Parse Delimited From Data Support
 
 + (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
                                  extensionRegistry:
-                                     (GPBExtensionRegistry *)extensionRegistry {
+                                     (GPBExtensionRegistry *)extensionRegistry
+                                             error:(NSError **)errorPtr {
   GPBMessage *message = [[[self alloc] init] autorelease];
-  [message mergeDelimitedFromCodedInputStream:input
-                            extensionRegistry:extensionRegistry];
-  DebugRaiseExceptionIfNotInitialized(message);
+  @try {
+    [message mergeDelimitedFromCodedInputStream:input
+                              extensionRegistry:extensionRegistry];
+  }
+  @catch (NSException *exception) {
+    [message release];
+    message = nil;
+    if (errorPtr) {
+      *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData,
+                                         exception.reason);
+    }
+  }
+#ifdef DEBUG
+  if (message && !message.initialized) {
+    [message release];
+    message = nil;
+    if (errorPtr) {
+      *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
+    }
+  }
+#endif
   return message;
 }
 
@@ -4661,7 +4839,9 @@
         context.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
           if (value) {
             [NSException raise:NSInvalidArgumentException
-                        format:@"has fields can only be set to NO"];
+                        format:@"%@: %@ can only be set to NO (to clear field).",
+                               [obj class],
+                               NSStringFromSelector(field->setHasSel_)];
           }
           GPBClearMessageField(obj, field);
         });
@@ -4684,9 +4864,15 @@
       }
     } else {
       if (sel == field->getSel_) {
-        context.impToAdd = imp_implementationWithBlock(^(id obj) {
-          return GetArrayIvarWithField(obj, field);
-        });
+        if (field.fieldType == GPBFieldTypeRepeated) {
+          context.impToAdd = imp_implementationWithBlock(^(id obj) {
+            return GetArrayIvarWithField(obj, field);
+          });
+        } else {
+          context.impToAdd = imp_implementationWithBlock(^(id obj) {
+            return GetMapIvarWithField(obj, field);
+          });
+        }
         context.encodingSelector = @selector(getArray);
         break;
       } else if (sel == field->setSel_) {
@@ -4711,18 +4897,37 @@
   return [super resolveInstanceMethod:sel];
 }
 
++ (BOOL)resolveClassMethod:(SEL)sel {
+  // Extensions scoped to a Message and looked up via class methods.
+  if (GPBResolveExtensionClassMethod(self, sel)) {
+    return YES;
+  }
+  return [super resolveClassMethod:sel];
+}
+
 #pragma mark - NSCoding Support
 
++ (BOOL)supportsSecureCoding {
+  return YES;
+}
+
 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
   self = [self init];
   if (self) {
-    [self mergeFromData:[aDecoder decodeDataObject] extensionRegistry:nil];
+    NSData *data =
+        [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
+    if (data.length) {
+      [self mergeFromData:data extensionRegistry:nil];
+    }
   }
   return self;
 }
 
 - (void)encodeWithCoder:(NSCoder *)aCoder {
-  [aCoder encodeDataObject:[self data]];
+  NSData *data = [self data];
+  if (data.length) {
+    [aCoder encodeObject:data forKey:kGPBDataCoderKey];
+  }
 }
 
 #pragma mark - KVC Support
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
index f2a3d5f..c437c55 100644
--- a/objectivec/GPBMessage_PackagePrivate.h
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -82,6 +82,7 @@
 // -[CodedInputStream checkLastTagWas:] after calling this to
 // verify that the last tag seen was the appropriate end-group tag,
 // or zero for EOF.
+// NOTE: This will throw if there is an error while parsing.
 - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
                 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry;
 
@@ -113,9 +114,10 @@
 // visible to its autocreator.
 void GPBBecomeVisibleToAutocreator(GPBMessage *self);
 
-// Call this when an array is mutabled so the parent message that autocreated
-// it can react.
+// Call this when an array/dictionary is mutated so the parent message that
+// autocreated it can react.
 void GPBAutocreatedArrayModified(GPBMessage *self, id array);
+void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary);
 
 // Clear the autocreator, if any. Asserts if the autocreator still has an
 // autocreated reference to this message.
diff --git a/objectivec/GPBProtocolBuffers_RuntimeSupport.h b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
index ac3226e..7fd7b4c 100644
--- a/objectivec/GPBProtocolBuffers_RuntimeSupport.h
+++ b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
@@ -35,7 +35,7 @@
 
 #import "GPBDescriptor_PackagePrivate.h"
 #import "GPBExtensionField_PackagePrivate.h"
-#import "GPBExtensionRegistry_PackagePrivate.h"
+#import "GPBExtensionRegistry.h"
 #import "GPBMessage_PackagePrivate.h"
 #import "GPBRootObject_PackagePrivate.h"
 #import "GPBUtilities_PackagePrivate.h"
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m
index b58f95c..38dab66 100644
--- a/objectivec/GPBRootObject.m
+++ b/objectivec/GPBRootObject.m
@@ -31,6 +31,7 @@
 #import "GPBRootObject_PackagePrivate.h"
 
 #import <objc/runtime.h>
+#import <libkern/OSAtomic.h>
 
 #import <CoreFoundation/CoreFoundation.h>
 
@@ -95,9 +96,11 @@
   return jenkins_one_at_a_time_hash(key);
 }
 
+static OSSpinLock gExtensionSingletonDictionaryLock_ = OS_SPINLOCK_INIT;
 static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL;
 
 + (void)initialize {
+  // Ensure the global is started up.
   if (!gExtensionSingletonDictionary) {
     CFDictionaryKeyCallBacks keyCallBacks = {
       // See description above for reason for using custom dictionary.
@@ -112,6 +115,13 @@
         CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks,
                                   &kCFTypeDictionaryValueCallBacks);
   }
+
+  if ([self superclass] == [GPBRootObject class]) {
+    // This is here to start up all the per file "Root" subclasses.
+    // This must be done in initialize to enforce thread safety of start up of
+    // the protocol buffer library.
+    [self extensionRegistry];
+  }
 }
 
 + (GPBExtensionRegistry *)extensionRegistry {
@@ -122,39 +132,54 @@
 
 + (void)globallyRegisterExtension:(GPBExtensionField *)field {
   const char *key = [field.descriptor singletonNameC];
-  // Register happens at startup, so there is no thread safety issue in
-  // modifying the dictionary.
+  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
   CFDictionarySetValue(gExtensionSingletonDictionary, key, field);
+  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
 }
 
-static id ExtensionForName(id self, SEL _cmd) {
+GPB_INLINE id ExtensionForName(id self, SEL _cmd) {
   // Really fast way of doing "classname_selName".
   // This came up as a hotspot (creation of NSString *) when accessing a
   // lot of extensions.
-  const char *className = class_getName(self);
   const char *selName = sel_getName(_cmd);
+  if (selName[0] == '_') {
+    return nil;  // Apple internal selector.
+  }
+  size_t selNameLen = 0;
+  while (1) {
+    char c = selName[selNameLen];
+    if (c == '\0') {  // String end.
+      break;
+    }
+    if (c == ':') {
+      return nil;  // Selector took an arg, not one of the runtime methods.
+    }
+    ++selNameLen;
+  }
+
+  const char *className = class_getName(self);
   size_t classNameLen = strlen(className);
-  size_t selNameLen = strlen(selName);
   char key[classNameLen + selNameLen + 2];
   memcpy(key, className, classNameLen);
   key[classNameLen] = '_';
   memcpy(&key[classNameLen + 1], selName, selNameLen);
   key[classNameLen + 1 + selNameLen] = '\0';
+  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
   id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
-  // We can't remove the key from the dictionary here (as an optimization),
-  // because resolveClassMethod can happen on any thread and we'd then need
-  // a lock.
+  if (extension) {
+    // The method is getting wired in to the class, so no need to keep it in
+    // the dictionary.
+    CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
+  }
+  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
   return extension;
 }
 
-+ (BOOL)resolveClassMethod:(SEL)sel {
+BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) {
   // Another option would be to register the extensions with the class at
   // globallyRegisterExtension:
   // Timing the two solutions, this solution turned out to be much faster
   // and reduced startup time, and runtime memory.
-  // On an iPhone 5s:
-  // ResolveClassMethod: 1515583 nanos
-  // globallyRegisterExtension: 2453083 nanos
   // The advantage to globallyRegisterExtension is that it would reduce the
   // size of the protos somewhat because the singletonNameC wouldn't need
   // to include the class name. For a class with a lot of extensions it
@@ -169,7 +194,17 @@
 #pragma unused(obj)
       return extension;
     });
-    return class_addMethod(metaClass, sel, imp, encoding);
+    if (class_addMethod(metaClass, sel, imp, encoding)) {
+      return YES;
+    }
+  }
+  return NO;
+}
+
+
++ (BOOL)resolveClassMethod:(SEL)sel {
+  if (GPBResolveExtensionClassMethod(self, sel)) {
+    return YES;
   }
   return [super resolveClassMethod:sel];
 }
diff --git a/objectivec/GPBRootObject_PackagePrivate.h b/objectivec/GPBRootObject_PackagePrivate.h
index 4e1d391..f1cfe99 100644
--- a/objectivec/GPBRootObject_PackagePrivate.h
+++ b/objectivec/GPBRootObject_PackagePrivate.h
@@ -40,3 +40,7 @@
 + (void)globallyRegisterExtension:(GPBExtensionField *)field;
 
 @end
+
+// Returns YES if the selector was resolved and added to the class,
+// NO otherwise.
+BOOL GPBResolveExtensionClassMethod(Class self, SEL sel);
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 09e34bf..f912b97 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -93,7 +93,9 @@
 }
 
 BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
   if (idx < 0) {
     NSCAssert(fieldNumber != 0, @"Invalid field number.");
     BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber);
@@ -109,7 +111,8 @@
 }
 
 uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) {
-  NSCAssert(idx < 0, @"invalid index for oneof.");
+  NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.",
+            [self class], idx);
   uint32_t result = self->messageStorage_->_has_storage_[-idx];
   return result;
 }
@@ -145,7 +148,9 @@
   // Like GPBClearMessageField(), free the memory if an objecttype is set,
   // pod types don't need to do anything.
   GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet];
-  NSCAssert(fieldSet, @"oneof set to something not in the oneof?");
+  NSCAssert(fieldSet,
+            @"%@: oneof set to something (%u) not in the oneof?",
+            [self class], fieldNumberSet);
   if (fieldSet && GPBFieldStoresObject(fieldSet)) {
     uint8_t *storage = (uint8_t *)self->messageStorage_;
     id *typePtr = (id *)&storage[fieldSet->description_->offset];
@@ -189,7 +194,9 @@
 //%  if (oneof) {
 //%    GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
 //%  }
-//%  NSCAssert(self->messageStorage_ != NULL, @"How?");
+//%  NSCAssert(self->messageStorage_ != NULL,
+//%            @"%@: All messages should have storage (from init)",
+//%            [self class]);
 //%#if defined(__clang_analyzer__)
 //%  if (self->messageStorage_ == NULL) return;
 //%#endif
@@ -263,7 +270,9 @@
 void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
                                                GPBFieldDescriptor *field,
                                                id value, GPBFileSyntax syntax) {
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -328,7 +337,7 @@
   if (oldValue) {
     if (isMapOrArray) {
       if (field.fieldType == GPBFieldTypeRepeated) {
-        // If the old message value was autocreated by us, then clear it.
+        // If the old array was autocreated by us, then clear it.
         if (GPBTypeIsObject(fieldType)) {
           GPBAutocreatedArray *autoArray = oldValue;
           if (autoArray->_autocreator == self) {
@@ -341,6 +350,21 @@
             gpbArray->_autocreator = nil;
           }
         }
+      } else { // GPBFieldTypeMap
+        // If the old map was autocreated by us, then clear it.
+        if ((field.mapKeyType == GPBTypeString) &&
+            GPBTypeIsObject(fieldType)) {
+          GPBAutocreatedDictionary *autoDict = oldValue;
+          if (autoDict->_autocreator == self) {
+            autoDict->_autocreator = nil;
+          }
+        } else {
+          // Type doesn't matter, it is a GPB*Dictionary.
+          GPBInt32Int32Dictionary *gpbDict = oldValue;
+          if (gpbDict->_autocreator == self) {
+            gpbDict->_autocreator = nil;
+          }
+        }
       }
     } else if (fieldIsMessage) {
       // If the old message value was autocreated by us, then clear it.
@@ -461,7 +485,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -507,7 +533,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -553,7 +581,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -599,7 +629,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -645,7 +677,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -691,7 +725,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -737,7 +773,9 @@
   if (oneof) {
     GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field));
   }
-  NSCAssert(self->messageStorage_ != NULL, @"How?");
+  NSCAssert(self->messageStorage_ != NULL,
+            @"%@: All messages should have storage (from init)",
+            [self class]);
 #if defined(__clang_analyzer__)
   if (self->messageStorage_ == NULL) return;
 #endif
@@ -1152,30 +1190,32 @@
                                             GPBFieldDescriptor *field,
                                             NSMutableString *toStr,
                                             NSString *lineIndent) {
-  id array;
-  NSUInteger arrayCount;
+  id arrayOrMap;
+  NSUInteger count;
   GPBFieldType fieldType = field.fieldType;
   switch (fieldType) {
     case GPBFieldTypeSingle:
-      array = nil;
-      arrayCount = (GPBGetHasIvarField(message, field) ? 1 : 0);
+      arrayOrMap = nil;
+      count = (GPBGetHasIvarField(message, field) ? 1 : 0);
       break;
 
     case GPBFieldTypeRepeated:
-      array = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
-      arrayCount = [(NSArray *)array count];
+      // Will be NSArray or GPB*Array, type doesn't matter, they both
+      // implement count.
+      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
+      count = [(NSArray *)arrayOrMap count];
       break;
 
     case GPBFieldTypeMap: {
-      // Could be a GPB*Dictionary or NSMutableDictionary, type doesn't matter,
-      // just want count.
-      array = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
-      arrayCount = [(NSArray *)array count];
+      // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
+      // they both implement count.
+      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
+      count = [(NSDictionary *)arrayOrMap count];
       break;
     }
   }
 
-  if (arrayCount == 0) {
+  if (count == 0) {
     // Nothing to print, out of here.
     return;
   }
@@ -1189,7 +1229,7 @@
     fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
     // If there is only one entry, put the objc name as a comment, other wise
     // add it before the the repeated values.
-    if (arrayCount > 1) {
+    if (count > 1) {
       [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
     } else {
       lineEnding = [NSString stringWithFormat:@"  # %@", field.name];
@@ -1197,16 +1237,17 @@
   }
 
   if (fieldType == GPBFieldTypeMap) {
-    AppendTextFormatForMapMessageField(array, field, toStr, lineIndent,
+    AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
                                        fieldName, lineEnding);
     return;
   }
 
+  id array = arrayOrMap;
   const BOOL isRepeated = (array != nil);
 
   GPBType fieldDataType = GPBGetFieldType(field);
   BOOL isMessageField = GPBTypeIsMessage(fieldDataType);
-  for (NSUInteger j = 0; j < arrayCount; ++j) {
+  for (NSUInteger j = 0; j < count; ++j) {
     // Start the line.
     [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
                         (isMessageField ? "" : ":")];
@@ -1291,7 +1332,7 @@
     // End the line.
     [toStr appendFormat:@"%@\n", lineEnding];
 
-  }  // for(arrayCount)
+  }  // for(count)
 }
 
 static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
index 4641604..f18ba2f 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -200,7 +200,6 @@
 		F4B6B8AF1A9CC98000892426 /* GPBField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBField_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B61A9CD1DE00892426 /* GPBExtensionField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField_PackagePrivate.h; sourceTree = "<group>"; };
-		F4B6B8B71A9CD1DE00892426 /* GPBExtensionRegistry_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B91A9D338B00892426 /* unittest_name_mangling.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_name_mangling.proto; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -301,7 +300,6 @@
 				F4B6B8B61A9CD1DE00892426 /* GPBExtensionField_PackagePrivate.h */,
 				748F0CAF0FD70602000858A9 /* GPBExtensionField.h */,
 				F45C69CB16DFD08D0081955B /* GPBExtensionField.m */,
-				F4B6B8B71A9CD1DE00892426 /* GPBExtensionRegistry_PackagePrivate.h */,
 				7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */,
 				7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */,
 				F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */,
@@ -595,7 +593,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/bash;
-			shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\nexport GPB_CLASSLIST_PATH=\"${PROJECT_DERIVED_FILE_DIR}/ClassList.txt\"\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n\nif [ -e ${GPB_CLASSLIST_PATH} ]; then\nrm ${GPB_CLASSLIST_PATH}\nfi\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n";
+			shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\n# Use the filter\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n";
 			showEnvVarsInLog = 0;
 		};
 		F4B62A781AF91F6000AFCEDC /* Script: Check Runtime Stamps */ = {
@@ -819,6 +817,7 @@
 				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_NS_ASSERTIONS = NO;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
index f6f6e12..617fb47 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -34,6 +34,20 @@
                ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "NO"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
index 7cf4135..d6e621e 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -224,7 +224,6 @@
 		F4B6B8B01A9CC99500892426 /* GPBField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBField_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B31A9CD1C600892426 /* GPBExtensionField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionField_PackagePrivate.h; sourceTree = "<group>"; };
-		F4B6B8B41A9CD1C600892426 /* GPBExtensionRegistry_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionRegistry_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8BA1A9D343B00892426 /* unittest_name_mangling.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_name_mangling.proto; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -339,7 +338,6 @@
 				F4B6B8B31A9CD1C600892426 /* GPBExtensionField_PackagePrivate.h */,
 				748F0CAF0FD70602000858A9 /* GPBExtensionField.h */,
 				F45C69CB16DFD08D0081955B /* GPBExtensionField.m */,
-				F4B6B8B41A9CD1C600892426 /* GPBExtensionRegistry_PackagePrivate.h */,
 				7461B4A80F94F99000A0C422 /* GPBExtensionRegistry.h */,
 				7461B4A90F94F99000A0C422 /* GPBExtensionRegistry.m */,
 				F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */,
@@ -683,7 +681,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/bash;
-			shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\nexport GPB_CLASSLIST_PATH=\"${PROJECT_DERIVED_FILE_DIR}/ClassList.txt\"\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n\nif [ -e ${GPB_CLASSLIST_PATH} ]; then\nrm ${GPB_CLASSLIST_PATH}\nfi\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n";
+			shellScript = "set -eu\nmkdir -p \"${PROJECT_DERIVED_FILE_DIR}/protos\"\nexport PATH=\"${PATH}:.\"\ncd \"${SRCROOT}\"/../src\n\nPROTOC=./protoc\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_custom_options.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_enormous_descriptor.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_embed_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_empty.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_mset.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_no_generic_services.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_optimize_for.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_import_public_lite.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_drop_unknown_fields.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/unittest_preserve_unknown_enum.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_lite_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_proto2_unittest.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. google/protobuf/map_unittest.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=google/protobuf/ --proto_path=. --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_objc.proto\n\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_cycle.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_name_mangling.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto2.proto\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_runtime_proto3.proto\n\n# Use the filter\nexport GPB_OBJC_CLASS_WHITELIST_PATHS=\"${SRCROOT}/Tests/Filter1.txt;${SRCROOT}/Tests/Filter2.txt\"\n$PROTOC --objc_out=\"${PROJECT_DERIVED_FILE_DIR}/protos/google/protobuf\" --proto_path=\"${SRCROOT}\"/Tests \"${SRCROOT}\"/Tests/unittest_filter.proto\n\n";
 			showEnvVarsInLog = 0;
 		};
 		F4B62A791AF91F7500AFCEDC /* Script: Check Runtime Stamps */ = {
@@ -984,6 +982,7 @@
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_NS_ASSERTIONS = NO;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
index a1b4cc4..c3c2c7d 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -34,6 +34,20 @@
                ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "NO"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8BBEA4A5147C727100C4ADB7"
+               BuildableName = "UnitTests.xctest"
+               BlueprintName = "UnitTests"
+               ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
diff --git a/objectivec/README.md b/objectivec/README.md
new file mode 100644
index 0000000..186e45b
--- /dev/null
+++ b/objectivec/README.md
@@ -0,0 +1,77 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the Objective C Protocol Buffers runtime library.
+
+Requirements
+------------
+
+The Objective C implemention requires:
+
+- Objective C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X).
+- Xcode 6.3 (or later).
+- The library code does *not* use ARC (for performance reasons), but it all can
+  be called from ARC code.
+
+Installation
+------------
+
+The full distribution pulled from github includes the sources for both the
+compiler (protoc) and the runtime (this directory).  To build the compiler
+and run the runtime tests, you can use:
+
+     $ objectivec/DevTools/full_mac_build.sh
+
+This will generate the `src/protoc` binary.
+
+Usage
+-----
+
+There are two ways to include the Runtime sources in your project:
+
+Add `objectivec/\*.h` & `objectivec/GPBProtocolBuffers.m` to your project.
+
+*or*
+
+Add `objectivec/\*.h` & `objectivec/\*.m` except for
+`objectivec/GPBProtocolBuffers.m` to your project.
+
+
+If the target is using ARC, remember to turn off ARC (`-fno-objc-arc`) for the
+`.m` files.
+
+The files generated by `protoc` for the `*.proto` files (`\*.pbobjc.h' and
+`\*.pbobjc.m`) are then also added to the target.
+
+The Objective C classes/enums can be used from Swift code.
+
+Objective C Generator Options
+-----------------------------
+
+**objc_class_prefix=\<prefix\>** (no default)
+
+Since Objective C uses a global namespace for all of its classes, there can
+be collisions.  This option provides a prefix that will be added to the Enums
+and Objects (for messages) generated from the proto.  Convention is to base
+the prefix on the package the proto is in.
+
+Contributing
+------------
+
+Please make updates to the tests along with changes. If just changing the
+runtime, the Xcode projects can be used to build and run tests.  If change also
+require changes to the generated code, `objectivec/DevTools/full_mac_build.sh`
+can be used to easily rebuild and test changes. Passing `-h` to the script will
+show the addition options that could be useful.
+
+Documentation
+-------------
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m
index 37724c5..0fb15e4 100644
--- a/objectivec/Tests/GPBArrayTests.m
+++ b/objectivec/Tests/GPBArrayTests.m
@@ -29,14 +29,11 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #import <Foundation/Foundation.h>
-
 #import <XCTest/XCTest.h>
 
 #import "GPBArray.h"
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
+#import "GPBTestUtilities.h"
 
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBEnumArray (TestingTweak)
@@ -233,6 +230,8 @@
 //%  // Should be new object but equal.
 //%  XCTAssertNotEqual(array, array2);
 //%  XCTAssertEqualObjects(array, array2);
+//%  [array2 release];
+//%  [array release];
 //%}
 //%
 //%- (void)testArrayFromArray {
@@ -248,6 +247,7 @@
 //%  // Should be new pointer, but equal objects.
 //%  XCTAssertNotEqual(array, array2);
 //%  XCTAssertEqualObjects(array, array2);
+//%  [array release];
 //%}
 //%
 //%- (void)testAdds {
@@ -275,6 +275,7 @@
 //%  XCTAssertEqual([array valueAtIndex:2], VAL3);
 //%  XCTAssertEqual([array valueAtIndex:3], VAL4);
 //%  XCTAssertEqual([array valueAtIndex:4], VAL1);
+//%  [array2 release];
 //%}
 //%
 //%- (void)testInsert {
@@ -307,6 +308,7 @@
 //%  XCTAssertEqual([array valueAtIndex:3], VAL2);
 //%  XCTAssertEqual([array valueAtIndex:4], VAL3);
 //%  XCTAssertEqual([array valueAtIndex:5], VAL4);
+//%  [array release];
 //%}
 //%
 //%- (void)testRemove {
@@ -343,6 +345,7 @@
 //%  XCTAssertEqual(array.count, 0U);
 //%  XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
 //%                               NSException, NSRangeException);
+//%  [array release];
 //%}
 //%
 //%- (void)testInplaceMutation {
@@ -381,6 +384,7 @@
 //%                               NSException, NSRangeException);
 //%  XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
 //%                               NSException, NSRangeException);
+//%  [array release];
 //%}
 //%
 //%- (void)testInternalResizing {
@@ -405,6 +409,7 @@
 //%  XCTAssertEqual(array.count, 404U);
 //%  [array removeAll];
 //%  XCTAssertEqual(array.count, 0U);
+//%  [array release];
 //%}
 //%
 //%@end
@@ -558,6 +563,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -573,6 +580,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -600,6 +608,7 @@
   XCTAssertEqual([array valueAtIndex:2], 3);
   XCTAssertEqual([array valueAtIndex:3], 4);
   XCTAssertEqual([array valueAtIndex:4], 1);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -632,6 +641,7 @@
   XCTAssertEqual([array valueAtIndex:3], 2);
   XCTAssertEqual([array valueAtIndex:4], 3);
   XCTAssertEqual([array valueAtIndex:5], 4);
+  [array release];
 }
 
 - (void)testRemove {
@@ -668,6 +678,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -706,6 +717,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -730,6 +742,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -883,6 +896,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -898,6 +913,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -925,6 +941,7 @@
   XCTAssertEqual([array valueAtIndex:2], 13U);
   XCTAssertEqual([array valueAtIndex:3], 14U);
   XCTAssertEqual([array valueAtIndex:4], 11U);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -957,6 +974,7 @@
   XCTAssertEqual([array valueAtIndex:3], 12U);
   XCTAssertEqual([array valueAtIndex:4], 13U);
   XCTAssertEqual([array valueAtIndex:5], 14U);
+  [array release];
 }
 
 - (void)testRemove {
@@ -993,6 +1011,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -1031,6 +1050,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -1055,6 +1075,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -1208,6 +1229,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -1223,6 +1246,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -1250,6 +1274,7 @@
   XCTAssertEqual([array valueAtIndex:2], 33LL);
   XCTAssertEqual([array valueAtIndex:3], 34LL);
   XCTAssertEqual([array valueAtIndex:4], 31LL);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -1282,6 +1307,7 @@
   XCTAssertEqual([array valueAtIndex:3], 32LL);
   XCTAssertEqual([array valueAtIndex:4], 33LL);
   XCTAssertEqual([array valueAtIndex:5], 34LL);
+  [array release];
 }
 
 - (void)testRemove {
@@ -1318,6 +1344,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -1356,6 +1383,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -1380,6 +1408,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -1533,6 +1562,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -1548,6 +1579,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -1575,6 +1607,7 @@
   XCTAssertEqual([array valueAtIndex:2], 43ULL);
   XCTAssertEqual([array valueAtIndex:3], 44ULL);
   XCTAssertEqual([array valueAtIndex:4], 41ULL);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -1607,6 +1640,7 @@
   XCTAssertEqual([array valueAtIndex:3], 42ULL);
   XCTAssertEqual([array valueAtIndex:4], 43ULL);
   XCTAssertEqual([array valueAtIndex:5], 44ULL);
+  [array release];
 }
 
 - (void)testRemove {
@@ -1643,6 +1677,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -1681,6 +1716,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -1705,6 +1741,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -1858,6 +1895,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -1873,6 +1912,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -1900,6 +1940,7 @@
   XCTAssertEqual([array valueAtIndex:2], 53.f);
   XCTAssertEqual([array valueAtIndex:3], 54.f);
   XCTAssertEqual([array valueAtIndex:4], 51.f);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -1932,6 +1973,7 @@
   XCTAssertEqual([array valueAtIndex:3], 52.f);
   XCTAssertEqual([array valueAtIndex:4], 53.f);
   XCTAssertEqual([array valueAtIndex:5], 54.f);
+  [array release];
 }
 
 - (void)testRemove {
@@ -1968,6 +2010,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -2006,6 +2049,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -2030,6 +2074,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -2183,6 +2228,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -2198,6 +2245,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -2225,6 +2273,7 @@
   XCTAssertEqual([array valueAtIndex:2], 63.);
   XCTAssertEqual([array valueAtIndex:3], 64.);
   XCTAssertEqual([array valueAtIndex:4], 61.);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -2257,6 +2306,7 @@
   XCTAssertEqual([array valueAtIndex:3], 62.);
   XCTAssertEqual([array valueAtIndex:4], 63.);
   XCTAssertEqual([array valueAtIndex:5], 64.);
+  [array release];
 }
 
 - (void)testRemove {
@@ -2293,6 +2343,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -2331,6 +2382,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -2355,6 +2407,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -2508,6 +2561,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -2523,6 +2578,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -2550,6 +2606,7 @@
   XCTAssertEqual([array valueAtIndex:2], FALSE);
   XCTAssertEqual([array valueAtIndex:3], FALSE);
   XCTAssertEqual([array valueAtIndex:4], TRUE);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -2582,6 +2639,7 @@
   XCTAssertEqual([array valueAtIndex:3], TRUE);
   XCTAssertEqual([array valueAtIndex:4], FALSE);
   XCTAssertEqual([array valueAtIndex:5], FALSE);
+  [array release];
 }
 
 - (void)testRemove {
@@ -2618,6 +2676,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -2656,6 +2715,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -2680,6 +2740,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -2833,6 +2894,8 @@
   // Should be new object but equal.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -2848,6 +2911,7 @@
   // Should be new pointer, but equal objects.
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
+  [array release];
 }
 
 - (void)testAdds {
@@ -2875,6 +2939,7 @@
   XCTAssertEqual([array valueAtIndex:2], 73);
   XCTAssertEqual([array valueAtIndex:3], 74);
   XCTAssertEqual([array valueAtIndex:4], 71);
+  [array2 release];
 }
 
 - (void)testInsert {
@@ -2907,6 +2972,7 @@
   XCTAssertEqual([array valueAtIndex:3], 72);
   XCTAssertEqual([array valueAtIndex:4], 73);
   XCTAssertEqual([array valueAtIndex:5], 74);
+  [array release];
 }
 
 - (void)testRemove {
@@ -2943,6 +3009,7 @@
   XCTAssertEqual(array.count, 0U);
   XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInplaceMutation {
@@ -2981,6 +3048,7 @@
                                NSException, NSRangeException);
   XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testInternalResizing {
@@ -3005,6 +3073,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
@@ -3165,6 +3234,8 @@
   XCTAssertEqual([array2 rawValueAtIndex:1], 72);
   XCTAssertEqual([array2 rawValueAtIndex:2], 1000);
   XCTAssertEqual([array2 valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
+  [array2 release];
+  [array release];
 }
 
 - (void)testArrayFromArray {
@@ -3182,6 +3253,7 @@
   XCTAssertNotEqual(array, array2);
   XCTAssertEqualObjects(array, array2);
   XCTAssertEqual(array.validationFunc, array2.validationFunc);
+  [array release];
 }
 
 - (void)testUnknownAdds {
@@ -3197,7 +3269,6 @@
   XCTAssertThrowsSpecificNamed([array addValues:kValues1 count:GPBARRAYSIZE(kValues1)],
                                NSException, NSInvalidArgumentException);
   XCTAssertEqual(array.count, 0U);
-
   [array release];
 }
 
@@ -3229,7 +3300,6 @@
   XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue);
   XCTAssertEqual([array rawValueAtIndex:3], 74);
   XCTAssertEqual([array rawValueAtIndex:4], 71);
-
   [array release];
 }
 
@@ -3256,6 +3326,7 @@
   XCTAssertThrowsSpecificNamed([array insertValue:374 atIndex:3],
                                NSException, NSInvalidArgumentException);
   XCTAssertEqual(array.count, 3U);
+  [array release];
 }
 
 - (void)testRawInsert {
@@ -3292,7 +3363,6 @@
   XCTAssertEqual([array rawValueAtIndex:4], 73);
   XCTAssertEqual([array rawValueAtIndex:5], 374);
   XCTAssertEqual([array valueAtIndex:5], kGPBUnrecognizedEnumeratorValue);
-
   [array release];
 }
 
@@ -3313,6 +3383,7 @@
   XCTAssertEqual([array valueAtIndex:1], 72);
   XCTAssertEqual([array valueAtIndex:2], 73);
   XCTAssertEqual([array valueAtIndex:3], 74);
+  [array release];
 }
 
 
@@ -3336,6 +3407,7 @@
 
   XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withRawValue:74],
                                NSException, NSRangeException);
+  [array release];
 }
 
 - (void)testRawInternalResizing {
@@ -3360,6 +3432,7 @@
   XCTAssertEqual(array.count, 404U);
   [array removeAll];
   XCTAssertEqual(array.count, 0U);
+  [array release];
 }
 
 @end
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
index 0a709cb..5f29d7c 100644
--- a/objectivec/Tests/GPBCodedInputStreamTests.m
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -184,7 +184,7 @@
   XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
 
   TestAllTypes* message2 =
-      [TestAllTypes parseFromData:rawBytes extensionRegistry:nil];
+      [TestAllTypes parseFromData:rawBytes extensionRegistry:nil error:NULL];
   [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
 }
 
@@ -227,8 +227,9 @@
   // reading.
   GPBCodedInputStream* stream =
       [GPBCodedInputStream streamWithData:message.data];
-  TestAllTypes* message2 =
-      [TestAllTypes parseFromCodedInputStream:stream extensionRegistry:nil];
+  TestAllTypes* message2 = [TestAllTypes parseFromCodedInputStream:stream
+                                                 extensionRegistry:nil
+                                                             error:NULL];
 
   XCTAssertEqualObjects(message.optionalBytes, message2.optionalBytes);
 
@@ -280,8 +281,9 @@
   NSData* data =
       [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
   GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
-  TestAllTypes* message =
-      [TestAllTypes parseFromCodedInputStream:input extensionRegistry:nil];
+  TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
+                                                extensionRegistry:nil
+                                                            error:NULL];
   // Make sure we can read string properties twice without crashing.
   XCTAssertEqual([message.defaultString length], (NSUInteger)0);
   XCTAssertEqualObjects(@"", message.defaultString);
diff --git a/objectivec/Tests/GPBConcurrencyTests.m b/objectivec/Tests/GPBConcurrencyTests.m
index 3749fc3..e500ad7 100644
--- a/objectivec/Tests/GPBConcurrencyTests.m
+++ b/objectivec/Tests/GPBConcurrencyTests.m
@@ -31,10 +31,16 @@
 #import "GPBTestUtilities.h"
 
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
 
 static const int kNumThreads = 100;
 static const int kNumMessages = 100;
 
+// NOTE: Most of these tests don't "fail" in the sense that the XCTAsserts
+// trip.  Rather, the asserts simply exercise the apis, and if there is
+// a concurancy issue, the NSAsserts in the runtime code fire and/or the
+// code just crashes outright.
+
 @interface ConcurrencyTests : GPBTestCase
 @end
 
@@ -132,6 +138,48 @@
   }
 }
 
+- (void)readInt32Int32Map:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestRecursiveMessageWithRepeatedField *message in messages) {
+      XCTAssertEqual([message.iToI count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetInt32Int32MapField {
+  NSArray *messages =
+      [self createMessagesWithType:[TestRecursiveMessageWithRepeatedField class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readInt32Int32Map:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestRecursiveMessageWithRepeatedField *message in messages) {
+    XCTAssertEqual([message.iToI count], (NSUInteger)0);
+  }
+}
+
+- (void)readStringStringMap:(NSArray *)messages {
+  for (int i = 0; i < 10; i++) {
+    for (TestRecursiveMessageWithRepeatedField *message in messages) {
+      XCTAssertEqual([message.strToStr count], (NSUInteger)0);
+    }
+  }
+}
+
+- (void)testConcurrentReadOfUnsetStringStringMapField {
+  NSArray *messages =
+      [self createMessagesWithType:[TestRecursiveMessageWithRepeatedField class]];
+  NSArray *threads =
+      [self createThreadsWithSelector:@selector(readStringStringMap:)
+                               object:messages];
+  [self startThreads:threads];
+  [self joinThreads:threads];
+  for (TestRecursiveMessageWithRepeatedField *message in messages) {
+    XCTAssertEqual([message.strToStr count], (NSUInteger)0);
+  }
+}
+
 - (void)readOptionalForeignMessageExtension:(NSArray *)messages {
   for (int i = 0; i < 10; i++) {
     for (TestAllExtensions *message in messages) {
diff --git a/objectivec/Tests/GPBDictionaryTests+Bool.m b/objectivec/Tests/GPBDictionaryTests+Bool.m
index bc4998b..43650f5 100644
--- a/objectivec/Tests/GPBDictionaryTests+Bool.m
+++ b/objectivec/Tests/GPBDictionaryTests+Bool.m
@@ -33,12 +33,9 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // Pull in the macros (using an external file because expanding all tests
 // in a single file makes a file that is failing to work with within Xcode.
 //%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm
diff --git a/objectivec/Tests/GPBDictionaryTests+Int32.m b/objectivec/Tests/GPBDictionaryTests+Int32.m
index 5e25799..1ee099e 100644
--- a/objectivec/Tests/GPBDictionaryTests+Int32.m
+++ b/objectivec/Tests/GPBDictionaryTests+Int32.m
@@ -33,6 +33,7 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
 // Pull in the macros (using an external file because expanding all tests
@@ -42,10 +43,6 @@
 //%PDDM-EXPAND TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14)
 // This block of code is generated, do not edit it directly.
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBInt32EnumDictionary (TestingTweak)
 + (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key;
diff --git a/objectivec/Tests/GPBDictionaryTests+Int64.m b/objectivec/Tests/GPBDictionaryTests+Int64.m
index 6e794d3..4a94e03 100644
--- a/objectivec/Tests/GPBDictionaryTests+Int64.m
+++ b/objectivec/Tests/GPBDictionaryTests+Int64.m
@@ -33,6 +33,7 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
 // Pull in the macros (using an external file because expanding all tests
@@ -42,10 +43,6 @@
 //%PDDM-EXPAND TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL)
 // This block of code is generated, do not edit it directly.
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBInt64EnumDictionary (TestingTweak)
 + (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key;
diff --git a/objectivec/Tests/GPBDictionaryTests+String.m b/objectivec/Tests/GPBDictionaryTests+String.m
index 95bf2d0..09fbc60 100644
--- a/objectivec/Tests/GPBDictionaryTests+String.m
+++ b/objectivec/Tests/GPBDictionaryTests+String.m
@@ -33,6 +33,7 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
 // Pull in the macros (using an external file because expanding all tests
@@ -42,10 +43,6 @@
 //%PDDM-EXPAND TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble")
 // This block of code is generated, do not edit it directly.
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBStringEnumDictionary (TestingTweak)
 + (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key;
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt32.m b/objectivec/Tests/GPBDictionaryTests+UInt32.m
index a89ded3..f8d280f 100644
--- a/objectivec/Tests/GPBDictionaryTests+UInt32.m
+++ b/objectivec/Tests/GPBDictionaryTests+UInt32.m
@@ -33,6 +33,7 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
 // Pull in the macros (using an external file because expanding all tests
@@ -42,10 +43,6 @@
 //%PDDM-EXPAND TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U)
 // This block of code is generated, do not edit it directly.
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBUInt32EnumDictionary (TestingTweak)
 + (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key;
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt64.m b/objectivec/Tests/GPBDictionaryTests+UInt64.m
index 355639c..cebd6df 100644
--- a/objectivec/Tests/GPBDictionaryTests+UInt64.m
+++ b/objectivec/Tests/GPBDictionaryTests+UInt64.m
@@ -33,6 +33,7 @@
 
 #import "GPBDictionary.h"
 
+#import "GPBTestUtilities.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 
 // Pull in the macros (using an external file because expanding all tests
@@ -42,10 +43,6 @@
 //%PDDM-EXPAND TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL)
 // This block of code is generated, do not edit it directly.
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 // To let the testing macros work, add some extra methods to simplify things.
 @interface GPBUInt64EnumDictionary (TestingTweak)
 + (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key;
diff --git a/objectivec/Tests/GPBDictionaryTests.pddm b/objectivec/Tests/GPBDictionaryTests.pddm
index 39793e0..ee26fac 100644
--- a/objectivec/Tests/GPBDictionaryTests.pddm
+++ b/objectivec/Tests/GPBDictionaryTests.pddm
@@ -720,10 +720,6 @@
 //
 
 //%PDDM-DEFINE TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP)
-//%#ifndef GPBARRAYSIZE
-//%#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-//%#endif  // GPBARRAYSIZE
-//%
 //%// To let the testing macros work, add some extra methods to simplify things.
 //%@interface GPB##KEY_NAME##EnumDictionary (TestingTweak)
 //%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key;
diff --git a/objectivec/Tests/GPBMessageTests+Merge.m b/objectivec/Tests/GPBMessageTests+Merge.m
index 599ad05..3b6fdbd 100644
--- a/objectivec/Tests/GPBMessageTests+Merge.m
+++ b/objectivec/Tests/GPBMessageTests+Merge.m
@@ -35,6 +35,7 @@
 #import "GPBMessage.h"
 
 #import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
 #import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
@@ -431,7 +432,7 @@
   XCTAssertNotNil(dst.oneofGroup);
   XCTAssertNotEqual(dst.oneofGroup, mergedGroup);  // Pointer comparision.
 
-  // Back to something else ot make sure message clears out ok.
+  // Back to something else to make sure message clears out ok.
 
   src.oneofInt32 = 10;
   [dst mergeFrom:src];
@@ -640,7 +641,7 @@
   XCTAssertEqualObjects(mergedSubMessage, subMessage);
   XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault);
 
-  // Back to something else ot make sure message clears out ok.
+  // Back to something else to make sure message clears out ok.
 
   src.oneofInt32 = 10;
   [dst mergeFrom:src];
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m
index 6ad29ca..4621f90 100644
--- a/objectivec/Tests/GPBMessageTests+Runtime.m
+++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -35,6 +35,7 @@
 #import "GPBMessage.h"
 
 #import "google/protobuf/MapUnittest.pbobjc.h"
+#import "google/protobuf/Unittest.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
 
@@ -772,6 +773,8 @@
   XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException,
                                NSInvalidArgumentException);
   XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
+
+  [msg release];
 }
 
 - (void)testAccessingProto3UnknownEnumValues {
@@ -1261,7 +1264,7 @@
     Message2_O_OneOfCase_OneofEnum,
   };
 
-  for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) {
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
     switch (values[i]) {
       case Message2_O_OneOfCase_OneofInt32:
         msg.oneofInt32 = 1;
@@ -1318,7 +1321,7 @@
         msg.oneofEnum = Message2_Enum_Bar;
         break;
       default:
-        XCTFail(@"shouldn't happen, loop: %zd", i);
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
         break;
     }
 
@@ -1770,7 +1773,7 @@
     Message3_O_OneOfCase_OneofEnum,
   };
 
-  for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) {
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
     switch (values[i]) {
       case Message3_O_OneOfCase_OneofInt32:
         msg.oneofInt32 = 1;
@@ -1824,7 +1827,7 @@
         msg.oneofEnum = Message3_Enum_Baz;
         break;
       default:
-        XCTFail(@"shouldn't happen, loop: %zd", i);
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
         break;
     }
 
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index ddc2ae1..8867f56 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -41,10 +41,6 @@
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
 
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
-
 static NSData *DataFromCStr(const char *str) {
   return [NSData dataWithBytes:str length:strlen(str)];
 }
@@ -124,7 +120,8 @@
   fooWithExtras.enumValue = DropUnknownsFooWithExtraFields_NestedEnum_Baz;
   fooWithExtras.extraInt32Value = 2;
 
-  DropUnknownsFoo *foo = [DropUnknownsFoo parseFromData:[fooWithExtras data]];
+  DropUnknownsFoo *foo =
+      [DropUnknownsFoo parseFromData:[fooWithExtras data] error:NULL];
 
   XCTAssertEqual(foo.int32Value, 1);
   XCTAssertEqual(foo.enumValue, DropUnknownsFoo_NestedEnum_Baz);
@@ -132,7 +129,8 @@
   XCTAssertEqual([foo.unknownFields countOfFields], 0U);
 
   [fooWithExtras release];
-  fooWithExtras = [DropUnknownsFooWithExtraFields parseFromData:[foo data]];
+  fooWithExtras =
+      [DropUnknownsFooWithExtraFields parseFromData:[foo data] error:NULL];
   XCTAssertEqual(fooWithExtras.int32Value, 1);
   XCTAssertEqual(fooWithExtras.enumValue,
                  DropUnknownsFooWithExtraFields_NestedEnum_Baz);
@@ -153,7 +151,7 @@
                                        rawValue:Message3_Enum_Extra3];
   orig.oneofEnum = Message3_Enum_Extra3;
 
-  Message2 *msg = [[Message2 alloc] initWithData:[orig data]];
+  Message2 *msg = [[Message2 alloc] initWithData:[orig data] error:NULL];
 
   // None of the fields should be set.
 
@@ -214,7 +212,7 @@
   // Everything should be there via raw values.
 
   UnknownEnumsMyMessage *msg =
-      [UnknownEnumsMyMessage parseFromData:[orig data]];
+      [UnknownEnumsMyMessage parseFromData:[orig data] error:NULL];
 
   XCTAssertEqual(msg.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
   XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(msg),
@@ -236,7 +234,7 @@
 
   // Everything should go out and come back.
 
-  orig = [UnknownEnumsMyMessagePlusExtra parseFromData:[msg data]];
+  orig = [UnknownEnumsMyMessagePlusExtra parseFromData:[msg data] error:NULL];
 
   XCTAssertEqual(orig.e, UnknownEnumsMyEnumPlusExtra_EExtra);
   XCTAssertEqual(orig.repeatedEArray.count, 1U);
@@ -255,7 +253,7 @@
 //%    MESSAGE *orig = [[MESSAGE alloc] init];
 //%    orig.oneof##FIELD = VALUE;
 //%    XCTAssertEqual(orig.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
-//%    MESSAGE *msg = [MESSAGE parseFromData:[orig data]];
+//%    MESSAGE *msg = [MESSAGE parseFromData:[orig data] error:NULL];
 //%    XCTAssertEqual(msg.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
 //%    XCTAssertEqual##EQ_SUFFIX(msg.oneof##FIELD, VALUE);
 //%    [orig release];
@@ -323,7 +321,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofInt32 = 1;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
     XCTAssertEqual(msg.oneofInt32, 1);
     [orig release];
@@ -333,7 +331,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofInt64 = 2;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
     XCTAssertEqual(msg.oneofInt64, 2);
     [orig release];
@@ -343,7 +341,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofUint32 = 3U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
     XCTAssertEqual(msg.oneofUint32, 3U);
     [orig release];
@@ -353,7 +351,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofUint64 = 4U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
     XCTAssertEqual(msg.oneofUint64, 4U);
     [orig release];
@@ -363,7 +361,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSint32 = 5;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
     XCTAssertEqual(msg.oneofSint32, 5);
     [orig release];
@@ -373,7 +371,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSint64 = 6;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
     XCTAssertEqual(msg.oneofSint64, 6);
     [orig release];
@@ -383,7 +381,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFixed32 = 7U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
     XCTAssertEqual(msg.oneofFixed32, 7U);
     [orig release];
@@ -393,7 +391,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFixed64 = 8U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
     XCTAssertEqual(msg.oneofFixed64, 8U);
     [orig release];
@@ -403,7 +401,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSfixed32 = 9;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
     XCTAssertEqual(msg.oneofSfixed32, 9);
     [orig release];
@@ -413,7 +411,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSfixed64 = 10;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
     XCTAssertEqual(msg.oneofSfixed64, 10);
     [orig release];
@@ -423,7 +421,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFloat = 11.0f;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
     XCTAssertEqual(msg.oneofFloat, 11.0f);
     [orig release];
@@ -433,7 +431,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofDouble = 12.0;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
     XCTAssertEqual(msg.oneofDouble, 12.0);
     [orig release];
@@ -443,7 +441,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofBool = NO;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBool);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool);
     XCTAssertEqual(msg.oneofBool, NO);
     [orig release];
@@ -453,7 +451,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofString = @"foo";
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofString);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString);
     XCTAssertEqualObjects(msg.oneofString, @"foo");
     [orig release];
@@ -463,7 +461,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
     XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
     [orig release];
@@ -473,7 +471,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofGroup = group;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
     XCTAssertEqualObjects(msg.oneofGroup, group);
     [orig release];
@@ -483,7 +481,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofMessage = subMessage;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
     XCTAssertEqualObjects(msg.oneofMessage, subMessage);
     [orig release];
@@ -493,7 +491,7 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofEnum = Message2_Enum_Bar;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
-    Message2 *msg = [Message2 parseFromData:[orig data]];
+    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
     XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
     [orig release];
@@ -516,7 +514,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofInt32 = 1;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
     XCTAssertEqual(msg.oneofInt32, 1);
     [orig release];
@@ -526,7 +524,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofInt64 = 2;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
     XCTAssertEqual(msg.oneofInt64, 2);
     [orig release];
@@ -536,7 +534,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofUint32 = 3U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
     XCTAssertEqual(msg.oneofUint32, 3U);
     [orig release];
@@ -546,7 +544,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofUint64 = 4U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
     XCTAssertEqual(msg.oneofUint64, 4U);
     [orig release];
@@ -556,7 +554,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSint32 = 5;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
     XCTAssertEqual(msg.oneofSint32, 5);
     [orig release];
@@ -566,7 +564,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSint64 = 6;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
     XCTAssertEqual(msg.oneofSint64, 6);
     [orig release];
@@ -576,7 +574,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFixed32 = 7U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
     XCTAssertEqual(msg.oneofFixed32, 7U);
     [orig release];
@@ -586,7 +584,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFixed64 = 8U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
     XCTAssertEqual(msg.oneofFixed64, 8U);
     [orig release];
@@ -596,7 +594,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSfixed32 = 9;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
     XCTAssertEqual(msg.oneofSfixed32, 9);
     [orig release];
@@ -606,7 +604,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSfixed64 = 10;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
     XCTAssertEqual(msg.oneofSfixed64, 10);
     [orig release];
@@ -616,7 +614,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFloat = 11.0f;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
     XCTAssertEqual(msg.oneofFloat, 11.0f);
     [orig release];
@@ -626,7 +624,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofDouble = 12.0;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
     XCTAssertEqual(msg.oneofDouble, 12.0);
     [orig release];
@@ -636,7 +634,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofBool = YES;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBool);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool);
     XCTAssertEqual(msg.oneofBool, YES);
     [orig release];
@@ -646,7 +644,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofString = @"foo";
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofString);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString);
     XCTAssertEqualObjects(msg.oneofString, @"foo");
     [orig release];
@@ -656,7 +654,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
     XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
     [orig release];
@@ -668,7 +666,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofMessage = subMessage;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
     XCTAssertEqualObjects(msg.oneofMessage, subMessage);
     [orig release];
@@ -678,7 +676,7 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofEnum = Message2_Enum_Bar;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
-    Message3 *msg = [Message3 parseFromData:[orig data]];
+    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
     XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
     [orig release];
@@ -695,7 +693,7 @@
 - (void)testMap_StandardWireFormat {
   NSData *data = DataFromCStr("\x0A\x04\x08\x01\x10\x01");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
@@ -709,7 +707,7 @@
   // put value before key in wire format
   NSData *data = DataFromCStr("\x0A\x04\x10\x01\x08\x02");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
@@ -723,7 +721,7 @@
   // Two key fields in wire format
   NSData *data = DataFromCStr("\x0A\x06\x08\x01\x08\x02\x10\x01");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
@@ -737,7 +735,7 @@
   // Two value fields in wire format
   NSData *data = DataFromCStr("\x0A\x06\x08\x01\x10\x01\x10\x02");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
@@ -751,7 +749,7 @@
   // No key field in wire format
   NSData *data = DataFromCStr("\x0A\x02\x10\x01");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:0 value:&val]);
@@ -765,7 +763,7 @@
   // No value field in wire format
   NSData *data = DataFromCStr("\x0A\x02\x08\x01");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]);
@@ -779,7 +777,7 @@
   // Unknown field in wire format
   NSData *data = DataFromCStr("\x0A\x06\x08\x02\x10\x03\x18\x01");
 
-  TestMap *msg = [[TestMap alloc] initWithData:data];
+  TestMap *msg = [[TestMap alloc] initWithData:data error:NULL];
   XCTAssertEqual(msg.mapInt32Int32.count, 1U);
   int32_t val = 666;
   XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]);
@@ -793,8 +791,12 @@
   // corrupted data in wire format
   NSData *data = DataFromCStr("\x0A\x06\x08\x02\x11\x03");
 
-  XCTAssertThrowsSpecificNamed([TestMap parseFromData:data], NSException,
-                               NSParseErrorException);
+  NSError *error = nil;
+  TestMap *msg = [TestMap parseFromData:data error:&error];
+  XCTAssertNil(msg);
+  XCTAssertNotNil(error);
+  XCTAssertEqualObjects(error.domain, GPBMessageErrorDomain);
+  XCTAssertEqual(error.code, GPBMessageErrorCodeMalformedData);
 }
 
 // TEST(GeneratedMapFieldTest, Proto2UnknownEnum)
@@ -810,14 +812,15 @@
   [orig.unknownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumExtra
                           forKey:0];
 
-  TestEnumMap *msg1 = [TestEnumMap parseFromData:[orig data]];
+  TestEnumMap *msg1 = [TestEnumMap parseFromData:[orig data] error:NULL];
   XCTAssertEqual(msg1.knownMapField.count, 1U);
   int32_t val = -1;
   XCTAssertTrue([msg1.knownMapField valueForKey:0 value:&val]);
   XCTAssertEqual(val, Proto2MapEnum_Proto2MapEnumFoo);
   XCTAssertEqual(msg1.unknownFields.countOfFields, 1U);
 
-  TestEnumMapPlusExtra *msg2 = [TestEnumMapPlusExtra parseFromData:[msg1 data]];
+  TestEnumMapPlusExtra *msg2 =
+      [TestEnumMapPlusExtra parseFromData:[msg1 data] error:NULL];
   val = -1;
   XCTAssertEqual(msg2.knownMapField.count, 1U);
   XCTAssertTrue([msg2.knownMapField valueForKey:0 value:&val]);
@@ -833,6 +836,72 @@
   [orig release];
 }
 
-#pragma mark -
+#pragma mark - Map Round Tripping
+
+- (void)testProto2MapRoundTripping {
+  Message2 *msg = [[Message2 alloc] init];
+
+  // Key/Value data should result in different byte lengths on wire to ensure
+  // everything is right.
+  [msg.mapInt32Int32 setValue:1000 forKey:200];
+  [msg.mapInt32Int32 setValue:101 forKey:2001];
+  [msg.mapInt64Int64 setValue:1002 forKey:202];
+  [msg.mapInt64Int64 setValue:103 forKey:2003];
+  [msg.mapUint32Uint32 setValue:1004 forKey:204];
+  [msg.mapUint32Uint32 setValue:105 forKey:2005];
+  [msg.mapUint64Uint64 setValue:1006 forKey:206];
+  [msg.mapUint64Uint64 setValue:107 forKey:2007];
+  [msg.mapSint32Sint32 setValue:1008 forKey:208];
+  [msg.mapSint32Sint32 setValue:109 forKey:2009];
+  [msg.mapSint64Sint64 setValue:1010 forKey:210];
+  [msg.mapSint64Sint64 setValue:111 forKey:2011];
+  [msg.mapFixed32Fixed32 setValue:1012 forKey:212];
+  [msg.mapFixed32Fixed32 setValue:113 forKey:2013];
+  [msg.mapFixed64Fixed64 setValue:1014 forKey:214];
+  [msg.mapFixed64Fixed64 setValue:115 forKey:2015];
+  [msg.mapSfixed32Sfixed32 setValue:1016 forKey:216];
+  [msg.mapSfixed32Sfixed32 setValue:117 forKey:2017];
+  [msg.mapSfixed64Sfixed64 setValue:1018 forKey:218];
+  [msg.mapSfixed64Sfixed64 setValue:119 forKey:2019];
+  [msg.mapInt32Float setValue:1020.f forKey:220];
+  [msg.mapInt32Float setValue:121.f forKey:2021];
+  [msg.mapInt32Double setValue:1022. forKey:222];
+  [msg.mapInt32Double setValue:123. forKey:2023];
+  [msg.mapBoolBool setValue:false forKey:true];
+  [msg.mapBoolBool setValue:true forKey:false];
+  msg.mapStringString[@"224"] = @"1024";
+  msg.mapStringString[@"2025"] = @"125";
+  msg.mapStringBytes[@"226"] = DataFromCStr("1026");
+  msg.mapStringBytes[@"2027"] = DataFromCStr("127");
+  Message2 *val1 = [[Message2 alloc] init];
+  val1.optionalInt32 = 1028;
+  Message2 *val2 = [[Message2 alloc] init];
+  val2.optionalInt32 = 129;
+  [msg.mapStringMessage setValue:val1 forKey:@"228"];
+  [msg.mapStringMessage setValue:val2 forKey:@"2029"];
+  [msg.mapInt32Bytes setValue:DataFromCStr("1030 bytes") forKey:230];
+  [msg.mapInt32Bytes setValue:DataFromCStr("131") forKey:2031];
+  [msg.mapInt32Enum setValue:Message2_Enum_Bar forKey:232];
+  [msg.mapInt32Enum setValue:Message2_Enum_Baz forKey:2033];
+  Message2 *val3 = [[Message2 alloc] init];
+  val3.optionalInt32 = 1034;
+  Message2 *val4 = [[Message2 alloc] init];
+  val4.optionalInt32 = 135;
+  [msg.mapInt32Message setValue:val3 forKey:234];
+  [msg.mapInt32Message setValue:val4 forKey:2035];
+
+  NSData *data = [msg data];
+  Message2 *msg2 = [[Message2 alloc] initWithData:data error:NULL];
+
+  XCTAssertNotEqual(msg2, msg);  // Pointer comparison
+  XCTAssertEqualObjects(msg2, msg);
+
+  [val4 release];
+  [val3 release];
+  [val2 release];
+  [val1 release];
+  [msg2 release];
+  [msg release];
+}
 
 @end
diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m
index 5ec67cd..e0154c1 100644
--- a/objectivec/Tests/GPBMessageTests.m
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -34,6 +34,7 @@
 
 #import "GPBArray_PackagePrivate.h"
 #import "GPBDescriptor.h"
+#import "GPBDictionary_PackagePrivate.h"
 #import "GPBField_PackagePrivate.h"
 #import "GPBMessage_PackagePrivate.h"
 #import "GPBUnknownFieldSet_PackagePrivate.h"
@@ -47,23 +48,9 @@
 @implementation MessageTests
 
 // TODO(thomasvl): this should get split into a few files of logic junks, it is
-// a jumble
-// of things at the moment (and the testutils have a bunch of the real
+// a jumble of things at the moment (and the testutils have a bunch of the real
 // assertions).
 
-#ifdef DEBUG
-- (void)assertBlock:(void (^)())block
-    throwsWithMessageInUserInfo:(GPBMessage *)message {
-  @try {
-    block();
-    XCTAssertTrue(NO);
-  }
-  @catch (NSException *e) {
-    XCTAssertEqualObjects([e userInfo][GPBExceptionMessageKey], message);
-  }
-}
-#endif  // DEBUG
-
 - (TestAllTypes *)mergeSource {
   TestAllTypes *message = [TestAllTypes message];
   [message setOptionalInt32:1];
@@ -290,14 +277,18 @@
   XCTAssertTrue(message.initialized);
 }
 
-#ifdef DEBUG
-- (void)testUninitializedException {
+- (void)testDataFromUninitialized {
   TestRequired *message = [TestRequired message];
-  [self assertBlock:^{
-    [message data];
-  } throwsWithMessageInUserInfo:message];
-}
+  NSData *data = [message data];
+  // In DEBUG, the data generation will fail, but in non DEBUG, it passes
+  // because the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(data);
+#else
+  XCTAssertNotNil(data);
+  XCTAssertFalse(message.initialized);
 #endif  // DEBUG
+}
 
 - (void)testInitialized {
   // We're mostly testing that no exception is thrown.
@@ -305,18 +296,22 @@
   XCTAssertFalse(message.initialized);
 }
 
-#ifdef DEBUG
-- (void)testNestedUninitializedException {
+- (void)testDataFromNestedUninitialized {
   TestRequiredForeign *message = [TestRequiredForeign message];
   [message setOptionalMessage:[TestRequired message]];
   message.repeatedMessageArray = [NSMutableArray array];
   [message.repeatedMessageArray addObject:[TestRequired message]];
   [message.repeatedMessageArray addObject:[TestRequired message]];
-  [self assertBlock:^{
-    [message data];
-  } throwsWithMessageInUserInfo:message];
-}
+  NSData *data = [message data];
+  // In DEBUG, the data generation will fail, but in non DEBUG, it passes
+  // because the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(data);
+#else
+  XCTAssertNotNil(data);
+  XCTAssertFalse(message.initialized);
 #endif  // DEBUG
+}
 
 - (void)testNestedInitialized {
   // We're mostly testing that no exception is thrown.
@@ -330,13 +325,23 @@
   XCTAssertFalse(message.initialized);
 }
 
-#ifdef DEBUG
 - (void)testParseUninitialized {
-  [self assertBlock:^{
-    [TestRequired parseFromData:GPBEmptyNSData()];
-  } throwsWithMessageInUserInfo:[TestRequired message]];
-}
+  NSError *error = nil;
+  TestRequired *msg =
+      [TestRequired parseFromData:GPBEmptyNSData() error:&error];
+  // In DEBUG, the parse will fail, but in non DEBUG, it passes because
+  // the check isn't done (for speed).
+#ifdef DEBUG
+  XCTAssertNil(msg);
+  XCTAssertNotNil(error);
+  XCTAssertEqualObjects(error.domain, GPBMessageErrorDomain);
+  XCTAssertEqual(error.code, GPBMessageErrorCodeMissingRequiredField);
+#else
+  XCTAssertNotNil(msg);
+  XCTAssertNil(error);
+  XCTAssertFalse(msg.initialized);
 #endif  // DEBUG
+}
 
 - (void)testCoding {
   NSData *data =
@@ -1033,7 +1038,7 @@
   message3.repeatedStringArray = [NSMutableArray arrayWithObject:@"wee"];
   XCTAssertNotNil(message.repeatedInt32Array);
   XCTAssertNotNil(message.repeatedStringArray);
-  TestAllTypes *message4 = [message3 copy];
+  TestAllTypes *message4 = [[message3 copy] autorelease];
   XCTAssertNotEqual(message3.repeatedInt32Array, message4.repeatedInt32Array);
   XCTAssertEqualObjects(message3.repeatedInt32Array,
                         message4.repeatedInt32Array);
@@ -1156,6 +1161,205 @@
   XCTAssertFalse([message hasA]);
 }
 
+- (void)testDefaultingMaps {
+  // Basic tests for default creation of maps in a message.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2 =
+      [TestRecursiveMessageWithRepeatedField message];
+
+  // Simply accessing the map should not make any fields visible.
+  XCTAssertNotNil(message.a.a.iToI);
+  XCTAssertFalse([message hasA]);
+  XCTAssertFalse([message.a hasA]);
+  XCTAssertNotNil(message2.a.a.strToStr);
+  XCTAssertFalse([message2 hasA]);
+  XCTAssertFalse([message2.a hasA]);
+
+  // But adding an element to the map should.
+  [message.a.a.iToI setValue:100 forKey:200];
+  XCTAssertTrue([message hasA]);
+  XCTAssertTrue([message.a hasA]);
+  XCTAssertEqual([message.a.a.iToI count], (NSUInteger)1);
+  [message2.a.a.strToStr setObject:@"foo" forKey:@"bar"];
+  XCTAssertTrue([message2 hasA]);
+  XCTAssertTrue([message2.a hasA]);
+  XCTAssertEqual([message2.a.a.strToStr count], (NSUInteger)1);
+}
+
+- (void)testAutocreatedMapShared {
+  // Multiple objects pointing to the same map.
+  TestRecursiveMessageWithRepeatedField *message1a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message1b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message1a.a.iToI = message1b.a.iToI;
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertFalse([message1b hasA]);
+  [message1a.a.iToI setValue:1 forKey:2];
+  XCTAssertTrue([message1a hasA]);
+  XCTAssertTrue([message1b hasA]);
+  XCTAssertEqual(message1a.a.iToI, message1b.a.iToI);
+
+  TestRecursiveMessageWithRepeatedField *message2a =
+      [TestRecursiveMessageWithRepeatedField message];
+  TestRecursiveMessageWithRepeatedField *message2b =
+      [TestRecursiveMessageWithRepeatedField message];
+  message2a.a.strToStr = message2b.a.strToStr;
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertFalse([message2b hasA]);
+  [message2a.a.strToStr setObject:@"bar" forKey:@"foo"];
+  XCTAssertTrue([message2a hasA]);
+  XCTAssertTrue([message2b hasA]);
+  XCTAssertEqual(message2a.a.strToStr, message2b.a.strToStr);
+}
+
+- (void)testAutocreatedMapCopy {
+  // Copy should not copy autocreated maps.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  XCTAssertNotNil(message.strToStr);
+  XCTAssertNotNil(message.iToI);
+  TestRecursiveMessageWithRepeatedField *message2 =
+      [[message copy] autorelease];
+  // Pointer conparisions.
+  XCTAssertNotEqual(message.strToStr, message2.strToStr);
+  XCTAssertNotEqual(message.iToI, message2.iToI);
+
+  // Mutable copy should copy empty arrays that were explicitly set (end up
+  // with different objects that are equal).
+  TestRecursiveMessageWithRepeatedField *message3 =
+      [TestRecursiveMessageWithRepeatedField message];
+  message3.iToI = [GPBInt32Int32Dictionary dictionaryWithValue:10 forKey:20];
+  message3.strToStr =
+      [NSMutableDictionary dictionaryWithObject:@"abc" forKey:@"123"];
+  XCTAssertNotNil(message.iToI);
+  XCTAssertNotNil(message.iToI);
+  TestRecursiveMessageWithRepeatedField *message4 =
+      [[message3 copy] autorelease];
+  XCTAssertNotEqual(message3.iToI, message4.iToI);
+  XCTAssertEqualObjects(message3.iToI, message4.iToI);
+  XCTAssertNotEqual(message3.strToStr, message4.strToStr);
+  XCTAssertEqualObjects(message3.strToStr, message4.strToStr);
+}
+
+- (void)testAutocreatedMapRetain {
+  // Should be able to retain autocreated map while the creator is dealloced.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+
+  @autoreleasepool {
+    TestRecursiveMessageWithRepeatedField *message2 =
+        [TestRecursiveMessageWithRepeatedField message];
+    message.iToI = message2.iToI;
+    message.strToStr = message2.strToStr;
+    // Pointer conparision
+    XCTAssertEqual(message.iToI->_autocreator, message2);
+    XCTAssertTrue([message.strToStr
+        isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertEqual(
+        ((GPBAutocreatedDictionary *)message.strToStr)->_autocreator,
+        message2);
+  }
+
+  XCTAssertNil(message.iToI->_autocreator);
+  XCTAssertTrue(
+      [message.strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+  XCTAssertNil(
+      ((GPBAutocreatedDictionary *)message.strToStr)->_autocreator);
+}
+
+- (void)testSetNilAutocreatedMap {
+  // Setting map to nil should cause it to lose its delegate.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  GPBInt32Int32Dictionary *iToI = [message.iToI retain];
+  GPBAutocreatedDictionary *strToStr =
+      (GPBAutocreatedDictionary *)[message.strToStr retain];
+  XCTAssertTrue([strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+  XCTAssertEqual(iToI->_autocreator, message);
+  XCTAssertEqual(strToStr->_autocreator, message);
+  message.iToI = nil;
+  message.strToStr = nil;
+  XCTAssertNil(iToI->_autocreator);
+  XCTAssertNil(strToStr->_autocreator);
+  [iToI release];
+  [strToStr release];
+}
+
+- (void)testReplaceAutocreatedMap {
+  // Replacing map should orphan the old one and cause its creator to become
+  // visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iToI);
+    XCTAssertFalse([message hasA]);
+    GPBInt32Int32Dictionary *iToI = [message.a.iToI retain];
+    XCTAssertEqual(iToI->_autocreator, message.a);  // Pointer comparision
+    message.a.iToI = [GPBInt32Int32Dictionary dictionaryWithValue:6 forKey:7];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.iToI, iToI);  // Pointer comparision
+    XCTAssertNil(iToI->_autocreator);
+    [iToI release];
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strToStr);
+    XCTAssertFalse([message hasA]);
+    GPBAutocreatedDictionary *strToStr =
+        (GPBAutocreatedDictionary *)[message.a.strToStr retain];
+    XCTAssertTrue([strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertEqual(strToStr->_autocreator, message.a);  // Pointer comparision
+    message.a.strToStr =
+        [NSMutableDictionary dictionaryWithObject:@"abc" forKey:@"def"];
+    XCTAssertTrue([message hasA]);
+    XCTAssertNotEqual(message.a.strToStr, strToStr);  // Pointer comparision
+    XCTAssertNil(strToStr->_autocreator);
+    [strToStr release];
+  }
+}
+
+- (void)testSetAutocreatedMapToSelf {
+  // Setting map to itself should cause it to become visible.
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.iToI);
+    XCTAssertFalse([message hasA]);
+    message.a.iToI = message.a.iToI;
+    XCTAssertTrue([message hasA]);
+    XCTAssertNil(message.a.iToI->_autocreator);
+  }
+
+  {
+    TestRecursiveMessageWithRepeatedField *message =
+        [TestRecursiveMessageWithRepeatedField message];
+    XCTAssertNotNil(message.a);
+    XCTAssertNotNil(message.a.strToStr);
+    XCTAssertFalse([message hasA]);
+    message.a.strToStr = message.a.strToStr;
+    XCTAssertTrue([message hasA]);
+    XCTAssertTrue([message.a.strToStr isKindOfClass:[GPBAutocreatedDictionary class]]);
+    XCTAssertNil(((GPBAutocreatedDictionary *)message.a.strToStr)->_autocreator);
+  }
+}
+
+- (void)testAutocreatedMapRemoveAllValues {
+  // Calling removeAll on autocreated map should not cause it to be visible.
+  TestRecursiveMessageWithRepeatedField *message =
+      [TestRecursiveMessageWithRepeatedField message];
+  [message.a.iToI removeAll];
+  XCTAssertFalse([message hasA]);
+  [message.a.strToStr removeAllObjects];
+  XCTAssertFalse([message hasA]);
+}
+
 - (void)testExtensionAccessors {
   TestAllExtensions *message = [TestAllExtensions message];
   [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
@@ -1555,7 +1759,8 @@
   GPBMessage *message = [GPBMessage message];
   [message setUnknownFields:unknowns];
   NSData *data = [message data];
-  GPBMessage *message2 = [GPBMessage parseFromData:data extensionRegistry:nil];
+  GPBMessage *message2 =
+      [GPBMessage parseFromData:data extensionRegistry:nil error:NULL];
   XCTAssertEqualObjects(message, message2);
 }
 
@@ -1579,9 +1784,11 @@
   GPBCodedInputStream *input =
       [GPBCodedInputStream streamWithData:delimitedData];
   GPBMessage *message3 = [GPBMessage parseDelimitedFromCodedInputStream:input
-                                                      extensionRegistry:nil];
+                                                      extensionRegistry:nil
+                                                                  error:NULL];
   GPBMessage *message4 = [GPBMessage parseDelimitedFromCodedInputStream:input
-                                                      extensionRegistry:nil];
+                                                      extensionRegistry:nil
+                                                                  error:NULL];
   XCTAssertEqualObjects(message1, message3);
   XCTAssertEqualObjects(message2, message4);
 }
@@ -1673,7 +1880,7 @@
   XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One);
   XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne);
   // Bounce to wire and back.
-  EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data]];
+  EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
   XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One);
@@ -1685,7 +1892,7 @@
   XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two);
   XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo);
   // Bounce to wire and back.
-  msgPrime = [EnumTestMsg parseFromData:[msg data]];
+  msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
   XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two);
@@ -1706,7 +1913,7 @@
   XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne);
   XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo);
   // Bounce to wire and back.
-  msgPrime = [EnumTestMsg parseFromData:[msg data]];
+  msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0],
                  EnumTestMsg_MyEnum_Zero);
diff --git a/objectivec/Tests/GPBPerfTests.m b/objectivec/Tests/GPBPerfTests.m
index d09021a..1259d14 100644
--- a/objectivec/Tests/GPBPerfTests.m
+++ b/objectivec/Tests/GPBPerfTests.m
@@ -30,6 +30,7 @@
 
 #import "GPBTestUtilities.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
 #import "google/protobuf/UnittestObjc.pbobjc.h"
 
 //
@@ -57,7 +58,7 @@
       [self setAllFields:message repeatedCount:kRepeatedCount];
       NSData* rawBytes = [message data];
       [message release];
-      message = [[TestAllTypes alloc] initWithData:rawBytes];
+      message = [[TestAllTypes alloc] initWithData:rawBytes error:NULL];
       [message release];
     }
   }];
@@ -71,7 +72,7 @@
       NSData* rawBytes = [message data];
       [message release];
       TestAllExtensions* message2 =
-          [[TestAllExtensions alloc] initWithData:rawBytes];
+          [[TestAllExtensions alloc] initWithData:rawBytes error:NULL];
       [message2 release];
     }
   }];
@@ -84,7 +85,7 @@
       [self setPackedFields:message repeatedCount:kRepeatedCount];
       NSData* rawBytes = [message data];
       [message release];
-      message = [[TestPackedTypes alloc] initWithData:rawBytes];
+      message = [[TestPackedTypes alloc] initWithData:rawBytes error:NULL];
       [message release];
     }
   }];
@@ -98,7 +99,7 @@
       NSData* rawBytes = [message data];
       [message release];
       TestPackedExtensions* message2 =
-          [[TestPackedExtensions alloc] initWithData:rawBytes];
+          [[TestPackedExtensions alloc] initWithData:rawBytes error:NULL];
       [message2 release];
     }
   }];
diff --git a/objectivec/Tests/GPBStringTests.m b/objectivec/Tests/GPBStringTests.m
index 30f1377..802afa7 100644
--- a/objectivec/Tests/GPBStringTests.m
+++ b/objectivec/Tests/GPBStringTests.m
@@ -31,10 +31,7 @@
 #import <XCTest/XCTest.h>
 
 #import "GPBCodedInputStream_PackagePrivate.h"
-
-#ifndef GPBARRAYSIZE
-#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
-#endif  // GPBARRAYSIZE
+#import "GPBTestUtilities.h"
 
 @interface TestClass : NSObject
 @property(nonatomic, retain) NSString *foo;
diff --git a/objectivec/Tests/GPBSwiftTests.swift b/objectivec/Tests/GPBSwiftTests.swift
index e7b6f94..30b9cbd 100644
--- a/objectivec/Tests/GPBSwiftTests.swift
+++ b/objectivec/Tests/GPBSwiftTests.swift
@@ -53,6 +53,12 @@
     msg.repeatedStringArray.addObject("pqr")
     msg.repeatedEnumArray.addValue(Message2_Enum.Bar.rawValue)
     msg.repeatedEnumArray.addValue(Message2_Enum.Baz.rawValue)
+    msg.mapInt32Int32.setValue(400, forKey:500)
+    msg.mapInt32Int32.setValue(401, forKey:501)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
+    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
+    msg.mapInt32Enum.setValue(Message2_Enum.Baz.rawValue, forKey:601)
 
     // Check has*.
     XCTAssertTrue(msg.hasOptionalInt32)
@@ -83,6 +89,20 @@
     XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue)
     XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue)
     XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    var intValue: Int32 = 0;
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
+    XCTAssertEqual(intValue, Int32(400))
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
+    XCTAssertEqual(intValue, Int32(401))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as! String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as! String, "abc")
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Baz.rawValue)
 
     // Clearing a string with nil.
     msg2.optionalString = nil
@@ -109,6 +129,9 @@
     XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0))
     XCTAssertEqual(msg.repeatedStringArray.count, Int(0))
     XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
+    XCTAssertEqual(msg.mapStringString.count, Int(0))
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
   }
 
   func testProto3Basics() {
@@ -128,6 +151,13 @@
     msg.repeatedEnumArray.addValue(Message3_Enum.Bar.rawValue)
     msg.repeatedEnumArray.addRawValue(666)
     SetMessage3_OptionalEnum_RawValue(msg2, 666)
+    msg.mapInt32Int32.setValue(400, forKey:500)
+    msg.mapInt32Int32.setValue(401, forKey:501)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
+    msg.mapInt32Enum.setValue(Message2_Enum.Bar.rawValue, forKey:600)
+    // "proto3" syntax lets enum get unknown values.
+    msg.mapInt32Enum.setRawValue(666, forKey:601)
 
     // Has only exists on for message fields.
     XCTAssertTrue(msg.hasOptionalMessage)
@@ -152,6 +182,22 @@
     XCTAssertEqual(msg.repeatedEnumArray.rawValueAtIndex(1), 666)
     XCTAssertEqual(msg2.optionalEnum, Message3_Enum.GPBUnrecognizedEnumeratorValue)
     XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Int32(666))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    var intValue: Int32 = 0;
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(500, value:&intValue))
+    XCTAssertEqual(intValue, Int32(400))
+    XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
+    XCTAssertEqual(intValue, Int32(401))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as! String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as! String, "abc")
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
+    XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, value:&intValue))
+    XCTAssertEqual(intValue, Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue)
+    XCTAssertTrue(msg.mapInt32Enum.valueForKey(601, rawValue:&intValue))
+    XCTAssertEqual(intValue, 666)
 
     // Clearing a string with nil.
     msg2.optionalString = nil
@@ -175,6 +221,9 @@
     msg2.clear()
     XCTAssertEqual(msg2.optionalEnum, Message3_Enum.Foo)  // Default
     XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Message3_Enum.Foo.rawValue)
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(0))
+    XCTAssertEqual(msg.mapStringString.count, Int(0))
+    XCTAssertEqual(msg.mapInt32Enum.count, UInt(0))
   }
 
   func testAutoCreation() {
@@ -390,15 +439,21 @@
     msg.optionalGroup.a = 102
     msg.repeatedStringArray.addObject("abc")
     msg.repeatedStringArray.addObject("def")
+    msg.mapInt32Int32.setValue(200, forKey:300)
+    msg.mapInt32Int32.setValue(201, forKey:201)
+    msg.mapStringString.setObject("foo", forKey:"bar")
+    msg.mapStringString.setObject("abc", forKey:"xyz")
 
     let data = msg.data()
 
-    let msg2 = Message2(data: data)
+    let msg2 = Message2(data: data, error:nil)
     XCTAssertTrue(msg2 !== msg)  // New instance
     XCTAssertEqual(msg.optionalInt32, Int32(100))
     XCTAssertEqual(msg.optionalInt64, Int64(101))
     XCTAssertEqual(msg.optionalGroup.a, Int32(102))
     XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
+    XCTAssertEqual(msg.mapInt32Int32.count, UInt(2))
+    XCTAssertEqual(msg.mapStringString.count, Int(2))
     XCTAssertEqual(msg2, msg)
   }
 
diff --git a/objectivec/Tests/GPBTestUtilities.h b/objectivec/Tests/GPBTestUtilities.h
index 37e30f9..6ae68c3 100644
--- a/objectivec/Tests/GPBTestUtilities.h
+++ b/objectivec/Tests/GPBTestUtilities.h
@@ -37,6 +37,13 @@
 @class TestPackedExtensions;
 @class GPBExtensionRegistry;
 
+
+// Helper for uses of C arrays in tests cases.
+#ifndef GPBARRAYSIZE
+#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))))
+#endif  // GPBARRAYSIZE
+
+
 // The number of repetitions of any repeated objects inside of test messages.
 extern const uint32_t kGPBDefaultRepeatCount;
 
diff --git a/objectivec/Tests/GPBTestUtilities.m b/objectivec/Tests/GPBTestUtilities.m
index d664a88..6058dfc 100644
--- a/objectivec/Tests/GPBTestUtilities.m
+++ b/objectivec/Tests/GPBTestUtilities.m
@@ -32,6 +32,7 @@
 
 #import "google/protobuf/MapUnittest.pbobjc.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
 
 const uint32_t kGPBDefaultRepeatCount = 2;
 
@@ -1060,25 +1061,6 @@
 }
 
 - (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count {
-  message.mapInt32Int32 = [GPBInt32Int32Dictionary dictionary];
-  message.mapInt64Int64 = [GPBInt64Int64Dictionary dictionary];
-  message.mapUint32Uint32 = [GPBUInt32UInt32Dictionary dictionary];
-  message.mapUint64Uint64 = [GPBUInt64UInt64Dictionary dictionary];
-  message.mapSint32Sint32 = [GPBInt32Int32Dictionary dictionary];
-  message.mapSint64Sint64 = [GPBInt64Int64Dictionary dictionary];
-  message.mapFixed32Fixed32 = [GPBUInt32UInt32Dictionary dictionary];
-  message.mapFixed64Fixed64 = [GPBUInt64UInt64Dictionary dictionary];
-  message.mapSfixed32Sfixed32 = [GPBInt32Int32Dictionary dictionary];
-  message.mapSfixed64Sfixed64 = [GPBInt64Int64Dictionary dictionary];
-  message.mapInt32Float = [GPBInt32FloatDictionary dictionary];
-  message.mapInt32Double = [GPBInt32DoubleDictionary dictionary];
-  message.mapBoolBool = [GPBBoolBoolDictionary dictionary];
-  message.mapStringString = [NSMutableDictionary dictionary];
-  message.mapInt32Bytes = [GPBInt32ObjectDictionary dictionary];
-  message.mapInt32Enum = [GPBInt32EnumDictionary
-      dictionaryWithValidationFunction:MapEnum_IsValidValue];
-  message.mapInt32ForeignMessage = [GPBInt32ObjectDictionary dictionary];
-
   for (uint32_t i = 0; i < count; i++) {
     [message.mapInt32Int32 setValue:(i + 1) forKey:100 + i * 100];
     [message.mapInt64Int64 setValue:(i + 1) forKey:101 + i * 100];
diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m
index 8018608..491bba9 100644
--- a/objectivec/Tests/GPBUnknownFieldSetTest.m
+++ b/objectivec/Tests/GPBUnknownFieldSetTest.m
@@ -56,7 +56,7 @@
 - (void)setUp {
   allFields_ = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
   allFieldsData_ = [allFields_ data];
-  emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_];
+  emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_ error:NULL];
   unknownFields_ = emptyMessage_.unknownFields;
 }
 
@@ -176,7 +176,7 @@
   [fields addField:field];
 
   NSData* data = fields.data;
-  TestAllTypes* destination = [TestAllTypes parseFromData:data];
+  TestAllTypes* destination = [TestAllTypes parseFromData:data error:NULL];
 
   [self assertAllFieldsSet:destination repeatedCount:kGPBDefaultRepeatCount];
   XCTAssertEqual(destination.unknownFields.countOfFields, (NSUInteger)1);
@@ -191,8 +191,10 @@
   // when parsing.
 
   NSData* bizarroData = [self getBizarroData];
-  TestAllTypes* allTypesMessage = [TestAllTypes parseFromData:bizarroData];
-  TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData];
+  TestAllTypes* allTypesMessage =
+      [TestAllTypes parseFromData:bizarroData error:NULL];
+  TestEmptyMessage* emptyMessage =
+      [TestEmptyMessage parseFromData:bizarroData error:NULL];
 
   // All fields should have been interpreted as unknown, so the debug strings
   // should be the same.
@@ -204,7 +206,7 @@
   // they are declared as extension numbers.
 
   TestEmptyMessageWithExtensions* message =
-      [TestEmptyMessageWithExtensions parseFromData:allFieldsData_];
+      [TestEmptyMessageWithExtensions parseFromData:allFieldsData_ error:NULL];
 
   XCTAssertEqual(unknownFields_.countOfFields,
                  message.unknownFields.countOfFields);
@@ -217,8 +219,9 @@
 
   NSData* bizarroData = [self getBizarroData];
   TestAllExtensions* allExtensionsMessage =
-      [TestAllExtensions parseFromData:bizarroData];
-  TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData];
+      [TestAllExtensions parseFromData:bizarroData error:NULL];
+  TestEmptyMessage* emptyMessage =
+      [TestEmptyMessage parseFromData:bizarroData error:NULL];
 
   // All fields should have been interpreted as unknown, so the debug strings
   // should be the same.
diff --git a/objectivec/Tests/GPBWireFormatTests.m b/objectivec/Tests/GPBWireFormatTests.m
index 1344af0..fc5c4bd 100644
--- a/objectivec/Tests/GPBWireFormatTests.m
+++ b/objectivec/Tests/GPBWireFormatTests.m
@@ -47,7 +47,7 @@
   NSData* rawBytes = message.data;
   XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
 
-  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes];
+  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes error:NULL];
 
   [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
 }
@@ -59,7 +59,8 @@
   NSData* rawBytes = message.data;
   XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
 
-  TestPackedTypes* message2 = [TestPackedTypes parseFromData:rawBytes];
+  TestPackedTypes* message2 =
+      [TestPackedTypes parseFromData:rawBytes error:NULL];
 
   [self assertPackedFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
 }
@@ -74,7 +75,7 @@
   NSData* rawBytes = message.data;
   XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
 
-  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes];
+  TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes error:NULL];
 
   [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
 }
@@ -103,8 +104,9 @@
 
   GPBExtensionRegistry* registry = [self extensionRegistry];
 
-  TestAllExtensions* message2 =
-      [TestAllExtensions parseFromData:rawBytes extensionRegistry:registry];
+  TestAllExtensions* message2 = [TestAllExtensions parseFromData:rawBytes
+                                               extensionRegistry:registry
+                                                           error:NULL];
 
   [self assertAllExtensionsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
 }
@@ -124,8 +126,9 @@
 
   GPBExtensionRegistry* registry = [self extensionRegistry];
 
-  TestPackedExtensions* message2 =
-      [TestPackedExtensions parseFromData:rawBytes extensionRegistry:registry];
+  TestPackedExtensions* message2 = [TestPackedExtensions parseFromData:rawBytes
+                                                     extensionRegistry:registry
+                                                                 error:NULL];
 
   [self assertPackedExtensionsSet:message2
                     repeatedCount:kGPBDefaultRepeatCount];
@@ -151,7 +154,7 @@
   NSData* data = [message_set data];
 
   // Parse back using RawMessageSet and check the contents.
-  RawMessageSet* raw = [RawMessageSet parseFromData:data];
+  RawMessageSet* raw = [RawMessageSet parseFromData:data error:NULL];
 
   XCTAssertEqual([raw.unknownFields countOfFields], (NSUInteger)0);
 
@@ -163,11 +166,13 @@
   XCTAssertEqual([raw.itemArray[2] typeId], kUnknownTypeId);
 
   TestMessageSetExtension1* message1 =
-      [TestMessageSetExtension1 parseFromData:[raw.itemArray[0] message]];
+      [TestMessageSetExtension1 parseFromData:[raw.itemArray[0] message]
+                                        error:NULL];
   XCTAssertEqual(message1.i, 123);
 
   TestMessageSetExtension2* message2 =
-      [TestMessageSetExtension2 parseFromData:[raw.itemArray[1] message]];
+      [TestMessageSetExtension2 parseFromData:[raw.itemArray[1] message]
+                                        error:NULL];
   XCTAssertEqualObjects(message2.str, @"foo");
 
   XCTAssertEqualObjects([raw.itemArray[2] message],
@@ -209,7 +214,8 @@
   // Parse as a TestMessageSet and check the contents.
   TestMessageSet* messageSet =
       [TestMessageSet parseFromData:data
-                  extensionRegistry:[UnittestMsetRoot extensionRegistry]];
+                  extensionRegistry:[UnittestMsetRoot extensionRegistry]
+                              error:NULL];
 
   XCTAssertEqual(
       [[messageSet
diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto
index d288a30..3bb9276 100644
--- a/objectivec/Tests/unittest_objc.proto
+++ b/objectivec/Tests/unittest_objc.proto
@@ -44,6 +44,8 @@
   optional TestRecursiveMessageWithRepeatedField a = 1;
   repeated int32 i = 2;
   repeated string str = 3;
+  map<int32, int32> i_to_i = 4;
+  map<string, string> str_to_str = 5;
 }
 
 // Recursive message and extension to for testing autocreators at different
diff --git a/objectivec/Tests/unittest_runtime_proto2.proto b/objectivec/Tests/unittest_runtime_proto2.proto
index f9fd3c3..12a2da6 100644
--- a/objectivec/Tests/unittest_runtime_proto2.proto
+++ b/objectivec/Tests/unittest_runtime_proto2.proto
@@ -105,4 +105,25 @@
      Message2 oneof_message = 68;
      Enum        oneof_enum = 69 [default = BAZ];
   }
+
+  // Some token map cases, too many combinations to list them all.
+  map<int32   , int32   > map_int32_int32       = 70;
+  map<int64   , int64   > map_int64_int64       = 71;
+  map<uint32  , uint32  > map_uint32_uint32     = 72;
+  map<uint64  , uint64  > map_uint64_uint64     = 73;
+  map<sint32  , sint32  > map_sint32_sint32     = 74;
+  map<sint64  , sint64  > map_sint64_sint64     = 75;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 76;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 77;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 78;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 79;
+  map<int32   , float   > map_int32_float       = 80;
+  map<int32   , double  > map_int32_double      = 81;
+  map<bool    , bool    > map_bool_bool         = 82;
+  map<string  , string  > map_string_string     = 83;
+  map<string  , bytes   > map_string_bytes      = 84;
+  map<string  , Message2> map_string_message    = 85;
+  map<int32   , bytes   > map_int32_bytes       = 86;
+  map<int32   , Enum    > map_int32_enum        = 87;
+  map<int32   , Message2> map_int32_message     = 88;
 }
diff --git a/objectivec/Tests/unittest_runtime_proto3.proto b/objectivec/Tests/unittest_runtime_proto3.proto
index b6a2f4d..feb7029 100644
--- a/objectivec/Tests/unittest_runtime_proto3.proto
+++ b/objectivec/Tests/unittest_runtime_proto3.proto
@@ -98,4 +98,25 @@
     Message3 oneof_message  = 68;
         Enum oneof_enum     = 69;
   }
+
+  // Some token map cases, too many combinations to list them all.
+  map<int32   , int32   > map_int32_int32       = 70;
+  map<int64   , int64   > map_int64_int64       = 71;
+  map<uint32  , uint32  > map_uint32_uint32     = 72;
+  map<uint64  , uint64  > map_uint64_uint64     = 73;
+  map<sint32  , sint32  > map_sint32_sint32     = 74;
+  map<sint64  , sint64  > map_sint64_sint64     = 75;
+  map<fixed32 , fixed32 > map_fixed32_fixed32   = 76;
+  map<fixed64 , fixed64 > map_fixed64_fixed64   = 77;
+  map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 78;
+  map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 79;
+  map<int32   , float   > map_int32_float       = 80;
+  map<int32   , double  > map_int32_double      = 81;
+  map<bool    , bool    > map_bool_bool         = 82;
+  map<string  , string  > map_string_string     = 83;
+  map<string  , bytes   > map_string_bytes      = 84;
+  map<string  , Message3> map_string_message    = 85;
+  map<int32   , bytes   > map_int32_bytes       = 86;
+  map<int32   , Enum    > map_int32_enum        = 87;
+  map<int32   , Message3> map_int32_message     = 88;
 }
diff --git a/objectivec/generate_descriptors_proto.sh b/objectivec/generate_descriptors_proto.sh
new file mode 100755
index 0000000..f2ed00b
--- /dev/null
+++ b/objectivec/generate_descriptors_proto.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Run this script to regenerate descriptor.pbobjc.{h,m} after the protocol
+# compiler changes.
+
+# HINT:  Flags passed to generate_descriptor_proto.sh will be passed directly
+#   to make when building protoc.  This is particularly useful for passing
+#   -j4 to run 4 jobs simultaneously.
+
+set -eu
+
+readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
+readonly ProtoRootDir="${ScriptDir}/.."
+readonly ProtoC="${ProtoRootDir}/src/protoc"
+
+pushd "${ProtoRootDir}" > /dev/null
+
+if test ! -e src/google/protobuf/stubs/common.h; then
+  cat >&2 << __EOF__
+Could not find source code.  Make sure you are running this script from the
+root of the distribution tree.
+__EOF__
+  exit 1
+fi
+
+if test ! -e src/Makefile; then
+  cat >&2 << __EOF__
+Could not find src/Makefile.  You must run ./configure (and perhaps
+./autogen.sh) first.
+__EOF__
+  exit 1
+fi
+
+# Make sure the compiler is current.
+cd src
+make $@ google/protobuf/stubs/pbconfig.h
+make $@ protoc
+
+declare -a RUNTIME_PROTO_FILES=(\
+  google/protobuf/any.proto \
+  google/protobuf/api.proto \
+  google/protobuf/descriptor.proto \
+  google/protobuf/duration.proto \
+  google/protobuf/empty.proto \
+  google/protobuf/field_mask.proto \
+  google/protobuf/source_context.proto \
+  google/protobuf/struct.proto \
+  google/protobuf/timestamp.proto \
+  google/protobuf/type.proto \
+  google/protobuf/wrappers.proto)
+
+./protoc --objc_out="${ProtoRootDir}/objectivec" ${RUNTIME_PROTO_FILES[@]}
+
+popd > /dev/null
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
new file mode 100644
index 0000000..8154318
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -0,0 +1,100 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+
+#pragma mark - GPBAnyRoot
+
+@interface GPBAnyRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBAny
+
+typedef GPB_ENUM(GPBAny_FieldNumber) {
+  GPBAny_FieldNumber_TypeURL = 1,
+  GPBAny_FieldNumber_Value = 2,
+};
+
+// `Any` contains an arbitrary serialized message along with a URL
+// that describes the type of the serialized message.
+//
+// The proto runtimes and/or compiler will eventually
+//  provide utilities to pack/unpack Any values (projected Q1/15).
+//
+// # JSON
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+//     package google.profile;
+//     message Person {
+//       string first_name = 1;
+//       string last_name = 2;
+//     }
+//
+//     {
+//       "@type": "type.googleapis.com/google.profile.Person",
+//       "firstName": <string>,
+//       "lastName": <string>
+//     }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the the `@type`
+// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+//
+//     {
+//       "@type": "type.googleapis.com/google.protobuf.Duration",
+//       "value": "1.212s"
+//     }
+@interface GPBAny : GPBMessage
+
+// A URL/resource name whose content describes the type of the
+// serialized message.
+//
+// For URLs which use the schema `http`, `https`, or no schema, the
+// following restrictions and interpretations apply:
+//
+// * If no schema is provided, `https` is assumed.
+// * The last segment of the URL's path must represent the fully
+//   qualified name of the type (as in `path/google.protobuf.Duration`).
+// * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+//   value in binary format, or produce an error.
+// * Applications are allowed to cache lookup results based on the
+//   URL, or have them precompiled into a binary to avoid any
+//   lookup. Therefore, binary compatibility needs to be preserved
+//   on changes to types. (Use versioned type names to manage
+//   breaking changes.)
+//
+// Schemas other than `http`, `https` (or the empty schema) might be
+// used with implementation specific semantics.
+//
+// Types originating from the `google.*` package
+// namespace should use `type.googleapis.com/full.type.name` (without
+// schema and path). A type service will eventually become available which
+// serves those URLs (projected Q2/15).
+@property(nonatomic, readwrite, copy) NSString *typeURL;
+
+// Must be valid serialized data of the above specified type.
+@property(nonatomic, readwrite, copy) NSData *value;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
new file mode 100644
index 0000000..4db73cb
--- /dev/null
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -0,0 +1,93 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/any.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Any.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBAnyRoot
+
+@implementation GPBAnyRoot
+
+@end
+
+static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBAny
+
+@implementation GPBAny
+
+@dynamic typeURL;
+@dynamic value;
+
+typedef struct GPBAny_Storage {
+  uint32_t _has_storage_[1];
+  NSString *typeURL;
+  NSData *value;
+} GPBAny_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "typeURL",
+        .number = GPBAny_FieldNumber_TypeURL,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBAny_Storage, typeURL),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "value",
+        .number = GPBAny_FieldNumber_Value,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeData,
+        .offset = offsetof(GPBAny_Storage, value),
+        .defaultValue.valueData = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\001\001\004\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBAny class]
+                                              rootClass:[GPBAnyRoot class]
+                                                   file:GPBAnyRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBAny_Storage)
+                                             wireFormat:NO
+                                    extraTextFormatInfo:extraTextFormatInfo];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
new file mode 100644
index 0000000..9e6fc85
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -0,0 +1,121 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBSourceContext;
+
+
+#pragma mark - GPBApiRoot
+
+@interface GPBApiRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBApi
+
+typedef GPB_ENUM(GPBApi_FieldNumber) {
+  GPBApi_FieldNumber_Name = 1,
+  GPBApi_FieldNumber_MethodsArray = 2,
+  GPBApi_FieldNumber_OptionsArray = 3,
+  GPBApi_FieldNumber_Version = 4,
+  GPBApi_FieldNumber_SourceContext = 5,
+};
+
+// Api is a light-weight descriptor for a protocol buffer service.
+@interface GPBApi : GPBMessage
+
+// The fully qualified name of this api, including package name
+// followed by the api's simple name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// The methods of this api, in unspecified order.
+// |methodsArray| contains |GPBMethod|
+@property(nonatomic, readwrite, strong) NSMutableArray *methodsArray;
+
+// Any metadata attached to the API.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+// A version string for this api. If specified, must have the form
+// `major-version.minor-version`, as in `1.10`. If the minor version
+// is omitted, it defaults to zero. If the entire version field is
+// empty, the major version is derived from the package name, as
+// outlined below. If the field is not empty, the version in the
+// package name will be verified to be consistent with what is
+// provided here.
+//
+// The versioning schema uses [semantic
+// versioning](http://semver.org) where the major version number
+// indicates a breaking change and the minor version an additive,
+// non-breaking change. Both version numbers are signals to users
+// what to expect from different versions, and should be carefully
+// chosen based on the product plan.
+//
+// The major version is also reflected in the package name of the
+// API, which must end in `v<major-version>`, as in
+// `google.feature.v1`. For major versions 0 and 1, the suffix can
+// be omitted. Zero major versions must only be used for
+// experimental, none-GA apis.
+//
+// See also: [design doc](http://go/api-versioning).
+@property(nonatomic, readwrite, copy) NSString *version;
+
+// Source context for the protocol buffer service represented by this
+// message.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong) GPBSourceContext *sourceContext;
+
+@end
+
+#pragma mark - GPBMethod
+
+typedef GPB_ENUM(GPBMethod_FieldNumber) {
+  GPBMethod_FieldNumber_Name = 1,
+  GPBMethod_FieldNumber_RequestTypeURL = 2,
+  GPBMethod_FieldNumber_RequestStreaming = 3,
+  GPBMethod_FieldNumber_ResponseTypeURL = 4,
+  GPBMethod_FieldNumber_ResponseStreaming = 5,
+  GPBMethod_FieldNumber_OptionsArray = 6,
+};
+
+// Method represents a method of an api.
+@interface GPBMethod : GPBMessage
+
+// The simple name of this method.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// A URL of the input message type.
+@property(nonatomic, readwrite, copy) NSString *requestTypeURL;
+
+// If true, the request is streamed.
+@property(nonatomic, readwrite) BOOL requestStreaming;
+
+// The URL of the output message type.
+@property(nonatomic, readwrite, copy) NSString *responseTypeURL;
+
+// If true, the response is streamed.
+@property(nonatomic, readwrite) BOOL responseStreaming;
+
+// Any metadata attached to the method.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
new file mode 100644
index 0000000..9416860
--- /dev/null
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -0,0 +1,262 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/api.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Api.pbobjc.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+#import "google/protobuf/Type.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBApiRoot
+
+@implementation GPBApiRoot
+
++ (GPBExtensionRegistry*)extensionRegistry {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety and initialization of registry.
+  static GPBExtensionRegistry* registry = nil;
+  if (!registry) {
+    registry = [[GPBExtensionRegistry alloc] init];
+    static GPBExtensionDescription descriptions[] = {
+    };
+    #pragma unused (descriptions)
+    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
+    [registry addExtensions:[GPBTypeRoot extensionRegistry]];
+  }
+  return registry;
+}
+
+@end
+
+static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBApi
+
+@implementation GPBApi
+
+@dynamic name;
+@dynamic methodsArray;
+@dynamic optionsArray;
+@dynamic version;
+@dynamic hasSourceContext, sourceContext;
+
+typedef struct GPBApi_Storage {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *methodsArray;
+  NSMutableArray *optionsArray;
+  NSString *version;
+  GPBSourceContext *sourceContext;
+} GPBApi_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBApi_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBApi_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "methodsArray",
+        .number = GPBApi_FieldNumber_MethodsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBApi_Storage, methodsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBMethod),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBApi_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBApi_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "version",
+        .number = GPBApi_FieldNumber_Version,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBApi_Storage, version),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBApi_FieldNumber_SourceContext,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBApi_Storage, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBApi class]
+                                              rootClass:[GPBApiRoot class]
+                                                   file:GPBApiRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBApi_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBMethod
+
+@implementation GPBMethod
+
+@dynamic name;
+@dynamic requestTypeURL;
+@dynamic requestStreaming;
+@dynamic responseTypeURL;
+@dynamic responseStreaming;
+@dynamic optionsArray;
+
+typedef struct GPBMethod_Storage {
+  uint32_t _has_storage_[1];
+  BOOL requestStreaming;
+  BOOL responseStreaming;
+  NSString *name;
+  NSString *requestTypeURL;
+  NSString *responseTypeURL;
+  NSMutableArray *optionsArray;
+} GPBMethod_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBMethod_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBMethod_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "requestTypeURL",
+        .number = GPBMethod_FieldNumber_RequestTypeURL,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBMethod_Storage, requestTypeURL),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "requestStreaming",
+        .number = GPBMethod_FieldNumber_RequestStreaming,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeBool,
+        .offset = offsetof(GPBMethod_Storage, requestStreaming),
+        .defaultValue.valueBool = NO,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "responseTypeURL",
+        .number = GPBMethod_FieldNumber_ResponseTypeURL,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBMethod_Storage, responseTypeURL),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "responseStreaming",
+        .number = GPBMethod_FieldNumber_ResponseStreaming,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeBool,
+        .offset = offsetof(GPBMethod_Storage, responseStreaming),
+        .defaultValue.valueBool = NO,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBMethod_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBMethod_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\002\002\007\244\241!!\000\004\010\244\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMethod class]
+                                              rootClass:[GPBApiRoot class]
+                                                   file:GPBApiRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBMethod_Storage)
+                                             wireFormat:NO
+                                    extraTextFormatInfo:extraTextFormatInfo];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.h b/objectivec/google/protobuf/Descriptor.pbobjc.h
index e3dacf2..19a82fd 100644
--- a/objectivec/google/protobuf/Descriptor.pbobjc.h
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.h
@@ -7,29 +7,18 @@
 #error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
 #endif
 
+// @@protoc_insertion_point(imports)
+
 CF_EXTERN_C_BEGIN
 
-@class GPBDescriptorProto;
-@class GPBDescriptorProto_ExtensionRange;
-@class GPBEnumDescriptorProto;
 @class GPBEnumOptions;
-@class GPBEnumValueDescriptorProto;
 @class GPBEnumValueOptions;
-@class GPBFieldDescriptorProto;
 @class GPBFieldOptions;
-@class GPBFileDescriptorProto;
-@class GPBFileDescriptorSet;
 @class GPBFileOptions;
 @class GPBMessageOptions;
-@class GPBMethodDescriptorProto;
 @class GPBMethodOptions;
-@class GPBOneofDescriptorProto;
-@class GPBServiceDescriptorProto;
 @class GPBServiceOptions;
 @class GPBSourceCodeInfo;
-@class GPBSourceCodeInfo_Location;
-@class GPBUninterpretedOption;
-@class GPBUninterpretedOption_NamePart;
 
 #pragma mark - Enum GPBFieldDescriptorProto_Type
 
@@ -126,6 +115,12 @@
 #pragma mark - GPBDescriptorRoot
 
 @interface GPBDescriptorRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
 @end
 
 #pragma mark - GPBFileDescriptorSet
@@ -1049,3 +1044,5 @@
 @end
 
 CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.m b/objectivec/google/protobuf/Descriptor.pbobjc.m
index 25e4cc7..2fc1953 100644
--- a/objectivec/google/protobuf/Descriptor.pbobjc.m
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.m
@@ -2,8 +2,8 @@
 // source: google/protobuf/descriptor.proto
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
-
 #import "google/protobuf/Descriptor.pbobjc.h"
+// @@protoc_insertion_point(imports)
 
 #pragma mark - GPBDescriptorRoot
 
@@ -2216,3 +2216,5 @@
 
 @end
 
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index c452d0b..f65df6c 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -7,14 +7,20 @@
 #error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
 #endif
 
-CF_EXTERN_C_BEGIN
+// @@protoc_insertion_point(imports)
 
-@class GPBDuration;
+CF_EXTERN_C_BEGIN
 
 
 #pragma mark - GPBDurationRoot
 
 @interface GPBDurationRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
 @end
 
 #pragma mark - GPBDuration
@@ -81,3 +87,5 @@
 @end
 
 CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
index cf0a306..4db030f 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.m
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -2,8 +2,8 @@
 // source: google/protobuf/duration.proto
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
-
 #import "google/protobuf/Duration.pbobjc.h"
+// @@protoc_insertion_point(imports)
 
 #pragma mark - GPBDurationRoot
 
@@ -83,3 +83,5 @@
 
 @end
 
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
new file mode 100644
index 0000000..1356c3a
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -0,0 +1,41 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+
+#pragma mark - GPBEmptyRoot
+
+@interface GPBEmptyRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBEmpty
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+//     service Foo {
+//       rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+//     }
+@interface GPBEmpty : GPBMessage
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
new file mode 100644
index 0000000..619fe90
--- /dev/null
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -0,0 +1,61 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/empty.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Empty.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBEmptyRoot
+
+@implementation GPBEmptyRoot
+
+@end
+
+static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBEmpty
+
+@implementation GPBEmpty
+
+
+typedef struct GPBEmpty_Storage {
+  uint32_t _has_storage_[0];
+} GPBEmpty_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEmpty class]
+                                              rootClass:[GPBEmptyRoot class]
+                                                   file:GPBEmptyRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBEmpty_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
new file mode 100644
index 0000000..ac6f03d
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -0,0 +1,160 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+
+#pragma mark - GPBFieldMaskRoot
+
+@interface GPBFieldMaskRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBFieldMask
+
+typedef GPB_ENUM(GPBFieldMask_FieldNumber) {
+  GPBFieldMask_FieldNumber_PathsArray = 1,
+};
+
+// `FieldMask` represents a set of symbolic field paths, for example:
+//
+//     paths: "f.a"
+//     paths: "f.b.d"
+//
+// Here `f` represents a field in some root message, `a` and `b`
+// fields in the message found in `f`, and `d` a field found in the
+// message in `f.b`.
+//
+// Field masks are used to specify a subset of fields that should be
+// returned by a get operation or modified by an update operation.
+// Field masks also have a custom JSON encoding (see below).
+//
+// # Field Masks in Projections
+// When used in the context of a projection, a response message or
+// sub-message is filtered by the API to only contain those fields as
+// specified in the mask. For example, if the mask in the previous
+// example is applied to a response message as follows:
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//         x : 2
+//       }
+//       y : 13
+//     }
+//     z: 8
+//
+// The result will not contain specific values for fields x,y and z
+// (there value will be set to the default, and omitted in proto text
+// output):
+//
+//
+//     f {
+//       a : 22
+//       b {
+//         d : 1
+//       }
+//     }
+//
+// A repeated field is not allowed except at the last position of a
+// field mask.
+//
+// If a FieldMask object is not present in a get operation, the
+// operation applies to all fields (as if a FieldMask of all fields
+// had been specified).
+//
+// Note that a field mask does not necessarily applies to the
+// top-level response message. In case of a REST get operation, the
+// field mask applies directly to the response, but in case of a REST
+// list operation, the mask instead applies to each individual message
+// in the returned resource list. In case of a REST custom method,
+// other definitions may be used. Where the mask applies will be
+// clearly documented together with its declaration in the API.  In
+// any case, the effect on the returned resource/resources is required
+// behavior for APIs.
+//
+// # Field Masks in Update Operations
+// A field mask in update operations specifies which fields of the
+// targeted resource are going to be updated. The API is required
+// to only change the values of the fields as specified in the mask
+// and leave the others untouched. If a resource is passed in to
+// describe the updated values, the API ignores the values of all
+// fields not covered by the mask.
+//
+// In order to reset a field's value to the default, the field must
+// be in the mask and set to the default value in the provided resource.
+// Hence, in order to reset all fields of a resource, provide a default
+// instance of the resource and set all fields in the mask, or do
+// not provide a mask as described below.
+//
+// If a field mask is not present on update, the operation applies to
+// all fields (as if a field mask of all fields has been specified).
+// Note that in the presence of schema evolution, this may mean that
+// fields the client does not know and has therefore not filled into
+// the request will be reset to their default. If this is unwanted
+// behavior, a specific service may require a client to always specify
+// a field mask, producing an error if not.
+//
+// As with get operations, the location of the resource which
+// describes the updated values in the request message depends on the
+// operation kind. In any case, the effect of the field mask is
+// required to be honored by the API.
+//
+// ## Considerations for HTTP REST
+// The HTTP kind of an update operation which uses a field mask must
+// be set to PATCH instead of PUT in order to satisfy HTTP semantics
+// (PUT must only be used for full updates).
+//
+// # JSON Encoding of Field Masks
+// In JSON, a field mask is encoded as a single string where paths are
+// separated by a comma. Fields name in each path are converted
+// to/from lower-camel naming conventions.
+//
+// As an example, consider the following message declarations:
+//
+//     message Profile {
+//       User user = 1;
+//       Photo photo = 2;
+//     }
+//     message User {
+//       string display_name = 1;
+//       string address = 2;
+//     }
+//
+// In proto a field mask for `Profile` may look as such:
+//
+//     mask {
+//       paths: "user.display_name"
+//       paths: "photo"
+//     }
+//
+// In JSON, the same mask is represented as below:
+//
+//     {
+//       mask: "user.displayName,photo"
+//     }
+@interface GPBFieldMask : GPBMessage
+
+// The set of field mask paths.
+// |pathsArray| contains |NSString|
+@property(nonatomic, readwrite, strong) NSMutableArray *pathsArray;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
new file mode 100644
index 0000000..e37ac6c
--- /dev/null
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -0,0 +1,74 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/field_mask.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/FieldMask.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBFieldMaskRoot
+
+@implementation GPBFieldMaskRoot
+
+@end
+
+static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBFieldMask
+
+@implementation GPBFieldMask
+
+@dynamic pathsArray;
+
+typedef struct GPBFieldMask_Storage {
+  uint32_t _has_storage_[1];
+  NSMutableArray *pathsArray;
+} GPBFieldMask_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "pathsArray",
+        .number = GPBFieldMask_FieldNumber_PathsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBFieldMask_Storage, pathsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFieldMask class]
+                                              rootClass:[GPBFieldMaskRoot class]
+                                                   file:GPBFieldMaskRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBFieldMask_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
new file mode 100644
index 0000000..bcbf1e3
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -0,0 +1,44 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+
+#pragma mark - GPBSourceContextRoot
+
+@interface GPBSourceContextRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBSourceContext
+
+typedef GPB_ENUM(GPBSourceContext_FieldNumber) {
+  GPBSourceContext_FieldNumber_FileName = 1,
+};
+
+// `SourceContext` represents information about the source of a
+// protobuf element, like the file in which it is defined.
+@interface GPBSourceContext : GPBMessage
+
+// The path-qualified name of the .proto file that contained the associated
+// protobuf element.  For example: `"google/protobuf/source.proto"`.
+@property(nonatomic, readwrite, copy) NSString *fileName;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
new file mode 100644
index 0000000..271f924
--- /dev/null
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -0,0 +1,74 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/source_context.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBSourceContextRoot
+
+@implementation GPBSourceContextRoot
+
+@end
+
+static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBSourceContext
+
+@implementation GPBSourceContext
+
+@dynamic fileName;
+
+typedef struct GPBSourceContext_Storage {
+  uint32_t _has_storage_[1];
+  NSString *fileName;
+} GPBSourceContext_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "fileName",
+        .number = GPBSourceContext_FieldNumber_FileName,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBSourceContext_Storage, fileName),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBSourceContext class]
+                                              rootClass:[GPBSourceContextRoot class]
+                                                   file:GPBSourceContextRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBSourceContext_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
new file mode 100644
index 0000000..f55af82
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -0,0 +1,134 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBListValue;
+@class GPBStruct;
+
+#pragma mark - Enum GPBNullValue
+
+// `NullValue` is a singleton enumeration to represent the null
+// value for the `Value` type union.
+typedef GPB_ENUM(GPBNullValue) {
+  GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  // Null value.
+  GPBNullValue_NullValue = 0,
+};
+
+GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void);
+
+BOOL GPBNullValue_IsValidValue(int32_t value);
+
+
+#pragma mark - GPBStructRoot
+
+@interface GPBStructRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBStruct
+
+typedef GPB_ENUM(GPBStruct_FieldNumber) {
+  GPBStruct_FieldNumber_Fields = 1,
+};
+
+// `Struct` represents a structured data value, consisting of fields
+// which map to dynamically typed values. In some languages, `Struct`
+// might be supported by a native representation. For example, in
+// scripting languages like JS a struct is represented as an
+// object. The details of that representation are described together
+// with the proto support for the language.
+@interface GPBStruct : GPBMessage
+
+// Map of dynamically typed values.
+// |fields| values are |GPBValue|
+@property(nonatomic, readwrite, strong) NSMutableDictionary *fields;
+
+@end
+
+#pragma mark - GPBValue
+
+typedef GPB_ENUM(GPBValue_FieldNumber) {
+  GPBValue_FieldNumber_NullValue = 1,
+  GPBValue_FieldNumber_NumberValue = 2,
+  GPBValue_FieldNumber_StringValue = 3,
+  GPBValue_FieldNumber_BoolValue = 4,
+  GPBValue_FieldNumber_StructValue = 5,
+  GPBValue_FieldNumber_ListValue = 6,
+};
+
+typedef GPB_ENUM(GPBValue_Kind_OneOfCase) {
+  GPBValue_Kind_OneOfCase_GPBUnsetOneOfCase = 0,
+  GPBValue_Kind_OneOfCase_NullValue = 1,
+  GPBValue_Kind_OneOfCase_NumberValue = 2,
+  GPBValue_Kind_OneOfCase_StringValue = 3,
+  GPBValue_Kind_OneOfCase_BoolValue = 4,
+  GPBValue_Kind_OneOfCase_StructValue = 5,
+  GPBValue_Kind_OneOfCase_ListValue = 6,
+};
+
+// `Value` represents a dynamically typed value which can be either
+// null, a number, a string, a boolean, a recursive struct value, or a
+// list of values. A producer of value is expected to set one of that
+// variants, absence of any variant indicates an error.
+@interface GPBValue : GPBMessage
+
+@property(nonatomic, readonly) GPBValue_Kind_OneOfCase kindOneOfCase;
+
+// Represents a null value.
+@property(nonatomic, readwrite) GPBNullValue nullValue;
+
+// Represents a double value.
+@property(nonatomic, readwrite) double numberValue;
+
+// Represents a string value.
+@property(nonatomic, readwrite, copy) NSString *stringValue;
+
+// Represents a boolean value.
+@property(nonatomic, readwrite) BOOL boolValue;
+
+// Represents a structured value.
+@property(nonatomic, readwrite, strong) GPBStruct *structValue;
+
+// Represents a repeated `Value`.
+@property(nonatomic, readwrite, strong) GPBListValue *listValue;
+
+@end
+
+int32_t GPBValue_NullValue_RawValue(GPBValue *message);
+void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value);
+
+void GPBValue_ClearKindOneOfCase(GPBValue *message);
+
+#pragma mark - GPBListValue
+
+typedef GPB_ENUM(GPBListValue_FieldNumber) {
+  GPBListValue_FieldNumber_ValuesArray = 1,
+};
+
+// `ListValue` is a wrapper around a repeated field of values.
+@interface GPBListValue : GPBMessage
+
+// Repeated field of dynamically typed values.
+// |valuesArray| contains |GPBValue|
+@property(nonatomic, readwrite, strong) NSMutableArray *valuesArray;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
new file mode 100644
index 0000000..e5a8b54
--- /dev/null
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -0,0 +1,284 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/struct.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Struct.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBStructRoot
+
+@implementation GPBStructRoot
+
+@end
+
+static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - Enum GPBNullValue
+
+GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "NullValue", .number = GPBNullValue_NullValue },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBNullValue_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBNullValue_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBNullValue_NullValue:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBStruct
+
+@implementation GPBStruct
+
+@dynamic fields;
+
+typedef struct GPBStruct_Storage {
+  uint32_t _has_storage_[1];
+  NSMutableDictionary *fields;
+} GPBStruct_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "fields",
+        .number = GPBStruct_FieldNumber_Fields,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldMapKeyString,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBStruct_Storage, fields),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBValue),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBStruct class]
+                                              rootClass:[GPBStructRoot class]
+                                                   file:GPBStructRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBStruct_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBValue
+
+@implementation GPBValue
+
+@dynamic kindOneOfCase;
+@dynamic nullValue;
+@dynamic numberValue;
+@dynamic stringValue;
+@dynamic boolValue;
+@dynamic structValue;
+@dynamic listValue;
+
+typedef struct GPBValue_Storage {
+  uint32_t _has_storage_[2];
+  BOOL boolValue;
+  GPBNullValue nullValue;
+  NSString *stringValue;
+  GPBStruct *structValue;
+  GPBListValue *listValue;
+  double numberValue;
+} GPBValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageOneofDescription oneofs[] = {
+      {
+        .name = "kind",
+        .index = -1,
+      },
+    };
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "nullValue",
+        .number = GPBValue_FieldNumber_NullValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .type = GPBTypeEnum,
+        .offset = offsetof(GPBValue_Storage, nullValue),
+        .defaultValue.valueEnum = GPBNullValue_NullValue,
+        .typeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "numberValue",
+        .number = GPBValue_FieldNumber_NumberValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeDouble,
+        .offset = offsetof(GPBValue_Storage, numberValue),
+        .defaultValue.valueDouble = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "stringValue",
+        .number = GPBValue_FieldNumber_StringValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBValue_Storage, stringValue),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "boolValue",
+        .number = GPBValue_FieldNumber_BoolValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeBool,
+        .offset = offsetof(GPBValue_Storage, boolValue),
+        .defaultValue.valueBool = NO,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "structValue",
+        .number = GPBValue_FieldNumber_StructValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBValue_Storage, structValue),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBStruct),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "listValue",
+        .number = GPBValue_FieldNumber_ListValue,
+        .hasIndex = -1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBValue_Storage, listValue),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBListValue),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBValue class]
+                                              rootClass:[GPBStructRoot class]
+                                                   file:GPBStructRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:oneofs
+                                             oneofCount:sizeof(oneofs) / sizeof(GPBMessageOneofDescription)
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBValue_NullValue_RawValue(GPBValue *message) {
+  GPBDescriptor *descriptor = [GPBValue descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue];
+  return GPBGetInt32IvarWithField(message, field);
+}
+
+void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBValue descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+void GPBValue_ClearKindOneOfCase(GPBValue *message) {
+  GPBDescriptor *descriptor = [message descriptor];
+  GPBOneofDescriptor *oneof = descriptor->oneofs_[0];
+  GPBMaybeClearOneof(message, oneof, 0);
+}
+#pragma mark - GPBListValue
+
+@implementation GPBListValue
+
+@dynamic valuesArray;
+
+typedef struct GPBListValue_Storage {
+  uint32_t _has_storage_[1];
+  NSMutableArray *valuesArray;
+} GPBListValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "valuesArray",
+        .number = GPBListValue_FieldNumber_ValuesArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBListValue_Storage, valuesArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBValue),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBListValue class]
+                                              rootClass:[GPBStructRoot class]
+                                                   file:GPBStructRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBListValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index c9fc917..a81321b 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -7,14 +7,20 @@
 #error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
 #endif
 
-CF_EXTERN_C_BEGIN
+// @@protoc_insertion_point(imports)
 
-@class GPBTimestamp;
+CF_EXTERN_C_BEGIN
 
 
 #pragma mark - GPBTimestampRoot
 
 @interface GPBTimestampRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
 @end
 
 #pragma mark - GPBTimestamp
@@ -92,3 +98,5 @@
 @end
 
 CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
index 1c8d3c7..197dff4 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.m
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -2,8 +2,8 @@
 // source: google/protobuf/timestamp.proto
 
 #import "GPBProtocolBuffers_RuntimeSupport.h"
-
 #import "google/protobuf/Timestamp.pbobjc.h"
+// @@protoc_insertion_point(imports)
 
 #pragma mark - GPBTimestampRoot
 
@@ -83,3 +83,5 @@
 
 @end
 
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
new file mode 100644
index 0000000..652a33a
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -0,0 +1,274 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+@class GPBAny;
+@class GPBSourceContext;
+
+#pragma mark - Enum GPBField_Kind
+
+// Kind represents a basic field type.
+typedef GPB_ENUM(GPBField_Kind) {
+  GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  // Field type unknown.
+  GPBField_Kind_TypeUnknown = 0,
+
+  // Field type double.
+  GPBField_Kind_TypeDouble = 1,
+
+  // Field type float.
+  GPBField_Kind_TypeFloat = 2,
+
+  // Field type int64.
+  GPBField_Kind_TypeInt64 = 3,
+
+  // Field type uint64.
+  GPBField_Kind_TypeUint64 = 4,
+
+  // Field type int32.
+  GPBField_Kind_TypeInt32 = 5,
+
+  // Field type fixed64.
+  GPBField_Kind_TypeFixed64 = 6,
+
+  // Field type fixed32.
+  GPBField_Kind_TypeFixed32 = 7,
+
+  // Field type bool.
+  GPBField_Kind_TypeBool = 8,
+
+  // Field type string.
+  GPBField_Kind_TypeString = 9,
+
+  // Field type message.
+  GPBField_Kind_TypeMessage = 11,
+
+  // Field type bytes.
+  GPBField_Kind_TypeBytes = 12,
+
+  // Field type uint32.
+  GPBField_Kind_TypeUint32 = 13,
+
+  // Field type enum.
+  GPBField_Kind_TypeEnum = 14,
+
+  // Field type sfixed32.
+  GPBField_Kind_TypeSfixed32 = 15,
+
+  // Field type sfixed64.
+  GPBField_Kind_TypeSfixed64 = 16,
+
+  // Field type sint32.
+  GPBField_Kind_TypeSint32 = 17,
+
+  // Field type sint64.
+  GPBField_Kind_TypeSint64 = 18,
+};
+
+GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void);
+
+BOOL GPBField_Kind_IsValidValue(int32_t value);
+
+#pragma mark - Enum GPBField_Cardinality
+
+// Cardinality represents whether a field is optional, required, or
+// repeated.
+typedef GPB_ENUM(GPBField_Cardinality) {
+  GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
+  // The field cardinality is unknown. Typically an error condition.
+  GPBField_Cardinality_CardinalityUnknown = 0,
+
+  // For optional fields.
+  GPBField_Cardinality_CardinalityOptional = 1,
+
+  // For required fields. Not used for proto3.
+  GPBField_Cardinality_CardinalityRequired = 2,
+
+  // For repeated fields.
+  GPBField_Cardinality_CardinalityRepeated = 3,
+};
+
+GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void);
+
+BOOL GPBField_Cardinality_IsValidValue(int32_t value);
+
+
+#pragma mark - GPBTypeRoot
+
+@interface GPBTypeRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBType
+
+typedef GPB_ENUM(GPBType_FieldNumber) {
+  GPBType_FieldNumber_Name = 1,
+  GPBType_FieldNumber_FieldsArray = 2,
+  GPBType_FieldNumber_OneofsArray = 3,
+  GPBType_FieldNumber_OptionsArray = 4,
+  GPBType_FieldNumber_SourceContext = 5,
+};
+
+// A light-weight descriptor for a proto message type.
+@interface GPBType : GPBMessage
+
+// The fully qualified message name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// The list of fields.
+// |fieldsArray| contains |GPBField|
+@property(nonatomic, readwrite, strong) NSMutableArray *fieldsArray;
+
+// The list of oneof definitions.
+// The list of oneofs declared in this Type
+// |oneofsArray| contains |NSString|
+@property(nonatomic, readwrite, strong) NSMutableArray *oneofsArray;
+
+// The proto options.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+// The source context.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong) GPBSourceContext *sourceContext;
+
+@end
+
+#pragma mark - GPBField
+
+typedef GPB_ENUM(GPBField_FieldNumber) {
+  GPBField_FieldNumber_Kind = 1,
+  GPBField_FieldNumber_Cardinality = 2,
+  GPBField_FieldNumber_Number = 3,
+  GPBField_FieldNumber_Name = 4,
+  GPBField_FieldNumber_TypeURL = 6,
+  GPBField_FieldNumber_OneofIndex = 7,
+  GPBField_FieldNumber_Packed = 8,
+  GPBField_FieldNumber_OptionsArray = 9,
+};
+
+// Field represents a single field of a message type.
+@interface GPBField : GPBMessage
+
+// The field kind.
+@property(nonatomic, readwrite) GPBField_Kind kind;
+
+// The field cardinality, i.e. optional/required/repeated.
+@property(nonatomic, readwrite) GPBField_Cardinality cardinality;
+
+// The proto field number.
+@property(nonatomic, readwrite) int32_t number;
+
+// The field name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// The type URL (without the scheme) when the type is MESSAGE or ENUM,
+// such as `type.googleapis.com/google.protobuf.Empty`.
+@property(nonatomic, readwrite, copy) NSString *typeURL;
+
+// Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
+@property(nonatomic, readwrite) int32_t oneofIndex;
+
+// Whether to use alternative packed wire representation.
+@property(nonatomic, readwrite) BOOL packed;
+
+// The proto options.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+@end
+
+int32_t GPBField_Kind_RawValue(GPBField *message);
+void SetGPBField_Kind_RawValue(GPBField *message, int32_t value);
+
+int32_t GPBField_Cardinality_RawValue(GPBField *message);
+void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value);
+
+#pragma mark - GPBEnum
+
+typedef GPB_ENUM(GPBEnum_FieldNumber) {
+  GPBEnum_FieldNumber_Name = 1,
+  GPBEnum_FieldNumber_EnumvalueArray = 2,
+  GPBEnum_FieldNumber_OptionsArray = 3,
+  GPBEnum_FieldNumber_SourceContext = 4,
+};
+
+// Enum type definition.
+@interface GPBEnum : GPBMessage
+
+// Enum type name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// Enum value definitions.
+// |enumvalueArray| contains |GPBEnumValue|
+@property(nonatomic, readwrite, strong) NSMutableArray *enumvalueArray;
+
+// Proto options for the enum type.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+// The source context.
+@property(nonatomic, readwrite) BOOL hasSourceContext;
+@property(nonatomic, readwrite, strong) GPBSourceContext *sourceContext;
+
+@end
+
+#pragma mark - GPBEnumValue
+
+typedef GPB_ENUM(GPBEnumValue_FieldNumber) {
+  GPBEnumValue_FieldNumber_Name = 1,
+  GPBEnumValue_FieldNumber_Number = 2,
+  GPBEnumValue_FieldNumber_OptionsArray = 3,
+};
+
+// Enum value definition.
+@interface GPBEnumValue : GPBMessage
+
+// Enum value name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// Enum value number.
+@property(nonatomic, readwrite) int32_t number;
+
+// Proto options for the enum value.
+// |optionsArray| contains |GPBOption|
+@property(nonatomic, readwrite, strong) NSMutableArray *optionsArray;
+
+@end
+
+#pragma mark - GPBOption
+
+typedef GPB_ENUM(GPBOption_FieldNumber) {
+  GPBOption_FieldNumber_Name = 1,
+  GPBOption_FieldNumber_Value = 2,
+};
+
+// Proto option attached to messages/fields/enums etc.
+@interface GPBOption : GPBMessage
+
+// Proto option name.
+@property(nonatomic, readwrite, copy) NSString *name;
+
+// Proto option value.
+@property(nonatomic, readwrite) BOOL hasValue;
+@property(nonatomic, readwrite, strong) GPBAny *value;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
new file mode 100644
index 0000000..182370c
--- /dev/null
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -0,0 +1,628 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/type.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Type.pbobjc.h"
+#import "google/protobuf/Any.pbobjc.h"
+#import "google/protobuf/SourceContext.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBTypeRoot
+
+@implementation GPBTypeRoot
+
++ (GPBExtensionRegistry*)extensionRegistry {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety and initialization of registry.
+  static GPBExtensionRegistry* registry = nil;
+  if (!registry) {
+    registry = [[GPBExtensionRegistry alloc] init];
+    static GPBExtensionDescription descriptions[] = {
+    };
+    #pragma unused (descriptions)
+    [registry addExtensions:[GPBAnyRoot extensionRegistry]];
+    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
+  }
+  return registry;
+}
+
+@end
+
+static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBType
+
+@implementation GPBType
+
+@dynamic name;
+@dynamic fieldsArray;
+@dynamic oneofsArray;
+@dynamic optionsArray;
+@dynamic hasSourceContext, sourceContext;
+
+typedef struct GPBType_Storage {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *fieldsArray;
+  NSMutableArray *oneofsArray;
+  NSMutableArray *optionsArray;
+  GPBSourceContext *sourceContext;
+} GPBType_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBType_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBType_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "fieldsArray",
+        .number = GPBType_FieldNumber_FieldsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBType_Storage, fieldsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBField),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofsArray",
+        .number = GPBType_FieldNumber_OneofsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBType_Storage, oneofsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBType_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBType_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBType_FieldNumber_SourceContext,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBType_Storage, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBType class]
+                                              rootClass:[GPBTypeRoot class]
+                                                   file:GPBTypeRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBType_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBField
+
+@implementation GPBField
+
+@dynamic kind;
+@dynamic cardinality;
+@dynamic number;
+@dynamic name;
+@dynamic typeURL;
+@dynamic oneofIndex;
+@dynamic packed;
+@dynamic optionsArray;
+
+typedef struct GPBField_Storage {
+  uint32_t _has_storage_[1];
+  BOOL packed;
+  GPBField_Kind kind;
+  GPBField_Cardinality cardinality;
+  int32_t number;
+  int32_t oneofIndex;
+  NSString *name;
+  NSString *typeURL;
+  NSMutableArray *optionsArray;
+} GPBField_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "kind",
+        .number = GPBField_FieldNumber_Kind,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .type = GPBTypeEnum,
+        .offset = offsetof(GPBField_Storage, kind),
+        .defaultValue.valueEnum = GPBField_Kind_TypeUnknown,
+        .typeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "cardinality",
+        .number = GPBField_FieldNumber_Cardinality,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .type = GPBTypeEnum,
+        .offset = offsetof(GPBField_Storage, cardinality),
+        .defaultValue.valueEnum = GPBField_Cardinality_CardinalityUnknown,
+        .typeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBField_FieldNumber_Number,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeInt32,
+        .offset = offsetof(GPBField_Storage, number),
+        .defaultValue.valueInt32 = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "name",
+        .number = GPBField_FieldNumber_Name,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBField_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "typeURL",
+        .number = GPBField_FieldNumber_TypeURL,
+        .hasIndex = 4,
+        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBField_Storage, typeURL),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "oneofIndex",
+        .number = GPBField_FieldNumber_OneofIndex,
+        .hasIndex = 5,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeInt32,
+        .offset = offsetof(GPBField_Storage, oneofIndex),
+        .defaultValue.valueInt32 = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "packed",
+        .number = GPBField_FieldNumber_Packed,
+        .hasIndex = 6,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeBool,
+        .offset = offsetof(GPBField_Storage, packed),
+        .defaultValue.valueBool = NO,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBField_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBField_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+    };
+    static GPBMessageEnumDescription enums[] = {
+      { .enumDescriptorFunc = GPBField_Kind_EnumDescriptor },
+      { .enumDescriptorFunc = GPBField_Cardinality_EnumDescriptor },
+    };
+#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    const char *extraTextFormatInfo = NULL;
+#else
+    static const char *extraTextFormatInfo = "\001\006\004\241!!\000";
+#endif  // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBField class]
+                                              rootClass:[GPBTypeRoot class]
+                                                   file:GPBTypeRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:enums
+                                              enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription)
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBField_Storage)
+                                             wireFormat:NO
+                                    extraTextFormatInfo:extraTextFormatInfo];
+  }
+  return descriptor;
+}
+
+@end
+
+int32_t GPBField_Kind_RawValue(GPBField *message) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind];
+  return GPBGetInt32IvarWithField(message, field);
+}
+
+void SetGPBField_Kind_RawValue(GPBField *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+int32_t GPBField_Cardinality_RawValue(GPBField *message) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality];
+  return GPBGetInt32IvarWithField(message, field);
+}
+
+void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) {
+  GPBDescriptor *descriptor = [GPBField descriptor];
+  GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality];
+  GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax);
+}
+
+#pragma mark - Enum GPBField_Kind
+
+GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "TypeUnknown", .number = GPBField_Kind_TypeUnknown },
+      { .name = "TypeDouble", .number = GPBField_Kind_TypeDouble },
+      { .name = "TypeFloat", .number = GPBField_Kind_TypeFloat },
+      { .name = "TypeInt64", .number = GPBField_Kind_TypeInt64 },
+      { .name = "TypeUint64", .number = GPBField_Kind_TypeUint64 },
+      { .name = "TypeInt32", .number = GPBField_Kind_TypeInt32 },
+      { .name = "TypeFixed64", .number = GPBField_Kind_TypeFixed64 },
+      { .name = "TypeFixed32", .number = GPBField_Kind_TypeFixed32 },
+      { .name = "TypeBool", .number = GPBField_Kind_TypeBool },
+      { .name = "TypeString", .number = GPBField_Kind_TypeString },
+      { .name = "TypeMessage", .number = GPBField_Kind_TypeMessage },
+      { .name = "TypeBytes", .number = GPBField_Kind_TypeBytes },
+      { .name = "TypeUint32", .number = GPBField_Kind_TypeUint32 },
+      { .name = "TypeEnum", .number = GPBField_Kind_TypeEnum },
+      { .name = "TypeSfixed32", .number = GPBField_Kind_TypeSfixed32 },
+      { .name = "TypeSfixed64", .number = GPBField_Kind_TypeSfixed64 },
+      { .name = "TypeSint32", .number = GPBField_Kind_TypeSint32 },
+      { .name = "TypeSint64", .number = GPBField_Kind_TypeSint64 },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBField_Kind_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBField_Kind_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBField_Kind_TypeUnknown:
+    case GPBField_Kind_TypeDouble:
+    case GPBField_Kind_TypeFloat:
+    case GPBField_Kind_TypeInt64:
+    case GPBField_Kind_TypeUint64:
+    case GPBField_Kind_TypeInt32:
+    case GPBField_Kind_TypeFixed64:
+    case GPBField_Kind_TypeFixed32:
+    case GPBField_Kind_TypeBool:
+    case GPBField_Kind_TypeString:
+    case GPBField_Kind_TypeMessage:
+    case GPBField_Kind_TypeBytes:
+    case GPBField_Kind_TypeUint32:
+    case GPBField_Kind_TypeEnum:
+    case GPBField_Kind_TypeSfixed32:
+    case GPBField_Kind_TypeSfixed64:
+    case GPBField_Kind_TypeSint32:
+    case GPBField_Kind_TypeSint64:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - Enum GPBField_Cardinality
+
+GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) {
+  static GPBEnumDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageEnumValueDescription values[] = {
+      { .name = "CardinalityUnknown", .number = GPBField_Cardinality_CardinalityUnknown },
+      { .name = "CardinalityOptional", .number = GPBField_Cardinality_CardinalityOptional },
+      { .name = "CardinalityRequired", .number = GPBField_Cardinality_CardinalityRequired },
+      { .name = "CardinalityRepeated", .number = GPBField_Cardinality_CardinalityRepeated },
+    };
+    descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality)
+                                                   values:values
+                                               valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)
+                                             enumVerifier:GPBField_Cardinality_IsValidValue];
+  }
+  return descriptor;
+}
+
+BOOL GPBField_Cardinality_IsValidValue(int32_t value__) {
+  switch (value__) {
+    case GPBField_Cardinality_CardinalityUnknown:
+    case GPBField_Cardinality_CardinalityOptional:
+    case GPBField_Cardinality_CardinalityRequired:
+    case GPBField_Cardinality_CardinalityRepeated:
+      return YES;
+    default:
+      return NO;
+  }
+}
+
+#pragma mark - GPBEnum
+
+@implementation GPBEnum
+
+@dynamic name;
+@dynamic enumvalueArray;
+@dynamic optionsArray;
+@dynamic hasSourceContext, sourceContext;
+
+typedef struct GPBEnum_Storage {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  NSMutableArray *enumvalueArray;
+  NSMutableArray *optionsArray;
+  GPBSourceContext *sourceContext;
+} GPBEnum_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBEnum_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBEnum_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "enumvalueArray",
+        .number = GPBEnum_FieldNumber_EnumvalueArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBEnum_Storage, enumvalueArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBEnumValue),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBEnum_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBEnum_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "sourceContext",
+        .number = GPBEnum_FieldNumber_SourceContext,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBEnum_Storage, sourceContext),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBSourceContext),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnum class]
+                                              rootClass:[GPBTypeRoot class]
+                                                   file:GPBTypeRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBEnum_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBEnumValue
+
+@implementation GPBEnumValue
+
+@dynamic name;
+@dynamic number;
+@dynamic optionsArray;
+
+typedef struct GPBEnumValue_Storage {
+  uint32_t _has_storage_[1];
+  int32_t number;
+  NSString *name;
+  NSMutableArray *optionsArray;
+} GPBEnumValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBEnumValue_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBEnumValue_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "number",
+        .number = GPBEnumValue_FieldNumber_Number,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeInt32,
+        .offset = offsetof(GPBEnumValue_Storage, number),
+        .defaultValue.valueInt32 = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "optionsArray",
+        .number = GPBEnumValue_FieldNumber_OptionsArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBEnumValue_Storage, optionsArray),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBOption),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBEnumValue class]
+                                              rootClass:[GPBTypeRoot class]
+                                                   file:GPBTypeRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBEnumValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBOption
+
+@implementation GPBOption
+
+@dynamic name;
+@dynamic hasValue, value;
+
+typedef struct GPBOption_Storage {
+  uint32_t _has_storage_[1];
+  NSString *name;
+  GPBAny *value;
+} GPBOption_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "name",
+        .number = GPBOption_FieldNumber_Name,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBOption_Storage, name),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "value",
+        .number = GPBOption_FieldNumber_Value,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeMessage,
+        .offset = offsetof(GPBOption_Storage, value),
+        .defaultValue.valueMessage = nil,
+        .typeSpecific.className = GPBStringifySymbol(GPBAny),
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBOption class]
+                                              rootClass:[GPBTypeRoot class]
+                                                   file:GPBTypeRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBOption_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
new file mode 100644
index 0000000..227d958
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -0,0 +1,154 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#import "GPBProtocolBuffers.h"
+
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
+#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#endif
+
+// @@protoc_insertion_point(imports)
+
+CF_EXTERN_C_BEGIN
+
+
+#pragma mark - GPBWrappersRoot
+
+@interface GPBWrappersRoot : GPBRootObject
+
+// The base class provides:
+//   + (GPBExtensionRegistry *)extensionRegistry;
+// which is an GPBExtensionRegistry that includes all the extensions defined by
+// this file and all files that it depends on.
+
+@end
+
+#pragma mark - GPBDoubleValue
+
+typedef GPB_ENUM(GPBDoubleValue_FieldNumber) {
+  GPBDoubleValue_FieldNumber_Value = 1,
+};
+
+// Wrapper message for double.
+@interface GPBDoubleValue : GPBMessage
+
+// The double value.
+@property(nonatomic, readwrite) double value;
+
+@end
+
+#pragma mark - GPBFloatValue
+
+typedef GPB_ENUM(GPBFloatValue_FieldNumber) {
+  GPBFloatValue_FieldNumber_Value = 1,
+};
+
+// Wrapper message for float.
+@interface GPBFloatValue : GPBMessage
+
+// The float value.
+@property(nonatomic, readwrite) float value;
+
+@end
+
+#pragma mark - GPBInt64Value
+
+typedef GPB_ENUM(GPBInt64Value_FieldNumber) {
+  GPBInt64Value_FieldNumber_Value = 1,
+};
+
+// Wrapper message for int64.
+@interface GPBInt64Value : GPBMessage
+
+// The int64 value.
+@property(nonatomic, readwrite) int64_t value;
+
+@end
+
+#pragma mark - GPBUInt64Value
+
+typedef GPB_ENUM(GPBUInt64Value_FieldNumber) {
+  GPBUInt64Value_FieldNumber_Value = 1,
+};
+
+// Wrapper message for uint64.
+@interface GPBUInt64Value : GPBMessage
+
+// The uint64 value.
+@property(nonatomic, readwrite) uint64_t value;
+
+@end
+
+#pragma mark - GPBInt32Value
+
+typedef GPB_ENUM(GPBInt32Value_FieldNumber) {
+  GPBInt32Value_FieldNumber_Value = 1,
+};
+
+// Wrapper message for int32.
+@interface GPBInt32Value : GPBMessage
+
+// The int32 value.
+@property(nonatomic, readwrite) int32_t value;
+
+@end
+
+#pragma mark - GPBUInt32Value
+
+typedef GPB_ENUM(GPBUInt32Value_FieldNumber) {
+  GPBUInt32Value_FieldNumber_Value = 1,
+};
+
+// Wrapper message for uint32.
+@interface GPBUInt32Value : GPBMessage
+
+// The uint32 value.
+@property(nonatomic, readwrite) uint32_t value;
+
+@end
+
+#pragma mark - GPBBoolValue
+
+typedef GPB_ENUM(GPBBoolValue_FieldNumber) {
+  GPBBoolValue_FieldNumber_Value = 1,
+};
+
+// Wrapper message for bool.
+@interface GPBBoolValue : GPBMessage
+
+// The bool value.
+@property(nonatomic, readwrite) BOOL value;
+
+@end
+
+#pragma mark - GPBStringValue
+
+typedef GPB_ENUM(GPBStringValue_FieldNumber) {
+  GPBStringValue_FieldNumber_Value = 1,
+};
+
+// Wrapper message for string.
+@interface GPBStringValue : GPBMessage
+
+// The string value.
+@property(nonatomic, readwrite, copy) NSString *value;
+
+@end
+
+#pragma mark - GPBBytesValue
+
+typedef GPB_ENUM(GPBBytesValue_FieldNumber) {
+  GPBBytesValue_FieldNumber_Value = 1,
+};
+
+// Wrapper message for bytes.
+@interface GPBBytesValue : GPBMessage
+
+// The bytes value.
+@property(nonatomic, readwrite, copy) NSData *value;
+
+@end
+
+CF_EXTERN_C_END
+
+// @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
new file mode 100644
index 0000000..6c34285
--- /dev/null
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -0,0 +1,458 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: google/protobuf/wrappers.proto
+
+#import "GPBProtocolBuffers_RuntimeSupport.h"
+#import "google/protobuf/Wrappers.pbobjc.h"
+// @@protoc_insertion_point(imports)
+
+#pragma mark - GPBWrappersRoot
+
+@implementation GPBWrappersRoot
+
+@end
+
+static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
+  // This is called by +initialize so there is no need to worry
+  // about thread safety of the singleton.
+  static GPBFileDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                     syntax:GPBFileSyntaxProto3];
+  }
+  return descriptor;
+}
+
+#pragma mark - GPBDoubleValue
+
+@implementation GPBDoubleValue
+
+@dynamic value;
+
+typedef struct GPBDoubleValue_Storage {
+  uint32_t _has_storage_[1];
+  double value;
+} GPBDoubleValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBDoubleValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeDouble,
+        .offset = offsetof(GPBDoubleValue_Storage, value),
+        .defaultValue.valueDouble = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBDoubleValue class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBDoubleValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBFloatValue
+
+@implementation GPBFloatValue
+
+@dynamic value;
+
+typedef struct GPBFloatValue_Storage {
+  uint32_t _has_storage_[1];
+  float value;
+} GPBFloatValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBFloatValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeFloat,
+        .offset = offsetof(GPBFloatValue_Storage, value),
+        .defaultValue.valueFloat = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBFloatValue class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBFloatValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBInt64Value
+
+@implementation GPBInt64Value
+
+@dynamic value;
+
+typedef struct GPBInt64Value_Storage {
+  uint32_t _has_storage_[1];
+  int64_t value;
+} GPBInt64Value_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeInt64,
+        .offset = offsetof(GPBInt64Value_Storage, value),
+        .defaultValue.valueInt64 = 0LL,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBInt64Value class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBInt64Value_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUInt64Value
+
+@implementation GPBUInt64Value
+
+@dynamic value;
+
+typedef struct GPBUInt64Value_Storage {
+  uint32_t _has_storage_[1];
+  uint64_t value;
+} GPBUInt64Value_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBUInt64Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeUInt64,
+        .offset = offsetof(GPBUInt64Value_Storage, value),
+        .defaultValue.valueUInt64 = 0ULL,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBUInt64Value class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBUInt64Value_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBInt32Value
+
+@implementation GPBInt32Value
+
+@dynamic value;
+
+typedef struct GPBInt32Value_Storage {
+  uint32_t _has_storage_[1];
+  int32_t value;
+} GPBInt32Value_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeInt32,
+        .offset = offsetof(GPBInt32Value_Storage, value),
+        .defaultValue.valueInt32 = 0,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBInt32Value class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBInt32Value_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBUInt32Value
+
+@implementation GPBUInt32Value
+
+@dynamic value;
+
+typedef struct GPBUInt32Value_Storage {
+  uint32_t _has_storage_[1];
+  uint32_t value;
+} GPBUInt32Value_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBUInt32Value_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeUInt32,
+        .offset = offsetof(GPBUInt32Value_Storage, value),
+        .defaultValue.valueUInt32 = 0U,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBUInt32Value class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBUInt32Value_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBBoolValue
+
+@implementation GPBBoolValue
+
+@dynamic value;
+
+typedef struct GPBBoolValue_Storage {
+  uint32_t _has_storage_[1];
+  BOOL value;
+} GPBBoolValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBBoolValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeBool,
+        .offset = offsetof(GPBBoolValue_Storage, value),
+        .defaultValue.valueBool = NO,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBBoolValue class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBBoolValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBStringValue
+
+@implementation GPBStringValue
+
+@dynamic value;
+
+typedef struct GPBStringValue_Storage {
+  uint32_t _has_storage_[1];
+  NSString *value;
+} GPBStringValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBStringValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeString,
+        .offset = offsetof(GPBStringValue_Storage, value),
+        .defaultValue.valueString = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBStringValue class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBStringValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBBytesValue
+
+@implementation GPBBytesValue
+
+@dynamic value;
+
+typedef struct GPBBytesValue_Storage {
+  uint32_t _has_storage_[1];
+  NSData *value;
+} GPBBytesValue_Storage;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = NULL;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "value",
+        .number = GPBBytesValue_FieldNumber_Value,
+        .hasIndex = 0,
+        .flags = GPBFieldOptional,
+        .type = GPBTypeData,
+        .offset = offsetof(GPBBytesValue_Storage, value),
+        .defaultValue.valueData = nil,
+        .typeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    descriptor = [GPBDescriptor allocDescriptorForClass:[GPBBytesValue class]
+                                              rootClass:[GPBWrappersRoot class]
+                                                   file:GPBWrappersRoot_FileDescriptor()
+                                                 fields:fields
+                                             fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                                 oneofs:NULL
+                                             oneofCount:0
+                                                  enums:NULL
+                                              enumCount:0
+                                                 ranges:NULL
+                                             rangeCount:0
+                                            storageSize:sizeof(GPBBytesValue_Storage)
+                                             wireFormat:NO];
+  }
+  return descriptor;
+}
+
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.h b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
index 2dc5547..0b41cf7 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.h
@@ -49,7 +49,7 @@
 
 class EnumGenerator {
  public:
-  EnumGenerator(const EnumDescriptor* descriptor);
+  explicit EnumGenerator(const EnumDescriptor* descriptor);
   ~EnumGenerator();
 
   void GenerateHeader(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
index 739282b..d660969 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -48,6 +48,13 @@
                       map<string, string>* variables) {
   string type = EnumName(descriptor->enum_type());
   (*variables)["storage_type"] = type;
+  // For non repeated fields, if it was defined in a different file, the
+  // property decls need to use "enum NAME" rather than just "NAME" to support
+  // the forward declaration of the enums.
+  if (!descriptor->is_repeated() &&
+      (descriptor->file() != descriptor->enum_type()->file())) {
+    (*variables)["property_type"] = "enum " + type;
+  }
   // TODO(thomasvl): Make inclusion of descriptor compile time and output
   // both of these. Note: Extensions currently have to have the EnumDescription.
   (*variables)["enum_verifier"] = type + "_IsValidValue";
@@ -76,7 +83,9 @@
 
 void EnumFieldGenerator::GenerateCFunctionDeclarations(
     io::Printer* printer) const {
-  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return;
+  if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+    return;
+  }
 
   printer->Print(
       variables_,
@@ -105,6 +114,18 @@
       "\n");
 }
 
+void EnumFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  // If it is an enum defined in a different file, then we'll need a forward
+  // declaration for it.  When it is in our file, all the enums are output
+  // before the message, so it will be declared before it is needed.
+  if (descriptor_->file() != descriptor_->enum_type()->file()) {
+    // Enum name is already in "storage_type".
+    const string& name = variable("storage_type");
+    fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")");
+  }
+}
+
 RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
     const FieldDescriptor* descriptor)
     : RepeatedFieldGenerator(descriptor) {
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
index 2d5822b..b629eae 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
@@ -47,9 +47,10 @@
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
   virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
   virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
 
  protected:
-  EnumFieldGenerator(const FieldDescriptor* descriptor);
+  explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~EnumFieldGenerator();
 
  private:
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
index 0574cca..76137c8 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -66,7 +66,7 @@
   }
   if (descriptor->is_map()) {
     // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
-    // error case, so it seem to be ok to use as a back door for errors.
+    // error cases, so it seems to be ok to use as a back door for errors.
     cerr << "error: Extension is a map<>!"
          << " That used to be blocked by the compiler." << endl;
     cerr.flush();
@@ -107,7 +107,7 @@
 
   std::vector<string> options;
   if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated");
-  if (descriptor_->options().packed()) options.push_back("GPBExtensionPacked");
+  if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked");
   if (descriptor_->containing_type()->options().message_set_wire_format())
     options.push_back("GPBExtensionSetWireFormat");
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.h b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
index d17f5be..553f088 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_extension.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.h
@@ -47,8 +47,8 @@
 
 class ExtensionGenerator {
  public:
-  explicit ExtensionGenerator(const string& root_class_name,
-                              const FieldDescriptor* descriptor);
+  ExtensionGenerator(const string& root_class_name,
+                     const FieldDescriptor* descriptor);
   ~ExtensionGenerator();
 
   void GenerateMembersHeader(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
index 93fffe0..ee5253a 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -80,7 +80,7 @@
   if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated");
   if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired");
   if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional");
-  if (descriptor->options().packed()) field_flags.push_back("GPBFieldPacked");
+  if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked");
 
   // ObjC custom flags.
   if (descriptor->has_default_value())
@@ -235,6 +235,11 @@
   // Nothing
 }
 
+void FieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  // Nothing
+}
+
 void FieldGenerator::GenerateFieldDescription(
     io::Printer* printer) const {
   printer->Print(
@@ -282,12 +287,16 @@
   if (descriptor_->containing_oneof() != NULL) {
     int index = descriptor_->containing_oneof()->index() + index_base;
     // Flip the sign to mark it as a oneof.
-    variables_["has_index"] = SimpleItoa(-index);;
+    variables_["has_index"] = SimpleItoa(-index);
   }
 }
 
 void FieldGenerator::FinishInitialization(void) {
-  // Nothing
+  // If "property_type" wasn't set, make it "storage_type".
+  if ((variables_.find("property_type") == variables_.end()) &&
+      (variables_.find("storage_type") != variables_.end())) {
+    variables_["property_type"] = variable("storage_type");
+  }
 }
 
 SingleFieldGenerator::SingleFieldGenerator(
@@ -313,7 +322,7 @@
   }
   printer->Print(
       variables_,
-      "@property(nonatomic, readwrite) $storage_type$ $name$;\n"
+      "@property(nonatomic, readwrite) $property_type$ $name$;\n"
       "\n");
 }
 
@@ -369,12 +378,12 @@
   }
   printer->Print(
       variables_,
-      "@property(nonatomic, readwrite, $property_storage_attribute$) $storage_type$ *$name$$storage_attribute$;\n");
+      "@property(nonatomic, readwrite, $property_storage_attribute$) $property_type$ *$name$$storage_attribute$;\n");
   if (IsInitName(variables_.at("name"))) {
     // If property name starts with init we need to annotate it to get past ARC.
     // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
     printer->Print(variables_,
-                   "- ($storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
+                   "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
   }
   printer->Print("\n");
 }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h
index c65e73b..130a52d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h
@@ -65,6 +65,8 @@
   virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
   virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
 
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
   void SetOneofIndexBase(int index_base);
 
   string variable(const char* key) const {
@@ -79,7 +81,7 @@
   string raw_field_name() const { return variable("raw_field_name"); }
 
  protected:
-  FieldGenerator(const FieldDescriptor* descriptor);
+  explicit FieldGenerator(const FieldDescriptor* descriptor);
 
   virtual void FinishInitialization(void);
   virtual bool WantsHasProperty(void) const = 0;
@@ -101,7 +103,7 @@
   virtual void GeneratePropertyImplementation(io::Printer* printer) const;
 
  protected:
-  SingleFieldGenerator(const FieldDescriptor* descriptor);
+  explicit SingleFieldGenerator(const FieldDescriptor* descriptor);
   virtual bool WantsHasProperty(void) const;
 
  private:
@@ -117,7 +119,7 @@
   virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
 
  protected:
-  ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
+  explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator);
@@ -133,7 +135,7 @@
   virtual void GeneratePropertyImplementation(io::Printer* printer) const;
 
  protected:
-  RepeatedFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor);
   virtual void FinishInitialization(void);
   virtual bool WantsHasProperty(void) const;
 
@@ -144,7 +146,7 @@
 // Convenience class which constructs FieldGenerators for a Descriptor.
 class FieldGeneratorMap {
  public:
-  FieldGeneratorMap(const Descriptor* descriptor);
+  explicit FieldGeneratorMap(const Descriptor* descriptor);
   ~FieldGeneratorMap();
 
   const FieldGenerator& get(const FieldDescriptor* field) const;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index b3ad448..d04eee8 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -50,11 +50,17 @@
 
 namespace compiler {
 namespace objectivec {
+
 FileGenerator::FileGenerator(const FileDescriptor *file)
     : file_(file),
       root_class_name_(FileClassName(file)),
       is_filtered_(true),
-      all_extensions_filtered_(true) {
+      all_extensions_filtered_(true),
+      is_public_dep_(false) {
+  // Validate the objc prefix, do this even if the file's contents are filtered
+  // to catch a bad prefix as soon as it is found.
+  ValidateObjCClassPrefix(file_);
+
   for (int i = 0; i < file_->enum_type_count(); i++) {
     EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
     // The enums are exposed via C functions, so they will dead strip if
@@ -96,7 +102,9 @@
       "\n",
       "filename", file_->name());
 
-  printer->Print("#import \"GPBProtocolBuffers.h\"\n\n");
+  printer->Print(
+      "#import \"GPBProtocolBuffers.h\"\n"
+      "\n");
 
   // Add some verification that the generated code matches the source the
   // code is being compiled with.
@@ -108,31 +116,34 @@
       "protoc_gen_objc_version",
       SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
 
-  if (!IsFiltered()) {
-    const vector<FileGenerator *> &dependency_generators =
-        DependencyGenerators();
-    if (dependency_generators.size() > 0) {
-      for (vector<FileGenerator *>::const_iterator iter =
-               dependency_generators.begin();
-           iter != dependency_generators.end(); ++iter) {
-        printer->Print("#import \"$header$.pbobjc.h\"\n",
-                       "header", (*iter)->Path());
-      }
-      printer->Print("\n");
+  const vector<FileGenerator *> &dependency_generators =
+      DependencyGenerators();
+  for (vector<FileGenerator *>::const_iterator iter =
+           dependency_generators.begin();
+       iter != dependency_generators.end(); ++iter) {
+    if ((*iter)->IsPublicDependency()) {
+      printer->Print("#import \"$header$.pbobjc.h\"\n",
+                     "header", (*iter)->Path());
     }
   }
 
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n");
+
   printer->Print("CF_EXTERN_C_BEGIN\n\n");
 
   if (!IsFiltered()) {
-    set<string> dependencies;
-    DetermineDependencies(&dependencies);
-    for (set<string>::const_iterator i(dependencies.begin());
-         i != dependencies.end(); ++i) {
+    set<string> fwd_decls;
+    for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
+         iter != message_generators_.end(); ++iter) {
+      (*iter)->DetermineForwardDeclarations(&fwd_decls);
+    }
+    for (set<string>::const_iterator i(fwd_decls.begin());
+         i != fwd_decls.end(); ++i) {
       printer->Print("$value$;\n", "value", *i);
     }
-
-    if (dependencies.begin() != dependencies.end()) {
+    if (fwd_decls.begin() != fwd_decls.end()) {
       printer->Print("\n");
     }
   }
@@ -156,7 +167,14 @@
         "#pragma mark - $root_class_name$\n"
         "\n"
         "@interface $root_class_name$ : GPBRootObject\n"
-        "@end\n\n",
+        "\n"
+        "// The base class provides:\n"
+        "//   + (GPBExtensionRegistry *)extensionRegistry;\n"
+        "// which is an GPBExtensionRegistry that includes all the extensions defined by\n"
+        "// this file and all files that it depends on.\n"
+        "\n"
+        "@end\n"
+        "\n",
         "root_class_name", root_class_name_);
   }
 
@@ -189,33 +207,10 @@
   }
 
   printer->Print("CF_EXTERN_C_END\n");
-}
 
-void DetermineDependenciesWorker(set<string> *dependencies,
-                                 set<string> *seen_files,
-                                 const string &classname,
-                                 const FileDescriptor *file) {
-  if (seen_files->find(file->name()) != seen_files->end()) {
-    // don't infinitely recurse
-    return;
-  }
-
-  seen_files->insert(file->name());
-
-  for (int i = 0; i < file->dependency_count(); i++) {
-    DetermineDependenciesWorker(dependencies, seen_files, classname,
-                                file->dependency(i));
-  }
-  for (int i = 0; i < file->message_type_count(); i++) {
-    MessageGenerator(classname, file->message_type(i))
-        .DetermineDependencies(dependencies);
-  }
-}
-
-void FileGenerator::DetermineDependencies(set<string> *dependencies) {
-  set<string> seen_files;
-  DetermineDependenciesWorker(dependencies, &seen_files, root_class_name_,
-                              file_);
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n");
 }
 
 void FileGenerator::GenerateSource(io::Printer *printer) {
@@ -225,6 +220,25 @@
       "\n",
       "filename", file_->name());
 
+  string header_file = Path() + ".pbobjc.h";
+  printer->Print(
+      "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n"
+      "#import \"$header_file$\"\n",
+      "header_file", header_file);
+  const vector<FileGenerator *> &dependency_generators =
+      DependencyGenerators();
+  for (vector<FileGenerator *>::const_iterator iter =
+           dependency_generators.begin();
+       iter != dependency_generators.end(); ++iter) {
+    if (!(*iter)->IsPublicDependency()) {
+      printer->Print("#import \"$header$.pbobjc.h\"\n",
+                     "header", (*iter)->Path());
+    }
+  }
+  printer->Print(
+      "// @@protoc_insertion_point(imports)\n"
+      "\n");
+
   if (IsFiltered()) {
     printer->Print(
         "// File empty because all messages, extensions and enum have been filtered.\n"
@@ -232,22 +246,17 @@
         "\n"
         "// Dummy symbol that will be stripped but will avoid linker warnings about\n"
         "// no symbols in the .o form compiling this file.\n"
-        "static int $root_class_name$_dummy __attribute__((unused,used)) = 0;\n",
+        "static int $root_class_name$_dummy __attribute__((unused,used)) = 0;\n"
+        "\n"
+        "// @@protoc_insertion_point(global_scope)\n",
         "root_class_name", root_class_name_);
     return;
   }
 
-  printer->Print("#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n\n");
-
-  string header_file = Path() + ".pbobjc.h";
-
   printer->Print(
-      "#import \"$header_file$\"\n"
-      "\n"
       "#pragma mark - $root_class_name$\n"
       "\n"
       "@implementation $root_class_name$\n\n",
-      "header_file", header_file,
       "root_class_name", root_class_name_);
 
   bool generated_extensions = false;
@@ -326,12 +335,7 @@
           "  }\n"
           "  return registry;\n"
           "}\n"
-          "\n"
-          "+ (void)load {\n"
-          "  @autoreleasepool {\n"
-          "    [self extensionRegistry]; // Construct extension registry.\n"
-          "  }\n"
-          "}\n\n");
+          "\n");
     }
   }
 
@@ -374,19 +378,31 @@
        iter != message_generators_.end(); ++iter) {
     (*iter)->GenerateSource(printer);
   }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(global_scope)\n");
 }
 
 const string FileGenerator::Path() const { return FilePath(file_); }
 
 const vector<FileGenerator *> &FileGenerator::DependencyGenerators() {
   if (file_->dependency_count() != dependency_generators_.size()) {
+    set<string> public_import_names;
+    for (int i = 0; i < file_->public_dependency_count(); i++) {
+      public_import_names.insert(file_->public_dependency(i)->name());
+    }
     for (int i = 0; i < file_->dependency_count(); i++) {
       FileGenerator *generator = new FileGenerator(file_->dependency(i));
+      const string& name = file_->dependency(i)->name();
+      bool public_import = (public_import_names.count(name) != 0);
+      generator->SetIsPublicDependency(public_import);
       dependency_generators_.push_back(generator);
     }
   }
   return dependency_generators_;
 }
+
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
index fbd08ea..95d17bf 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -66,6 +66,12 @@
 
   bool IsFiltered() const { return is_filtered_; }
   bool AreAllExtensionsFiltered() const { return all_extensions_filtered_; }
+  bool IsPublicDependency() const { return is_public_dep_; }
+
+ protected:
+  void SetIsPublicDependency(bool is_public_dep) {
+    is_public_dep_ = is_public_dep;
+  }
 
  private:
   const FileDescriptor* file_;
@@ -80,15 +86,16 @@
   vector<ExtensionGenerator*> extension_generators_;
   bool is_filtered_;
   bool all_extensions_filtered_;
-
-  void DetermineDependencies(set<string>* dependencies);
+  bool is_public_dep_;
 
   const vector<FileGenerator*>& DependencyGenerators();
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
 };
+
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace google
+
 #endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index d4675f0..6d6e595 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -41,7 +41,7 @@
 #include <google/protobuf/stubs/strutil.h>
 
 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
-// error case, so it seem to be ok to use as a back door for errors.
+// error cases, so it seems to be ok to use as a back door for errors.
 
 namespace google {
 namespace protobuf {
@@ -53,6 +53,11 @@
 hash_set<string> gClassWhitelist;
 
 // islower()/isupper()/tolower()/toupper() change based on locale.
+//
+// src/google/protobuf/stubs/strutil.h:150 has the same pattern. For the
+// Objective C plugin, test failures were seen on TravisCI because isupper('A')
+// was coming back false for some server's locale.  This approach avoids any
+// such issues.
 
 bool IsLower(const char c) {
   return ('a' <= c && c <= 'z');
@@ -205,10 +210,9 @@
     // Only need to add instance methods that may conflict with
     // method declared in protos. The main cases are methods
     // that take no arguments, or setFoo:/hasFoo: type methods.
-    // These are currently in the same order as in GPBMessage.h.
-    "unknownFields", "extensionRegistry", "isInitialized",
-    "data", "delimitedData", "serializedSize",
-    "descriptor", "extensionsCurrentlySet", "clear", "sortedExtensionsInUse",
+    "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
+    "extensionsCurrentlySet", "isInitialized", "serializedSize",
+    "sortedExtensionsInUse", "unknownFields",
 
     // MacTypes.h names
     "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
@@ -335,7 +339,32 @@
 
 string FileClassPrefix(const FileDescriptor* file) {
   // Default is empty string, no need to check has_objc_class_prefix.
-  return file->options().objc_class_prefix();
+  string result = file->options().objc_class_prefix();
+  return result;
+}
+
+void ValidateObjCClassPrefix(const FileDescriptor* file) {
+  string prefix = file->options().objc_class_prefix();
+  if (prefix.length() > 0) {
+    // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
+    // error cases, so it seems to be ok to use as a back door for errors.
+    if (!IsUpper(prefix[0])) {
+      cerr << endl
+           << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+           << prefix << "\";' in '" << file->name() << "';"
+           << " it should start with a capital letter."
+           << endl;
+      cerr.flush();
+    }
+    if (prefix.length() < 3) {
+      cerr << endl
+           << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+           << prefix << "\";' in '" << file->name() << "';"
+           << " Apple recommends they should be at least 3 characters long."
+           << endl;
+      cerr.flush();
+    }
+  }
 }
 
 string FileClassName(const FileDescriptor* file) {
@@ -468,7 +497,7 @@
   const Descriptor* fieldDescriptor = descriptor->containing_type();
   string name = ClassName(fieldDescriptor);
   name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase";
-  // No sanitize needed because it the OS never has names that end in OneOfCase.
+  // No sanitize needed because the OS never has names that end in _OneOfCase.
   return name;
 }
 
@@ -560,6 +589,8 @@
       return "Message";
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
@@ -607,6 +638,8 @@
       return OBJECTIVECTYPE_MESSAGE;
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return OBJECTIVECTYPE_INT32;
 }
@@ -683,6 +716,8 @@
       return "valueMessage";
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
@@ -753,6 +788,8 @@
       return "nil";
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index ab030d1..2916893 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -62,6 +62,9 @@
 // declared in the proto package.
 string FilePath(const FileDescriptor* file);
 
+// Checks the prefix for a given file and outputs any warnings/errors needed.
+void ValidateObjCClassPrefix(const FileDescriptor* file);
+
 // Gets the name of the root class we'll generate in the file.  This class
 // is not meant for external consumption, but instead contains helpers that
 // the rest of the the classes need
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
index cafdf39..2987f3d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -76,6 +76,8 @@
       return "Object";
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
index 8862dc3..173541f 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -48,7 +48,7 @@
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
 
  protected:
-  MapFieldGenerator(const FieldDescriptor* descriptor);
+  explicit MapFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~MapFieldGenerator();
 
  private:
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index f6a5852..52e583b 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -120,6 +120,8 @@
       return 1;
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return 0;
 }
@@ -188,7 +190,7 @@
       extension_generators_.push_back(
           new ExtensionGenerator(class_name_, descriptor_->extension(i)));
     }
-    // No need to oneofs if this message is filtered
+    // No need to generate oneofs if this message is filtered.
     for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
       OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
       oneof_generators_.push_back(generator);
@@ -253,15 +255,24 @@
   }
 }
 
-void MessageGenerator::DetermineDependencies(set<string>* dependencies) {
+void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) {
   if (!IsFiltered() && !IsMapEntryMessage(descriptor_)) {
-    dependencies->insert("@class " + class_name_);
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+      // If it is a the field is repeated, the type will be and *Array,
+      // and we don't need any forward decl.
+      if (fieldDescriptor->is_repeated()) {
+        continue;
+      }
+      field_generators_.get(fieldDescriptor)
+          .DetermineForwardDeclarations(fwd_decls);
+    }
   }
 
   for (vector<MessageGenerator*>::iterator iter =
            nested_message_generators_.begin();
        iter != nested_message_generators_.end(); ++iter) {
-    (*iter)->DetermineDependencies(dependencies);
+    (*iter)->DetermineForwardDeclarations(fwd_decls);
   }
 }
 
@@ -361,13 +372,13 @@
         "classname", class_name_,
         "comments", message_comments);
 
-    vector<bool> seen_oneofs(descriptor_->oneof_decl_count(), false);
+    vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* field = descriptor_->field(i);
       if (field->containing_oneof() != NULL) {
         const int oneof_index = field->containing_oneof()->index();
         if (!seen_oneofs[oneof_index]) {
-          seen_oneofs[oneof_index] = true;
+          seen_oneofs[oneof_index] = 1;
           oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
               printer);
         }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h
index 5992d0c..8d03c0b 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -63,7 +63,7 @@
   void GenerateMessageHeader(io::Printer* printer);
   void GenerateSource(io::Printer* printer);
   void GenerateExtensionRegistrationSource(io::Printer* printer);
-  void DetermineDependencies(set<string>* dependencies);
+  void DetermineForwardDeclarations(set<string>* fwd_decls);
 
   // This only speaks for this message, not sub message/enums.
   bool IsFiltered() const { return filter_reason_.length() > 0; }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
index 9c4a4e4..2e3bdfd 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -65,6 +65,12 @@
 
 MessageFieldGenerator::~MessageFieldGenerator() {}
 
+void MessageFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  // Class name is already in "storage_type".
+  fwd_decls->insert("@class " + variable("storage_type"));
+}
+
 bool MessageFieldGenerator::WantsHasProperty(void) const {
   if (descriptor_->containing_oneof() != NULL) {
     // If in a oneof, it uses the oneofcase instead of a has bit.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
index a1ac2d3..708ea56 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
@@ -44,10 +44,13 @@
   friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
 
  protected:
-  MessageFieldGenerator(const FieldDescriptor* descriptor);
+  explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~MessageFieldGenerator();
   virtual bool WantsHasProperty(void) const;
 
+ public:
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
 };
@@ -56,7 +59,7 @@
   friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
 
  protected:
-  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~RepeatedMessageFieldGenerator();
 
  private:
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
index 77b7f80..bcba82d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
@@ -49,7 +49,7 @@
 
 class OneofGenerator {
  public:
-  OneofGenerator(const OneofDescriptor* descriptor);
+  explicit OneofGenerator(const OneofDescriptor* descriptor);
   ~OneofGenerator();
 
   void SetOneofIndexBase(int index_base);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
index 54f9428..c185b66 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
@@ -77,6 +77,8 @@
       return NULL;
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
@@ -108,6 +110,8 @@
       return "";  // Want NSArray
   }
 
+  // Some compilers report reaching end of function even though all cases of
+  // the enum are handed in the switch.
   GOOGLE_LOG(FATAL) << "Can't get here.";
   return NULL;
 }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
index b359929..9bb7934 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
@@ -44,7 +44,7 @@
   friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
 
  protected:
-  PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~PrimitiveFieldGenerator();
 
  private:
@@ -55,7 +55,7 @@
   friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
 
  protected:
-  PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
+  explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~PrimitiveObjFieldGenerator();
 
  private:
@@ -66,7 +66,7 @@
   friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
 
  protected:
-  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
   virtual ~RepeatedPrimitiveFieldGenerator();
   virtual void FinishInitialization(void);