Merge pull request #1765 from mbarbon/master

Add https://metacpan.org/pod/Google::ProtocolBuffers::Dynamic
diff --git a/.gitignore b/.gitignore
index 5cb8cba..052dd14 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,8 @@
 src/unittest_proto_middleman
 
 # Generated test scaffolding
+src/no_warning_test.cc
+src/no-warning-test
 src/protobuf*-test
 src/test_plugin
 src/testzip.*
@@ -108,8 +110,11 @@
 conformance/conformance.pb.h
 conformance/Conformance.pbobjc.h
 conformance/Conformance.pbobjc.m
-conformance/conformance.rb
+conformance/conformance_pb.rb
+conformance/failing_tests.txt
 conformance/google/
 conformance/javac_middleman
 conformance/lite/
+conformance/nonexistent_tests.txt
 conformance/protoc_middleman
+conformance/succeeding_tests.txt
diff --git a/.travis.yml b/.travis.yml
index 46abbb9..094235e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,6 @@
 # rvm/gemfile/jdk/etc. entries rather than manually doing the work.
 language: cpp
 os:
-  - linux
   - osx
 # The Objective C build needs Xcode 7.0 or later.
 osx_image: xcode7.3
@@ -14,12 +13,9 @@
 env:
   - CONFIG=cpp
   - CONFIG=cpp_distcheck
-  - CONFIG=csharp
   - CONFIG=golang
-  - CONFIG=java_jdk6
   - CONFIG=java_jdk7
   - CONFIG=java_oracle7
-  - CONFIG=javanano_jdk6
   - CONFIG=javanano_jdk7
   - CONFIG=javanano_oracle7
   - CONFIG=javascript
@@ -31,8 +27,6 @@
   - CONFIG=objectivec_cocoapods_integration
   - CONFIG=python
   - CONFIG=python_cpp
-  - CONFIG=ruby19
-  - CONFIG=ruby20
   - CONFIG=ruby21
   - CONFIG=ruby22
   - CONFIG=jruby
@@ -41,35 +35,32 @@
     # It's nontrivial to programmatically install a new JDK from the command
     # line on OS X, so we rely on testing on Linux for Java code.
     - os: osx
-      env: CONFIG=java_jdk6
-    - os: osx
       env: CONFIG=java_jdk7
     - os: osx
       env: CONFIG=java_oracle7
     - os: osx
-      env: CONFIG=javanano_jdk6
-    - os: osx
       env: CONFIG=javanano_jdk7
     - os: osx
       env: CONFIG=javanano_oracle7
-    # Requires installing mono, currently travis.sh is doing that with apt-get
-    # which doesn't work on OS X.
-    - os: osx
-      env: CONFIG=csharp
     # Requires installing golang, currently travis.sh is doing that with apt-get
     # which doesn't work on OS X.
     - os: osx
       env: CONFIG=golang
-    # OS X/iOS tests of Objective C (needs Xcode, so it won't work on other
-    # platforms).
+  include:
+    # The dotnet environment requires Ubuntu 14.04 or 16.04. This
+    # configuration is effectively an "extra" one, outside the
+    # autogenerated matrix.
     - os: linux
-      env: CONFIG=objectivec_ios_debug
+      env: CONFIG=csharp
+      dist: trusty
+    # This test is kept on travis because it doesn't play nicely with other
+    # tests on jenkins running in parallel.
     - os: linux
-      env: CONFIG=objectivec_ios_release
+      env: CONFIG=cpp_distcheck
+    # The Java compatibility test currently only runs on Linux because it will
+    # fetch pre-built Linux protoc binaries in the test.
     - os: linux
-      env: CONFIG=objectivec_osx
-    - os: linux
-      env: CONFIG=objectivec_cocoapods_integration
+      env: CONFIG=java_compatibility
   allow_failures:
     # These currently do not work on OS X but are being worked on by @haberman.
     - os: osx
diff --git a/BUILD b/BUILD
index 0941d8c..941ca69 100644
--- a/BUILD
+++ b/BUILD
@@ -2,6 +2,8 @@
 
 licenses(["notice"])
 
+exports_files(["LICENSE"])
+
 ################################################################################
 # Protobuf Runtime Library
 ################################################################################
diff --git a/CHANGES.txt b/CHANGES.txt
index 3459ccc..822136c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,135 @@
+2016-07-27 version 3.0.0 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript/Lite)
+  General
+  * This log only contains changes since the beta-4 release. Summarized change
+    log since the last stable release (v2.6.1) can be found in the github
+    release page.
+
+  Compatibility Notice
+  * v3.0.0 is the first API stable release of the v3.x series. We do not expect
+    any future API breaking changes.
+  * For C++, Java Lite and Objective-C, source level compatibility is
+    guaranteed.  Upgrading from v3.0.0 to newer minor version releases will be
+    source compatible. For example, if your code compiles against protobuf
+    v3.0.0, it will continue to compile after you upgrade protobuf library to
+    v3.1.0.
+  * For other languages, both source level compatibility and binary level
+    compatibility are guaranteed. For example, if you have a Java binary built
+    against protobuf v3.0.0. After switching the protobuf runtime binary to
+    v3.1.0, your built binary should continue to work.
+  * Compatibility is only guaranteed for documented API and documented
+    behaviors. If you are using undocumented API (e.g., use anything in the C++
+    internal namespace), it can be broken by minor version releases in an
+    undetermined manner.
+
+  Ruby
+  * When you assign a string field `a.string_field = "X"`, we now call
+    #encode(UTF-8) on the string and freeze the copy. This saves you from
+    needing to ensure the string is already encoded as UTF-8. It also prevents
+    you from mutating the string after it has been assigned (this is how we
+    ensure it stays valid UTF-8).
+  * The generated file for `foo.proto` is now `foo_pb.rb` instead of just
+    `foo.rb`. This makes it easier to see which imports/requires are from
+    protobuf generated code, and also prevents conflicts with any `foo.rb` file
+    you might have written directly in Ruby. It is a backward-incompatible
+    change: you will need to update all of your `require` statements.
+  * For package names like `foo_bar`, we now translate this to the Ruby module
+    `FooBar`. This is more idiomatic Ruby than what we used to do (`Foo_bar`).
+
+  JavaScript
+  * Scalar fields like numbers and boolean now return defaults instead of
+    `undefined` or `null` when they are unset. You can test for presence
+    explicitly by calling `hasFoo()`, which we now generate for scalar fields.
+
+  Java Lite
+  * Java Lite is now implemented as a separate plugin, maintained in the
+    `javalite` branch. Both lite runtime and protoc artifacts will be available
+    in Maven.
+
+  C#
+  * Target platforms now .NET 4.5, selected portable subsets and .NET Core.
+  * legacy_enum_values option is no longer supported.
+
+2016-07-15 version 3.0.0-beta-4 (C++/Java/Python/Ruby/Objective-C/C#/JavaScript)
+  General
+  * Added a deterministic serialization API for C++. The deterministic
+    serialization guarantees that given a binary, equal messages will be
+    serialized to the same bytes. This allows applications like MapReduce to
+    group equal messages based on the serialized bytes. The deterministic
+    serialization is, however, NOT canonical across languages; it is also
+    unstable across different builds with schema changes due to unknown fields.
+    Users who need canonical serialization, e.g. persistent storage in a
+    canonical form, fingerprinting, etc, should define their own
+    canonicalization specification and implement the serializer using reflection
+    APIs rather than relying on this API.
+  * Added OneofOptions. You can now define custom options for oneof groups.
+      import "google/protobuf/descriptor.proto";
+      extend google.protobuf.OneofOptions {
+        optional int32 my_oneof_extension = 12345;
+      }
+      message Foo {
+        oneof oneof_group {
+          (my_oneof_extension) = 54321;
+          ...
+        }
+      }
+
+  C++ (beta)
+  * Introduced a deterministic serialization API in
+    CodedOutputStream::SetSerializationDeterministic(bool). See the notes about
+    deterministic serialization in the General section.
+  * Added google::protobuf::Map::swap() to swap two map fields.
+  * Fixed a memory leak when calling Reflection::ReleaseMessage() on a message
+    allocated on arena.
+  * Improved error reporting when parsing text format protos.
+  * JSON
+      - Added a new parser option to ignore unknown fields when parsing JSON.
+      - Added convenient methods for message to/from JSON conversion.
+  * Various performance optimizations.
+
+  Java (beta)
+  * File option "java_generate_equals_and_hash" is now deprecated. equals() and
+    hashCode() methods are generated by default.
+  * Added a new JSON printer option "omittingInsignificantWhitespace" to produce
+    a more compact JSON output. The printer will pretty-print by default.
+  * Updated Java runtime to be compatible with 2.5.0/2.6.1 generated protos.
+
+  Python (beta)
+  * Added support to pretty print Any messages in text format.
+  * Added a flag to ignore unknown fields when parsing JSON.
+  * Bugfix: "@type" field of a JSON Any message is now correctly put before
+    other fields.
+
+  Objective-C (beta)
+  * Updated the code to support compiling with more compiler warnings
+    enabled. (Issue 1616)
+  * Exposing more detailed errors for parsing failures. (PR 1623)
+  * Small (breaking) change to the naming of some methods on the support classes
+    for map<>. There were collisions with the system provided KVO support, so
+    the names were changed to avoid those issues.  (PR 1699)
+  * Fixed for proper Swift bridging of error handling during parsing. (PR 1712)
+  * Complete support for generating sources that will go into a Framework and
+    depend on generated sources from other Frameworks. (Issue 1457)
+
+  C# (beta)
+  * RepeatedField optimizations.
+  * Support for .NET Core.
+  * Minor bug fixes.
+  * Ability to format a single value in JsonFormatter (advanced usage only).
+  * Modifications to attributes applied to generated code.
+
+  Javascript (alpha)
+  * Maps now have a real map API instead of being treated as repeated fields.
+  * Well-known types are now provided in the google-protobuf package, and the
+    code generator knows to require() them from that package.
+  * Bugfix: non-canonical varints are correctly decoded.
+
+  Ruby (alpha)
+  * Accessors for oneof fields now return default values instead of nil.
+
+  Java Lite
+  * Java lite support is removed from protocol compiler. It will be supported
+    as a protocol compiler plugin in a separate code branch.
+
 2016-05-16 version 3.0.0-beta-3 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
   General
   * Supported Proto3 lite-runtime in C++/Java for mobile platforms.
diff --git a/Makefile.am b/Makefile.am
index 1443b75..a4de1bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,30 +51,29 @@
 csharp_EXTRA_DIST=                                                           \
   csharp/.gitignore                                                          \
   csharp/CHANGES.txt                                                         \
+  csharp/Google.Protobuf.Tools.nuspec                                        \
   csharp/README.md                                                           \
   csharp/build_packages.bat                                                  \
   csharp/buildall.sh                                                         \
   csharp/generate_protos.sh                                                  \
   csharp/keys/Google.Protobuf.public.snk                                     \
+  csharp/keys/Google.Protobuf.snk                                            \
   csharp/keys/README.md                                                      \
   csharp/protos/unittest_issues.proto                                        \
   csharp/src/AddressBook/AddPerson.cs                                        \
-  csharp/src/AddressBook/AddressBook.csproj                                  \
   csharp/src/AddressBook/Addressbook.cs                                      \
+  csharp/src/AddressBook/AddressBook.xproj                                   \
   csharp/src/AddressBook/ListPeople.cs                                       \
   csharp/src/AddressBook/Program.cs                                          \
-  csharp/src/AddressBook/Properties/AssemblyInfo.cs                          \
   csharp/src/AddressBook/SampleUsage.cs                                      \
-  csharp/src/AddressBook/app.config                                          \
-  csharp/src/Google.Protobuf.Conformance/App.config                          \
+  csharp/src/AddressBook/project.json                                        \
   csharp/src/Google.Protobuf.Conformance/Conformance.cs                      \
-  csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj  \
+  csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.xproj   \
   csharp/src/Google.Protobuf.Conformance/Program.cs                          \
-  csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs          \
-  csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj        \
+  csharp/src/Google.Protobuf.Conformance/project.json                        \
+  csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.xproj         \
   csharp/src/Google.Protobuf.JsonDump/Program.cs                             \
-  csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs             \
-  csharp/src/Google.Protobuf.JsonDump/app.config                             \
+  csharp/src/Google.Protobuf.JsonDump/project.json                           \
   csharp/src/Google.Protobuf.Test/ByteStringTest.cs                          \
   csharp/src/Google.Protobuf.Test/CodedInputStreamExtensions.cs              \
   csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs                    \
@@ -87,19 +86,18 @@
   csharp/src/Google.Protobuf.Test/EqualityTester.cs                          \
   csharp/src/Google.Protobuf.Test/FieldCodecTest.cs                          \
   csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs                    \
-  csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj                \
+  csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.xproj                 \
   csharp/src/Google.Protobuf.Test/IssuesTest.cs                              \
   csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs                       \
   csharp/src/Google.Protobuf.Test/JsonParserTest.cs                          \
   csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs                       \
-  csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml                 \
-  csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs                 \
   csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs              \
   csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs              \
   csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs             \
   csharp/src/Google.Protobuf.Test/SampleEnum.cs                              \
   csharp/src/Google.Protobuf.Test/SampleMessages.cs                          \
   csharp/src/Google.Protobuf.Test/TestCornerCases.cs                         \
+  csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs        \
   csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs            \
   csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs         \
   csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs   \
@@ -108,9 +106,10 @@
   csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs       \
   csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs                  \
   csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs             \
+  csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs            \
   csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs            \
   csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs             \
-  csharp/src/Google.Protobuf.Test/packages.config                            \
+  csharp/src/Google.Protobuf.Test/project.json                               \
   csharp/src/Google.Protobuf.sln                                             \
   csharp/src/Google.Protobuf/ByteArray.cs                                    \
   csharp/src/Google.Protobuf/ByteString.cs                                   \
@@ -124,8 +123,8 @@
   csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs                 \
   csharp/src/Google.Protobuf/FieldCodec.cs                                   \
   csharp/src/Google.Protobuf/FrameworkPortability.cs                         \
-  csharp/src/Google.Protobuf/Google.Protobuf.csproj                          \
-  csharp/src/Google.Protobuf/Google.Protobuf.nuspec                          \
+  csharp/src/Google.Protobuf/Google.Protobuf.xproj                           \
+  csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs                     \
   csharp/src/Google.Protobuf/IDeepCloneable.cs                               \
   csharp/src/Google.Protobuf/IMessage.cs                                     \
   csharp/src/Google.Protobuf/InvalidJsonException.cs                         \
@@ -173,6 +172,7 @@
   csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs               \
   csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs                         \
   csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs                     \
+  csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs              \
   csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs                 \
   csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs                        \
   csharp/src/Google.Protobuf/WellKnownTypes/TimeExtensions.cs                \
@@ -183,7 +183,7 @@
   csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs                      \
   csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs               \
   csharp/src/Google.Protobuf/WireFormat.cs                                   \
-  csharp/src/Google.Protobuf/packages.config                                 \
+  csharp/src/Google.Protobuf/project.json                                    \
   csharp/src/packages/repositories.config
 
 java_EXTRA_DIST=                                                                   \
@@ -206,6 +206,7 @@
   java/core/src/main/java/com/google/protobuf/Descriptors.java                     \
   java/core/src/main/java/com/google/protobuf/DoubleArrayList.java                 \
   java/core/src/main/java/com/google/protobuf/DynamicMessage.java                  \
+  java/core/src/main/java/com/google/protobuf/ExperimentalApi.java                 \
   java/core/src/main/java/com/google/protobuf/Extension.java                       \
   java/core/src/main/java/com/google/protobuf/ExtensionLite.java                   \
   java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java               \
@@ -215,6 +216,7 @@
   java/core/src/main/java/com/google/protobuf/FloatArrayList.java                  \
   java/core/src/main/java/com/google/protobuf/GeneratedMessage.java                \
   java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java            \
+  java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java              \
   java/core/src/main/java/com/google/protobuf/IntArrayList.java                    \
   java/core/src/main/java/com/google/protobuf/Internal.java                        \
   java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java  \
@@ -240,6 +242,7 @@
   java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java             \
   java/core/src/main/java/com/google/protobuf/ProtocolStringList.java              \
   java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java          \
   java/core/src/main/java/com/google/protobuf/RopeByteString.java                  \
   java/core/src/main/java/com/google/protobuf/RpcCallback.java                     \
   java/core/src/main/java/com/google/protobuf/RpcChannel.java                      \
@@ -248,6 +251,7 @@
   java/core/src/main/java/com/google/protobuf/Service.java                         \
   java/core/src/main/java/com/google/protobuf/ServiceException.java                \
   java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java              \
+  java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java            \
   java/core/src/main/java/com/google/protobuf/SmallSortedMap.java                  \
   java/core/src/main/java/com/google/protobuf/TextFormat.java                      \
   java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java               \
@@ -258,6 +262,7 @@
   java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java             \
   java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java      \
   java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java            \
+  java/core/src/main/java/com/google/protobuf/UnsafeUtil.java                      \
   java/core/src/main/java/com/google/protobuf/Utf8.java                            \
   java/core/src/main/java/com/google/protobuf/WireFormat.java                      \
   java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java             \
@@ -297,16 +302,18 @@
   java/core/src/test/java/com/google/protobuf/MessageTest.java                     \
   java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java              \
   java/core/src/test/java/com/google/protobuf/NioByteStringTest.java               \
+  java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java             \
   java/core/src/test/java/com/google/protobuf/ParserTest.java                      \
   java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java           \
-  java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java        \
+  java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java      \
   java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java     \
   java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java              \
   java/core/src/test/java/com/google/protobuf/ServiceTest.java                     \
-  java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java          \
+  java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java        \
   java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java              \
   java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java              \
   java/core/src/test/java/com/google/protobuf/TestUtil.java                        \
+  java/core/src/test/java/com/google/protobuf/TestUtilLite.java                    \
   java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java     \
   java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java     \
   java/core/src/test/java/com/google/protobuf/TextFormatTest.java                  \
@@ -338,13 +345,17 @@
   java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto          \
   java/core/src/test/proto/com/google/protobuf/test_custom_options.proto           \
   java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto         \
+  java/lite/generate-sources-build.xml                                             \
+  java/lite/generate-test-sources-build.xml                                        \
   java/lite/pom.xml                                                                \
   java/pom.xml                                                                     \
   java/util/pom.xml                                                                \
+  java/util/src/main/java/com/google/protobuf/util/Durations.java                  \
   java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java              \
   java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java              \
   java/util/src/main/java/com/google/protobuf/util/JsonFormat.java                 \
   java/util/src/main/java/com/google/protobuf/util/TimeUtil.java                   \
+  java/util/src/main/java/com/google/protobuf/util/Timestamps.java                 \
   java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java          \
   java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java          \
   java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java             \
@@ -463,8 +474,6 @@
   objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj                   \
   objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
   objectivec/ProtocolBuffers_iOS.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings \
-  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/FFE465CA-0E74-40E8-9F09-500B66B7DCB2.plist \
-  objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcbaselines/8BBEA4A5147C727100C4ADB7.xcbaseline/Info.plist \
   objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
   objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
   objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj                   \
@@ -473,6 +482,33 @@
   objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme \
   objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme \
   objectivec/README.md                                                       \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester.xcodeproj/project.pbxproj \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester.xcodeproj/xcshareddata/xcschemes/OSXCocoaPodsTester.xcscheme \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/AppDelegate.h \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/AppDelegate.m \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/Assets.xcassets/AppIcon.appiconset/Contents.json \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/Base.lproj/MainMenu.xib \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/Info.plist \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/OSXCocoaPodsTester/main.m    \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/Podfile-framework            \
+  objectivec/Tests/CocoaPods/OSXCocoaPodsTester/Podfile-static               \
+  objectivec/Tests/CocoaPods/README.md                                       \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/Podfile-framework            \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/Podfile-static               \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester.xcodeproj/project.pbxproj \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester.xcodeproj/project.xcworkspace/contents.xcworkspacedata \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester.xcodeproj/xcshareddata/xcschemes/iOSCocoaPodsTester.xcscheme \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/AppDelegate.h \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/AppDelegate.m \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/Assets.xcassets/AppIcon.appiconset/Contents.json \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/Base.lproj/LaunchScreen.storyboard \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/Base.lproj/Main.storyboard \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/Info.plist \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/ViewController.h \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/ViewController.m \
+  objectivec/Tests/CocoaPods/iOSCocoaPodsTester/iOSCocoaPodsTester/main.m    \
+  objectivec/Tests/CocoaPods/run_tests.sh                                    \
   objectivec/Tests/golden_message                                            \
   objectivec/Tests/golden_packed_fields_message                              \
   objectivec/Tests/GPBARCUnittestProtos.m                                    \
@@ -498,6 +534,7 @@
   objectivec/Tests/GPBTestUtilities.h                                        \
   objectivec/Tests/GPBTestUtilities.m                                        \
   objectivec/Tests/GPBUnittestProtos.m                                       \
+  objectivec/Tests/GPBUnittestProtos2.m                                      \
   objectivec/Tests/GPBUnknownFieldSetTest.m                                  \
   objectivec/Tests/GPBUtilitiesTests.m                                       \
   objectivec/Tests/GPBWellKnownTypesTest.m                                   \
@@ -519,6 +556,13 @@
   objectivec/Tests/text_format_map_unittest_data.txt                          \
   objectivec/Tests/text_format_unittest_data.txt                              \
   objectivec/Tests/unittest_cycle.proto                                       \
+  objectivec/Tests/unittest_extension_chain_a.proto                           \
+  objectivec/Tests/unittest_extension_chain_b.proto                           \
+  objectivec/Tests/unittest_extension_chain_c.proto                           \
+  objectivec/Tests/unittest_extension_chain_d.proto                           \
+  objectivec/Tests/unittest_extension_chain_e.proto                           \
+  objectivec/Tests/unittest_extension_chain_f.proto                           \
+  objectivec/Tests/unittest_extension_chain_g.proto                           \
   objectivec/Tests/unittest_objc.proto                                        \
   objectivec/Tests/unittest_objc_startup.proto                                \
   objectivec/Tests/unittest_runtime_proto2.proto                              \
@@ -551,6 +595,7 @@
   python/google/protobuf/internal/enum_type_wrapper.py                       \
   python/google/protobuf/internal/factory_test1.proto                        \
   python/google/protobuf/internal/factory_test2.proto                        \
+  python/google/protobuf/internal/file_options_test.proto                    \
   python/google/protobuf/internal/generator_test.py                          \
   python/google/protobuf/internal/import_test_package/__init__.py            \
   python/google/protobuf/internal/import_test_package/inner.proto            \
@@ -603,6 +648,7 @@
   python/google/protobuf/pyext/map_container.h                               \
   python/google/protobuf/pyext/message.cc                                    \
   python/google/protobuf/pyext/message.h                                     \
+  python/google/protobuf/pyext/message_module.cc                             \
   python/google/protobuf/pyext/proto2_api_test.proto                         \
   python/google/protobuf/pyext/python.proto                                  \
   python/google/protobuf/pyext/python_protobuf.h                             \
@@ -618,6 +664,7 @@
   python/google/protobuf/text_encoding.py                                    \
   python/google/protobuf/text_format.py                                      \
   python/mox.py                                                              \
+  python/setup.cfg                                                           \
   python/setup.py                                                            \
   python/stubout.py                                                          \
   python/tox.ini                                                             \
@@ -643,6 +690,7 @@
   ruby/google-protobuf.gemspec                                               \
   ruby/lib/google/protobuf/message_exts.rb                                   \
   ruby/lib/google/protobuf/repeated_field.rb                                 \
+  ruby/lib/google/protobuf/well_known_types.rb                               \
   ruby/lib/google/protobuf.rb                                                \
   ruby/pom.xml                                                               \
   ruby/src/main/java/com/google/protobuf/jruby/RubyBuilder.java              \
@@ -667,42 +715,53 @@
   ruby/tests/repeated_field_test.rb                                          \
   ruby/tests/stress.rb                                                       \
   ruby/tests/generated_code.proto                                            \
+  ruby/tests/test_import.proto                                               \
   ruby/tests/generated_code_test.rb                                          \
+  ruby/tests/well_known_types_test.rb                                        \
   ruby/travis-test.sh
 
-js_EXTRA_DIST=              \
-  js/README.md              \
-  js/binary/arith.js        \
-  js/binary/arith_test.js   \
-  js/binary/constants.js    \
-  js/binary/decoder.js      \
-  js/binary/decoder_test.js \
-  js/binary/encoder.js      \
-  js/binary/proto_test.js   \
-  js/binary/reader.js       \
-  js/binary/reader_test.js  \
-  js/binary/utils.js        \
-  js/binary/utils_test.js   \
-  js/binary/writer.js       \
-  js/binary/writer_test.js  \
-  js/data.proto             \
-  js/debug.js               \
-  js/debug_test.js          \
-  js/gulpfile.js            \
-  js/jasmine.json           \
-  js/message.js             \
-  js/message_test.js        \
-  js/node_loader.js         \
-  js/package.json           \
-  js/proto3_test.js         \
-  js/proto3_test.proto      \
-  js/test.proto             \
-  js/test2.proto            \
-  js/test3.proto            \
-  js/test4.proto            \
-  js/test5.proto            \
-  js/test_bootstrap.js      \
-  js/testbinary.proto       \
+js_EXTRA_DIST=                              \
+  js/README.md                              \
+  js/binary/arith.js                        \
+  js/binary/arith_test.js                   \
+  js/binary/constants.js                    \
+  js/binary/decoder.js                      \
+  js/binary/decoder_test.js                 \
+  js/binary/encoder.js                      \
+  js/binary/proto_test.js                   \
+  js/binary/reader.js                       \
+  js/binary/reader_test.js                  \
+  js/binary/utils.js                        \
+  js/binary/utils_test.js                   \
+  js/binary/writer.js                       \
+  js/binary/writer_test.js                  \
+  js/commonjs/export.js                     \
+  js/commonjs/export_asserts.js             \
+  js/commonjs/export_testdeps.js            \
+  js/commonjs/import_test.js                \
+  js/commonjs/jasmine.json                  \
+  js/commonjs/rewrite_tests_for_commonjs.js \
+  js/commonjs/test6/test6.proto             \
+  js/commonjs/test7/test7.proto             \
+  js/data.proto                             \
+  js/debug.js                               \
+  js/debug_test.js                          \
+  js/gulpfile.js                            \
+  js/jasmine.json                           \
+  js/map.js                                 \
+  js/message.js                             \
+  js/message_test.js                        \
+  js/node_loader.js                         \
+  js/package.json                           \
+  js/proto3_test.js                         \
+  js/proto3_test.proto                      \
+  js/test.proto                             \
+  js/test2.proto                            \
+  js/test3.proto                            \
+  js/test4.proto                            \
+  js/test5.proto                            \
+  js/test_bootstrap.js                      \
+  js/testbinary.proto                       \
   js/testempty.proto
 
 all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST) $(js_EXTRA_DIST)
@@ -720,6 +779,7 @@
   WORKSPACE                              \
   cmake/CMakeLists.txt                   \
   cmake/README.md                        \
+  cmake/examples.cmake                   \
   cmake/extract_includes.bat.in          \
   cmake/install.cmake                    \
   cmake/libprotobuf.cmake                \
@@ -728,11 +788,13 @@
   cmake/protobuf-config-version.cmake.in \
   cmake/protobuf-config.cmake.in         \
   cmake/protobuf-module.cmake.in         \
+  cmake/protobuf-options.cmake           \
   cmake/protoc.cmake                     \
   cmake/tests.cmake                      \
   editors/README.txt                     \
   editors/proto.vim                      \
   editors/protobuf-mode.el               \
+  examples/CMakeLists.txt                \
   examples/README.txt                    \
   examples/Makefile                      \
   examples/addressbook.proto             \
@@ -742,6 +804,7 @@
   examples/list_people.cc                \
   examples/list_people.go                \
   examples/AddPerson.java                \
+  examples/CMakeLists.txt                \
   examples/ListPeople.java               \
   examples/add_person.py                 \
   examples/list_people.py                \
diff --git a/Protobuf.podspec b/Protobuf.podspec
index 2523076..72e6dd0 100644
--- a/Protobuf.podspec
+++ b/Protobuf.podspec
@@ -5,7 +5,7 @@
 # dependent projects use the :git notation to refer to the library.
 Pod::Spec.new do |s|
   s.name     = 'Protobuf'
-  s.version  = '3.0.0-beta-3'
+  s.version  = '3.0.0'
   s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
   s.homepage = 'https://github.com/google/protobuf'
   s.license  = 'New BSD'
@@ -36,5 +36,6 @@
 
   s.ios.deployment_target = '7.1'
   s.osx.deployment_target = '10.9'
+  s.watchos.deployment_target = '2.0'
   s.requires_arc = false
 end
diff --git a/README.md b/README.md
index ba9c589..67be3e9 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 Protocol Buffers - Google's data interchange format
 ===================================================
 
-[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf)
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf) [![Build status](https://ci.appveyor.com/api/projects/status/73ctee6ua4w2ruin?svg=true)](https://ci.appveyor.com/project/protobuf/protobuf) [![Build Status](https://grpc-testing.appspot.com/buildStatus/icon?job=protobuf_branch)](https://grpc-testing.appspot.com/job/protobuf_branch)
 
 Copyright 2008 Google Inc.
 
diff --git a/WORKSPACE b/WORKSPACE
index 065dc81..df919ad 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,15 +1,15 @@
-new_http_archive(
-    name = "gmock_archive",
-    url = "https://googlemock.googlecode.com/files/gmock-1.7.0.zip",
-    sha256 = "26fcbb5925b74ad5fc8c26b0495dfc96353f4d553492eb97e85a8a6d2f43095b",
+new_git_repository(
+    name = "googletest",
     build_file = "gmock.BUILD",
+    remote = "https://github.com/google/googletest",
+    tag = "release-1.8.0",
 )
 
 new_http_archive(
     name = "six_archive",
-    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
-    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
     build_file = "six.BUILD",
+    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
+    url = "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55",
 )
 
 bind(
@@ -19,12 +19,12 @@
 
 bind(
     name = "gtest",
-    actual = "@gmock_archive//:gtest",
+    actual = "@googletest//:gtest",
 )
 
 bind(
     name = "gtest_main",
-    actual = "@gmock_archive//:gtest_main",
+    actual = "@googletest//:gtest_main",
 )
 
 bind(
@@ -33,8 +33,8 @@
 )
 
 maven_jar(
-  name = "guava_maven",
-  artifact = "com.google.guava:guava:18.0",
+    name = "guava_maven",
+    artifact = "com.google.guava:guava:18.0",
 )
 
 bind(
@@ -43,8 +43,8 @@
 )
 
 maven_jar(
-  name = "gson_maven",
-  artifact = "com.google.code.gson:gson:2.3",
+    name = "gson_maven",
+    artifact = "com.google.code.gson:gson:2.3",
 )
 
 bind(
diff --git a/appveyor.bat b/appveyor.bat
index 9a46b92..916f443 100644
--- a/appveyor.bat
+++ b/appveyor.bat
@@ -10,7 +10,7 @@
 echo Building C++
 mkdir build_msvc
 cd build_msvc
-cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
+cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% -Dprotobuf_UNICODE=%UNICODE% ../cmake
 msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
 cd %configuration%
 tests.exe || goto error
@@ -19,9 +19,12 @@
 :build_csharp
 echo Building C#
 cd csharp\src
-nuget restore
-msbuild Google.Protobuf.sln /p:Platform="Any CPU" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
-nunit-console Google.Protobuf.Test\bin\%configuration%\Google.Protobuf.Test.dll || goto error
+dotnet restore
+dotnet build -c %configuration% Google.Protobuf Google.Protobuf.Test Google.Protobuf.Conformance || goto error
+
+echo Testing C#
+dotnet test -c %configuration% Google.Protobuf.Test || goto error
+
 goto :EOF
 
 :error
diff --git a/appveyor.yml b/appveyor.yml
index c84ecae..20fc8ad 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -11,13 +11,26 @@
   matrix:
     - language: cpp
       BUILD_DLL: ON
+      UNICODE: ON
 
     - language: csharp
 
+# Our build scripts run tests automatically; we don't want AppVeyor
+# to try to detect them itself.
+test: off
+
 install:
-  - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip
-  - 7z x gmock-1.7.0.zip
-  - rename gmock-1.7.0 gmock
+  - ps: Start-FileDownload https://github.com/google/googlemock/archive/release-1.7.0.zip
+  - 7z x release-1.7.0.zip
+  - del /Q release-1.7.0.zip
+  - rename googlemock-release-1.7.0 gmock
+  - ps: Start-FileDownload https://github.com/google/googletest/archive/release-1.7.0.zip
+  - 7z x release-1.7.0.zip
+  - del /Q release-1.7.0.zip
+  - rename googletest-release-1.7.0 gtest
+  - move gtest gmock
+  - ps: Start-FileDownload https://go.microsoft.com/fwlink/?LinkID=809122 -FileName dotnetsdk.exe
+  - dotnetsdk.exe /install /quiet /norestart
 
 before_build:
   - if %platform%==Win32 set generator=Visual Studio 12
diff --git a/autogen.sh b/autogen.sh
index 5b4c29f..9f26642 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -31,10 +31,15 @@
 # directory is set up as an SVN external.
 if test ! -e gmock; then
   echo "Google Mock not present.  Fetching gmock-1.7.0 from the web..."
-  curl $curlopts -O https://googlemock.googlecode.com/files/gmock-1.7.0.zip
-  unzip -q gmock-1.7.0.zip
-  rm gmock-1.7.0.zip
-  mv gmock-1.7.0 gmock
+  curl $curlopts -L -O https://github.com/google/googlemock/archive/release-1.7.0.zip
+  unzip -q release-1.7.0.zip
+  rm release-1.7.0.zip
+  mv googlemock-release-1.7.0 gmock
+
+  curl $curlopts -L -O https://github.com/google/googletest/archive/release-1.7.0.zip
+  unzip -q release-1.7.0.zip
+  rm release-1.7.0.zip
+  mv googletest-release-1.7.0 gmock/gtest
 fi
 
 set -ex
diff --git a/benchmarks/readme.txt b/benchmarks/readme.txt
index 2c836d0..b08b8bc 100644
--- a/benchmarks/readme.txt
+++ b/benchmarks/readme.txt
@@ -22,29 +22,25 @@
    $ javac -d tmp -cp protobuf.jar ProtoBench.java
    
 3) Generate code for the relevant benchmark protocol buffer, e.g.
-   $ protoc --java_out=tmp google_size.proto google_speed.proto
+   $ protoc --java_out=tmp google_size.proto
    
 4) Build the generated code, e.g.
-   $ cd tmp
-   $ javac -d . -cp ../protobuf.jar benchmarks/*.java
+   $ javac -d tmp -cp protobuf.jar tmp/benchmarks/*.java
            
 5) Run the test. Arguments are given in pairs - the first argument
    is the descriptor type; the second is the filename. For example:
-   $ java -cp .;../protobuf.jar com.google.protocolbuffers.ProtoBench
-          benchmarks.GoogleSize$SizeMessage1 ../google_message1.dat
-          benchmarks.GoogleSpeed$SpeedMessage1 ../google_message1.dat
-          benchmarks.GoogleSize$SizeMessage2 ../google_message2.dat
-          benchmarks.GoogleSpeed$SpeedMessage2 ../google_message2.dat
+   $ java -cp tmp:protobuf.jar com.google.protocolbuffers.ProtoBench \
+       'benchmarks.GoogleSize$SizeMessage1' google_message1.dat \
+       'benchmarks.GoogleSize$SizeMessage2' google_message2.dat
           
-6) Wait! Each test runs for around 30 seconds, and there are 6 tests
+6) Wait! Each test runs for around 30 seconds, and there are 8 tests
    per class/data combination. The above command would therefore take
-   about 12 minutes to run.
+   about 8 minutes to run.
 
    
 Benchmarks available
 --------------------
 
 From Google:
-google_size.proto and google_speed.proto, messages
-google_message1.dat and google_message2.dat. The proto files are
-equivalent, but optimized differently.
+google_size.proto,
+messages google_message1.dat and google_message2.dat.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 07b176d..df3b201 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -86,6 +86,7 @@
   add_definitions(-DHAVE_PTHREAD)
 endif (CMAKE_USE_PTHREADS_INIT)
 
+set(_protobuf_FIND_ZLIB)
 if (protobuf_WITH_ZLIB)
   find_package(ZLIB)
   if (ZLIB_FOUND)
@@ -96,6 +97,7 @@
     # Using imported target if exists
     if (TARGET ZLIB::ZLIB)
       set(ZLIB_LIBRARIES ZLIB::ZLIB)
+      set(_protobuf_FIND_ZLIB "if(NOT ZLIB_FOUND)\n  find_package(ZLIB)\nendif()")
     endif (TARGET ZLIB::ZLIB)
   else (ZLIB_FOUND)
     set(HAVE_ZLIB 0)
@@ -157,6 +159,10 @@
   set(LIB_PREFIX)
 endif (MSVC)
 
+if (protobuf_UNICODE)
+  add_definitions(-DUNICODE -D_UNICODE)
+endif (protobuf_UNICODE)
+
 include(libprotobuf-lite.cmake)
 include(libprotobuf.cmake)
 include(libprotoc.cmake)
diff --git a/cmake/examples.cmake b/cmake/examples.cmake
index 0a65105..e5cad63 100644
--- a/cmake/examples.cmake
+++ b/cmake/examples.cmake
@@ -1,57 +1,57 @@
-if(protobuf_VERBOSE)

-  message(STATUS "Protocol Buffers Examples Configuring...")

-endif()

-

-get_filename_component(examples_dir "../examples" ABSOLUTE)

-

-if(protobuf_VERBOSE)

-  message(STATUS "Protocol Buffers Examples Configuring done")

-endif()

-include(ExternalProject)

-

-# Internal utility function: Create a custom target representing a build of examples with custom options.

-function(add_examples_build NAME)

-

-  ExternalProject_Add(${NAME}

-    PREFIX ${NAME}

-    SOURCE_DIR "${examples_dir}"

-    BINARY_DIR ${NAME}

-    STAMP_DIR ${NAME}/logs

-    INSTALL_COMMAND "" #Skip

-    LOG_CONFIGURE 1

-    CMAKE_CACHE_ARGS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"

-                     "-Dprotobuf_VERBOSE:BOOL=${protobuf_VERBOSE}"

-                     ${ARGN}

-  )

-  set_property(TARGET ${NAME} PROPERTY FOLDER "Examples")

-  set_property(TARGET ${NAME} PROPERTY EXCLUDE_FROM_ALL TRUE)

-endfunction()

-

-# Add examples as an external project.

-# sub_directory cannot be used because the find_package(protobuf) call would cause failures with redefined targets.

-add_examples_build(examples "-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}")

-add_dependencies(examples libprotobuf protoc)

-

-option(protobuf_BUILD_EXAMPLES_MULTITEST "Build Examples in multiple configurations. Useful for testing." OFF)

-mark_as_advanced(protobuf_BUILD_EXAMPLES_MULTITEST)

-if(protobuf_BUILD_EXAMPLES_MULTITEST)

-  set_property(GLOBAL PROPERTY USE_FOLDERS ON)

-

-  #Build using the legacy compatibility module.

-  add_examples_build(examples-legacy

-    "-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}"

-    "-Dprotobuf_MODULE_COMPATIBLE:BOOL=TRUE"

-  )

-  add_dependencies(examples-legacy libprotobuf protoc)

-

-  #Build using the installed library.

-  add_examples_build(examples-installed

-    "-Dprotobuf_DIR:PATH=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}"

-  )

-

-  #Build using the installed library in legacy compatibility mode.

-  add_examples_build(examples-installed-legacy

-    "-Dprotobuf_DIR:PATH=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}"

-    "-Dprotobuf_MODULE_COMPATIBLE:BOOL=TRUE"

-  )

-endif()

+if(protobuf_VERBOSE)
+  message(STATUS "Protocol Buffers Examples Configuring...")
+endif()
+
+get_filename_component(examples_dir "../examples" ABSOLUTE)
+
+if(protobuf_VERBOSE)
+  message(STATUS "Protocol Buffers Examples Configuring done")
+endif()
+include(ExternalProject)
+
+# Internal utility function: Create a custom target representing a build of examples with custom options.
+function(add_examples_build NAME)
+
+  ExternalProject_Add(${NAME}
+    PREFIX ${NAME}
+    SOURCE_DIR "${examples_dir}"
+    BINARY_DIR ${NAME}
+    STAMP_DIR ${NAME}/logs
+    INSTALL_COMMAND "" #Skip
+    LOG_CONFIGURE 1
+    CMAKE_CACHE_ARGS "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
+                     "-Dprotobuf_VERBOSE:BOOL=${protobuf_VERBOSE}"
+                     ${ARGN}
+  )
+  set_property(TARGET ${NAME} PROPERTY FOLDER "Examples")
+  set_property(TARGET ${NAME} PROPERTY EXCLUDE_FROM_ALL TRUE)
+endfunction()
+
+# Add examples as an external project.
+# sub_directory cannot be used because the find_package(protobuf) call would cause failures with redefined targets.
+add_examples_build(examples "-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}")
+add_dependencies(examples libprotobuf protoc)
+
+option(protobuf_BUILD_EXAMPLES_MULTITEST "Build Examples in multiple configurations. Useful for testing." OFF)
+mark_as_advanced(protobuf_BUILD_EXAMPLES_MULTITEST)
+if(protobuf_BUILD_EXAMPLES_MULTITEST)
+  set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+  #Build using the legacy compatibility module.
+  add_examples_build(examples-legacy
+    "-Dprotobuf_DIR:PATH=${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}"
+    "-Dprotobuf_MODULE_COMPATIBLE:BOOL=TRUE"
+  )
+  add_dependencies(examples-legacy libprotobuf protoc)
+
+  #Build using the installed library.
+  add_examples_build(examples-installed
+    "-Dprotobuf_DIR:PATH=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}"
+  )
+
+  #Build using the installed library in legacy compatibility mode.
+  add_examples_build(examples-installed-legacy
+    "-Dprotobuf_DIR:PATH=${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}"
+    "-Dprotobuf_MODULE_COMPATIBLE:BOOL=TRUE"
+  )
+endif()
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index c76973c..9edafca 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -69,7 +69,6 @@
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h include\google\protobuf\reflection.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h include\google\protobuf\reflection_ops.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h include\google\protobuf\repeated_field.h
-copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field_reflection.h include\google\protobuf\repeated_field_reflection.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h include\google\protobuf\service.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h include\google\protobuf\source_context.pb.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h include\google\protobuf\struct.pb.h
diff --git a/cmake/install.cmake b/cmake/install.cmake
index 94ef219..73e3198 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -110,7 +110,7 @@
   NAMESPACE protobuf::
   COMPONENT protobuf-export)
 
-install(DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_CMAKEDIR}/
   DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
   COMPONENT protobuf-export
   PATTERN protobuf-targets.cmake EXCLUDE
diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake
index 8930c1c..26e1f35 100644
--- a/cmake/libprotobuf.cmake
+++ b/cmake/libprotobuf.cmake
@@ -56,7 +56,10 @@
 
 add_library(libprotobuf ${protobuf_SHARED_OR_STATIC}
   ${libprotobuf_lite_files} ${libprotobuf_files})
-target_link_libraries(libprotobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES})
+target_link_libraries(libprotobuf ${CMAKE_THREAD_LIBS_INIT})
+if(protobuf_WITH_ZLIB)
+    target_link_libraries(libprotobuf ${ZLIB_LIBRARIES})
+endif()
 target_include_directories(libprotobuf PUBLIC ${protobuf_source_dir}/src)
 if(MSVC AND protobuf_BUILD_SHARED_LIBS)
   target_compile_definitions(libprotobuf
diff --git a/cmake/protobuf-config-version.cmake.in b/cmake/protobuf-config-version.cmake.in
index 3b8ced2..0036c9e 100644
--- a/cmake/protobuf-config-version.cmake.in
+++ b/cmake/protobuf-config-version.cmake.in
@@ -3,7 +3,7 @@
 
 # Prerelease versions cannot be passed in directly via the find_package command,
 # so we allow users to specify it in a variable
-if(NOT DEFINED "${${PACKAGE_FIND_NAME}_FIND_VERSION_PRERELEASE}")
+if(NOT DEFINED "${PACKAGE_FIND_NAME}_FIND_VERSION_PRERELEASE")
   set("${${PACKAGE_FIND_NAME}_FIND_VERSION_PRERELEASE}" "")
 else()
   set(PACKAGE_FIND_VERSION ${PACKAGE_FIND_VERSION}-${${PACKAGE_FIND_NAME}_FIND_VERSION_PRERELEASE})
diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in
index 3731551..a044fe5 100644
--- a/cmake/protobuf-config.cmake.in
+++ b/cmake/protobuf-config.cmake.in
@@ -1,6 +1,9 @@
 # User options
 include("${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake")
 
+# Depend packages
+@_protobuf_FIND_ZLIB@
+
 # Imported targets
 include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake")
 
diff --git a/cmake/protobuf-module.cmake.in b/cmake/protobuf-module.cmake.in
index 6e0bcf9..614e4c0 100644
--- a/cmake/protobuf-module.cmake.in
+++ b/cmake/protobuf-module.cmake.in
@@ -147,7 +147,6 @@
       LOCATION_RELEASE)
     get_target_property(${name}_LIBRARY_DEBUG protobuf::lib${filename}
       LOCATION_DEBUG)
-    endif()
 
     select_library_configurations(${name})
     set(${name}_LIBRARY ${${name}_LIBRARY} PARENT_SCOPE)
diff --git a/cmake/protobuf-options.cmake b/cmake/protobuf-options.cmake
index 99c85eb..47fb158 100644
--- a/cmake/protobuf-options.cmake
+++ b/cmake/protobuf-options.cmake
@@ -1,7 +1,7 @@
-# Verbose output

-option(protobuf_VERBOSE "Enable for verbose output" OFF)

-mark_as_advanced(protobuf_VERBOSE)

-

-# FindProtobuf module compatibel

-option(protobuf_MODULE_COMPATIBLE "CMake build-in FindProtobuf.cmake module compatible" OFF)

-mark_as_advanced(protobuf_MODULE_COMPATIBLE)

+# Verbose output
+option(protobuf_VERBOSE "Enable for verbose output" OFF)
+mark_as_advanced(protobuf_VERBOSE)
+
+# FindProtobuf module compatibel
+option(protobuf_MODULE_COMPATIBLE "CMake build-in FindProtobuf.cmake module compatible" OFF)
+mark_as_advanced(protobuf_MODULE_COMPATIBLE)
diff --git a/configure.ac b/configure.ac
index d858e17..4188799 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
 # In the SVN trunk, the version should always be the next anticipated release
 # version with the "-pre" suffix.  (We used to use "-SNAPSHOT" but this pushed
 # the size of one file name in the dist tarfile over the 99-char limit.)
-AC_INIT([Protocol Buffers],[3.0.0-beta-3],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.0.0],[protobuf@googlegroups.com],[protobuf])
 
 AM_MAINTAINER_MODE([enable])
 
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index 5538cc7..28ac3c8 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -20,7 +20,7 @@
   conformance_pb2.py                                           \
   Conformance.pbobjc.h                                         \
   Conformance.pbobjc.m                                         \
-  conformance.rb                                               \
+  conformance_pb.rb                                            \
   com/google/protobuf/Any.java                                 \
   com/google/protobuf/AnyOrBuilder.java                        \
   com/google/protobuf/AnyProto.java                            \
@@ -84,47 +84,47 @@
   google/protobuf/wrappers.pb.cc                               \
   google/protobuf/wrappers.pb.h                                \
   google/protobuf/wrappers.rb                                  \
-  google/protobuf/wrappers_pb2.py                              \
-  lite/com/google/protobuf/Any.java                            \
-  lite/com/google/protobuf/AnyOrBuilder.java                   \
-  lite/com/google/protobuf/AnyProto.java                       \
-  lite/com/google/protobuf/BoolValue.java                      \
-  lite/com/google/protobuf/BoolValueOrBuilder.java             \
-  lite/com/google/protobuf/BytesValue.java                     \
-  lite/com/google/protobuf/BytesValueOrBuilder.java            \
-  lite/com/google/protobuf/conformance/Conformance.java        \
-  lite/com/google/protobuf/DoubleValue.java                    \
-  lite/com/google/protobuf/DoubleValueOrBuilder.java           \
-  lite/com/google/protobuf/Duration.java                       \
-  lite/com/google/protobuf/DurationOrBuilder.java              \
-  lite/com/google/protobuf/DurationProto.java                  \
-  lite/com/google/protobuf/FieldMask.java                      \
-  lite/com/google/protobuf/FieldMaskOrBuilder.java             \
-  lite/com/google/protobuf/FieldMaskProto.java                 \
-  lite/com/google/protobuf/FloatValue.java                     \
-  lite/com/google/protobuf/FloatValueOrBuilder.java            \
-  lite/com/google/protobuf/Int32Value.java                     \
-  lite/com/google/protobuf/Int32ValueOrBuilder.java            \
-  lite/com/google/protobuf/Int64Value.java                     \
-  lite/com/google/protobuf/Int64ValueOrBuilder.java            \
-  lite/com/google/protobuf/ListValue.java                      \
-  lite/com/google/protobuf/ListValueOrBuilder.java             \
-  lite/com/google/protobuf/NullValue.java                      \
-  lite/com/google/protobuf/StringValue.java                    \
-  lite/com/google/protobuf/StringValueOrBuilder.java           \
-  lite/com/google/protobuf/Struct.java                         \
-  lite/com/google/protobuf/StructOrBuilder.java                \
-  lite/com/google/protobuf/StructProto.java                    \
-  lite/com/google/protobuf/Timestamp.java                      \
-  lite/com/google/protobuf/TimestampOrBuilder.java             \
-  lite/com/google/protobuf/TimestampProto.java                 \
-  lite/com/google/protobuf/UInt32Value.java                    \
-  lite/com/google/protobuf/UInt32ValueOrBuilder.java           \
-  lite/com/google/protobuf/UInt64Value.java                    \
-  lite/com/google/protobuf/UInt64ValueOrBuilder.java           \
-  lite/com/google/protobuf/Value.java                          \
-  lite/com/google/protobuf/ValueOrBuilder.java                 \
-  lite/com/google/protobuf/WrappersProto.java
+  google/protobuf/wrappers_pb2.py
+  # lite/com/google/protobuf/Any.java                            \
+  # lite/com/google/protobuf/AnyOrBuilder.java                   \
+  # lite/com/google/protobuf/AnyProto.java                       \
+  # lite/com/google/protobuf/BoolValue.java                      \
+  # lite/com/google/protobuf/BoolValueOrBuilder.java             \
+  # lite/com/google/protobuf/BytesValue.java                     \
+  # lite/com/google/protobuf/BytesValueOrBuilder.java            \
+  # lite/com/google/protobuf/conformance/Conformance.java        \
+  # lite/com/google/protobuf/DoubleValue.java                    \
+  # lite/com/google/protobuf/DoubleValueOrBuilder.java           \
+  # lite/com/google/protobuf/Duration.java                       \
+  # lite/com/google/protobuf/DurationOrBuilder.java              \
+  # lite/com/google/protobuf/DurationProto.java                  \
+  # lite/com/google/protobuf/FieldMask.java                      \
+  # lite/com/google/protobuf/FieldMaskOrBuilder.java             \
+  # lite/com/google/protobuf/FieldMaskProto.java                 \
+  # lite/com/google/protobuf/FloatValue.java                     \
+  # lite/com/google/protobuf/FloatValueOrBuilder.java            \
+  # lite/com/google/protobuf/Int32Value.java                     \
+  # lite/com/google/protobuf/Int32ValueOrBuilder.java            \
+  # lite/com/google/protobuf/Int64Value.java                     \
+  # lite/com/google/protobuf/Int64ValueOrBuilder.java            \
+  # lite/com/google/protobuf/ListValue.java                      \
+  # lite/com/google/protobuf/ListValueOrBuilder.java             \
+  # lite/com/google/protobuf/NullValue.java                      \
+  # lite/com/google/protobuf/StringValue.java                    \
+  # lite/com/google/protobuf/StringValueOrBuilder.java           \
+  # lite/com/google/protobuf/Struct.java                         \
+  # lite/com/google/protobuf/StructOrBuilder.java                \
+  # lite/com/google/protobuf/StructProto.java                    \
+  # lite/com/google/protobuf/Timestamp.java                      \
+  # lite/com/google/protobuf/TimestampOrBuilder.java             \
+  # lite/com/google/protobuf/TimestampProto.java                 \
+  # lite/com/google/protobuf/UInt32Value.java                    \
+  # lite/com/google/protobuf/UInt32ValueOrBuilder.java           \
+  # lite/com/google/protobuf/UInt64Value.java                    \
+  # lite/com/google/protobuf/UInt64ValueOrBuilder.java           \
+  # lite/com/google/protobuf/Value.java                          \
+  # lite/com/google/protobuf/ValueOrBuilder.java                 \
+  # lite/com/google/protobuf/WrappersProto.java
 
 bin_PROGRAMS = conformance-test-runner conformance-cpp
 
@@ -192,7 +192,7 @@
 protoc_middleman: $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
 	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --objc_out=. --python_out=. $(conformance_protoc_inputs)
 	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --python_out=. $(well_known_type_protoc_inputs)
-	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
+	## $(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
 	touch protoc_middleman
 
 else
@@ -203,8 +203,8 @@
 protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
 	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --objc_out=$$oldpwd --python_out=$$oldpwd $(conformance_protoc_inputs) )
 	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --python_out=$$oldpwd $(well_known_type_protoc_inputs) )
-	@mkdir -p lite
-	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) )
+	## @mkdir -p lite
+	## oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) )
 	touch protoc_middleman
 
 endif
@@ -246,7 +246,7 @@
 conformance-csharp: $(other_language_protoc_outputs)
 	@echo "Writing shortcut script conformance-csharp..."
 	@echo '#! /bin/sh' > conformance-csharp
-	@echo 'mono ../csharp/src/Google.Protobuf.Conformance/bin/Release/Google.Protobuf.Conformance.exe "$$@"' >> conformance-csharp
+	@echo 'dotnet ../csharp/src/Google.Protobuf.Conformance/bin/Release/netcoreapp1.0/Google.Protobuf.Conformance.dll "$$@"' >> conformance-csharp
 	@chmod +x conformance-csharp
 
 # Targets for actually running tests.
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
index fc96074..95a8fd1 100644
--- a/conformance/conformance.proto
+++ b/conformance/conformance.proto
@@ -210,6 +210,11 @@
     NestedMessage oneof_nested_message = 112;
     string oneof_string = 113;
     bytes oneof_bytes = 114;
+    bool oneof_bool = 115;
+    uint64 oneof_uint64 = 116;
+    float oneof_float = 117;
+    double oneof_double = 118;
+    NestedEnum oneof_enum = 119;
   }
 
   // Well-known types
@@ -248,6 +253,7 @@
   repeated google.protobuf.Value repeated_value = 316;
 
   // Test field-name-to-JSON-name convention.
+  // (protobuf says names can be any valid C/C++ identifier.)
   int32 fieldname1 = 401;
   int32 field_name2 = 402;
   int32 _field_name3 = 403;
@@ -260,6 +266,12 @@
   int32 Field_Name10 = 410;
   int32 FIELD_NAME11 = 411;
   int32 FIELD_name12 = 412;
+  int32 __field_name13 = 413;
+  int32 __Field_name14 = 414;
+  int32 field__name15 = 415;
+  int32 field__Name16 = 416;
+  int32 field_name17__ = 417;
+  int32 Field_name18__ = 418;
 }
 
 message ForeignMessage {
diff --git a/conformance/conformance_ruby.rb b/conformance/conformance_ruby.rb
index c716fac..aa57214 100755
--- a/conformance/conformance_ruby.rb
+++ b/conformance/conformance_ruby.rb
@@ -30,7 +30,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.
 
-require 'conformance'
+require 'conformance_pb'
 
 $test_count = 0
 $verbose = false
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 59a61e5..fb963f6 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -272,11 +272,16 @@
   TestAllTypes test_message;
 
   switch (response.result_case()) {
+    case ConformanceResponse::RESULT_NOT_SET:
+      ReportFailure(test_name, request, response,
+                    "Response didn't have any field in the Response.");
+      return;
+
     case ConformanceResponse::kParseError:
     case ConformanceResponse::kRuntimeError:
     case ConformanceResponse::kSerializeError:
       ReportFailure(test_name, request, response,
-                    "Failed to parse JSON input or produce JSON output.");
+                    "Failed to parse input or produce output.");
       return;
 
     case ConformanceResponse::kSkipped:
@@ -400,6 +405,17 @@
                     equivalent_text_format, conformance::JSON);
 }
 
+void ConformanceTestSuite::RunValidProtobufTest(
+    const string& test_name, const TestAllTypes& input,
+    const string& equivalent_text_format) {
+  RunValidInputTest("ProtobufInput." + test_name + ".ProtobufOutput",
+                    input.SerializeAsString(), conformance::PROTOBUF,
+                    equivalent_text_format, conformance::PROTOBUF);
+  RunValidInputTest("ProtobufInput." + test_name + ".JsonOutput",
+                    input.SerializeAsString(), conformance::PROTOBUF,
+                    equivalent_text_format, conformance::JSON);
+}
+
 // According to proto3 JSON specification, JSON serializers follow more strict
 // rules than parsers (e.g., a serializer must serialize int32 values as JSON
 // numbers while the parser is allowed to accept them as JSON strings). This
@@ -638,18 +654,22 @@
   RunValidJsonTest("HelloWorld", "{\"optionalString\":\"Hello, World!\"}",
                    "optional_string: 'Hello, World!'");
 
+  // NOTE: The spec for JSON support is still being sorted out, these may not
+  // all be correct.
   // Test field name conventions.
   RunValidJsonTest(
       "FieldNameInSnakeCase",
       R"({
         "fieldname1": 1,
         "fieldName2": 2,
-        "FieldName3": 3
+        "fieldName3": 3,
+        "fieldName4": 4
       })",
       R"(
         fieldname1: 1
         field_name2: 2
         _field_name3: 3
+        field__name4_: 4
       )");
   RunValidJsonTest(
       "FieldNameWithNumbers",
@@ -679,6 +699,24 @@
         FIELD_NAME11: 11
         FIELD_name12: 12
       )");
+  RunValidJsonTest(
+      "FieldNameWithDoubleUnderscores",
+      R"({
+        "fieldName13": 13,
+        "fieldName14": 14,
+        "fieldName15": 15,
+        "fieldName16": 16,
+        "fieldName17": 17,
+        "fieldName18": 18
+      })",
+      R"(
+        __field_name13: 13
+        __Field_name14: 14
+        field__name15: 15
+        field__Name16: 16
+        field_name17__: 17
+        Field_name18__: 18
+      )");
   // Using the original proto field name in JSON is also allowed.
   RunValidJsonTest(
       "OriginalProtoFieldName",
@@ -686,6 +724,7 @@
         "fieldname1": 1,
         "field_name2": 2,
         "_field_name3": 3,
+        "field__name4_": 4,
         "field0name5": 5,
         "field_0_name6": 6,
         "fieldName7": 7,
@@ -693,12 +732,19 @@
         "field_Name9": 9,
         "Field_Name10": 10,
         "FIELD_NAME11": 11,
-        "FIELD_name12": 12
+        "FIELD_name12": 12,
+        "__field_name13": 13,
+        "__Field_name14": 14,
+        "field__name15": 15,
+        "field__Name16": 16,
+        "field_name17__": 17,
+        "Field_name18__": 18
       })",
       R"(
         fieldname1: 1
         field_name2: 2
         _field_name3: 3
+        field__name4_: 4
         field0name5: 5
         field_0_name6: 6
         fieldName7: 7
@@ -707,12 +753,22 @@
         Field_Name10: 10
         FIELD_NAME11: 11
         FIELD_name12: 12
+        __field_name13: 13
+        __Field_name14: 14
+        field__name15: 15
+        field__Name16: 16
+        field_name17__: 17
+        Field_name18__: 18
       )");
   // Field names can be escaped.
   RunValidJsonTest(
       "FieldNameEscaped",
       R"({"fieldn\u0061me1": 1})",
       "fieldname1: 1");
+  // String ends with escape character.
+  ExpectParseFailureForJson(
+      "StringEndsWithEscapeChar",
+      "{\"optionalString\": \"abc\\");
   // Field names must be quoted (or it's not valid JSON).
   ExpectParseFailureForJson(
       "FieldNameNotQuoted",
@@ -721,6 +777,17 @@
   ExpectParseFailureForJson(
       "TrailingCommaInAnObject",
       R"({"fieldname1":1,})");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithSpace",
+      R"({"fieldname1":1 ,})");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithSpaceCommaSpace",
+      R"({"fieldname1":1 , })");
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObjectWithNewlines",
+      R"({
+        "fieldname1":1,
+      })");
   // JSON doesn't support comments.
   ExpectParseFailureForJson(
       "JsonWithComments",
@@ -728,6 +795,42 @@
         // This is a comment.
         "fieldname1": 1
       })");
+  // JSON spec says whitespace doesn't matter, so try a few spacings to be sure.
+  RunValidJsonTest(
+      "OneLineNoSpaces",
+      "{\"optionalInt32\":1,\"optionalInt64\":2}",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "OneLineWithSpaces",
+      "{ \"optionalInt32\" : 1 , \"optionalInt64\" : 2 }",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "MultilineNoSpaces",
+      "{\n\"optionalInt32\"\n:\n1\n,\n\"optionalInt64\"\n:\n2\n}",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  RunValidJsonTest(
+      "MultilineWithSpaces",
+      "{\n  \"optionalInt32\"  :  1\n  ,\n  \"optionalInt64\"  :  2\n}\n",
+      R"(
+        optional_int32: 1
+        optional_int64: 2
+      )");
+  // Missing comma between key/value pairs.
+  ExpectParseFailureForJson(
+      "MissingCommaOneLine",
+      "{ \"optionalInt32\": 1 \"optionalInt64\": 2 }");
+  ExpectParseFailureForJson(
+      "MissingCommaMultiline",
+      "{\n  \"optionalInt32\": 1\n  \"optionalInt64\": 2\n}");
   // Duplicated field names are not allowed.
   ExpectParseFailureForJson(
       "FieldNameDuplicate",
@@ -747,18 +850,22 @@
         "optionalNestedMessage": {a: 1},
         "optional_nested_message": {}
       })");
+  // NOTE: The spec for JSON support is still being sorted out, these may not
+  // all be correct.
   // Serializers should use lowerCamelCase by default.
   RunValidJsonTestWithValidator(
       "FieldNameInLowerCamelCase",
       R"({
         "fieldname1": 1,
         "fieldName2": 2,
-        "FieldName3": 3
+        "fieldName3": 3,
+        "fieldName4": 4
       })",
       [](const Json::Value& value) {
         return value.isMember("fieldname1") &&
             value.isMember("fieldName2") &&
-            value.isMember("FieldName3");
+            value.isMember("fieldName3") &&
+            value.isMember("fieldName4");
       });
   RunValidJsonTestWithValidator(
       "FieldNameWithNumbers",
@@ -788,6 +895,24 @@
             value.isMember("fIELDNAME11") &&
             value.isMember("fIELDName12");
       });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithDoubleUnderscores",
+      R"({
+        "fieldName13": 13,
+        "fieldName14": 14,
+        "fieldName15": 15,
+        "fieldName16": 16,
+        "fieldName17": 17,
+        "fieldName18": 18
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldName13") &&
+            value.isMember("fieldName14") &&
+            value.isMember("fieldName15") &&
+            value.isMember("fieldName16") &&
+            value.isMember("fieldName17") &&
+            value.isMember("fieldName18");
+      });
 
   // Integer fields.
   RunValidJsonTest(
@@ -814,18 +939,26 @@
       "Uint64FieldMaxValue",
       R"({"optionalUint64": "18446744073709551615"})",
       "optional_uint64: 18446744073709551615");
+  // While not the largest Int64, this is the largest
+  // Int64 which can be exactly represented within an
+  // IEEE-754 64-bit float, which is the expected level
+  // of interoperability guarantee. Larger values may
+  // work in some implementations, but should not be
+  // relied upon.
   RunValidJsonTest(
       "Int64FieldMaxValueNotQuoted",
-      R"({"optionalInt64": 9223372036854775807})",
-      "optional_int64: 9223372036854775807");
+      R"({"optionalInt64": 9223372036854774784})",
+      "optional_int64: 9223372036854774784");
   RunValidJsonTest(
       "Int64FieldMinValueNotQuoted",
       R"({"optionalInt64": -9223372036854775808})",
       "optional_int64: -9223372036854775808");
+  // Largest interoperable Uint64; see comment above
+  // for Int64FieldMaxValueNotQuoted.
   RunValidJsonTest(
       "Uint64FieldMaxValueNotQuoted",
-      R"({"optionalUint64": 18446744073709551615})",
-      "optional_uint64: 18446744073709551615");
+      R"({"optionalUint64": 18446744073709549568})",
+      "optional_uint64: 18446744073709549568");
   // Values can be represented as JSON strings.
   RunValidJsonTest(
       "Int32FieldStringValue",
@@ -1217,6 +1350,64 @@
   ExpectParseFailureForJson(
       "OneofFieldDuplicate",
       R"({"oneofUint32": 1, "oneofString": "test"})");
+  // Ensure zero values for oneof make it out/backs.
+  {
+    TestAllTypes message;
+    message.set_oneof_uint32(0);
+    RunValidProtobufTest(
+        "OneofZeroUint32", message, "oneof_uint32: 0");
+    message.mutable_oneof_nested_message()->set_a(0);
+    RunValidProtobufTest(
+        "OneofZeroMessage", message, "oneof_nested_message: {}");
+    message.set_oneof_string("");
+    RunValidProtobufTest(
+        "OneofZeroString", message, "oneof_string: \"\"");
+    message.set_oneof_bytes("");
+    RunValidProtobufTest(
+        "OneofZeroBytes", message, "oneof_bytes: \"\"");
+    message.set_oneof_bool(false);
+    RunValidProtobufTest(
+        "OneofZeroBool", message, "oneof_bool: false");
+    message.set_oneof_uint64(0);
+    RunValidProtobufTest(
+        "OneofZeroUint64", message, "oneof_uint64: 0");
+    message.set_oneof_float(0.0f);
+    RunValidProtobufTest(
+        "OneofZeroFloat", message, "oneof_float: 0");
+    message.set_oneof_double(0.0);
+    RunValidProtobufTest(
+        "OneofZeroDouble", message, "oneof_double: 0");
+    message.set_oneof_enum(TestAllTypes::FOO);
+    RunValidProtobufTest(
+        "OneofZeroEnum", message, "oneof_enum: FOO");
+  }
+  RunValidJsonTest(
+      "OneofZeroUint32",
+      R"({"oneofUint32": 0})", "oneof_uint32: 0");
+  RunValidJsonTest(
+      "OneofZeroMessage",
+      R"({"oneofNestedMessage": {}})", "oneof_nested_message: {}");
+  RunValidJsonTest(
+      "OneofZeroString",
+      R"({"oneofString": ""})", "oneof_string: \"\"");
+  RunValidJsonTest(
+      "OneofZeroBytes",
+      R"({"oneofBytes": ""})", "oneof_bytes: \"\"");
+  RunValidJsonTest(
+      "OneofZeroBool",
+      R"({"oneofBool": false})", "oneof_bool: false");
+  RunValidJsonTest(
+      "OneofZeroUint64",
+      R"({"oneofUint64": 0})", "oneof_uint64: 0");
+  RunValidJsonTest(
+      "OneofZeroFloat",
+      R"({"oneofFloat": 0.0})", "oneof_float: 0");
+  RunValidJsonTest(
+      "OneofZeroDouble",
+      R"({"oneofDouble": 0.0})", "oneof_double: 0");
+  RunValidJsonTest(
+      "OneofZeroEnum",
+      R"({"oneofEnum":"FOO"})", "oneof_enum: FOO");
 
   // Repeated fields.
   RunValidJsonTest(
@@ -1273,6 +1464,15 @@
   ExpectParseFailureForJson(
       "RepeatedFieldTrailingComma",
       R"({"repeatedInt32": [1, 2, 3, 4,]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithSpace",
+      "{\"repeatedInt32\": [1, 2, 3, 4 ,]}");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithSpaceCommaSpace",
+      "{\"repeatedInt32\": [1, 2, 3, 4 , ]}");
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingCommaWithNewlines",
+      "{\"repeatedInt32\": [\n  1,\n  2,\n  3,\n  4,\n]}");
 
   // Map fields.
   RunValidJsonTest(
@@ -1391,6 +1591,18 @@
       "MapFieldValueIsNull",
       R"({"mapInt32Int32": {"0": null}})");
 
+  // http://www.rfc-editor.org/rfc/rfc7159.txt says strings have to use double
+  // quotes.
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteKey",
+      R"({'optionalString': "Hello world!"})");
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteValue",
+      R"({"optionalString": 'Hello world!'})");
+  ExpectParseFailureForJson(
+      "StringFieldSingleQuoteBoth",
+      R"({'optionalString': 'Hello world!'})");
+
   // Wrapper types.
   RunValidJsonTest(
       "OptionalBoolWrapper",
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index c9c5213..5668931 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -133,6 +133,9 @@
   void RunValidJsonTestWithProtobufInput(const string& test_name,
                                          const conformance::TestAllTypes& input,
                                          const string& equivalent_text_format);
+  void RunValidProtobufTest(const string& test_name,
+                            const conformance::TestAllTypes& input,
+                            const string& equivalent_text_format);
 
   typedef std::function<bool(const Json::Value&)> Validator;
   void RunValidJsonTestWithValidator(const string& test_name,
diff --git a/conformance/failure_list_cpp.txt b/conformance/failure_list_cpp.txt
index 839e521..5e17176 100644
--- a/conformance/failure_list_cpp.txt
+++ b/conformance/failure_list_cpp.txt
@@ -22,16 +22,22 @@
 JsonInput.FieldNameDuplicate
 JsonInput.FieldNameDuplicateDifferentCasing1
 JsonInput.FieldNameDuplicateDifferentCasing2
-JsonInput.FieldNameInLowerCamelCase.Validator
-JsonInput.FieldNameInSnakeCase.JsonOutput
-JsonInput.FieldNameInSnakeCase.ProtobufOutput
 JsonInput.FieldNameNotQuoted
 JsonInput.MapFieldValueIsNull
 JsonInput.RepeatedFieldMessageElementIsNull
 JsonInput.RepeatedFieldPrimitiveElementIsNull
 JsonInput.RepeatedFieldTrailingComma
+JsonInput.RepeatedFieldTrailingCommaWithNewlines
+JsonInput.RepeatedFieldTrailingCommaWithSpace
+JsonInput.RepeatedFieldTrailingCommaWithSpaceCommaSpace
+JsonInput.StringFieldSingleQuoteBoth
+JsonInput.StringFieldSingleQuoteKey
+JsonInput.StringFieldSingleQuoteValue
 JsonInput.StringFieldUppercaseEscapeLetter
 JsonInput.TrailingCommaInAnObject
+JsonInput.TrailingCommaInAnObjectWithNewlines
+JsonInput.TrailingCommaInAnObjectWithSpace
+JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
 JsonInput.WrapperTypesWithNullValue.JsonOutput
 JsonInput.WrapperTypesWithNullValue.ProtobufOutput
 ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
diff --git a/conformance/failure_list_csharp.txt b/conformance/failure_list_csharp.txt
index e7de4b9..d8bfe1b 100644
--- a/conformance/failure_list_csharp.txt
+++ b/conformance/failure_list_csharp.txt
@@ -1,11 +1,4 @@
-JsonInput.FieldNameInLowerCamelCase.Validator
-JsonInput.FieldNameInSnakeCase.JsonOutput
-JsonInput.FieldNameInSnakeCase.ProtobufOutput
 JsonInput.FieldNameWithMixedCases.JsonOutput
 JsonInput.FieldNameWithMixedCases.ProtobufOutput
 JsonInput.FieldNameWithMixedCases.Validator
-JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
-JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
 JsonInput.OriginalProtoFieldName.JsonOutput
-JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
-JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
diff --git a/conformance/failure_list_java.txt b/conformance/failure_list_java.txt
index 850712b..b2122c8 100644
--- a/conformance/failure_list_java.txt
+++ b/conformance/failure_list_java.txt
@@ -20,8 +20,13 @@
 JsonInput.EnumFieldNotQuoted
 JsonInput.FieldMaskInvalidCharacter
 JsonInput.FieldNameDuplicate
+JsonInput.FieldNameInLowerCamelCase.Validator
 JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
 JsonInput.FieldNameNotQuoted
+JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
+JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+JsonInput.FieldNameWithDoubleUnderscores.Validator
 JsonInput.FloatFieldInfinityNotQuoted
 JsonInput.FloatFieldNanNotQuoted
 JsonInput.FloatFieldNegativeInfinityNotQuoted
@@ -35,6 +40,9 @@
 JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
 JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
 JsonInput.StringFieldNotAString
+JsonInput.StringFieldSingleQuoteBoth
+JsonInput.StringFieldSingleQuoteKey
+JsonInput.StringFieldSingleQuoteValue
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldUnpairedHighSurrogate
 JsonInput.StringFieldUnpairedLowSurrogate
diff --git a/conformance/failure_list_objc.txt b/conformance/failure_list_objc.txt
index 5dac350..dd538c1 100644
--- a/conformance/failure_list_objc.txt
+++ b/conformance/failure_list_objc.txt
@@ -1,4 +1,4 @@
-# No tests currently failing.
+# All tests currently passing.
 #
-# json input or output tests are skipped (in conformance_objc.m) as mobile
-# platforms don't support json wire format to avoid code bloat.
+# JSON input or output tests are skipped (in conformance_objc.m) as mobile
+# platforms don't support JSON wire format to avoid code bloat.
diff --git a/conformance/failure_list_python.txt b/conformance/failure_list_python.txt
index 550a043..d38b782 100644
--- a/conformance/failure_list_python.txt
+++ b/conformance/failure_list_python.txt
@@ -19,9 +19,6 @@
 JsonInput.EnumFieldUnknownValue.Validator
 JsonInput.FieldMask.ProtobufOutput
 JsonInput.FieldMaskInvalidCharacter
-JsonInput.FieldNameInLowerCamelCase.Validator
-JsonInput.FieldNameInSnakeCase.JsonOutput
-JsonInput.FieldNameInSnakeCase.ProtobufOutput
 JsonInput.FloatFieldInfinityNotQuoted
 JsonInput.FloatFieldNanNotQuoted
 JsonInput.FloatFieldNegativeInfinityNotQuoted
@@ -35,6 +32,8 @@
 JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
 JsonInput.Int32FieldMinFloatValue.JsonOutput
 JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.OneofZeroMessage.JsonOutput
+JsonInput.OneofZeroMessage.ProtobufOutput
 JsonInput.OriginalProtoFieldName.JsonOutput
 JsonInput.OriginalProtoFieldName.ProtobufOutput
 JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
diff --git a/conformance/failure_list_python_cpp.txt b/conformance/failure_list_python_cpp.txt
index 1eb916a..84d9fcc 100644
--- a/conformance/failure_list_python_cpp.txt
+++ b/conformance/failure_list_python_cpp.txt
@@ -28,9 +28,6 @@
 JsonInput.EnumFieldUnknownValue.Validator
 JsonInput.FieldMask.ProtobufOutput
 JsonInput.FieldMaskInvalidCharacter
-JsonInput.FieldNameInLowerCamelCase.Validator
-JsonInput.FieldNameInSnakeCase.JsonOutput
-JsonInput.FieldNameInSnakeCase.ProtobufOutput
 JsonInput.FloatFieldInfinityNotQuoted
 JsonInput.FloatFieldNanNotQuoted
 JsonInput.FloatFieldNegativeInfinityNotQuoted
@@ -44,6 +41,8 @@
 JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
 JsonInput.Int32FieldMinFloatValue.JsonOutput
 JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.OneofZeroMessage.JsonOutput
+JsonInput.OneofZeroMessage.ProtobufOutput
 JsonInput.OriginalProtoFieldName.JsonOutput
 JsonInput.OriginalProtoFieldName.ProtobufOutput
 JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
index 7c12da0..2a533aa 100644
--- a/conformance/failure_list_ruby.txt
+++ b/conformance/failure_list_ruby.txt
@@ -58,7 +58,12 @@
 JsonInput.EnumFieldUnknownValue.Validator
 JsonInput.FieldMask.JsonOutput
 JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldNameInLowerCamelCase.Validator
 JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
+JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
+JsonInput.FieldNameWithDoubleUnderscores.Validator
 JsonInput.FieldNameWithMixedCases.JsonOutput
 JsonInput.FieldNameWithMixedCases.ProtobufOutput
 JsonInput.FieldNameWithMixedCases.Validator
@@ -103,6 +108,14 @@
 JsonInput.MessageMapField.ProtobufOutput
 JsonInput.MessageRepeatedField.JsonOutput
 JsonInput.MessageRepeatedField.ProtobufOutput
+JsonInput.OneofZeroDouble.JsonOutput
+JsonInput.OneofZeroDouble.ProtobufOutput
+JsonInput.OneofZeroFloat.JsonOutput
+JsonInput.OneofZeroFloat.ProtobufOutput
+JsonInput.OneofZeroUint32.JsonOutput
+JsonInput.OneofZeroUint32.ProtobufOutput
+JsonInput.OneofZeroUint64.JsonOutput
+JsonInput.OneofZeroUint64.ProtobufOutput
 JsonInput.OptionalBoolWrapper.JsonOutput
 JsonInput.OptionalBoolWrapper.ProtobufOutput
 JsonInput.OptionalBytesWrapper.JsonOutput
@@ -145,6 +158,7 @@
 JsonInput.RepeatedUint32Wrapper.ProtobufOutput
 JsonInput.RepeatedUint64Wrapper.JsonOutput
 JsonInput.RepeatedUint64Wrapper.ProtobufOutput
+JsonInput.StringEndsWithEscapeChar
 JsonInput.StringFieldNotAString
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldSurrogatePair.JsonOutput
diff --git a/csharp/.gitignore b/csharp/.gitignore
index c88f741..8ba8849 100644
--- a/csharp/.gitignore
+++ b/csharp/.gitignore
@@ -1,16 +1,10 @@
-#
-# 	Untracked directories
-#
-src/AddressBook/bin
-src/AddressBook/obj
-src/Google.Protobuf/bin/
-src/Google.Protobuf/obj/
-src/Google.Protobuf.Conformance/bin/
-src/Google.Protobuf.Conformance/obj/
-src/Google.Protobuf.Test/bin/
-src/Google.Protobuf.Test/obj/
-src/Google.Protobuf.JsonDump/bin/
-src/Google.Protobuf.JsonDump/obj/
+# Output
+bin
+obj
+project.lock.json
+TestResult.xml
+
+# Possibly legacy now?
 mono/bin
 mono/tmp
 mono/protoc
@@ -23,6 +17,7 @@
 #
 # 	Untracked files
 #
+.vs
 *.user
 *.suo
 *.nupkg
diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec
index e4240da..24b4a77 100644
--- a/csharp/Google.Protobuf.Tools.nuspec
+++ b/csharp/Google.Protobuf.Tools.nuspec
@@ -5,7 +5,7 @@
     <title>Google Protocol Buffers tools</title>
     <summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
     <description>See project site for more info.</description>
-    <version>3.0.0-beta3</version>
+    <version>3.0.0</version>
     <authors>Google Inc.</authors>
     <owners>protobuf-packages</owners>
     <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
diff --git a/csharp/README.md b/csharp/README.md
index 8c3993e..ddf1d2b 100644
--- a/csharp/README.md
+++ b/csharp/README.md
@@ -9,8 +9,8 @@
 The easiest way how to use C# protobufs is via the `Google.Protobuf`
 NuGet package. Just add the NuGet package to your VS project.
 
-Besides C# runtime library, the NuGet package also contains 
-precompiled version of `protoc.exe` and a copy of well known `.proto`
+You will also want to install the `Google.Protobuf.Tools` NuGet package, which
+contains precompiled version of `protoc.exe` and a copy of well known `.proto`
 files under the package's `tools` directory.
 
 To generate C# files from your `.proto` files, invoke `protoc` with the 
diff --git a/csharp/build_packages.bat b/csharp/build_packages.bat
index 1502f06..37732e7 100644
--- a/csharp/build_packages.bat
+++ b/csharp/build_packages.bat
@@ -1,10 +1,7 @@
 @rem Builds Google.Protobuf NuGet packages
 
-@rem Adjust the location of nuget.exe
-set NUGET=C:\nuget\nuget.exe
-
-@rem Build src/Google.Protobuf.sln solution in Release configuration first.
-%NUGET% pack src\Google.Protobuf\Google.Protobuf.nuspec -Symbols || goto :error
+dotnet restore src
+dotnet pack -c Release src\Google.Protobuf || goto :error
 
 goto :EOF
 
diff --git a/csharp/buildall.sh b/csharp/buildall.sh
index 45af705..cab3222 100755
--- a/csharp/buildall.sh
+++ b/csharp/buildall.sh
@@ -1,17 +1,16 @@
 #!/bin/bash
-# Use mono to build solution and run all tests.
 
-# Adjust these to reflect the location of nunit-console in your system.
-NUNIT_CONSOLE=nunit-console
-
-# The rest you can leave intact
 CONFIG=Release
 SRC=$(dirname $0)/src
 
 set -ex
 
-echo Building the solution.
-xbuild /p:Configuration=$CONFIG $SRC/Google.Protobuf.sln
+echo Building relevant projects.
+dotnet build -c $CONFIG $SRC/Google.Protobuf $SRC/Google.Protobuf.Test $SRC/Google.Protobuf.Conformance
 
 echo Running tests.
-$NUNIT_CONSOLE $SRC/Google.Protobuf.Test/bin/$CONFIG/Google.Protobuf.Test.dll
+# Only test netcoreapp1.0, which uses the .NET Core runtime.
+# If we want to test the .NET 4.5 version separately, we could
+# run Mono explicitly. However, we don't have any differences between
+# the .NET 4.5 and netstandard1.0 assemblies.
+dotnet test -c $CONFIG -f netcoreapp1.0 $SRC/Google.Protobuf.Test
diff --git a/csharp/src/AddressBook/AddressBook.csproj b/csharp/src/AddressBook/AddressBook.csproj
deleted file mode 100644
index 8f8ca7e..0000000
--- a/csharp/src/AddressBook/AddressBook.csproj
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{A31F5FB2-4FF3-432A-B35B-5CD203606311}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>Google.Protobuf.Examples.AddressBook</RootNamespace>

-    <AssemblyName>AddressBook</AssemblyName>

-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <StartupObject>Google.Protobuf.Examples.AddressBook.Program</StartupObject>

-    <TargetFrameworkProfile>

-    </TargetFrameworkProfile>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug</OutputPath>

-    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release</OutputPath>

-    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="mscorlib" />

-    <Reference Include="System" />

-    <Reference Include="System.Data" />

-    <Reference Include="System.Xml" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="AddPerson.cs" />

-    <Compile Include="Addressbook.cs" />

-    <Compile Include="SampleUsage.cs" />

-    <Compile Include="ListPeople.cs" />

-    <Compile Include="Program.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

-      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

-      <Name>Google.Protobuf</Name>

-    </ProjectReference>

-  </ItemGroup>

-  <ItemGroup>

-    <None Include="app.config" />

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

-</Project>
\ No newline at end of file
diff --git a/csharp/src/AddressBook/AddressBook.xproj b/csharp/src/AddressBook/AddressBook.xproj
new file mode 100644
index 0000000..4c9925e
--- /dev/null
+++ b/csharp/src/AddressBook/AddressBook.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>afb63919-1e05-43b4-802a-8fb8c9b2f463</ProjectGuid>
+    <RootNamespace>AddressBook</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/csharp/src/AddressBook/Properties/AssemblyInfo.cs b/csharp/src/AddressBook/Properties/AssemblyInfo.cs
deleted file mode 100644
index 9cb014c..0000000
--- a/csharp/src/AddressBook/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Reflection;

-using System.Runtime.InteropServices;

-

-// General Information about an assembly is controlled through the following 

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-

-[assembly: AssemblyTitle("AddressBook")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("AddressBook")]

-[assembly: AssemblyCopyright("Copyright ©  2015")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-[assembly: AssemblyVersion("3.0.0.0")]

-[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/AddressBook/SampleUsage.cs b/csharp/src/AddressBook/SampleUsage.cs
index aaaedda..941d865 100644
--- a/csharp/src/AddressBook/SampleUsage.cs
+++ b/csharp/src/AddressBook/SampleUsage.cs
@@ -66,7 +66,7 @@
             // The message performs a deep-comparison on equality:

             if (restored.People.Count != 1 || !person.Equals(restored.People[0]))

             {

-                throw new ApplicationException("There is a bad person in here!");

+                throw new Exception("There is a bad person in here!");

             }

         }

     }

diff --git a/csharp/src/AddressBook/app.config b/csharp/src/AddressBook/app.config
deleted file mode 100644
index a80813a..0000000
--- a/csharp/src/AddressBook/app.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0"?>
-<configuration>
-	<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
diff --git a/csharp/src/AddressBook/project.json b/csharp/src/AddressBook/project.json
new file mode 100644
index 0000000..c500bdc
--- /dev/null
+++ b/csharp/src/AddressBook/project.json
@@ -0,0 +1,20 @@
+{
+  "buildOptions": {
+    "debugType": "portable",
+    "emitEntryPoint": true,
+    "additionalArguments": [ "/main:Google.Protobuf.Examples.AddressBook.Program" ]
+  },
+  "dependencies": {
+    "Google.Protobuf": { "target": "project" }
+  },
+  "frameworks": {
+    "netcoreapp1.0": {
+      "dependencies": {
+        "Microsoft.NETCore.App": {
+          "type": "platform",
+          "version": "1.0.0"
+        }
+      }
+    }
+  }
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/App.config b/csharp/src/Google.Protobuf.Conformance/App.config
deleted file mode 100644
index 8e15646..0000000
--- a/csharp/src/Google.Protobuf.Conformance/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-    </startup>
-</configuration>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
index 5fcbff7..431ac4f 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
@@ -34,7 +34,7 @@
             "IAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgAEhcKDXJ1bnRpbWVf",
             "ZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2FkGAMgASgMSAASFgoM",
             "anNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgFIAEoCUgAQggKBnJl",
-            "c3VsdCLVMgoMVGVzdEFsbFR5cGVzEhYKDm9wdGlvbmFsX2ludDMyGAEgASgF",
+            "c3VsdCKCNQoMVGVzdEFsbFR5cGVzEhYKDm9wdGlvbmFsX2ludDMyGAEgASgF",
             "EhYKDm9wdGlvbmFsX2ludDY0GAIgASgDEhcKD29wdGlvbmFsX3VpbnQzMhgD",
             "IAEoDRIXCg9vcHRpb25hbF91aW50NjQYBCABKAQSFwoPb3B0aW9uYWxfc2lu",
             "dDMyGAUgASgREhcKD29wdGlvbmFsX3NpbnQ2NBgGIAEoEhIYChBvcHRpb25h",
@@ -102,93 +102,100 @@
             "TWFwU3RyaW5nRm9yZWlnbkVudW1FbnRyeRIWCgxvbmVvZl91aW50MzIYbyAB",
             "KA1IABJHChRvbmVvZl9uZXN0ZWRfbWVzc2FnZRhwIAEoCzInLmNvbmZvcm1h",
             "bmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlSAASFgoMb25lb2Zfc3Ry",
-            "aW5nGHEgASgJSAASFQoLb25lb2ZfYnl0ZXMYciABKAxIABI6ChVvcHRpb25h",
-            "bF9ib29sX3dyYXBwZXIYyQEgASgLMhouZ29vZ2xlLnByb3RvYnVmLkJvb2xW",
-            "YWx1ZRI8ChZvcHRpb25hbF9pbnQzMl93cmFwcGVyGMoBIAEoCzIbLmdvb2ds",
-            "ZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjwKFm9wdGlvbmFsX2ludDY0X3dyYXBw",
-            "ZXIYywEgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDY0VmFsdWUSPgoXb3B0",
-            "aW9uYWxfdWludDMyX3dyYXBwZXIYzAEgASgLMhwuZ29vZ2xlLnByb3RvYnVm",
-            "LlVJbnQzMlZhbHVlEj4KF29wdGlvbmFsX3VpbnQ2NF93cmFwcGVyGM0BIAEo",
-            "CzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZRI8ChZvcHRpb25hbF9m",
-            "bG9hdF93cmFwcGVyGM4BIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5GbG9hdFZh",
-            "bHVlEj4KF29wdGlvbmFsX2RvdWJsZV93cmFwcGVyGM8BIAEoCzIcLmdvb2ds",
-            "ZS5wcm90b2J1Zi5Eb3VibGVWYWx1ZRI+ChdvcHRpb25hbF9zdHJpbmdfd3Jh",
-            "cHBlchjQASABKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSPAoW",
-            "b3B0aW9uYWxfYnl0ZXNfd3JhcHBlchjRASABKAsyGy5nb29nbGUucHJvdG9i",
-            "dWYuQnl0ZXNWYWx1ZRI6ChVyZXBlYXRlZF9ib29sX3dyYXBwZXIY0wEgAygL",
-            "MhouZ29vZ2xlLnByb3RvYnVmLkJvb2xWYWx1ZRI8ChZyZXBlYXRlZF9pbnQz",
-            "Ml93cmFwcGVyGNQBIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVl",
-            "EjwKFnJlcGVhdGVkX2ludDY0X3dyYXBwZXIY1QEgAygLMhsuZ29vZ2xlLnBy",
-            "b3RvYnVmLkludDY0VmFsdWUSPgoXcmVwZWF0ZWRfdWludDMyX3dyYXBwZXIY",
-            "1gEgAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEj4KF3JlcGVh",
-            "dGVkX3VpbnQ2NF93cmFwcGVyGNcBIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5V",
-            "SW50NjRWYWx1ZRI8ChZyZXBlYXRlZF9mbG9hdF93cmFwcGVyGNgBIAMoCzIb",
-            "Lmdvb2dsZS5wcm90b2J1Zi5GbG9hdFZhbHVlEj4KF3JlcGVhdGVkX2RvdWJs",
-            "ZV93cmFwcGVyGNkBIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5Eb3VibGVWYWx1",
-            "ZRI+ChdyZXBlYXRlZF9zdHJpbmdfd3JhcHBlchjaASADKAsyHC5nb29nbGUu",
-            "cHJvdG9idWYuU3RyaW5nVmFsdWUSPAoWcmVwZWF0ZWRfYnl0ZXNfd3JhcHBl",
-            "chjbASADKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZRI1ChFvcHRp",
-            "b25hbF9kdXJhdGlvbhitAiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRp",
-            "b24SNwoSb3B0aW9uYWxfdGltZXN0YW1wGK4CIAEoCzIaLmdvb2dsZS5wcm90",
-            "b2J1Zi5UaW1lc3RhbXASOAoTb3B0aW9uYWxfZmllbGRfbWFzaxivAiABKAsy",
-            "Gi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrEjEKD29wdGlvbmFsX3N0cnVj",
-            "dBiwAiABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EisKDG9wdGlvbmFs",
-            "X2FueRixAiABKAsyFC5nb29nbGUucHJvdG9idWYuQW55Ei8KDm9wdGlvbmFs",
-            "X3ZhbHVlGLICIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZRI1ChFyZXBl",
-            "YXRlZF9kdXJhdGlvbhi3AiADKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRp",
-            "b24SNwoScmVwZWF0ZWRfdGltZXN0YW1wGLgCIAMoCzIaLmdvb2dsZS5wcm90",
-            "b2J1Zi5UaW1lc3RhbXASNwoScmVwZWF0ZWRfZmllbGRtYXNrGLkCIAMoCzIa",
-            "Lmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sSMQoPcmVwZWF0ZWRfc3RydWN0",
-            "GMQCIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSKwoMcmVwZWF0ZWRf",
-            "YW55GLsCIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnkSLwoOcmVwZWF0ZWRf",
-            "dmFsdWUYvAIgAygLMhYuZ29vZ2xlLnByb3RvYnVmLlZhbHVlEhMKCmZpZWxk",
-            "bmFtZTEYkQMgASgFEhQKC2ZpZWxkX25hbWUyGJIDIAEoBRIVCgxfZmllbGRf",
-            "bmFtZTMYkwMgASgFEhYKDWZpZWxkX19uYW1lNF8YlAMgASgFEhQKC2ZpZWxk",
-            "MG5hbWU1GJUDIAEoBRIWCg1maWVsZF8wX25hbWU2GJYDIAEoBRITCgpmaWVs",
-            "ZE5hbWU3GJcDIAEoBRITCgpGaWVsZE5hbWU4GJgDIAEoBRIUCgtmaWVsZF9O",
-            "YW1lORiZAyABKAUSFQoMRmllbGRfTmFtZTEwGJoDIAEoBRIVCgxGSUVMRF9O",
-            "QU1FMTEYmwMgASgFEhUKDEZJRUxEX25hbWUxMhicAyABKAUaSgoNTmVzdGVk",
-            "TWVzc2FnZRIJCgFhGAEgASgFEi4KC2NvcmVjdXJzaXZlGAIgASgLMhkuY29u",
-            "Zm9ybWFuY2UuVGVzdEFsbFR5cGVzGjQKEk1hcEludDMySW50MzJFbnRyeRIL",
-            "CgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcEludDY0SW50",
-            "NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgBGjYKFE1h",
-            "cFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1ZRgCIAEo",
-            "DToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEgASgEEg0K",
-            "BXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRyeRILCgNr",
-            "ZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2NFNpbnQ2",
-            "NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEaOAoWTWFw",
-            "Rml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFsdWUYAiAB",
-            "KAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5GAEgASgG",
-            "Eg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhlZDMyRW50",
-            "cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhNYXBTZml4",
-            "ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVlGAIgASgQ",
-            "OgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgFEg0KBXZh",
-            "bHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsKA2tleRgB",
-            "IAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xFbnRyeRIL",
-            "CgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGjYKFE1hcFN0cmluZ1N0",
-            "cmluZ0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEaNQoT",
-            "TWFwU3RyaW5nQnl0ZXNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiAB",
-            "KAw6AjgBGmYKG01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRILCgNrZXkY",
-            "ASABKAkSNgoFdmFsdWUYAiABKAsyJy5jb25mb3JtYW5jZS5UZXN0QWxsVHlw",
-            "ZXMuTmVzdGVkTWVzc2FnZToCOAEaWwocTWFwU3RyaW5nRm9yZWlnbk1lc3Nh",
-            "Z2VFbnRyeRILCgNrZXkYASABKAkSKgoFdmFsdWUYAiABKAsyGy5jb25mb3Jt",
-            "YW5jZS5Gb3JlaWduTWVzc2FnZToCOAEaYAoYTWFwU3RyaW5nTmVzdGVkRW51",
-            "bUVudHJ5EgsKA2tleRgBIAEoCRIzCgV2YWx1ZRgCIAEoDjIkLmNvbmZvcm1h",
-            "bmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRFbnVtOgI4ARpVChlNYXBTdHJpbmdG",
-            "b3JlaWduRW51bUVudHJ5EgsKA2tleRgBIAEoCRInCgV2YWx1ZRgCIAEoDjIY",
-            "LmNvbmZvcm1hbmNlLkZvcmVpZ25FbnVtOgI4ASI5CgpOZXN0ZWRFbnVtEgcK",
-            "A0ZPTxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8BQg0K",
-            "C29uZW9mX2ZpZWxkIhsKDkZvcmVpZ25NZXNzYWdlEgkKAWMYASABKAUqNQoK",
-            "V2lyZUZvcm1hdBIPCgtVTlNQRUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoE",
-            "SlNPThACKkAKC0ZvcmVpZ25FbnVtEg8KC0ZPUkVJR05fRk9PEAASDwoLRk9S",
-            "RUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACQiEKH2NvbS5nb29nbGUucHJv",
-            "dG9idWYuY29uZm9ybWFuY2ViBnByb3RvMw=="));
+            "aW5nGHEgASgJSAASFQoLb25lb2ZfYnl0ZXMYciABKAxIABIUCgpvbmVvZl9i",
+            "b29sGHMgASgISAASFgoMb25lb2ZfdWludDY0GHQgASgESAASFQoLb25lb2Zf",
+            "ZmxvYXQYdSABKAJIABIWCgxvbmVvZl9kb3VibGUYdiABKAFIABI6CgpvbmVv",
+            "Zl9lbnVtGHcgASgOMiQuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk5lc3Rl",
+            "ZEVudW1IABI6ChVvcHRpb25hbF9ib29sX3dyYXBwZXIYyQEgASgLMhouZ29v",
+            "Z2xlLnByb3RvYnVmLkJvb2xWYWx1ZRI8ChZvcHRpb25hbF9pbnQzMl93cmFw",
+            "cGVyGMoBIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjwKFm9w",
+            "dGlvbmFsX2ludDY0X3dyYXBwZXIYywEgASgLMhsuZ29vZ2xlLnByb3RvYnVm",
+            "LkludDY0VmFsdWUSPgoXb3B0aW9uYWxfdWludDMyX3dyYXBwZXIYzAEgASgL",
+            "MhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEj4KF29wdGlvbmFsX3Vp",
+            "bnQ2NF93cmFwcGVyGM0BIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRW",
+            "YWx1ZRI8ChZvcHRpb25hbF9mbG9hdF93cmFwcGVyGM4BIAEoCzIbLmdvb2ds",
+            "ZS5wcm90b2J1Zi5GbG9hdFZhbHVlEj4KF29wdGlvbmFsX2RvdWJsZV93cmFw",
+            "cGVyGM8BIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5Eb3VibGVWYWx1ZRI+Chdv",
+            "cHRpb25hbF9zdHJpbmdfd3JhcHBlchjQASABKAsyHC5nb29nbGUucHJvdG9i",
+            "dWYuU3RyaW5nVmFsdWUSPAoWb3B0aW9uYWxfYnl0ZXNfd3JhcHBlchjRASAB",
+            "KAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZRI6ChVyZXBlYXRlZF9i",
+            "b29sX3dyYXBwZXIY0wEgAygLMhouZ29vZ2xlLnByb3RvYnVmLkJvb2xWYWx1",
+            "ZRI8ChZyZXBlYXRlZF9pbnQzMl93cmFwcGVyGNQBIAMoCzIbLmdvb2dsZS5w",
+            "cm90b2J1Zi5JbnQzMlZhbHVlEjwKFnJlcGVhdGVkX2ludDY0X3dyYXBwZXIY",
+            "1QEgAygLMhsuZ29vZ2xlLnByb3RvYnVmLkludDY0VmFsdWUSPgoXcmVwZWF0",
+            "ZWRfdWludDMyX3dyYXBwZXIY1gEgAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJ",
+            "bnQzMlZhbHVlEj4KF3JlcGVhdGVkX3VpbnQ2NF93cmFwcGVyGNcBIAMoCzIc",
+            "Lmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZRI8ChZyZXBlYXRlZF9mbG9h",
+            "dF93cmFwcGVyGNgBIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5GbG9hdFZhbHVl",
+            "Ej4KF3JlcGVhdGVkX2RvdWJsZV93cmFwcGVyGNkBIAMoCzIcLmdvb2dsZS5w",
+            "cm90b2J1Zi5Eb3VibGVWYWx1ZRI+ChdyZXBlYXRlZF9zdHJpbmdfd3JhcHBl",
+            "chjaASADKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSPAoWcmVw",
+            "ZWF0ZWRfYnl0ZXNfd3JhcHBlchjbASADKAsyGy5nb29nbGUucHJvdG9idWYu",
+            "Qnl0ZXNWYWx1ZRI1ChFvcHRpb25hbF9kdXJhdGlvbhitAiABKAsyGS5nb29n",
+            "bGUucHJvdG9idWYuRHVyYXRpb24SNwoSb3B0aW9uYWxfdGltZXN0YW1wGK4C",
+            "IAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASOAoTb3B0aW9uYWxf",
+            "ZmllbGRfbWFzaxivAiABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNr",
+            "EjEKD29wdGlvbmFsX3N0cnVjdBiwAiABKAsyFy5nb29nbGUucHJvdG9idWYu",
+            "U3RydWN0EisKDG9wdGlvbmFsX2FueRixAiABKAsyFC5nb29nbGUucHJvdG9i",
+            "dWYuQW55Ei8KDm9wdGlvbmFsX3ZhbHVlGLICIAEoCzIWLmdvb2dsZS5wcm90",
+            "b2J1Zi5WYWx1ZRI1ChFyZXBlYXRlZF9kdXJhdGlvbhi3AiADKAsyGS5nb29n",
+            "bGUucHJvdG9idWYuRHVyYXRpb24SNwoScmVwZWF0ZWRfdGltZXN0YW1wGLgC",
+            "IAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASNwoScmVwZWF0ZWRf",
+            "ZmllbGRtYXNrGLkCIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sS",
+            "MQoPcmVwZWF0ZWRfc3RydWN0GMQCIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5T",
+            "dHJ1Y3QSKwoMcmVwZWF0ZWRfYW55GLsCIAMoCzIULmdvb2dsZS5wcm90b2J1",
+            "Zi5BbnkSLwoOcmVwZWF0ZWRfdmFsdWUYvAIgAygLMhYuZ29vZ2xlLnByb3Rv",
+            "YnVmLlZhbHVlEhMKCmZpZWxkbmFtZTEYkQMgASgFEhQKC2ZpZWxkX25hbWUy",
+            "GJIDIAEoBRIVCgxfZmllbGRfbmFtZTMYkwMgASgFEhYKDWZpZWxkX19uYW1l",
+            "NF8YlAMgASgFEhQKC2ZpZWxkMG5hbWU1GJUDIAEoBRIWCg1maWVsZF8wX25h",
+            "bWU2GJYDIAEoBRITCgpmaWVsZE5hbWU3GJcDIAEoBRITCgpGaWVsZE5hbWU4",
+            "GJgDIAEoBRIUCgtmaWVsZF9OYW1lORiZAyABKAUSFQoMRmllbGRfTmFtZTEw",
+            "GJoDIAEoBRIVCgxGSUVMRF9OQU1FMTEYmwMgASgFEhUKDEZJRUxEX25hbWUx",
+            "MhicAyABKAUSFwoOX19maWVsZF9uYW1lMTMYnQMgASgFEhcKDl9fRmllbGRf",
+            "bmFtZTE0GJ4DIAEoBRIWCg1maWVsZF9fbmFtZTE1GJ8DIAEoBRIWCg1maWVs",
+            "ZF9fTmFtZTE2GKADIAEoBRIXCg5maWVsZF9uYW1lMTdfXxihAyABKAUSFwoO",
+            "RmllbGRfbmFtZTE4X18YogMgASgFGkoKDU5lc3RlZE1lc3NhZ2USCQoBYRgB",
+            "IAEoBRIuCgtjb3JlY3Vyc2l2ZRgCIAEoCzIZLmNvbmZvcm1hbmNlLlRlc3RB",
+            "bGxUeXBlcxo0ChJNYXBJbnQzMkludDMyRW50cnkSCwoDa2V5GAEgASgFEg0K",
+            "BXZhbHVlGAIgASgFOgI4ARo0ChJNYXBJbnQ2NEludDY0RW50cnkSCwoDa2V5",
+            "GAEgASgDEg0KBXZhbHVlGAIgASgDOgI4ARo2ChRNYXBVaW50MzJVaW50MzJF",
+            "bnRyeRILCgNrZXkYASABKA0SDQoFdmFsdWUYAiABKA06AjgBGjYKFE1hcFVp",
+            "bnQ2NFVpbnQ2NEVudHJ5EgsKA2tleRgBIAEoBBINCgV2YWx1ZRgCIAEoBDoC",
+            "OAEaNgoUTWFwU2ludDMyU2ludDMyRW50cnkSCwoDa2V5GAEgASgREg0KBXZh",
+            "bHVlGAIgASgROgI4ARo2ChRNYXBTaW50NjRTaW50NjRFbnRyeRILCgNrZXkY",
+            "ASABKBISDQoFdmFsdWUYAiABKBI6AjgBGjgKFk1hcEZpeGVkMzJGaXhlZDMy",
+            "RW50cnkSCwoDa2V5GAEgASgHEg0KBXZhbHVlGAIgASgHOgI4ARo4ChZNYXBG",
+            "aXhlZDY0Rml4ZWQ2NEVudHJ5EgsKA2tleRgBIAEoBhINCgV2YWx1ZRgCIAEo",
+            "BjoCOAEaOgoYTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5EgsKA2tleRgBIAEo",
+            "DxINCgV2YWx1ZRgCIAEoDzoCOAEaOgoYTWFwU2ZpeGVkNjRTZml4ZWQ2NEVu",
+            "dHJ5EgsKA2tleRgBIAEoEBINCgV2YWx1ZRgCIAEoEDoCOAEaNAoSTWFwSW50",
+            "MzJGbG9hdEVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoAjoCOAEa",
+            "NQoTTWFwSW50MzJEb3VibGVFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUY",
+            "AiABKAE6AjgBGjIKEE1hcEJvb2xCb29sRW50cnkSCwoDa2V5GAEgASgIEg0K",
+            "BXZhbHVlGAIgASgIOgI4ARo2ChRNYXBTdHJpbmdTdHJpbmdFbnRyeRILCgNr",
+            "ZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGjUKE01hcFN0cmluZ0J5dGVz",
+            "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgMOgI4ARpmChtNYXBT",
+            "dHJpbmdOZXN0ZWRNZXNzYWdlRW50cnkSCwoDa2V5GAEgASgJEjYKBXZhbHVl",
+            "GAIgASgLMicuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk5lc3RlZE1lc3Nh",
+            "Z2U6AjgBGlsKHE1hcFN0cmluZ0ZvcmVpZ25NZXNzYWdlRW50cnkSCwoDa2V5",
+            "GAEgASgJEioKBXZhbHVlGAIgASgLMhsuY29uZm9ybWFuY2UuRm9yZWlnbk1l",
+            "c3NhZ2U6AjgBGmAKGE1hcFN0cmluZ05lc3RlZEVudW1FbnRyeRILCgNrZXkY",
+            "ASABKAkSMwoFdmFsdWUYAiABKA4yJC5jb25mb3JtYW5jZS5UZXN0QWxsVHlw",
+            "ZXMuTmVzdGVkRW51bToCOAEaVQoZTWFwU3RyaW5nRm9yZWlnbkVudW1FbnRy",
+            "eRILCgNrZXkYASABKAkSJwoFdmFsdWUYAiABKA4yGC5jb25mb3JtYW5jZS5G",
+            "b3JlaWduRW51bToCOAEiOQoKTmVzdGVkRW51bRIHCgNGT08QABIHCgNCQVIQ",
+            "ARIHCgNCQVoQAhIQCgNORUcQ////////////AUINCgtvbmVvZl9maWVsZCIb",
+            "Cg5Gb3JlaWduTWVzc2FnZRIJCgFjGAEgASgFKjUKCldpcmVGb3JtYXQSDwoL",
+            "VU5TUEVDSUZJRUQQABIMCghQUk9UT0JVRhABEggKBEpTT04QAipACgtGb3Jl",
+            "aWduRW51bRIPCgtGT1JFSUdOX0ZPTxAAEg8KC0ZPUkVJR05fQkFSEAESDwoL",
+            "Rk9SRUlHTl9CQVoQAkIhCh9jb20uZ29vZ2xlLnByb3RvYnVmLmNvbmZvcm1h",
+            "bmNlYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.ForeignEnum), }, new pbr::GeneratedClrTypeInfo[] {
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat" }, new[]{ "Payload" }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes), global::Conformance.TestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OptionalBoolWrapper", "OptionalInt32Wrapper", "OptionalInt64Wrapper", "OptionalUint32Wrapper", "OptionalUint64Wrapper", "OptionalFloatWrapper", "OptionalDoubleWrapper", "OptionalStringWrapper", "OptionalBytesWrapper", "RepeatedBoolWrapper", "RepeatedInt32Wrapper", "RepeatedInt64Wrapper", "RepeatedUint32Wrapper", "RepeatedUint64Wrapper", "RepeatedFloatWrapper", "RepeatedDoubleWrapper", "RepeatedStringWrapper", "RepeatedBytesWrapper", "OptionalDuration", "OptionalTimestamp", "OptionalFieldMask", "OptionalStruct", "OptionalAny", "OptionalValue", "RepeatedDuration", "RepeatedTimestamp", "RepeatedFieldmask", "RepeatedStruct", "RepeatedAny", "RepeatedValue", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12" }, new[]{ "OneofField" }, new[]{ typeof(global::Conformance.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes.Types.NestedMessage), global::Conformance.TestAllTypes.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes), global::Conformance.TestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "OptionalBoolWrapper", "OptionalInt32Wrapper", "OptionalInt64Wrapper", "OptionalUint32Wrapper", "OptionalUint64Wrapper", "OptionalFloatWrapper", "OptionalDoubleWrapper", "OptionalStringWrapper", "OptionalBytesWrapper", "RepeatedBoolWrapper", "RepeatedInt32Wrapper", "RepeatedInt64Wrapper", "RepeatedUint32Wrapper", "RepeatedUint64Wrapper", "RepeatedFloatWrapper", "RepeatedDoubleWrapper", "RepeatedStringWrapper", "RepeatedBytesWrapper", "OptionalDuration", "OptionalTimestamp", "OptionalFieldMask", "OptionalStruct", "OptionalAny", "OptionalValue", "RepeatedDuration", "RepeatedTimestamp", "RepeatedFieldmask", "RepeatedStruct", "RepeatedAny", "RepeatedValue", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::Conformance.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.TestAllTypes.Types.NestedMessage), global::Conformance.TestAllTypes.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null),
             null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ForeignMessage), global::Conformance.ForeignMessage.Parser, new[]{ "C" }, null, null, null)
           }));
@@ -890,6 +897,12 @@
       fieldName10_ = other.fieldName10_;
       fIELDNAME11_ = other.fIELDNAME11_;
       fIELDName12_ = other.fIELDName12_;
+      FieldName13_ = other.FieldName13_;
+      FieldName14_ = other.FieldName14_;
+      fieldName15_ = other.fieldName15_;
+      fieldName16_ = other.fieldName16_;
+      fieldName17_ = other.fieldName17_;
+      fieldName18_ = other.fieldName18_;
       switch (other.OneofFieldCase) {
         case OneofFieldOneofCase.OneofUint32:
           OneofUint32 = other.OneofUint32;
@@ -903,6 +916,21 @@
         case OneofFieldOneofCase.OneofBytes:
           OneofBytes = other.OneofBytes;
           break;
+        case OneofFieldOneofCase.OneofBool:
+          OneofBool = other.OneofBool;
+          break;
+        case OneofFieldOneofCase.OneofUint64:
+          OneofUint64 = other.OneofUint64;
+          break;
+        case OneofFieldOneofCase.OneofFloat:
+          OneofFloat = other.OneofFloat;
+          break;
+        case OneofFieldOneofCase.OneofDouble:
+          OneofDouble = other.OneofDouble;
+          break;
+        case OneofFieldOneofCase.OneofEnum:
+          OneofEnum = other.OneofEnum;
+          break;
       }
 
     }
@@ -1607,6 +1635,61 @@
       }
     }
 
+    /// <summary>Field number for the "oneof_bool" field.</summary>
+    public const int OneofBoolFieldNumber = 115;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool OneofBool {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBool ? (bool) oneofField_ : false; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofBool;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_uint64" field.</summary>
+    public const int OneofUint64FieldNumber = 116;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public ulong OneofUint64 {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint64 ? (ulong) oneofField_ : 0UL; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofUint64;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_float" field.</summary>
+    public const int OneofFloatFieldNumber = 117;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public float OneofFloat {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofFloat ? (float) oneofField_ : 0F; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofFloat;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_double" field.</summary>
+    public const int OneofDoubleFieldNumber = 118;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public double OneofDouble {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofDouble ? (double) oneofField_ : 0D; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofDouble;
+      }
+    }
+
+    /// <summary>Field number for the "oneof_enum" field.</summary>
+    public const int OneofEnumFieldNumber = 119;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public global::Conformance.TestAllTypes.Types.NestedEnum OneofEnum {
+      get { return oneofFieldCase_ == OneofFieldOneofCase.OneofEnum ? (global::Conformance.TestAllTypes.Types.NestedEnum) oneofField_ : 0; }
+      set {
+        oneofField_ = value;
+        oneofFieldCase_ = OneofFieldOneofCase.OneofEnum;
+      }
+    }
+
     /// <summary>Field number for the "optional_bool_wrapper" field.</summary>
     public const int OptionalBoolWrapperFieldNumber = 201;
     private static readonly pb::FieldCodec<bool?> _single_optionalBoolWrapper_codec = pb::FieldCodec.ForStructWrapper<bool>(1610);
@@ -1939,6 +2022,7 @@
     private int fieldname1_;
     /// <summary>
     ///  Test field-name-to-JSON-name convention.
+    ///  (protobuf says names can be any valid C/C++ identifier.)
     /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     public int Fieldname1 {
@@ -2069,6 +2153,72 @@
       }
     }
 
+    /// <summary>Field number for the "__field_name13" field.</summary>
+    public const int FieldName13FieldNumber = 413;
+    private int FieldName13_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName13 {
+      get { return FieldName13_; }
+      set {
+        FieldName13_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "__Field_name14" field.</summary>
+    public const int FieldName14FieldNumber = 414;
+    private int FieldName14_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName14 {
+      get { return FieldName14_; }
+      set {
+        FieldName14_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field__name15" field.</summary>
+    public const int FieldName15FieldNumber = 415;
+    private int fieldName15_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName15 {
+      get { return fieldName15_; }
+      set {
+        fieldName15_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field__Name16" field.</summary>
+    public const int FieldName16FieldNumber = 416;
+    private int fieldName16_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName16 {
+      get { return fieldName16_; }
+      set {
+        fieldName16_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_name17__" field.</summary>
+    public const int FieldName17FieldNumber = 417;
+    private int fieldName17_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName17 {
+      get { return fieldName17_; }
+      set {
+        fieldName17_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "Field_name18__" field.</summary>
+    public const int FieldName18FieldNumber = 418;
+    private int fieldName18_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int FieldName18 {
+      get { return fieldName18_; }
+      set {
+        fieldName18_ = value;
+      }
+    }
+
     private object oneofField_;
     /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
     public enum OneofFieldOneofCase {
@@ -2077,6 +2227,11 @@
       OneofNestedMessage = 112,
       OneofString = 113,
       OneofBytes = 114,
+      OneofBool = 115,
+      OneofUint64 = 116,
+      OneofFloat = 117,
+      OneofDouble = 118,
+      OneofEnum = 119,
     }
     private OneofFieldOneofCase oneofFieldCase_ = OneofFieldOneofCase.None;
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -2169,6 +2324,11 @@
       if (!object.Equals(OneofNestedMessage, other.OneofNestedMessage)) return false;
       if (OneofString != other.OneofString) return false;
       if (OneofBytes != other.OneofBytes) return false;
+      if (OneofBool != other.OneofBool) return false;
+      if (OneofUint64 != other.OneofUint64) return false;
+      if (OneofFloat != other.OneofFloat) return false;
+      if (OneofDouble != other.OneofDouble) return false;
+      if (OneofEnum != other.OneofEnum) return false;
       if (OptionalBoolWrapper != other.OptionalBoolWrapper) return false;
       if (OptionalInt32Wrapper != other.OptionalInt32Wrapper) return false;
       if (OptionalInt64Wrapper != other.OptionalInt64Wrapper) return false;
@@ -2211,6 +2371,12 @@
       if (FieldName10 != other.FieldName10) return false;
       if (FIELDNAME11 != other.FIELDNAME11) return false;
       if (FIELDName12 != other.FIELDName12) return false;
+      if (FieldName13 != other.FieldName13) return false;
+      if (FieldName14 != other.FieldName14) return false;
+      if (FieldName15 != other.FieldName15) return false;
+      if (FieldName16 != other.FieldName16) return false;
+      if (FieldName17 != other.FieldName17) return false;
+      if (FieldName18 != other.FieldName18) return false;
       if (OneofFieldCase != other.OneofFieldCase) return false;
       return true;
     }
@@ -2284,6 +2450,11 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) hash ^= OneofBool.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) hash ^= OneofUint64.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) hash ^= OneofFloat.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) hash ^= OneofDouble.GetHashCode();
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) hash ^= OneofEnum.GetHashCode();
       if (optionalBoolWrapper_ != null) hash ^= OptionalBoolWrapper.GetHashCode();
       if (optionalInt32Wrapper_ != null) hash ^= OptionalInt32Wrapper.GetHashCode();
       if (optionalInt64Wrapper_ != null) hash ^= OptionalInt64Wrapper.GetHashCode();
@@ -2326,6 +2497,12 @@
       if (FieldName10 != 0) hash ^= FieldName10.GetHashCode();
       if (FIELDNAME11 != 0) hash ^= FIELDNAME11.GetHashCode();
       if (FIELDName12 != 0) hash ^= FIELDName12.GetHashCode();
+      if (FieldName13 != 0) hash ^= FieldName13.GetHashCode();
+      if (FieldName14 != 0) hash ^= FieldName14.GetHashCode();
+      if (FieldName15 != 0) hash ^= FieldName15.GetHashCode();
+      if (FieldName16 != 0) hash ^= FieldName16.GetHashCode();
+      if (FieldName17 != 0) hash ^= FieldName17.GetHashCode();
+      if (FieldName18 != 0) hash ^= FieldName18.GetHashCode();
       hash ^= (int) oneofFieldCase_;
       return hash;
     }
@@ -2481,6 +2658,26 @@
         output.WriteRawTag(146, 7);
         output.WriteBytes(OneofBytes);
       }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) {
+        output.WriteRawTag(152, 7);
+        output.WriteBool(OneofBool);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) {
+        output.WriteRawTag(160, 7);
+        output.WriteUInt64(OneofUint64);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) {
+        output.WriteRawTag(173, 7);
+        output.WriteFloat(OneofFloat);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) {
+        output.WriteRawTag(177, 7);
+        output.WriteDouble(OneofDouble);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) {
+        output.WriteRawTag(184, 7);
+        output.WriteEnum((int) OneofEnum);
+      }
       if (optionalBoolWrapper_ != null) {
         _single_optionalBoolWrapper_codec.WriteTagAndValue(output, OptionalBoolWrapper);
       }
@@ -2595,6 +2792,30 @@
         output.WriteRawTag(224, 25);
         output.WriteInt32(FIELDName12);
       }
+      if (FieldName13 != 0) {
+        output.WriteRawTag(232, 25);
+        output.WriteInt32(FieldName13);
+      }
+      if (FieldName14 != 0) {
+        output.WriteRawTag(240, 25);
+        output.WriteInt32(FieldName14);
+      }
+      if (FieldName15 != 0) {
+        output.WriteRawTag(248, 25);
+        output.WriteInt32(FieldName15);
+      }
+      if (FieldName16 != 0) {
+        output.WriteRawTag(128, 26);
+        output.WriteInt32(FieldName16);
+      }
+      if (FieldName17 != 0) {
+        output.WriteRawTag(136, 26);
+        output.WriteInt32(FieldName17);
+      }
+      if (FieldName18 != 0) {
+        output.WriteRawTag(144, 26);
+        output.WriteInt32(FieldName18);
+      }
     }
 
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -2718,6 +2939,21 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
         size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
       }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) {
+        size += 2 + 1;
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) {
+        size += 2 + pb::CodedOutputStream.ComputeUInt64Size(OneofUint64);
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) {
+        size += 2 + 4;
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) {
+        size += 2 + 8;
+      }
+      if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) {
+        size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OneofEnum);
+      }
       if (optionalBoolWrapper_ != null) {
         size += _single_optionalBoolWrapper_codec.CalculateSizeWithTag(OptionalBoolWrapper);
       }
@@ -2814,6 +3050,24 @@
       if (FIELDName12 != 0) {
         size += 2 + pb::CodedOutputStream.ComputeInt32Size(FIELDName12);
       }
+      if (FieldName13 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName13);
+      }
+      if (FieldName14 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName14);
+      }
+      if (FieldName15 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName15);
+      }
+      if (FieldName16 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName16);
+      }
+      if (FieldName17 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName17);
+      }
+      if (FieldName18 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName18);
+      }
       return size;
     }
 
@@ -3069,6 +3323,24 @@
       if (other.FIELDName12 != 0) {
         FIELDName12 = other.FIELDName12;
       }
+      if (other.FieldName13 != 0) {
+        FieldName13 = other.FieldName13;
+      }
+      if (other.FieldName14 != 0) {
+        FieldName14 = other.FieldName14;
+      }
+      if (other.FieldName15 != 0) {
+        FieldName15 = other.FieldName15;
+      }
+      if (other.FieldName16 != 0) {
+        FieldName16 = other.FieldName16;
+      }
+      if (other.FieldName17 != 0) {
+        FieldName17 = other.FieldName17;
+      }
+      if (other.FieldName18 != 0) {
+        FieldName18 = other.FieldName18;
+      }
       switch (other.OneofFieldCase) {
         case OneofFieldOneofCase.OneofUint32:
           OneofUint32 = other.OneofUint32;
@@ -3082,6 +3354,21 @@
         case OneofFieldOneofCase.OneofBytes:
           OneofBytes = other.OneofBytes;
           break;
+        case OneofFieldOneofCase.OneofBool:
+          OneofBool = other.OneofBool;
+          break;
+        case OneofFieldOneofCase.OneofUint64:
+          OneofUint64 = other.OneofUint64;
+          break;
+        case OneofFieldOneofCase.OneofFloat:
+          OneofFloat = other.OneofFloat;
+          break;
+        case OneofFieldOneofCase.OneofDouble:
+          OneofDouble = other.OneofDouble;
+          break;
+        case OneofFieldOneofCase.OneofEnum:
+          OneofEnum = other.OneofEnum;
+          break;
       }
 
     }
@@ -3387,6 +3674,27 @@
             OneofBytes = input.ReadBytes();
             break;
           }
+          case 920: {
+            OneofBool = input.ReadBool();
+            break;
+          }
+          case 928: {
+            OneofUint64 = input.ReadUInt64();
+            break;
+          }
+          case 941: {
+            OneofFloat = input.ReadFloat();
+            break;
+          }
+          case 945: {
+            OneofDouble = input.ReadDouble();
+            break;
+          }
+          case 952: {
+            oneofField_ = input.ReadEnum();
+            oneofFieldCase_ = OneofFieldOneofCase.OneofEnum;
+            break;
+          }
           case 1610: {
             bool? value = _single_optionalBoolWrapper_codec.Read(input);
             if (optionalBoolWrapper_ == null || value != false) {
@@ -3600,6 +3908,30 @@
             FIELDName12 = input.ReadInt32();
             break;
           }
+          case 3304: {
+            FieldName13 = input.ReadInt32();
+            break;
+          }
+          case 3312: {
+            FieldName14 = input.ReadInt32();
+            break;
+          }
+          case 3320: {
+            FieldName15 = input.ReadInt32();
+            break;
+          }
+          case 3328: {
+            FieldName16 = input.ReadInt32();
+            break;
+          }
+          case 3336: {
+            FieldName17 = input.ReadInt32();
+            break;
+          }
+          case 3344: {
+            FieldName18 = input.ReadInt32();
+            break;
+          }
         }
       }
     }
diff --git a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
deleted file mode 100644
index 82f728d..0000000
--- a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{0607D1B8-80D6-4B35-9857-1263C1B32B94}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Google.Protobuf.Conformance</RootNamespace>
-    <AssemblyName>Google.Protobuf.Conformance</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="Microsoft.CSharp" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Conformance.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">
-      <Project>{6908bdce-d925-43f3-94ac-a531e6df2591}</Project>
-      <Name>Google.Protobuf</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.xproj b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.xproj
new file mode 100644
index 0000000..99ff146
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>dddc055b-e185-4181-bab0-072f0f984569</ProjectGuid>
+    <RootNamespace>Google.Protobuf.Conformance</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Conformance/project.json b/csharp/src/Google.Protobuf.Conformance/project.json
new file mode 100644
index 0000000..84b23c4
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Conformance/project.json
@@ -0,0 +1,19 @@
+{
+  "buildOptions": {
+    "debugType": "portable",
+    "emitEntryPoint": true
+  },
+  "dependencies": {
+    "Google.Protobuf": { "target": "project" }
+  },
+  "frameworks": {
+    "netcoreapp1.0": {
+      "dependencies": {
+        "Microsoft.NETCore.App": {
+          "type": "platform",
+          "version": "1.0.0"
+        }
+      }
+    }
+  }
+}
diff --git a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
deleted file mode 100644
index ede1f77..0000000
--- a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{D7282E99-2DC3-405B-946F-177DB2FD2AE2}</ProjectGuid>

-    <OutputType>Exe</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>Google.Protobuf.JsonDump</RootNamespace>

-    <AssemblyName>Google.Protobuf.JsonDump</AssemblyName>

-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <TargetFrameworkProfile>

-    </TargetFrameworkProfile>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug</OutputPath>

-    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release</OutputPath>

-    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="mscorlib" />

-    <Reference Include="System" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="Program.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

-      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

-      <Name>Google.Protobuf</Name>

-    </ProjectReference>

-  </ItemGroup>

-  <ItemGroup>

-    <None Include="app.config" />

-  </ItemGroup>

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

-</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.xproj b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.xproj
new file mode 100644
index 0000000..27095be
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>9695e08f-9829-497d-b95c-b38f28d48690</ProjectGuid>
+    <RootNamespace>Google.Protobuf.JsonDump</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.JsonDump/Program.cs b/csharp/src/Google.Protobuf.JsonDump/Program.cs
index 99e60e9..296b2f3 100644
--- a/csharp/src/Google.Protobuf.JsonDump/Program.cs
+++ b/csharp/src/Google.Protobuf.JsonDump/Program.cs
@@ -32,6 +32,7 @@
 

 using System;

 using System.IO;

+using System.Reflection;

 

 namespace Google.Protobuf.ProtoDump

 {

@@ -55,7 +56,7 @@
                 Console.Error.WriteLine("Unable to load type {0}.", args[0]);

                 return 1;

             }

-            if (!typeof(IMessage).IsAssignableFrom(type))

+            if (!typeof(IMessage).GetTypeInfo().IsAssignableFrom(type))

             {

                 Console.Error.WriteLine("Type {0} doesn't implement IMessage.", args[0]);

                 return 1;

diff --git a/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs
deleted file mode 100644
index d980b01..0000000
--- a/csharp/src/Google.Protobuf.JsonDump/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Reflection;

-using System.Runtime.CompilerServices;

-using System.Runtime.InteropServices;

-

-// General Information about an assembly is controlled through the following 

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-

-[assembly: AssemblyTitle("ProtoDump")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("ProtoDump")]

-[assembly: AssemblyCopyright("Copyright ©  2015")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-[assembly: AssemblyVersion("3.0.0.0")]

-[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/Google.Protobuf.JsonDump/app.config b/csharp/src/Google.Protobuf.JsonDump/app.config
deleted file mode 100644
index 51278a4..0000000
--- a/csharp/src/Google.Protobuf.JsonDump/app.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
diff --git a/csharp/src/Google.Protobuf.JsonDump/project.json b/csharp/src/Google.Protobuf.JsonDump/project.json
new file mode 100644
index 0000000..84b23c4
--- /dev/null
+++ b/csharp/src/Google.Protobuf.JsonDump/project.json
@@ -0,0 +1,19 @@
+{
+  "buildOptions": {
+    "debugType": "portable",
+    "emitEntryPoint": true
+  },
+  "dependencies": {
+    "Google.Protobuf": { "target": "project" }
+  },
+  "frameworks": {
+    "netcoreapp1.0": {
+      "dependencies": {
+        "Microsoft.NETCore.App": {
+          "type": "platform",
+          "version": "1.0.0"
+        }
+      }
+    }
+  }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
index 8ed54cf..6852f75 100644
--- a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
@@ -75,10 +75,96 @@
         }
 
         [Test]
-        public void Add_RepeatedField()
+        public void AddRange_SlowPath()
+        {
+            var list = new RepeatedField<string>();
+            list.AddRange(new[] { "foo", "bar" }.Select(x => x));
+            Assert.AreEqual(2, list.Count);
+            Assert.AreEqual("foo", list[0]);
+            Assert.AreEqual("bar", list[1]);
+        }
+
+        [Test]
+        public void AddRange_SlowPath_NullsProhibited_ReferenceType()
+        {
+            var list = new RepeatedField<string>();
+            // It's okay for this to throw ArgumentNullException if necessary.
+            // It's not ideal, but not awful.
+            Assert.Catch<ArgumentException>(() => list.AddRange(new[] { "foo", null }.Select(x => x)));
+        }
+
+        [Test]
+        public void AddRange_SlowPath_NullsProhibited_NullableValueType()
+        {
+            var list = new RepeatedField<int?>();
+            // It's okay for this to throw ArgumentNullException if necessary.
+            // It's not ideal, but not awful.
+            Assert.Catch<ArgumentException>(() => list.AddRange(new[] { 20, (int?)null }.Select(x => x)));
+        }
+
+        [Test]
+        public void AddRange_Optimized_NonNullableValueType()
+        {
+            var list = new RepeatedField<int>();
+            list.AddRange(new List<int> { 20, 30 });
+            Assert.AreEqual(2, list.Count);
+            Assert.AreEqual(20, list[0]);
+            Assert.AreEqual(30, list[1]);
+        }
+
+        [Test]
+        public void AddRange_Optimized_ReferenceType()
+        {
+            var list = new RepeatedField<string>();
+            list.AddRange(new List<string> { "foo", "bar" });
+            Assert.AreEqual(2, list.Count);
+            Assert.AreEqual("foo", list[0]);
+            Assert.AreEqual("bar", list[1]);
+        }
+
+        [Test]
+        public void AddRange_Optimized_NullableValueType()
+        {
+            var list = new RepeatedField<int?>();
+            list.AddRange(new List<int?> { 20, 30 });
+            Assert.AreEqual(2, list.Count);
+            Assert.AreEqual((int?) 20, list[0]);
+            Assert.AreEqual((int?) 30, list[1]);
+        }
+
+        [Test]
+        public void AddRange_Optimized_NullsProhibited_ReferenceType()
+        {
+            // We don't just trust that a collection with a nullable element type doesn't contain nulls
+            var list = new RepeatedField<string>();
+            // It's okay for this to throw ArgumentNullException if necessary.
+            // It's not ideal, but not awful.
+            Assert.Catch<ArgumentException>(() => list.AddRange(new List<string> { "foo", null }));
+        }
+
+        [Test]
+        public void AddRange_Optimized_NullsProhibited_NullableValueType()
+        {
+            // We don't just trust that a collection with a nullable element type doesn't contain nulls
+            var list = new RepeatedField<int?>();
+            // It's okay for this to throw ArgumentNullException if necessary.
+            // It's not ideal, but not awful.
+            Assert.Catch<ArgumentException>(() => list.AddRange(new List<int?> { 20, null }));
+        }
+
+        [Test]
+        public void AddRange_AlreadyNotEmpty()
+        {
+            var list = new RepeatedField<int> { 1, 2, 3 };
+            list.AddRange(new List<int> { 4, 5, 6 });
+            CollectionAssert.AreEqual(new[] { 1, 2, 3, 4, 5, 6 }, list);
+        }
+
+        [Test]
+        public void AddRange_RepeatedField()
         {
             var list = new RepeatedField<string> { "original" };
-            list.Add(new RepeatedField<string> { "foo", "bar" });
+            list.AddRange(new RepeatedField<string> { "foo", "bar" });
             Assert.AreEqual(3, list.Count);
             Assert.AreEqual("original", list[0]);
             Assert.AreEqual("foo", list[1]);
diff --git a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
index c616470..0e2bad5 100644
--- a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
+++ b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
@@ -32,6 +32,7 @@
 
 using System.Collections.Generic;
 using System.IO;
+using System.Reflection;
 using Google.Protobuf.TestProtos;
 using NUnit.Framework;
 
@@ -162,7 +163,7 @@
                 codedOutput.Flush();
                 Assert.AreEqual(0, stream.Position);
                 Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
-                if (typeof(T).IsValueType)
+                if (typeof(T).GetTypeInfo().IsValueType)
                 {
                     Assert.AreEqual(default(T), codec.DefaultValue);
                 }
diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
deleted file mode 100644
index 4f37c5e..0000000
--- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{DD01ED24-3750-4567-9A23-1DB676A15610}</ProjectGuid>

-    <OutputType>Library</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>Google.Protobuf</RootNamespace>

-    <AssemblyName>Google.Protobuf.Test</AssemblyName>

-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <TargetFrameworkProfile>

-    </TargetFrameworkProfile>

-    <NuGetPackageImportStamp>

-    </NuGetPackageImportStamp>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug</OutputPath>

-    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

-    <DefineConstants>DEBUG;TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release</OutputPath>

-    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

-    <DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\ReleaseSigned</OutputPath>

-    <IntermediateOutputPath>obj\ReleaseSigned\</IntermediateOutputPath>

-    <DefineConstants>TRACE;$(EnvironmentFlavor);$(EnvironmentTemplate)</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <Prefer32Bit>false</Prefer32Bit>

-    <SignAssembly>True</SignAssembly>

-    <AssemblyOriginatorKeyFile>..\..\keys\Google.Protobuf.snk</AssemblyOriginatorKeyFile>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="mscorlib" />

-    <Reference Include="nunit.core, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

-      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath>

-      <Private>True</Private>

-    </Reference>

-    <Reference Include="nunit.core.interfaces, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

-      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath>

-      <Private>True</Private>

-    </Reference>

-    <Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

-      <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>

-      <Private>True</Private>

-    </Reference>

-    <Reference Include="nunit.util, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">

-      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath>

-      <Private>True</Private>

-    </Reference>

-    <Reference Include="NUnit.VisualStudio.TestAdapter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac, processorArchitecture=MSIL">

-      <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>

-      <Private>True</Private>

-    </Reference>

-    <Reference Include="System" />

-    <Reference Include="System.Xml" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="ByteStringTest.cs" />

-    <Compile Include="CodedInputStreamExtensions.cs" />

-    <Compile Include="CodedInputStreamTest.cs" />

-    <Compile Include="CodedOutputStreamTest.cs" />

-    <Compile Include="Compatibility\PropertyInfoExtensionsTest.cs" />

-    <Compile Include="Compatibility\TypeExtensionsTest.cs" />

-    <Compile Include="EqualityTester.cs" />

-    <Compile Include="FieldCodecTest.cs" />

-    <Compile Include="GeneratedMessageTest.cs" />

-    <Compile Include="Collections\MapFieldTest.cs" />

-    <Compile Include="Collections\RepeatedFieldTest.cs" />

-    <Compile Include="JsonFormatterTest.cs" />

-    <Compile Include="JsonParserTest.cs" />

-    <Compile Include="JsonTokenizerTest.cs" />

-    <Compile Include="Reflection\DescriptorsTest.cs" />

-    <Compile Include="Reflection\FieldAccessTest.cs" />

-    <Compile Include="Reflection\TypeRegistryTest.cs" />

-    <Compile Include="SampleEnum.cs" />

-    <Compile Include="SampleMessages.cs" />

-    <Compile Include="TestProtos\ForeignMessagePartial.cs" />

-    <Compile Include="TestProtos\MapUnittestProto3.cs" />

-    <Compile Include="TestProtos\UnittestImportProto3.cs" />

-    <Compile Include="TestProtos\UnittestImportPublicProto3.cs" />

-    <Compile Include="TestProtos\UnittestIssues.cs" />

-    <Compile Include="TestProtos\UnittestProto3.cs" />

-    <Compile Include="DeprecatedMemberTest.cs" />

-    <Compile Include="IssuesTest.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="TestCornerCases.cs" />

-    <Compile Include="TestProtos\UnittestWellKnownTypes.cs" />

-    <Compile Include="WellKnownTypes\AnyTest.cs" />

-    <Compile Include="WellKnownTypes\DurationTest.cs" />

-    <Compile Include="WellKnownTypes\FieldMaskTest.cs" />

-    <Compile Include="WellKnownTypes\TimestampTest.cs" />

-    <Compile Include="WellKnownTypes\WrappersTest.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj">

-      <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>

-      <Name>Google.Protobuf</Name>

-    </ProjectReference>

-  </ItemGroup>

-  <ItemGroup>

-    <None Include="packages.config" />

-  </ItemGroup>

-  <ItemGroup>

-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

-  </ItemGroup>

-  <ItemGroup />

-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

-</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.xproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.xproj
new file mode 100644
index 0000000..a9a1cc0
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>580eb013-d3c7-4578-b845-015f4a3b0591</ProjectGuid>
+    <RootNamespace>Google.Protobuf.Test</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
index 51b3ca2..261ac6a 100644
--- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
@@ -230,6 +230,12 @@
         [TestCase("foo_bar", "fooBar")]
         [TestCase("bananaBanana", "bananaBanana")]
         [TestCase("BANANABanana", "bananaBanana")]
+        [TestCase("simple", "simple")]
+        [TestCase("ACTION_AND_ADVENTURE", "actionAndAdventure")]
+        [TestCase("action_and_adventure", "actionAndAdventure")]
+        [TestCase("kFoo", "kFoo")]
+        [TestCase("HTTPServer", "httpServer")]
+        [TestCase("CLIENT", "client")]
         public void ToCamelCase(string original, string expected)
         {
             Assert.AreEqual(expected, JsonFormatter.ToCamelCase(original));
diff --git a/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml b/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml
deleted file mode 100644
index a955232..0000000
--- a/csharp/src/Google.Protobuf.Test/Properties/AppManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"

-        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

->

-    <Deployment.Parts>

-    </Deployment.Parts>

-</Deployment>

diff --git a/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs
deleted file mode 100644
index d00acf8..0000000
--- a/csharp/src/Google.Protobuf.Test/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;

-using System.Reflection;

-using System.Runtime.CompilerServices;

-using System.Runtime.InteropServices;

-

-// General Information about an assembly is controlled through the following 

-// set of attributes. Change these attribute values to modify the information

-// associated with an assembly.

-

-[assembly: AssemblyTitle("Google.Protobuf.Test")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("Google.Protobuf.Test")]

-[assembly: AssemblyCopyright("Copyright ©  2015")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

-[assembly: AssemblyVersion("3.0.0.0")]

-[assembly: AssemblyFileVersion("3.0.0.0")]

diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
index f21be7d..4aecc99 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
@@ -96,7 +96,7 @@
             var message = SampleMessages.CreateFullTestAllTypes();
             var any = Any.Pack(message);
             var text = any.ToString();
-            Assert.That(text, Is.StringContaining("\"@value\": \"" + message.ToByteString().ToBase64() + "\""));
+            Assert.That(text, Does.Contain("\"@value\": \"" + message.ToByteString().ToBase64() + "\""));
         }
 
         [Test]
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
index 89bc827..1d9908b 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
@@ -46,8 +46,8 @@
             var mask = new FieldMask { Paths = { input } };
             var text = mask.ToString();
             // More specific test below
-            Assert.That(text, Is.StringContaining("@warning"));
-            Assert.That(text, Is.StringContaining(input));
+            Assert.That(text, Does.Contain("@warning"));
+            Assert.That(text, Does.Contain(input));
         }
 
         [Test]
diff --git a/csharp/src/Google.Protobuf.Test/packages.config b/csharp/src/Google.Protobuf.Test/packages.config
deleted file mode 100644
index c765399..0000000
--- a/csharp/src/Google.Protobuf.Test/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="NUnit" version="2.6.4" targetFramework="net45" userInstalled="true" />
-  <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" userInstalled="true" />
-</packages>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/project.json b/csharp/src/Google.Protobuf.Test/project.json
new file mode 100644
index 0000000..87b732c
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/project.json
@@ -0,0 +1,44 @@
+{
+  "buildOptions": {
+    "debugType": "portable",
+    "keyFile": "../../keys/Google.Protobuf.snk"
+  },
+
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "define": [ "DEBUG", "TRACE" ]
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "define": [ "RELEASE", "TRACE" ],
+        "optimize": true
+      }
+    }
+  },
+
+  "dependencies": {
+    "Google.Protobuf": { "target": "project" },
+    "NUnit": "3.4.0",
+    "dotnet-test-nunit": "3.4.0-alpha-2",
+  },
+
+  "testRunner": "nunit",
+
+  "frameworks": {
+    "netcoreapp1.0": {
+      "imports" : [ "dnxcore50", "netcoreapp1.0", "portable-net45+win8" ],
+      "buildOptions": {
+        "define": [ "PCL" ]
+      },
+      "dependencies": {
+        "Microsoft.NETCore.App": { 
+          "version": "1.0.0",
+          "type": "platform"
+        },
+        "System.Console": "4.0.0"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.sln b/csharp/src/Google.Protobuf.sln
index 72d87f7..3c62bba 100644
--- a/csharp/src/Google.Protobuf.sln
+++ b/csharp/src/Google.Protobuf.sln
@@ -1,54 +1,43 @@
 Microsoft Visual Studio Solution File, Format Version 12.00

-# Visual Studio 2015

-VisualStudioVersion = 14.0.24720.0

+# Visual Studio 14

+VisualStudioVersion = 14.0.25420.1

 MinimumVisualStudioVersion = 14.0.24720.0

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf", "Google.Protobuf\Google.Protobuf.csproj", "{6908BDCE-D925-43F3-94AC-A531E6DF2591}"

+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AddressBook", "AddressBook\AddressBook.xproj", "{AFB63919-1E05-43B4-802A-8FB8C9B2F463}"

 EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Test", "Google.Protobuf.Test\Google.Protobuf.Test.csproj", "{DD01ED24-3750-4567-9A23-1DB676A15610}"

+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Google.Protobuf", "Google.Protobuf\Google.Protobuf.xproj", "{9B576380-726D-4142-8238-60A43AB0E35A}"

 EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddressBook", "AddressBook\AddressBook.csproj", "{A31F5FB2-4FF3-432A-B35B-5CD203606311}"

+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Google.Protobuf.Test", "Google.Protobuf.Test\Google.Protobuf.Test.xproj", "{580EB013-D3C7-4578-B845-015F4A3B0591}"

 EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.JsonDump", "Google.Protobuf.JsonDump\Google.Protobuf.JsonDump.csproj", "{D7282E99-2DC3-405B-946F-177DB2FD2AE2}"

+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Google.Protobuf.Conformance", "Google.Protobuf.Conformance\Google.Protobuf.Conformance.xproj", "{DDDC055B-E185-4181-BAB0-072F0F984569}"

 EndProject

-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Conformance", "Google.Protobuf.Conformance\Google.Protobuf.Conformance.csproj", "{0607D1B8-80D6-4B35-9857-1263C1B32B94}"

+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Google.Protobuf.JsonDump", "Google.Protobuf.JsonDump\Google.Protobuf.JsonDump.xproj", "{9695E08F-9829-497D-B95C-B38F28D48690}"

 EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Debug|Any CPU = Debug|Any CPU

 		Release|Any CPU = Release|Any CPU

-		ReleaseSigned|Any CPU = ReleaseSigned|Any CPU

 	EndGlobalSection

 	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.Release|Any CPU.Build.0 = Release|Any CPU

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU

-		{6908BDCE-D925-43F3-94AC-A531E6DF2591}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.Release|Any CPU.Build.0 = Release|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU

-		{DD01ED24-3750-4567-9A23-1DB676A15610}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.Release|Any CPU.Build.0 = Release|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

-		{A31F5FB2-4FF3-432A-B35B-5CD203606311}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.Release|Any CPU.Build.0 = Release|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

-		{D7282E99-2DC3-405B-946F-177DB2FD2AE2}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Debug|Any CPU.Build.0 = Debug|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Release|Any CPU.ActiveCfg = Release|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.Release|Any CPU.Build.0 = Release|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU

-		{0607D1B8-80D6-4B35-9857-1263C1B32B94}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU

+		{AFB63919-1E05-43B4-802A-8FB8C9B2F463}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{AFB63919-1E05-43B4-802A-8FB8C9B2F463}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{AFB63919-1E05-43B4-802A-8FB8C9B2F463}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{AFB63919-1E05-43B4-802A-8FB8C9B2F463}.Release|Any CPU.Build.0 = Release|Any CPU

+		{9B576380-726D-4142-8238-60A43AB0E35A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{9B576380-726D-4142-8238-60A43AB0E35A}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{9B576380-726D-4142-8238-60A43AB0E35A}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{9B576380-726D-4142-8238-60A43AB0E35A}.Release|Any CPU.Build.0 = Release|Any CPU

+		{580EB013-D3C7-4578-B845-015F4A3B0591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{580EB013-D3C7-4578-B845-015F4A3B0591}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{580EB013-D3C7-4578-B845-015F4A3B0591}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{580EB013-D3C7-4578-B845-015F4A3B0591}.Release|Any CPU.Build.0 = Release|Any CPU

+		{DDDC055B-E185-4181-BAB0-072F0F984569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{DDDC055B-E185-4181-BAB0-072F0F984569}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{DDDC055B-E185-4181-BAB0-072F0F984569}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{DDDC055B-E185-4181-BAB0-072F0F984569}.Release|Any CPU.Build.0 = Release|Any CPU

+		{9695E08F-9829-497D-B95C-B38F28D48690}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{9695E08F-9829-497D-B95C-B38F28D48690}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{9695E08F-9829-497D-B95C-B38F28D48690}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{9695E08F-9829-497D-B95C-B38F28D48690}.Release|Any CPU.Build.0 = Release|Any CPU

 	EndGlobalSection

 	GlobalSection(SolutionProperties) = preSolution

 		HideSolutionNode = FALSE

diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index ce6856d..072e2e1 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -612,9 +612,7 @@
         }

 

         /// <summary>

-        /// Reads an enum field value from the stream. If the enum is valid for type T,

-        /// then the ref value is set and it returns true.  Otherwise the unknown output

-        /// value is set and this method returns false.

+        /// Reads an enum field value from the stream.

         /// </summary>   

         public int ReadEnum()

         {

diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 053f755..537ce26 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -30,14 +30,13 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 
+using Google.Protobuf.Compatibility;
 using Google.Protobuf.Reflection;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Text;
-using Google.Protobuf.Compatibility;
 
 namespace Google.Protobuf.Collections
 {
@@ -113,7 +112,7 @@
             // Validation of arguments happens in ContainsKey and the indexer
             if (ContainsKey(key))
             {
-                throw new ArgumentException("Key already exists in map", "key");
+                throw new ArgumentException("Key already exists in map", nameof(key));
             }
             this[key] = value;
         }
@@ -125,7 +124,7 @@
         /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
         public bool ContainsKey(TKey key)
         {
-            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
             return map.ContainsKey(key);
         }
 
@@ -142,7 +141,7 @@
         /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
         public bool Remove(TKey key)
         {
-            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+            ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
             LinkedListNode<KeyValuePair<TKey, TValue>> node;
             if (map.TryGetValue(key, out node))
             {
@@ -190,7 +189,7 @@
         {
             get
             {
-                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
                 TValue value;
                 if (TryGetValue(key, out value))
                 {
@@ -200,11 +199,11 @@
             }
             set
             {
-                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
+                ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
                 // value == null check here is redundant, but avoids boxing.
                 if (value == null)
                 {
-                    ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
+                    ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
                 }
                 LinkedListNode<KeyValuePair<TKey, TValue>> node;
                 var pair = new KeyValuePair<TKey, TValue>(key, value);
@@ -236,7 +235,7 @@
         /// <param name="entries">The entries to add to the map.</param>
         public void Add(IDictionary<TKey, TValue> entries)
         {
-            ProtoPreconditions.CheckNotNull(entries, "entries");
+            ProtoPreconditions.CheckNotNull(entries, nameof(entries));
             foreach (var pair in entries)
             {
                 Add(pair.Key, pair.Value);
@@ -315,7 +314,7 @@
         {
             if (item.Key == null)
             {
-                throw new ArgumentException("Key is null", "item");
+                throw new ArgumentException("Key is null", nameof(item));
             }
             LinkedListNode<KeyValuePair<TKey, TValue>> node;
             if (map.TryGetValue(item.Key, out node) &&
@@ -503,7 +502,7 @@
 
         void IDictionary.Remove(object key)
         {
-            ProtoPreconditions.CheckNotNull(key, "key");
+            ProtoPreconditions.CheckNotNull(key, nameof(key));
             if (!(key is TKey))
             {
                 return;
@@ -532,7 +531,7 @@
         {
             get
             {
-                ProtoPreconditions.CheckNotNull(key, "key");
+                ProtoPreconditions.CheckNotNull(key, nameof(key));
                 if (!(key is TKey))
                 {
                     return null;
@@ -714,11 +713,11 @@
             {
                 if (arrayIndex < 0)
                 {
-                    throw new ArgumentOutOfRangeException("arrayIndex");
+                    throw new ArgumentOutOfRangeException(nameof(arrayIndex));
                 }
                 if (arrayIndex + Count  >= array.Length)
                 {
-                    throw new ArgumentException("Not enough space in the array", "array");
+                    throw new ArgumentException("Not enough space in the array", nameof(array));
                 }
                 foreach (var item in this)
                 {
@@ -745,11 +744,11 @@
             {
                 if (index < 0)
                 {
-                    throw new ArgumentOutOfRangeException("index");
+                    throw new ArgumentOutOfRangeException(nameof(index));
                 }
                 if (index + Count >= array.Length)
                 {
-                    throw new ArgumentException("Not enough space in the array", "array");
+                    throw new ArgumentException("Not enough space in the array", nameof(array));
                 }
                 foreach (var item in this)
                 {
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index d1db856..7bb5644 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -34,7 +34,6 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
-using System.Text;
 
 namespace Google.Protobuf.Collections
 {
@@ -227,10 +226,7 @@
         /// <param name="item">The item to add.</param>
         public void Add(T item)
         {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
-            }
+            ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
             EnsureSize(count + 1);
             array[count++] = item;
         }
@@ -285,42 +281,66 @@
         /// <summary>
         /// Gets the number of elements contained in the collection.
         /// </summary>
-        public int Count { get { return count; } }
+        public int Count => count;
 
         /// <summary>
         /// Gets a value indicating whether the collection is read-only.
         /// </summary>
-        public bool IsReadOnly { get { return false; } }
-
-        // TODO: Remove this overload and just handle it in the one below, at execution time?
+        public bool IsReadOnly => false;
 
         /// <summary>
         /// Adds all of the specified values into this collection.
         /// </summary>
         /// <param name="values">The values to add to this collection.</param>
-        public void Add(RepeatedField<T> values)
+        public void AddRange(IEnumerable<T> values)
         {
-            if (values == null)
-            {
-                throw new ArgumentNullException("values");
-            }
-            EnsureSize(count + values.count);
-            // We know that all the values will be valid, because it's a RepeatedField.
-            Array.Copy(values.array, 0, array, count, values.count);
-            count += values.count;
-        }
+            ProtoPreconditions.CheckNotNull(values, nameof(values));
 
-        /// <summary>
-        /// Adds all of the specified values into this collection.
-        /// </summary>
-        /// <param name="values">The values to add to this collection.</param>
-        public void Add(IEnumerable<T> values)
-        {
-            if (values == null)
+            // Optimization 1: If the collection we're adding is already a RepeatedField<T>,
+            // we know the values are valid.
+            var otherRepeatedField = values as RepeatedField<T>;
+            if (otherRepeatedField != null)
             {
-                throw new ArgumentNullException("values");
+                EnsureSize(count + otherRepeatedField.count);
+                Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
+                count += otherRepeatedField.count;
+                return;
             }
-            // TODO: Check for ICollection and get the Count, to optimize?
+
+            // Optimization 2: The collection is an ICollection, so we can expand
+            // just once and ask the collection to copy itself into the array.
+            var collection = values as ICollection;
+            if (collection != null)
+            {
+                var extraCount = collection.Count;
+                // For reference types and nullable value types, we need to check that there are no nulls
+                // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
+                // We expect the JITter to optimize this test to true/false, so it's effectively conditional
+                // specialization.
+                if (default(T) == null)
+                {
+                    // TODO: Measure whether iterating once to check and then letting the collection copy
+                    // itself is faster or slower than iterating and adding as we go. For large
+                    // collections this will not be great in terms of cache usage... but the optimized
+                    // copy may be significantly faster than doing it one at a time.
+                    foreach (var item in collection)
+                    {
+                        if (item == null)
+                        {
+                            throw new ArgumentException("Sequence contained null element", nameof(values));
+                        }
+                    }
+                }
+                EnsureSize(count + extraCount);
+                collection.CopyTo(array, count);
+                count += extraCount;
+                return;
+            }
+
+            // We *could* check for ICollection<T> as well, but very very few collections implement
+            // ICollection<T> but not ICollection. (HashSet<T> does, for one...)
+
+            // Fall back to a slower path of adding items one at a time.
             foreach (T item in values)
             {
                 Add(item);
@@ -328,6 +348,18 @@
         }
 
         /// <summary>
+        /// Adds all of the specified values into this collection. This method is present to
+        /// allow repeated fields to be constructed from queries within collection initializers.
+        /// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
+        /// method instead for clarity.
+        /// </summary>
+        /// <param name="values">The values to add to this collection.</param>
+        public void Add(IEnumerable<T> values)
+        {
+            AddRange(values);
+        }
+
+        /// <summary>
         /// Returns an enumerator that iterates through the collection.
         /// </summary>
         /// <returns>
@@ -418,10 +450,7 @@
         /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
         public int IndexOf(T item)
         {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
-            }
+            ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
             EqualityComparer<T> comparer = EqualityComparer<T>.Default;
             for (int i = 0; i < count; i++)
             {
@@ -440,13 +469,10 @@
         /// <param name="item">The item to insert.</param>
         public void Insert(int index, T item)
         {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
-            }
+            ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
             if (index < 0 || index > count)
             {
-                throw new ArgumentOutOfRangeException("index");
+                throw new ArgumentOutOfRangeException(nameof(index));
             }
             EnsureSize(count + 1);
             Array.Copy(array, index, array, index + 1, count - index);
@@ -462,7 +488,7 @@
         {
             if (index < 0 || index >= count)
             {
-                throw new ArgumentOutOfRangeException("index");
+                throw new ArgumentOutOfRangeException(nameof(index));
             }
             Array.Copy(array, index + 1, array, index, count - index - 1);
             count--;
@@ -494,7 +520,7 @@
             {
                 if (index < 0 || index >= count)
                 {
-                    throw new ArgumentOutOfRangeException("index");
+                    throw new ArgumentOutOfRangeException(nameof(index));
                 }
                 return array[index];
             }
@@ -502,27 +528,24 @@
             {
                 if (index < 0 || index >= count)
                 {
-                    throw new ArgumentOutOfRangeException("index");
+                    throw new ArgumentOutOfRangeException(nameof(index));
                 }
-                if (value == null)
-                {
-                    throw new ArgumentNullException("value");
-                }
+                ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
                 array[index] = value;
             }
         }
 
         #region Explicit interface implementation for IList and ICollection.
-        bool IList.IsFixedSize { get { return false; } }
+        bool IList.IsFixedSize => false;
 
         void ICollection.CopyTo(Array array, int index)
         {
             Array.Copy(this.array, 0, array, index, count);
         }
 
-        bool ICollection.IsSynchronized { get { return false; } }
+        bool ICollection.IsSynchronized => false;
 
-        object ICollection.SyncRoot { get { return this; } }
+        object ICollection.SyncRoot => this;
 
         object IList.this[int index]
         {
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
deleted file mode 100644
index 5557612..0000000
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ /dev/null
@@ -1,168 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

-  <PropertyGroup>

-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

-    <ProductVersion>9.0.30729</ProductVersion>

-    <SchemaVersion>2.0</SchemaVersion>

-    <ProjectGuid>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</ProjectGuid>

-    <OutputType>Library</OutputType>

-    <AppDesignerFolder>Properties</AppDesignerFolder>

-    <RootNamespace>Google.Protobuf</RootNamespace>

-    <AssemblyName>Google.Protobuf</AssemblyName>

-    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

-    <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>

-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

-    <FileAlignment>512</FileAlignment>

-    <OldToolsVersion>3.5</OldToolsVersion>

-    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>

-    <NuGetPackageImportStamp>

-    </NuGetPackageImportStamp>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

-    <DebugSymbols>true</DebugSymbols>

-    <DebugType>full</DebugType>

-    <Optimize>false</Optimize>

-    <OutputPath>bin\Debug</OutputPath>

-    <IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>

-    <DocumentationFile>bin\Debug\Google.Protobuf.xml</DocumentationFile>

-    <NoWarn>

-    </NoWarn>

-    <DefineConstants>DEBUG;TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\Release</OutputPath>

-    <IntermediateOutputPath>obj\Release\</IntermediateOutputPath>

-    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

-    <NoWarn>

-    </NoWarn>

-    <DefineConstants>TRACE</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

-  </PropertyGroup>

-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">

-    <DebugType>pdbonly</DebugType>

-    <Optimize>true</Optimize>

-    <OutputPath>bin\ReleaseSigned</OutputPath>

-    <IntermediateOutputPath>obj\ReleaseSigned\</IntermediateOutputPath>

-    <DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>

-    <NoWarn>

-    </NoWarn>

-    <DefineConstants>TRACE;SIGNED</DefineConstants>

-    <ErrorReport>prompt</ErrorReport>

-    <WarningLevel>4</WarningLevel>

-    <NoStdLib>true</NoStdLib>

-    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

-    <SignAssembly>True</SignAssembly>

-    <AssemblyOriginatorKeyFile>..\..\keys\Google.Protobuf.snk</AssemblyOriginatorKeyFile>

-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

-  </PropertyGroup>

-  <ItemGroup>

-    <Reference Include="mscorlib" />

-    <Reference Include="System" />

-    <Reference Include="System.Xml" />

-  </ItemGroup>

-  <ItemGroup>

-    <Compile Include="ByteArray.cs" />

-    <Compile Include="ByteString.cs" />

-    <Compile Include="CodedOutputStream.ComputeSize.cs" />

-    <Compile Include="CodedInputStream.cs" />

-    <Compile Include="CodedOutputStream.cs" />

-    <Compile Include="Collections\MapField.cs" />

-    <Compile Include="Collections\ReadOnlyDictionary.cs" />

-    <Compile Include="Collections\RepeatedField.cs" />

-    <Compile Include="Compatibility\PropertyInfoExtensions.cs" />

-    <Compile Include="Compatibility\TypeExtensions.cs" />

-    <Compile Include="FieldCodec.cs" />

-    <Compile Include="FrameworkPortability.cs" />

-    <Compile Include="ICustomDiagnosticMessage.cs" />

-    <Compile Include="IDeepCloneable.cs" />

-    <Compile Include="InvalidJsonException.cs" />

-    <Compile Include="JsonFormatter.cs" />

-    <Compile Include="JsonParser.cs" />

-    <Compile Include="JsonToken.cs" />

-    <Compile Include="JsonTokenizer.cs" />

-    <Compile Include="MessageExtensions.cs" />

-    <Compile Include="IMessage.cs" />

-    <Compile Include="InvalidProtocolBufferException.cs" />

-    <Compile Include="LimitedInputStream.cs" />

-    <Compile Include="MessageParser.cs" />

-    <Compile Include="Properties\AssemblyInfo.cs" />

-    <Compile Include="Reflection\Descriptor.cs" />

-    <Compile Include="Reflection\DescriptorBase.cs" />

-    <Compile Include="Reflection\DescriptorPool.cs" />

-    <Compile Include="Reflection\DescriptorUtil.cs" />

-    <Compile Include="Reflection\DescriptorValidationException.cs" />

-    <Compile Include="Reflection\EnumDescriptor.cs" />

-    <Compile Include="Reflection\EnumValueDescriptor.cs" />

-    <Compile Include="Reflection\FieldAccessorBase.cs" />

-    <Compile Include="Reflection\FieldDescriptor.cs" />

-    <Compile Include="Reflection\FieldType.cs" />

-    <Compile Include="Reflection\FileDescriptor.cs" />

-    <Compile Include="Reflection\GeneratedClrTypeInfo.cs" />

-    <Compile Include="Reflection\IDescriptor.cs" />

-    <Compile Include="Reflection\IFieldAccessor.cs" />

-    <Compile Include="Reflection\MapFieldAccessor.cs" />

-    <Compile Include="Reflection\MessageDescriptor.cs" />

-    <Compile Include="Reflection\MethodDescriptor.cs" />

-    <Compile Include="Reflection\OneofAccessor.cs" />

-    <Compile Include="Reflection\OneofDescriptor.cs" />

-    <Compile Include="Reflection\OriginalNameAttribute.cs" />

-    <Compile Include="Reflection\PackageDescriptor.cs" />

-    <Compile Include="Reflection\PartialClasses.cs" />

-    <Compile Include="Reflection\ReflectionUtil.cs" />

-    <Compile Include="Reflection\RepeatedFieldAccessor.cs" />

-    <Compile Include="Reflection\ServiceDescriptor.cs" />

-    <Compile Include="Reflection\SingleFieldAccessor.cs" />

-    <Compile Include="ProtoPreconditions.cs" />

-    <Compile Include="Reflection\TypeRegistry.cs" />

-    <Compile Include="WellKnownTypes\Any.cs" />

-    <Compile Include="WellKnownTypes\AnyPartial.cs" />

-    <Compile Include="WellKnownTypes\Api.cs" />

-    <Compile Include="WellKnownTypes\Duration.cs" />

-    <Compile Include="WellKnownTypes\DurationPartial.cs" />

-    <Compile Include="WellKnownTypes\Empty.cs" />

-    <Compile Include="WellKnownTypes\FieldMask.cs" />

-    <Compile Include="WellKnownTypes\FieldMaskPartial.cs" />

-    <Compile Include="WellKnownTypes\SourceContext.cs" />

-    <Compile Include="WellKnownTypes\Struct.cs" />

-    <Compile Include="WellKnownTypes\TimeExtensions.cs" />

-    <Compile Include="WellKnownTypes\Timestamp.cs" />

-    <Compile Include="WellKnownTypes\TimestampPartial.cs" />

-    <Compile Include="WellKnownTypes\Type.cs" />

-    <Compile Include="WellKnownTypes\ValuePartial.cs" />

-    <Compile Include="WellKnownTypes\Wrappers.cs" />

-    <Compile Include="WellKnownTypes\WrappersPartial.cs" />

-    <Compile Include="WireFormat.cs" />

-  </ItemGroup>

-  <ItemGroup>

-    <None Include="Google.Protobuf.nuspec" />

-    <None Include="packages.config" />

-  </ItemGroup>

-  <ItemGroup />

-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />

-  <Import Project="..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets" Condition="Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" />

-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

-    <PropertyGroup>

-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>

-    </PropertyGroup>

-    <Error Condition="!Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets'))" />

-  </Target>

-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

-       Other similar extension points exist, see Microsoft.Common.targets.

-  <Target Name="BeforeBuild">

-  </Target>

-  <Target Name="AfterBuild">

-  </Target>

-  -->

-</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
deleted file mode 100644
index 2aabf36..0000000
--- a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package>
-  <metadata>
-    <id>Google.Protobuf</id>
-    <title>Google Protocol Buffers C#</title>
-    <summary>C# runtime library for Protocol Buffers - Google's data interchange format.</summary>
-    <description>See project site for more info.</description>
-    <version>3.0.0-beta3</version>
-    <authors>Google Inc.</authors>
-    <owners>protobuf-packages</owners>
-    <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
-    <projectUrl>https://github.com/google/protobuf</projectUrl>
-    <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>C# proto3 support</releaseNotes>
-    <copyright>Copyright 2015, Google Inc.</copyright>
-    <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
-    <dependencies>
-      <!-- Dependencies for older, monolithic-assembly platforms -->
-      <group targetFramework="net45" />
-      <group targetFramework="wp8" />
-      <group targetFramework="win8" />
-      <group targetFramework="wpa81" />
-      <group targetFramework="xamarin.ios" />
-      <group targetFramework="monotouch" />
-      <group targetFramework="monoandroid" />
-      <!-- Dependencies for newer, more granular platforms (.NET Core etc) -->
-      <group targetFramework="dotnet">
-        <dependency id="System.Collections" version="4.0.0" />
-        <dependency id="System.Diagnostics.Debug" version="4.0.0" />
-        <dependency id="System.Globalization" version="4.0.0" />
-        <dependency id="System.IO" version="4.0.0" />
-        <dependency id="System.Linq" version="4.0.0" />
-        <dependency id="System.Linq.Expressions" version="4.0.0" />
-        <dependency id="System.ObjectModel" version="4.0.0" />
-        <dependency id="System.Reflection" version="4.0.0" />
-        <dependency id="System.Reflection.Extensions" version="4.0.0" />
-        <dependency id="System.Runtime" version="4.0.0" />
-        <dependency id="System.Runtime.Extensions" version="4.0.0" />
-        <dependency id="System.Text.Encoding" version="4.0.0" />
-        <dependency id="System.Text.RegularExpressions" version="4.0.0" />
-        <dependency id="System.Threading" version="4.0.0" />
-      </group>
-    </dependencies>
-  </metadata>
-  <files>
-    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" />
-    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" />
-    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" />
-    <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" />
-    <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
-    <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
-    <file src="**\*.cs" target="src" />
-  </files>
-</package>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.xproj b/csharp/src/Google.Protobuf/Google.Protobuf.xproj
new file mode 100644
index 0000000..c68e0db
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.xproj
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>9b576380-726d-4142-8238-60a43ab0e35a</ProjectGuid>
+    <RootNamespace>Google.Protobuf</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index a894ffa..d8a814d 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -274,7 +274,6 @@
         }
 
         // Converted from src/google/protobuf/util/internal/utility.cc ToCamelCase
-        // TODO: Use the new field in FieldDescriptor.
         internal static string ToCamelCase(string input)
         {
             bool capitalizeNext = false;
@@ -305,6 +304,7 @@
                         (!wasCap || (i + 1 < input.Length && char.IsLower(input[i + 1]))))
                     {
                         firstWord = false;
+                        result.Append(input[i]);
                     }
                     else
                     {
@@ -320,8 +320,16 @@
                         result.Append(char.ToUpperInvariant(input[i]));
                         continue;
                     }
+                    else
+                    {
+                        result.Append(input[i]);
+                        continue;
+                    }
                 }
-                result.Append(input[i]);
+                else
+                {
+                    result.Append(char.ToLowerInvariant(input[i]));
+                }
             }
             return result.ToString();
         }
diff --git a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
index 0516f18..9b179bd 100644
--- a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
+++ b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
@@ -30,7 +30,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 #endregion

 

-using System.Reflection;

 using System.Runtime.CompilerServices;

 using System.Security;

 

@@ -38,30 +37,13 @@
 // set of attributes. Change these attribute values to modify the information

 // associated with an assembly.

 

-[assembly: AssemblyTitle("Google.Protobuf")]

-[assembly: AssemblyDescription("")]

-[assembly: AssemblyConfiguration("")]

-[assembly: AssemblyCompany("")]

-[assembly: AssemblyProduct("Google.Protobuf")]

-[assembly: AssemblyCopyright("Copyright ©  2015")]

-[assembly: AssemblyTrademark("")]

-[assembly: AssemblyCulture("")]

-

 #if !NCRUNCH

 [assembly: AllowPartiallyTrustedCallers]

 #endif

 

-#if SIGNED

 [assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" +

     "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" +

     "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" +

     "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +

     "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +

     "c5ae9cb6")]

-#else

-[assembly: InternalsVisibleTo("Google.Protobuf.Test")]

-#endif

-

-[assembly: AssemblyVersion("3.0.0.0")]

-[assembly: AssemblyFileVersion("3.0.0.0")]

-[assembly: AssemblyInformationalVersion("3.0.0-beta3")]

diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
index 7ce7573..83e7928 100644
--- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -137,9 +137,9 @@
             "dGVkQ29kZUluZm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90",
             "b2J1Zi5HZW5lcmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRp",
             "b24SEAoEcGF0aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoF",
-            "YmVnaW4YAyABKAUSCwoDZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9i",
-            "dWZCEERlc2NyaXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdv",
-            "b2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9u"));
+            "YmVnaW4YAyABKAUSCwoDZW5kGAQgASgFQlsKE2NvbS5nb29nbGUucHJvdG9i",
+            "dWZCEERlc2NyaXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqABAaICA0dQQqoC",
+            "Gkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9u"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index ab7cd92..94efea9 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -251,17 +251,6 @@
                     "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
                     "those listed in the FileDescriptorProto.");
             }
-            for (int i = 0; i < proto.Dependency.Count; i++)
-            {
-                if (dependencies[i].Name != proto.Dependency[i])
-                {
-                    throw new DescriptorValidationException(
-                        result,
-                        "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
-                        "those listed in the FileDescriptorProto. Expected: " +
-                        proto.Dependency[i] + " but was: " + dependencies[i].Name);
-                }
-            }
 
             result.CrossLink();
             return result;
@@ -341,4 +330,4 @@
         /// </value>
         public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
     }
-}
\ No newline at end of file
+}
diff --git a/csharp/src/Google.Protobuf/packages.config b/csharp/src/Google.Protobuf/packages.config
deleted file mode 100644
index 40b8fd9..0000000
--- a/csharp/src/Google.Protobuf/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="NuSpec.ReferenceGenerator" version="1.4.1" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
-</packages>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/project.json b/csharp/src/Google.Protobuf/project.json
new file mode 100644
index 0000000..9b831f1
--- /dev/null
+++ b/csharp/src/Google.Protobuf/project.json
@@ -0,0 +1,65 @@
+{
+  "version": "3.0.0",
+  "title": "Google Protocol Buffers",
+  "description": "See project site for more info.",
+  "authors": [ "Google Inc." ],
+  "copyright": "Copyright 2015, Google Inc.",
+
+  "packOptions": {
+    "summary": "C# runtime library for Protocol Buffers - Google's data interchange format.",
+    "tags": [ "Protocol", "Buffers", "Binary", "Serialization", "Format", "Google", "proto", "proto3" ],
+    "owners": [ "protobuf-packages" ],
+    "licenseUrl": "https://github.com/google/protobuf/blob/master/LICENSE",
+    "projectUrl": "https://github.com/google/protobuf",
+    "releaseNotes": "C# proto3 support",
+    "requireLicenseAcceptance": false,
+    "repository": {
+      "url": "https://github.com/nodatime/nodatime.git"
+    }
+  },
+
+  "buildOptions": {
+    "debugType": "portable",
+    "keyFile": "../../keys/Google.Protobuf.snk",
+    "xmlDoc": true
+  },
+
+  "configurations": {
+    "Debug": {
+      "buildOptions": {
+        "define": [ "DEBUG", "TRACE" ]
+      }
+    },
+    "Release": {
+      "buildOptions": {
+        "define": [ "RELEASE", "TRACE" ],
+        "optimize": true
+      }
+    }
+  },
+
+  "frameworks": {
+    // This target allows the package to be installed in a .NET 4.5+
+    // project without asking for myriad other dependencies.
+    "net45": {
+    },
+    "netstandard1.0": {
+      "dependencies": {
+        "System.Collections": "4.0.11",
+        "System.Diagnostics.Debug": "4.0.11",
+        "System.Globalization": "4.0.11",
+        "System.IO": "4.1.0",
+        "System.Linq": "4.1.0",
+        "System.Linq.Expressions": "4.1.0",
+        "System.ObjectModel": "4.0.12",
+        "System.Reflection": "4.1.0",
+        "System.Reflection.Extensions": "4.0.1",
+        "System.Runtime": "4.1.0",
+        "System.Runtime.Extensions": "4.1.0",
+        "System.Text.Encoding": "4.0.11",
+        "System.Text.RegularExpressions": "4.1.0",
+        "System.Threading": "4.0.11"
+      }
+    }
+  }
+}
diff --git a/docs/third_party.md b/docs/third_party.md
index 3366608..21a7907 100644
--- a/docs/third_party.md
+++ b/docs/third_party.md
@@ -36,6 +36,7 @@
 * Erlang: http://piqi.org/
 * Erlang: https://code.google.com/p/protoc-gen-erl/
 * Erlang: https://github.com/basho/erlang_protobuffs
+* Erlang: https://github.com/tomas-abrahamsson/gpb
 * Go: https://github.com/golang/protobuf (Google-official implementation)
 * Go: http://code.google.com/p/goprotobuf/
 * Go: https://github.com/akunspy/gopbuf
diff --git a/editors/protobuf-mode.el b/editors/protobuf-mode.el
index f615a0a..1cef413 100644
--- a/editors/protobuf-mode.el
+++ b/editors/protobuf-mode.el
@@ -64,12 +64,13 @@
 ;;; Code:
 
 (require 'cc-mode)
+(require 'cl)
 
 (eval-when-compile
   (require 'cc-langs)
   (require 'cc-fonts))
 
-;; This mode does not inherit properties from other modes. So, we do not use 
+;; This mode does not inherit properties from other modes. So, we do not use
 ;; the usual `c-add-language' function.
 (eval-and-compile
   (put 'protobuf-mode 'c-mode-prefix "protobuf-"))
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index c9d4688..2cd2acc 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,63 +1,63 @@
-# Minimum CMake required

-cmake_minimum_required(VERSION 2.8.12)

-

-# Project

-project(protobuf-examples)

-

-# Find required protobuf package

-find_package(protobuf CONFIG REQUIRED)

-

-if(protobuf_VERBOSE)

-  message(STATUS "Using Protocol Buffers ${Protobuf_VERSION}")

-endif()

-

-set(CMAKE_INCLUDE_CURRENT_DIR TRUE)

-

-# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F

-if(MSVC AND protobuf_MSVC_STATIC_RUNTIME)

-  foreach(flag_var

-      CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE

-      CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)

-    if(${flag_var} MATCHES "/MD")

-      string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")

-    endif(${flag_var} MATCHES "/MD")

-  endforeach()

-endif()

-

-foreach(example add_person list_people)

-  set(${example}_SRCS ${example}.cc)

-  set(${example}_PROTOS addressbook.proto)

-

-  #Code Generation

-  if(protobuf_MODULE_COMPATIBLE) #Legacy Support

-    protobuf_generate_cpp(${example}_PROTO_SRCS ${example}_PROTO_HDRS ${${example}_PROTOS})

-    list(APPEND ${example}_SRCS ${${example}_PROTO_SRCS} ${${example}_PROTO_HDRS})

-  else()

-

-    foreach(proto_file ${${example}_PROTOS})

-      get_filename_component(proto_file_abs ${proto_file} ABSOLUTE)

-      get_filename_component(basename ${proto_file} NAME_WE)

-      set(generated_files ${basename}.pb.cc ${basename}.pb.h)

-      list(APPEND ${example}_SRCS ${generated_files})

-

-      add_custom_command(

-        OUTPUT ${generated_files}

-        COMMAND protobuf::protoc

-        ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR} ${proto_file_abs}

-        COMMENT "Generating ${generated_files} from ${proto_file}"

-        VERBATIM

-      )

-    endforeach()

-  endif()

-

-  #Executable setup

-  set(executable_name ${example}_cpp)

-  add_executable(${executable_name} ${${example}_SRCS} ${${example}_PROTOS})

-  if(protobuf_MODULE_COMPATIBLE) #Legacy mode

-    target_include_directories(${executable_name} PUBLIC ${PROTOBUF_INCLUDE_DIRS})

-    target_link_libraries(${executable_name} ${PROTOBUF_LIBRARIES})

-  else()

-    target_link_libraries(${executable_name} protobuf::libprotobuf)

-  endif()

-

-endforeach()

+# Minimum CMake required
+cmake_minimum_required(VERSION 2.8.12)
+
+# Project
+project(protobuf-examples)
+
+# Find required protobuf package
+find_package(protobuf CONFIG REQUIRED)
+
+if(protobuf_VERBOSE)
+  message(STATUS "Using Protocol Buffers ${Protobuf_VERSION}")
+endif()
+
+set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
+
+# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
+if(MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+  foreach(flag_var
+      CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+      CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+    if(${flag_var} MATCHES "/MD")
+      string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+    endif(${flag_var} MATCHES "/MD")
+  endforeach()
+endif()
+
+foreach(example add_person list_people)
+  set(${example}_SRCS ${example}.cc)
+  set(${example}_PROTOS addressbook.proto)
+
+  #Code Generation
+  if(protobuf_MODULE_COMPATIBLE) #Legacy Support
+    protobuf_generate_cpp(${example}_PROTO_SRCS ${example}_PROTO_HDRS ${${example}_PROTOS})
+    list(APPEND ${example}_SRCS ${${example}_PROTO_SRCS} ${${example}_PROTO_HDRS})
+  else()
+
+    foreach(proto_file ${${example}_PROTOS})
+      get_filename_component(proto_file_abs ${proto_file} ABSOLUTE)
+      get_filename_component(basename ${proto_file} NAME_WE)
+      set(generated_files ${basename}.pb.cc ${basename}.pb.h)
+      list(APPEND ${example}_SRCS ${generated_files})
+
+      add_custom_command(
+        OUTPUT ${generated_files}
+        COMMAND protobuf::protoc
+        ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR} ${proto_file_abs}
+        COMMENT "Generating ${generated_files} from ${proto_file}"
+        VERBATIM
+      )
+    endforeach()
+  endif()
+
+  #Executable setup
+  set(executable_name ${example}_cpp)
+  add_executable(${executable_name} ${${example}_SRCS} ${${example}_PROTOS})
+  if(protobuf_MODULE_COMPATIBLE) #Legacy mode
+    target_include_directories(${executable_name} PUBLIC ${PROTOBUF_INCLUDE_DIRS})
+    target_link_libraries(${executable_name} ${PROTOBUF_LIBRARIES})
+  else()
+    target_link_libraries(${executable_name} protobuf::libprotobuf)
+  endif()
+
+endforeach()
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index c170c83..668e6d1 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
 
 # Run this script to regenerate descriptor.pb.{h,cc} after the protocol
 # compiler changes.  Since these files are compiled into the protocol compiler
diff --git a/gmock.BUILD b/gmock.BUILD
index 82abf27..b1ae15a 100644
--- a/gmock.BUILD
+++ b/gmock.BUILD
@@ -1,19 +1,19 @@
 cc_library(
     name = "gtest",
     srcs = [
-        "gmock-1.7.0/gtest/src/gtest-all.cc",
-        "gmock-1.7.0/src/gmock-all.cc",
+        "googletest/src/gtest-all.cc",
+        "googlemock/src/gmock-all.cc",
     ],
     hdrs = glob([
-        "gmock-1.7.0/**/*.h",
-        "gmock-1.7.0/gtest/src/*.cc",
-        "gmock-1.7.0/src/*.cc",
+        "**/*.h",
+        "googletest/src/*.cc",
+        "googlemock/src/*.cc",
     ]),
     includes = [
-        "gmock-1.7.0",
-        "gmock-1.7.0/gtest",
-        "gmock-1.7.0/gtest/include",
-        "gmock-1.7.0/include",
+        "googlemock",
+        "googletest",
+        "googletest/include",
+        "googlemock/include",
     ],
     linkopts = ["-pthread"],
     visibility = ["//visibility:public"],
@@ -21,7 +21,7 @@
 
 cc_library(
     name = "gtest_main",
-    srcs = ["gmock-1.7.0/src/gmock_main.cc"],
+    srcs = ["googlemock/src/gmock_main.cc"],
     linkopts = ["-pthread"],
     visibility = ["//visibility:public"],
     deps = [":gtest"],
diff --git a/java/compatibility_tests/v2.5.0/test.sh b/java/compatibility_tests/v2.5.0/test.sh
index b7922b1..5d5e9ed 100755
--- a/java/compatibility_tests/v2.5.0/test.sh
+++ b/java/compatibility_tests/v2.5.0/test.sh
@@ -21,15 +21,23 @@
     ;;
   2.6.1)
     OLD_VERSION=2.6.1
-    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/2.6.1-build2/protoc-2.6.1-build2-linux-x86_32.exe
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/2.6.1-build2/protoc-2.6.1-build2-linux-x86_64.exe
     ;;
   3.0.0-beta-1)
     OLD_VERSION=3.0.0-beta-1
-    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-1/protoc-3.0.0-beta-1-linux-x86_32.exe
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-1/protoc-3.0.0-beta-1-linux-x86_64.exe
     ;;
   3.0.0-beta-2)
     OLD_VERSION=3.0.0-beta-2
-    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-2/protoc-3.0.0-beta-2-linux-x86_32.exe
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-2/protoc-3.0.0-beta-2-linux-x86_64.exe
+    ;;
+  3.0.0-beta-3)
+    OLD_VERSION=3.0.0-beta-3
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-3/protoc-3.0.0-beta-3-linux-x86_64.exe
+    ;;
+  3.0.0-beta-4)
+    OLD_VERSION=3.0.0-beta-4
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.0.0-beta-4/protoc-3.0.0-beta-4-linux-x86_64.exe
     ;;
   *)
     echo "[ERROR]: Unknown version number: $1"
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RepeatedFieldBuilderTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RepeatedFieldBuilderTest.java
deleted file mode 100644
index 9a1d8ca..0000000
--- a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/RepeatedFieldBuilderTest.java
+++ /dev/null
@@ -1,191 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.test;
-import com.google.protobuf.*;
-
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-
-import junit.framework.TestCase;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Tests for {@link RepeatedFieldBuilder}. This tests basic functionality.
- * More extensive testing is provided via other tests that exercise the
- * builder.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class RepeatedFieldBuilderTest extends TestCase {
-
-  public void testBasicUse() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-
-    // Make sure it doesn't change.
-    List<TestAllTypes> list2 = builder.build();
-    assertSame(list, list2);
-    assertEquals(0, mockParent.getInvalidationCount());
-  }
-
-  public void testGoingBackAndForth() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    // Convert to list
-    List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-
-    // Update 0th item
-    assertEquals(0, mockParent.getInvalidationCount());
-    builder.getBuilder(0).setOptionalString("foo");
-    assertEquals(1, mockParent.getInvalidationCount());
-    list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-      assertEquals("foo", list.get(0).getOptionalString());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-    assertEquals(1, mockParent.getInvalidationCount());
-  }
-
-  public void testVariousMethods() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build());
-    builder.addBuilder(0, TestAllTypes.getDefaultInstance())
-        .setOptionalInt32(0);
-    builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
-
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(2, builder.getMessage(2).getOptionalInt32());
-    assertEquals(3, builder.getMessage(3).getOptionalInt32());
-
-    assertEquals(0, mockParent.getInvalidationCount());
-    List<TestAllTypes> messages = builder.build();
-    assertEquals(4, messages.size());
-    assertSame(messages, builder.build()); // expect same list
-
-    // Remove a message.
-    builder.remove(2);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(3, builder.getCount());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(3, builder.getMessage(2).getOptionalInt32());
-
-    // Remove a builder.
-    builder.remove(0);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(2, builder.getCount());
-    assertEquals(1, builder.getMessage(0).getOptionalInt32());
-    assertEquals(3, builder.getMessage(1).getOptionalInt32());
-
-    // Test clear.
-    builder.clear();
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(0, builder.getCount());
-    assertTrue(builder.isEmpty());
-  }
-
-  public void testLists() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    builder.addMessage(0,
-        TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    // Use list of builders.
-    List<TestAllTypes.Builder> builders = builder.getBuilderList();
-    assertEquals(0, builders.get(0).getOptionalInt32());
-    assertEquals(1, builders.get(1).getOptionalInt32());
-    builders.get(0).setOptionalInt32(10);
-    builders.get(1).setOptionalInt32(11);
-
-    // Use list of protos
-    List<TestAllTypes> protos = builder.getMessageList();
-    assertEquals(10, protos.get(0).getOptionalInt32());
-    assertEquals(11, protos.get(1).getOptionalInt32());
-
-    // Add an item to the builders and verify it's updated in both
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
-    assertEquals(3, builders.size());
-    assertEquals(3, protos.size());
-  }
-
-  private void assertIsUnmodifiable(List<?> list) {
-    if (list == Collections.emptyList()) {
-      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
-    } else {
-      try {
-        list.clear();
-        fail("List wasn't immutable");
-      } catch (UnsupportedOperationException e) {
-        // good
-      }
-    }
-  }
-
-  private RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-      TestAllTypesOrBuilder>
-      newRepeatedFieldBuilder(TestUtil.MockBuilderParent parent) {
-    return new RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false,
-        parent, false);
-  }
-}
diff --git a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/SingleFieldBuilderTest.java b/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/SingleFieldBuilderTest.java
deleted file mode 100644
index 534fee6..0000000
--- a/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/SingleFieldBuilderTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// 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.
-
-package com.google.protobuf.test;
-import com.google.protobuf.*;
-
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-
-import junit.framework.TestCase;
-
-/**
- * Tests for {@link SingleFieldBuilder}. This tests basic functionality.
- * More extensive testing is provided via other tests that exercise the
- * builder.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class SingleFieldBuilderTest extends TestCase {
-
-  public void testBasicUseAndInvalidations() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    assertEquals(TestAllTypes.getDefaultInstance(),
-        builder.getBuilder().buildPartial());
-    assertEquals(0, mockParent.getInvalidationCount());
-
-    builder.getBuilder().setOptionalInt32(10);
-    assertEquals(0, mockParent.getInvalidationCount());
-    TestAllTypes message = builder.build();
-    assertEquals(10, message.getOptionalInt32());
-
-    // Test that we receive invalidations now that build has been called.
-    assertEquals(0, mockParent.getInvalidationCount());
-    builder.getBuilder().setOptionalInt32(20);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-    // Test that we don't keep getting invalidations on every change
-    builder.getBuilder().setOptionalInt32(30);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-  }
-
-  public void testSetMessage() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage().getOptionalInt32());
-
-    // Update message using the builder
-    builder.getBuilder().setOptionalInt32(1);
-    assertEquals(0, mockParent.getInvalidationCount());
-    assertEquals(1, builder.getBuilder().getOptionalInt32());
-    assertEquals(1, builder.getMessage().getOptionalInt32());
-    builder.build();
-    builder.getBuilder().setOptionalInt32(2);
-    assertEquals(2, builder.getBuilder().getOptionalInt32());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
-
-    // Make sure message stays cached
-    assertSame(builder.getMessage(), builder.getMessage());
-  }
-
-  public void testClear() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-
-    builder.getBuilder().setOptionalInt32(1);
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-  }
-
-  public void testMerge() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-
-    // Merge into default field.
-    builder.mergeFrom(TestAllTypes.getDefaultInstance());
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-
-    // Merge into non-default field on existing builder.
-    builder.getBuilder().setOptionalInt32(2);
-    builder.mergeFrom(TestAllTypes.newBuilder()
-        .setOptionalDouble(4.0)
-        .buildPartial());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
-    assertEquals(4.0, builder.getMessage().getOptionalDouble());
-
-    // Merge into non-default field on existing message
-    builder.setMessage(TestAllTypes.newBuilder()
-        .setOptionalInt32(10)
-        .buildPartial());
-    builder.mergeFrom(TestAllTypes.newBuilder()
-        .setOptionalDouble(5.0)
-        .buildPartial());
-    assertEquals(10, builder.getMessage().getOptionalInt32());
-    assertEquals(5.0, builder.getMessage().getOptionalDouble());
-  }
-}
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 0d4c5c7..39d6781 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-3</version>
+    <version>3.0.0</version>
   </parent>
 
   <artifactId>protobuf-java</artifactId>
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 46ddbf4..7639efc 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -490,7 +490,7 @@
 
     /**
      * Used to support nested builders and called to mark this builder as clean.
-     * Clean builders will propagate the {@link BuildParent#markDirty()} event
+     * Clean builders will propagate the {@link BuilderParent#markDirty()} event
      * to their parent builders, while dirty builders will not, as their parents
      * should be dirty already.
      *
diff --git a/java/core/src/main/java/com/google/protobuf/ByteOutput.java b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
index 8b7b04c..ee58875 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteOutput.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteOutput.java
@@ -37,11 +37,11 @@
  * An output target for raw bytes. This interface provides semantics that support two types of
  * writing:
  *
- * <p/><b>Traditional write operations:</b>
+ * <p><b>Traditional write operations:</b>
  * (as defined by {@link java.io.OutputStream}) where the target method is responsible for either
  * copying the data or completing the write before returning from the method call.
  *
- * <p/><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
+ * <p><b>Lazy write operations:</b> where the caller guarantees that it will never modify the
  * provided buffer and it can therefore be considered immutable. The target method is free to
  * maintain a reference to the buffer beyond the scope of the method call (e.g. until the write
  * operation completes).
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 576a350..e551528 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -145,6 +145,44 @@
   }
 
   /**
+   * Configures serialization to be deterministic.
+   *
+   * <p>The deterministic serialization guarantees that for a given binary, equal (defined by the
+   * {@code equals()} methods in protos) messages will always be serialized to the same bytes. This
+   * implies:
+   *
+   * <ul>
+   * <li>repeated serialization of a message will return the same bytes
+   * <li>different processes of the same binary (which may be executing on different machines) will
+   *     serialize equal messages to the same bytes.
+   * </ul>
+   *
+   * <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable
+   * across different builds with schema changes due to unknown fields. Users who need canonical
+   * serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define
+   * their own canonicalization specification and implement the serializer using reflection APIs
+   * rather than relying on this API.
+   *
+   * <p> Once set, the serializer will:  (Note this is an implementation detail and may subject to
+   * change in the future)
+   *
+   * <ul>
+   * <li> sort map entries by keys in lexicographical order or numerical order. Note: For string
+   *     keys, the order is based on comparing the Unicode value of each character in the strings.
+   *     The order may be different from the deterministic serialization in other languages where
+   *     maps are sorted on the lexicographical order of the UTF8 encoded keys.
+   * </ul>
+   */
+  void useDeterministicSerialization() {
+    serializationDeterministic = true;
+  }
+
+  boolean isSerializationDeterministic() {
+    return serializationDeterministic;
+  }
+  private boolean serializationDeterministic;
+
+  /**
    * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
    *
    * @deprecated the size parameter is no longer used since use of an internal buffer is useless
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index 859a9e8..c54da67 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -526,6 +526,14 @@
           fields.clearField(oldField);
         }
         oneofCases[index] = field;
+      } else if (field.getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) {
+        if (!field.isRepeated()
+            && field.getJavaType() != FieldDescriptor.JavaType.MESSAGE
+            && value.equals(field.getDefaultValue())) {
+          // In proto3, setting a field to its default value is equivalent to clearing the field.
+          fields.clearField(field);
+          return this;
+        }
       }
       fields.setField(field, value);
       return this;
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index 2c87302..cea0579 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -1396,7 +1396,7 @@
       return setExtension((ExtensionLite<MessageType, Type>) extension, value);
     }
     /** Set the value of an extension. */
-    public final <Type> BuilderType setExtension(
+    public <Type> BuilderType setExtension(
         final GeneratedExtension<MessageType, Type> extension, final Type value) {
       return setExtension((ExtensionLite<MessageType, Type>) extension, value);
     }
@@ -1407,7 +1407,7 @@
       return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
     }
     /** Set the value of one element of a repeated extension. */
-    public final <Type> BuilderType setExtension(
+    public <Type> BuilderType setExtension(
         final GeneratedExtension<MessageType, List<Type>> extension,
         final int index, final Type value) {
       return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
@@ -1418,7 +1418,7 @@
       return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
     }
     /** Append a value to a repeated extension. */
-    public final <Type> BuilderType addExtension(
+    public <Type> BuilderType addExtension(
         final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
       return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
     }
@@ -1428,7 +1428,7 @@
       return clearExtension((ExtensionLite<MessageType, ?>) extension);
     }
     /** Clear an extension. */
-    public final <Type> BuilderType clearExtension(
+    public <Type> BuilderType clearExtension(
         final GeneratedExtension<MessageType, ?> extension) {
       return clearExtension((ExtensionLite<MessageType, ?>) extension);
     }
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
new file mode 100644
index 0000000..5dfe7ff
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -0,0 +1,2716 @@
+// 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.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
+import com.google.protobuf.GeneratedMessage.GeneratedExtension;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * All generated protocol message classes extend this class.  This class
+ * implements most of the Message and Builder interfaces using Java reflection.
+ * Users can ignore this class and pretend that generated messages implement
+ * the Message interface directly.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessageV3 extends AbstractMessage
+    implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * For testing. Allows a test to disable the optimization that avoids using
+   * field builders for nested messages until they are requested. By disabling
+   * this optimization, existing tests can be reused to test the field builders.
+   */
+  protected static boolean alwaysUseFieldBuilders = false;
+
+  /** For use by generated code only.  */
+  protected UnknownFieldSet unknownFields;
+
+  protected GeneratedMessageV3() {
+    unknownFields = UnknownFieldSet.getDefaultInstance();
+  }
+
+  protected GeneratedMessageV3(Builder<?> builder) {
+    unknownFields = builder.getUnknownFields();
+  }
+
+  @Override
+  public Parser<? extends GeneratedMessageV3> getParserForType() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+ /**
+  * For testing. Allows a test to disable the optimization that avoids using
+  * field builders for nested messages until they are requested. By disabling
+  * this optimization, existing tests can be reused to test the field builders.
+  * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
+  */
+  static void enableAlwaysUseFieldBuildersForTesting() {
+    alwaysUseFieldBuilders = true;
+  }
+
+  /**
+   * Get the FieldAccessorTable for this type.  We can't have the message
+   * class pass this in to the constructor because of bootstrapping trouble
+   * with DescriptorProtos.
+   */
+  protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+  @Override
+  public Descriptor getDescriptorForType() {
+    return internalGetFieldAccessorTable().descriptor;
+  }
+
+  /**
+   * Internal helper to return a modifiable map containing all the fields.
+   * The returned Map is modifialbe so that the caller can add additional
+   * extension fields to implement {@link #getAllFields()}.
+   *
+   * @param getBytesForString whether to generate ByteString for string fields
+   */
+  private Map<FieldDescriptor, Object> getAllFieldsMutable(
+      boolean getBytesForString) {
+    final TreeMap<FieldDescriptor, Object> result =
+      new TreeMap<FieldDescriptor, Object>();
+    final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+    final List<FieldDescriptor> fields = descriptor.getFields();
+
+    for (int i = 0; i < fields.size(); i++) {
+      FieldDescriptor field = fields.get(i);
+      final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+      /*
+       * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+       * and it is not repeated. There is no need to iterate through the others.
+       */
+      if (oneofDescriptor != null) {
+        // Skip other fields in the Oneof we know are not set
+        i += oneofDescriptor.getFieldCount() - 1;
+        if (!hasOneof(oneofDescriptor)) {
+          // If no field is set in the Oneof, skip all the fields in the Oneof
+          continue;
+        }
+        // Get the pointer to the only field which is set in the Oneof
+        field = getOneofFieldDescriptor(oneofDescriptor);
+      } else {
+        // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+        if (field.isRepeated()) {
+          final List<?> value = (List<?>) getField(field);
+          if (!value.isEmpty()) {
+            result.put(field, value);
+          }
+          continue;
+        }
+        if (!hasField(field)) {
+          continue;
+        }
+      }
+      // Add the field to the map
+      if (getBytesForString && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+        result.put(field, getFieldRaw(field));
+      } else {
+        result.put(field, getField(field));
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+      // Check that all required fields are present.
+      if (field.isRequired()) {
+        if (!hasField(field)) {
+          return false;
+        }
+      }
+      // Check that embedded messages are initialized.
+      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+        if (field.isRepeated()) {
+          @SuppressWarnings("unchecked") final
+          List<Message> messageList = (List<Message>) getField(field);
+          for (final Message element : messageList) {
+            if (!element.isInitialized()) {
+              return false;
+            }
+          }
+        } else {
+          if (hasField(field) && !((Message) getField(field)).isInitialized()) {
+            return false;
+          }
+        }
+      }
+    }
+
+    return true;
+  }
+
+  @Override
+  public Map<FieldDescriptor, Object> getAllFields() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ false));
+  }
+
+  /**
+   * Returns a collection of all the fields in this message which are set
+   * and their corresponding values.  A singular ("required" or "optional")
+   * field is set iff hasField() returns true for that field.  A "repeated"
+   * field is set iff getRepeatedFieldCount() is greater than zero.  The
+   * values are exactly what would be returned by calling
+   * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field.  The map
+   * is guaranteed to be a sorted map, so iterating over it will return fields
+   * in order by field number.
+   */
+  Map<FieldDescriptor, Object> getAllFieldsRaw() {
+    return Collections.unmodifiableMap(
+        getAllFieldsMutable(/* getBytesForString = */ true));
+  }
+
+  @Override
+  public boolean hasOneof(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+  }
+
+  @Override
+  public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+    return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+  }
+
+  @Override
+  public boolean hasField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).has(this);
+  }
+
+  @Override
+  public Object getField(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).get(this);
+  }
+
+  /**
+   * Obtains the value of the given field, or the default value if it is
+   * not set.  For primitive fields, the boxed primitive value is returned.
+   * For enum fields, the EnumValueDescriptor for the value is returned. For
+   * embedded message fields, the sub-message is returned.  For repeated
+   * fields, a java.util.List is returned. For present string fields, a
+   * ByteString is returned representing the bytes that the field contains.
+   */
+  Object getFieldRaw(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field).getRaw(this);
+  }
+
+  @Override
+  public int getRepeatedFieldCount(final FieldDescriptor field) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeatedCount(this);
+  }
+
+  @Override
+  public Object getRepeatedField(final FieldDescriptor field, final int index) {
+    return internalGetFieldAccessorTable().getField(field)
+      .getRepeated(this, index);
+  }
+
+  @Override
+  public UnknownFieldSet getUnknownFields() {
+    throw new UnsupportedOperationException(
+        "This is supposed to be overridden by subclasses.");
+  }
+
+  /**
+   * Called by subclasses to parse an unknown field.
+   * @return {@code true} unless the tag is an end-group tag.
+   */
+  protected boolean parseUnknownField(
+      CodedInputStream input,
+      UnknownFieldSet.Builder unknownFields,
+      ExtensionRegistryLite extensionRegistry,
+      int tag) throws IOException {
+    return unknownFields.mergeFieldFrom(tag, input);
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
+      throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input,
+      ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input) throws IOException {
+    try {
+      return parser.parseFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseWithIOException(Parser<M> parser,
+      CodedInputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
+      InputStream input, ExtensionRegistryLite extensions) throws IOException {
+    try {
+      return parser.parseDelimitedFrom(input, extensions);
+    } catch (InvalidProtocolBufferException e) {
+      throw e.unwrapIOException();
+    }
+  }
+
+  @Override
+  public void writeTo(final CodedOutputStream output) throws IOException {
+    MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
+  }
+
+  @Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) {
+      return size;
+    }
+
+    memoizedSize = MessageReflection.getSerializedSize(
+        this, getAllFieldsRaw());
+    return memoizedSize;
+  }
+
+
+
+  /**
+   * Used by parsing constructors in generated classes.
+   */
+  protected void makeExtensionsImmutable() {
+    // Noop for messages without extensions.
+  }
+
+  /**
+   * TODO(xiaofeng): remove this after b/29368482 is fixed. We need to move this
+   * interface to AbstractMessage in order to versioning GeneratedMessageV3 but
+   * this move breaks binary compatibility for AppEngine. After AppEngine is
+   * fixed we can exlude this from google3.
+   */
+  protected interface BuilderParent extends AbstractMessage.BuilderParent {}
+
+  /**
+   * TODO(xiaofeng): remove this together with GeneratedMessageV3.BuilderParent.
+   */
+  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
+
+  @Override
+  protected Message.Builder newBuilderForType(final AbstractMessage.BuilderParent parent) {
+    return newBuilderForType(new BuilderParent() {
+      @Override
+      public void markDirty() {
+        parent.markDirty();
+      }
+    });
+  }
+
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Builder <BuilderType extends Builder<BuilderType>>
+      extends AbstractMessage.Builder<BuilderType> {
+
+    private BuilderParent builderParent;
+
+    private BuilderParentImpl meAsParent;
+
+    // Indicates that we've built a message and so we are now obligated
+    // to dispatch dirty invalidations. See GeneratedMessageV3.BuilderListener.
+    private boolean isClean;
+
+    private UnknownFieldSet unknownFields =
+        UnknownFieldSet.getDefaultInstance();
+
+    protected Builder() {
+      this(null);
+    }
+
+    protected Builder(BuilderParent builderParent) {
+      this.builderParent = builderParent;
+    }
+
+    @Override
+    void dispose() {
+      builderParent = null;
+    }
+
+    /**
+     * Called by the subclass when a message is built.
+     */
+    protected void onBuilt() {
+      if (builderParent != null) {
+        markClean();
+      }
+    }
+
+    /**
+     * Called by the subclass or a builder to notify us that a message was
+     * built and may be cached and therefore invalidations are needed.
+     */
+    @Override
+    protected void markClean() {
+      this.isClean = true;
+    }
+
+    /**
+     * Gets whether invalidations are needed
+     *
+     * @return whether invalidations are needed
+     */
+    protected boolean isClean() {
+      return isClean;
+    }
+
+    @Override
+    public BuilderType clone() {
+      BuilderType builder =
+          (BuilderType) getDefaultInstanceForType().newBuilderForType();
+      builder.mergeFrom(buildPartial());
+      return builder;
+    }
+
+    /**
+     * Called by the initialization and clear code paths to allow subclasses to
+     * reset any of their builtin fields back to the initial values.
+     */
+    @Override
+    public BuilderType clear() {
+      unknownFields = UnknownFieldSet.getDefaultInstance();
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /**
+     * Get the FieldAccessorTable for this type.  We can't have the message
+     * class pass this in to the constructor because of bootstrapping trouble
+     * with DescriptorProtos.
+     */
+    protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+    @Override
+    public Descriptor getDescriptorForType() {
+      return internalGetFieldAccessorTable().descriptor;
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      return Collections.unmodifiableMap(getAllFieldsMutable());
+    }
+
+    /** Internal helper which returns a mutable map. */
+    private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+      final TreeMap<FieldDescriptor, Object> result =
+        new TreeMap<FieldDescriptor, Object>();
+      final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+      final List<FieldDescriptor> fields = descriptor.getFields();
+
+      for (int i = 0; i < fields.size(); i++) {
+        FieldDescriptor field = fields.get(i);
+        final OneofDescriptor oneofDescriptor = field.getContainingOneof();
+
+        /*
+         * If the field is part of a Oneof, then at maximum one field in the Oneof is set
+         * and it is not repeated. There is no need to iterate through the others.
+         */
+        if (oneofDescriptor != null) {
+          // Skip other fields in the Oneof we know are not set
+          i += oneofDescriptor.getFieldCount() - 1;
+          if (!hasOneof(oneofDescriptor)) {
+            // If no field is set in the Oneof, skip all the fields in the Oneof
+            continue;
+          }
+          // Get the pointer to the only field which is set in the Oneof
+          field = getOneofFieldDescriptor(oneofDescriptor);
+        } else {
+          // If we are not in a Oneof, we need to check if the field is set and if it is repeated
+          if (field.isRepeated()) {
+            final List<?> value = (List<?>) getField(field);
+            if (!value.isEmpty()) {
+              result.put(field, value);
+            }
+            continue;
+          }
+          if (!hasField(field)) {
+            continue;
+          }
+        }
+        // Add the field to the map
+        result.put(field, getField(field));
+      }
+      return result;
+    }
+
+    @Override
+    public Message.Builder newBuilderForField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).newBuilder();
+    }
+
+    @Override
+    public Message.Builder getFieldBuilder(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).getBuilder(this);
+    }
+
+    @Override
+    public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
+      return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
+          this, index);
+    }
+
+    @Override
+    public boolean hasOneof(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).has(this);
+    }
+
+    @Override
+    public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
+      return internalGetFieldAccessorTable().getOneof(oneof).get(this);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field).has(this);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      Object object = internalGetFieldAccessorTable().getField(field).get(this);
+      if (field.isRepeated()) {
+        // The underlying list object is still modifiable at this point.
+        // Make sure not to expose the modifiable list to the caller.
+        return Collections.unmodifiableList((List) object);
+      } else {
+        return object;
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).set(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      internalGetFieldAccessorTable().getField(field).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType clearOneof(final OneofDescriptor oneof) {
+      internalGetFieldAccessorTable().getOneof(oneof).clear(this);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeatedCount(this);
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field, final int index) {
+      return internalGetFieldAccessorTable().getField(field)
+          .getRepeated(this, index);
+    }
+
+    @Override
+    public BuilderType setRepeatedField(
+        final FieldDescriptor field, final int index, final Object value) {
+      internalGetFieldAccessorTable().getField(field)
+        .setRepeated(this, index, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
+      internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
+      this.unknownFields = unknownFields;
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    @Override
+    public BuilderType mergeUnknownFields(
+        final UnknownFieldSet unknownFields) {
+      this.unknownFields =
+        UnknownFieldSet.newBuilder(this.unknownFields)
+                       .mergeFrom(unknownFields)
+                       .build();
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+        // Check that all required fields are present.
+        if (field.isRequired()) {
+          if (!hasField(field)) {
+            return false;
+          }
+        }
+        // Check that embedded messages are initialized.
+        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+          if (field.isRepeated()) {
+            @SuppressWarnings("unchecked") final
+            List<Message> messageList = (List<Message>) getField(field);
+            for (final Message element : messageList) {
+              if (!element.isInitialized()) {
+                return false;
+              }
+            }
+          } else {
+            if (hasField(field) &&
+                !((Message) getField(field)).isInitialized()) {
+              return false;
+            }
+          }
+        }
+      }
+      return true;
+    }
+
+    @Override
+    public final UnknownFieldSet getUnknownFields() {
+      return unknownFields;
+    }
+
+    /**
+     * Called by subclasses to parse an unknown field.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      return unknownFields.mergeFieldFrom(tag, input);
+    }
+
+    /**
+     * Implementation of {@link BuilderParent} for giving to our children. This
+     * small inner class makes it so we don't publicly expose the BuilderParent
+     * methods.
+     */
+    private class BuilderParentImpl implements BuilderParent {
+
+      @Override
+      public void markDirty() {
+        onChanged();
+      }
+    }
+
+    /**
+     * Gets the {@link BuilderParent} for giving to our children.
+     * @return The builder parent for our children.
+     */
+    protected BuilderParent getParentForChildren() {
+      if (meAsParent == null) {
+        meAsParent = new BuilderParentImpl();
+      }
+      return meAsParent;
+    }
+
+    /**
+     * Called when a the builder or one of its nested children has changed
+     * and any parent should be notified of its invalidation.
+     */
+    protected final void onChanged() {
+      if (isClean && builderParent != null) {
+        builderParent.markDirty();
+
+        // Don't keep dispatching invalidations until build is called again.
+        isClean = false;
+      }
+    }
+
+    /**
+     * Gets the map field with the given field number. This method should be
+     * overridden in the generated message class if the message contains map
+     * fields.
+     *
+     * Unlike other field types, reflection support for map fields can't be
+     * implemented based on generated public API because we need to access a
+     * map field as a list in reflection API but the generated API only allows
+     * us to access it as a map. This method returns the underlying map field
+     * directly and thus enables us to access the map field as a list.
+     */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+
+    /** Like {@link #internalGetMapField} but return a mutable version. */
+    @SuppressWarnings({"unused", "rawtypes"})
+    protected MapField internalGetMutableMapField(int fieldNumber) {
+      // Note that we can't use descriptor names here because this method will
+      // be called when descriptor is being initialized.
+      throw new RuntimeException(
+          "No map fields found in " + getClass().getName());
+    }
+  }
+
+  // =================================================================
+  // Extensions-related stuff
+
+  public interface ExtendableMessageOrBuilder<
+      MessageType extends ExtendableMessage> extends MessageOrBuilder {
+    // Re-define for return type covariance.
+    @Override
+    Message getDefaultInstanceForType();
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        ExtensionLite<MessageType, List<Type>> extension);
+
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, Type> extension);
+
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        ExtensionLite<MessageType, List<Type>> extension,
+        int index);
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        Extension<MessageType, Type> extension);
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        Extension<MessageType, List<Type>> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        GeneratedExtension<MessageType, List<Type>> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, Type> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, List<Type>> extension,
+        int index);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, List<Type>> extension,
+        int index);
+  }
+
+  /**
+   * Generated message classes for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "has", "get", and "getCount" -- but for extensions.  The extensions
+   * are identified using instances of the class {@link GeneratedExtension};
+   * the protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo = getFoo();
+   * int i = foo.getExtension(MyProto.bar);
+   * </pre>
+   *
+   * <p>See also {@link ExtendableBuilder}.
+   */
+  public abstract static class ExtendableMessage<
+        MessageType extends ExtendableMessage>
+      extends GeneratedMessageV3
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final FieldSet<FieldDescriptor> extensions;
+
+    protected ExtendableMessage() {
+      this.extensions = FieldSet.newFieldSet();
+    }
+
+    protected ExtendableMessage(
+        ExtendableBuilder<MessageType, ?> builder) {
+      super(builder);
+      this.extensions = builder.buildExtensions();
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    @Override
+    protected boolean parseUnknownField(
+        CodedInputStream input,
+        UnknownFieldSet.Builder unknownFields,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.ExtensionAdapter(extensions), tag);
+    }
+
+
+    /**
+     * Used by parsing constructors in generated classes.
+     */
+    @Override
+    protected void makeExtensionsImmutable() {
+      extensions.makeImmutable();
+    }
+
+    /**
+     * Used by subclasses to serialize extensions.  Extension ranges may be
+     * interleaved with field numbers, but we must write them in canonical
+     * (sorted by field number) order.  ExtensionWriter helps us write
+     * individual ranges of extensions at once.
+     */
+    protected class ExtensionWriter {
+      // Imagine how much simpler this code would be if Java iterators had
+      // a way to get the next element without advancing the iterator.
+
+      private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
+        extensions.iterator();
+      private Map.Entry<FieldDescriptor, Object> next;
+      private final boolean messageSetWireFormat;
+
+      private ExtensionWriter(final boolean messageSetWireFormat) {
+        if (iter.hasNext()) {
+          next = iter.next();
+        }
+        this.messageSetWireFormat = messageSetWireFormat;
+      }
+
+      public void writeUntil(final int end, final CodedOutputStream output)
+                             throws IOException {
+        while (next != null && next.getKey().getNumber() < end) {
+          FieldDescriptor descriptor = next.getKey();
+          if (messageSetWireFormat && descriptor.getLiteJavaType() ==
+                  WireFormat.JavaType.MESSAGE &&
+              !descriptor.isRepeated()) {
+            if (next instanceof LazyField.LazyEntry<?>) {
+              output.writeRawMessageSetExtension(descriptor.getNumber(),
+                  ((LazyField.LazyEntry<?>) next).getField().toByteString());
+            } else {
+              output.writeMessageSetExtension(descriptor.getNumber(),
+                                              (Message) next.getValue());
+            }
+          } else {
+            // TODO(xiangl): Taken care of following code, it may cause
+            // problem when we use LazyField for normal fields/extensions.
+            // Due to the optional field can be duplicated at the end of
+            // serialized bytes, which will make the serialized size change
+            // after lazy field parsed. So when we use LazyField globally,
+            // we need to change the following write method to write cached
+            // bytes directly rather than write the parsed message.
+            FieldSet.writeField(descriptor, next.getValue(), output);
+          }
+          if (iter.hasNext()) {
+            next = iter.next();
+          } else {
+            next = null;
+          }
+        }
+      }
+    }
+
+    protected ExtensionWriter newExtensionWriter() {
+      return new ExtensionWriter(false);
+    }
+    protected ExtensionWriter newMessageSetExtensionWriter() {
+      return new ExtensionWriter(true);
+    }
+
+    /** Called by subclasses to compute the size of extensions. */
+    protected int extensionsSerializedSize() {
+      return extensions.getSerializedSize();
+    }
+    protected int extensionsSerializedSizeAsMessageSet() {
+      return extensions.getMessageSetSerializedSize();
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    protected Map<FieldDescriptor, Object> getExtensionFields() {
+      return extensions.getAllFields();
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFieldsRaw() {
+      final Map<FieldDescriptor, Object> result =
+          super.getAllFieldsMutable(/* getBytesForString = */ false);
+      result.putAll(getExtensionFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.isRepeated()) {
+            return Collections.emptyList();
+          } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  /**
+   * Generated message builders for message types that contain extension ranges
+   * subclass this.
+   *
+   * <p>This class implements type-safe accessors for extensions.  They
+   * implement all the same operations that you can do with normal fields --
+   * e.g. "get", "set", and "add" -- but for extensions.  The extensions are
+   * identified using instances of the class {@link GeneratedExtension}; the
+   * protocol compiler generates a static instance of this class for every
+   * extension in its input.  Through the magic of generics, all is made
+   * type-safe.
+   *
+   * <p>For example, imagine you have the {@code .proto} file:
+   *
+   * <pre>
+   * option java_class = "MyProto";
+   *
+   * message Foo {
+   *   extensions 1000 to max;
+   * }
+   *
+   * extend Foo {
+   *   optional int32 bar;
+   * }
+   * </pre>
+   *
+   * <p>Then you might write code like:
+   *
+   * <pre>
+   * MyProto.Foo foo =
+   *   MyProto.Foo.newBuilder()
+   *     .setExtension(MyProto.bar, 123)
+   *     .build();
+   * </pre>
+   *
+   * <p>See also {@link ExtendableMessage}.
+   */
+  @SuppressWarnings("unchecked")
+  public abstract static class ExtendableBuilder<
+        MessageType extends ExtendableMessage,
+        BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+      extends Builder<BuilderType>
+      implements ExtendableMessageOrBuilder<MessageType> {
+
+    private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
+
+    protected ExtendableBuilder() {}
+
+    protected ExtendableBuilder(
+        BuilderParent parent) {
+      super(parent);
+    }
+
+    // For immutable message conversion.
+    void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
+      this.extensions = extensions;
+    }
+
+    @Override
+    public BuilderType clear() {
+      extensions = FieldSet.emptySet();
+      return super.clear();
+    }
+
+    // This is implemented here only to work around an apparent bug in the
+    // Java compiler and/or build system.  See bug #1898463.  The mere presence
+    // of this clone() implementation makes it go away.
+    @Override
+    public BuilderType clone() {
+      return super.clone();
+    }
+
+    private void ensureExtensionsIsMutable() {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+    }
+
+    private void verifyExtensionContainingType(
+        final Extension<MessageType, ?> extension) {
+      if (extension.getDescriptor().getContainingType() !=
+          getDescriptorForType()) {
+        // This can only happen if someone uses unchecked operations.
+        throw new IllegalArgumentException(
+          "Extension is for type \"" +
+          extension.getDescriptor().getContainingType().getFullName() +
+          "\" which does not match message type \"" +
+          getDescriptorForType().getFullName() + "\".");
+      }
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      return extensions.hasField(extension.getDescriptor());
+    }
+
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final ExtensionLite<MessageType, List<Type>> extensionLite) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      return extensions.getRepeatedFieldCount(descriptor);
+    }
+
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      final Object value = extensions.getField(descriptor);
+      if (value == null) {
+        if (descriptor.isRepeated()) {
+          return (Type) Collections.emptyList();
+        } else if (descriptor.getJavaType() ==
+                   FieldDescriptor.JavaType.MESSAGE) {
+          return (Type) extension.getMessageDefaultInstance();
+        } else {
+          return (Type) extension.fromReflectionType(
+              descriptor.getDefaultValue());
+        }
+      } else {
+        return (Type) extension.fromReflectionType(value);
+      }
+    }
+
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      FieldDescriptor descriptor = extension.getDescriptor();
+      return (Type) extension.singularFromReflectionType(
+          extensions.getRepeatedField(descriptor, index));
+    }
+
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, Type> extensionLite,
+        final Type value) {
+      Extension<MessageType, Type> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setField(descriptor, extension.toReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final int index, final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.setRepeatedField(
+        descriptor, index,
+        extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final ExtensionLite<MessageType, List<Type>> extensionLite,
+        final Type value) {
+      Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      final FieldDescriptor descriptor = extension.getDescriptor();
+      extensions.addRepeatedField(
+          descriptor, extension.singularToReflectionType(value));
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final ExtensionLite<MessageType, ?> extensionLite) {
+      Extension<MessageType, ?> extension = checkNotLite(extensionLite);
+
+      verifyExtensionContainingType(extension);
+      ensureExtensionsIsMutable();
+      extensions.clearField(extension.getDescriptor());
+      onChanged();
+      return (BuilderType) this;
+    }
+
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of an extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final Extension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Append a value to a repeated extension. */
+    public <Type> BuilderType addExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final Extension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+    /** Clear an extension. */
+    public <Type> BuilderType clearExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+
+    /** Called by subclasses to check if all extensions are initialized. */
+    protected boolean extensionsAreInitialized() {
+      return extensions.isInitialized();
+    }
+
+    /**
+     * Called by the build code path to create a copy of the extensions for
+     * building the message.
+     */
+    private FieldSet<FieldDescriptor> buildExtensions() {
+      extensions.makeImmutable();
+      return extensions;
+    }
+
+    @Override
+    public boolean isInitialized() {
+      return super.isInitialized() && extensionsAreInitialized();
+    }
+
+    /**
+     * Called by subclasses to parse an unknown field or an extension.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    @Override
+    protected boolean parseUnknownField(
+        final CodedInputStream input,
+        final UnknownFieldSet.Builder unknownFields,
+        final ExtensionRegistryLite extensionRegistry,
+        final int tag) throws IOException {
+      return MessageReflection.mergeFieldFrom(
+          input, unknownFields, extensionRegistry, getDescriptorForType(),
+          new MessageReflection.BuilderAdapter(this), tag);
+    }
+
+    // ---------------------------------------------------------------
+    // Reflection
+
+    @Override
+    public Map<FieldDescriptor, Object> getAllFields() {
+      final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+      result.putAll(extensions.getAllFields());
+      return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Object getField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        final Object value = extensions.getField(field);
+        if (value == null) {
+          if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+            // Lacking an ExtensionRegistry, we have no way to determine the
+            // extension's real type, so we return a DynamicMessage.
+            return DynamicMessage.getDefaultInstance(field.getMessageType());
+          } else {
+            return field.getDefaultValue();
+          }
+        } else {
+          return value;
+        }
+      } else {
+        return super.getField(field);
+      }
+    }
+
+    @Override
+    public int getRepeatedFieldCount(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedFieldCount(field);
+      } else {
+        return super.getRepeatedFieldCount(field);
+      }
+    }
+
+    @Override
+    public Object getRepeatedField(final FieldDescriptor field,
+                                   final int index) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.getRepeatedField(field, index);
+      } else {
+        return super.getRepeatedField(field, index);
+      }
+    }
+
+    @Override
+    public boolean hasField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        return extensions.hasField(field);
+      } else {
+        return super.hasField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setField(final FieldDescriptor field,
+                                final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setField(field, value);
+      }
+    }
+
+    @Override
+    public BuilderType clearField(final FieldDescriptor field) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.clearField(field);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.clearField(field);
+      }
+    }
+
+    @Override
+    public BuilderType setRepeatedField(final FieldDescriptor field,
+                                        final int index, final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.setRepeatedField(field, index, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.setRepeatedField(field, index, value);
+      }
+    }
+
+    @Override
+    public BuilderType addRepeatedField(final FieldDescriptor field,
+                                        final Object value) {
+      if (field.isExtension()) {
+        verifyContainingType(field);
+        ensureExtensionsIsMutable();
+        extensions.addRepeatedField(field, value);
+        onChanged();
+        return (BuilderType) this;
+      } else {
+        return super.addRepeatedField(field, value);
+      }
+    }
+
+    protected final void mergeExtensionFields(final ExtendableMessage other) {
+      ensureExtensionsIsMutable();
+      extensions.mergeFrom(other.extensions);
+      onChanged();
+    }
+
+    private void verifyContainingType(final FieldDescriptor field) {
+      if (field.getContainingType() != getDescriptorForType()) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Gets the descriptor for an extension. The implementation depends on whether
+   * the extension is scoped in the top level of a file or scoped in a Message.
+   */
+  static interface ExtensionDescriptorRetriever {
+    FieldDescriptor getDescriptor();
+  }
+
+  private abstract static class CachedDescriptorRetriever
+      implements ExtensionDescriptorRetriever {
+    private volatile FieldDescriptor descriptor;
+    protected abstract FieldDescriptor loadDescriptor();
+
+    @Override
+    public FieldDescriptor getDescriptor() {
+      if (descriptor == null) {
+        synchronized (this) {
+          if (descriptor == null) {
+            descriptor = loadDescriptor();
+          }
+        }
+      }
+      return descriptor;
+    }
+  }
+
+  // =================================================================
+
+  /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+  @SuppressWarnings("unchecked")
+  private static Method getMethodOrDie(
+      final Class clazz, final String name, final Class... params) {
+    try {
+      return clazz.getMethod(name, params);
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(
+        "Generated message class \"" + clazz.getName() +
+        "\" missing method \"" + name + "\".", e);
+    }
+  }
+
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  private static Object invokeOrDie(
+      final Method method, final Object object, final Object... params) {
+    try {
+      return method.invoke(object, params);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(
+        "Couldn't use Java reflection to implement protocol message " +
+        "reflection.", e);
+    } catch (InvocationTargetException e) {
+      final Throwable cause = e.getCause();
+      if (cause instanceof RuntimeException) {
+        throw (RuntimeException) cause;
+      } else if (cause instanceof Error) {
+        throw (Error) cause;
+      } else {
+        throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", cause);
+      }
+    }
+  }
+
+  /**
+   * Gets the map field with the given field number. This method should be
+   * overridden in the generated message class if the message contains map
+   * fields.
+   *
+   * Unlike other field types, reflection support for map fields can't be
+   * implemented based on generated public API because we need to access a
+   * map field as a list in reflection API but the generated API only allows
+   * us to access it as a map. This method returns the underlying map field
+   * directly and thus enables us to access the map field as a list.
+   */
+  @SuppressWarnings({"rawtypes", "unused"})
+  protected MapField internalGetMapField(int fieldNumber) {
+    // Note that we can't use descriptor names here because this method will
+    // be called when descriptor is being initialized.
+    throw new RuntimeException(
+        "No map fields found in " + getClass().getName());
+  }
+
+  /**
+   * Users should ignore this class.  This class provides the implementation
+   * with access to the fields of a message object using Java reflection.
+   */
+  public static final class FieldAccessorTable {
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class.  Only
+     * one FieldAccessorTable should ever be constructed per class.
+     *
+     * @param descriptor     The type's descriptor.
+     * @param camelCaseNames The camelcase names of all fields in the message.
+     *                       These are used to derive the accessor method names.
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames,
+        final Class<? extends GeneratedMessageV3> messageClass,
+        final Class<? extends Builder> builderClass) {
+      this(descriptor, camelCaseNames);
+      ensureFieldAccessorsInitialized(messageClass, builderClass);
+    }
+
+    /**
+     * Construct a FieldAccessorTable for a particular message class without
+     * initializing FieldAccessors.
+     */
+    public FieldAccessorTable(
+        final Descriptor descriptor,
+        final String[] camelCaseNames) {
+      this.descriptor = descriptor;
+      this.camelCaseNames = camelCaseNames;
+      fields = new FieldAccessor[descriptor.getFields().size()];
+      oneofs = new OneofAccessor[descriptor.getOneofs().size()];
+      initialized = false;
+    }
+
+    private boolean isMapFieldEnabled(FieldDescriptor field) {
+      boolean result = true;
+      return result;
+    }
+
+    /**
+     * Ensures the field accessors are initialized. This method is thread-safe.
+     *
+     * @param messageClass   The message type.
+     * @param builderClass   The builder type.
+     * @return this
+     */
+    public FieldAccessorTable ensureFieldAccessorsInitialized(
+        Class<? extends GeneratedMessageV3> messageClass,
+        Class<? extends Builder> builderClass) {
+      if (initialized) { return this; }
+      synchronized (this) {
+        if (initialized) { return this; }
+        int fieldsSize = fields.length;
+        for (int i = 0; i < fieldsSize; i++) {
+          FieldDescriptor field = descriptor.getFields().get(i);
+          String containingOneofCamelCaseName = null;
+          if (field.getContainingOneof() != null) {
+            containingOneofCamelCaseName =
+                camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
+          }
+          if (field.isRepeated()) {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              if (field.isMapField() && isMapFieldEnabled(field)) {
+                fields[i] = new MapFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              } else {
+                fields[i] = new RepeatedMessageFieldAccessor(
+                    field, camelCaseNames[i], messageClass, builderClass);
+              }
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new RepeatedEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            } else {
+              fields[i] = new RepeatedFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass);
+            }
+          } else {
+            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+              fields[i] = new SingularMessageFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+              fields[i] = new SingularEnumFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
+              fields[i] = new SingularStringFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            } else {
+              fields[i] = new SingularFieldAccessor(
+                  field, camelCaseNames[i], messageClass, builderClass,
+                  containingOneofCamelCaseName);
+            }
+          }
+        }
+
+        int oneofsSize = oneofs.length;
+        for (int i = 0; i < oneofsSize; i++) {
+          oneofs[i] = new OneofAccessor(
+              descriptor, camelCaseNames[i + fieldsSize],
+              messageClass, builderClass);
+        }
+        initialized = true;
+        camelCaseNames = null;
+        return this;
+      }
+    }
+
+    private final Descriptor descriptor;
+    private final FieldAccessor[] fields;
+    private String[] camelCaseNames;
+    private final OneofAccessor[] oneofs;
+    private volatile boolean initialized;
+
+    /** Get the FieldAccessor for a particular field. */
+    private FieldAccessor getField(final FieldDescriptor field) {
+      if (field.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "FieldDescriptor does not match message type.");
+      } else if (field.isExtension()) {
+        // If this type had extensions, it would subclass ExtendableMessage,
+        // which overrides the reflection interface to handle extensions.
+        throw new IllegalArgumentException(
+          "This type does not have extensions.");
+      }
+      return fields[field.getIndex()];
+    }
+
+    /** Get the OneofAccessor for a particular oneof. */
+    private OneofAccessor getOneof(final OneofDescriptor oneof) {
+      if (oneof.getContainingType() != descriptor) {
+        throw new IllegalArgumentException(
+          "OneofDescriptor does not match message type.");
+      }
+      return oneofs[oneof.getIndex()];
+    }
+
+    /**
+     * Abstract interface that provides access to a single field.  This is
+     * implemented differently depending on the field type and cardinality.
+     */
+    private interface FieldAccessor {
+      Object get(GeneratedMessageV3 message);
+      Object get(GeneratedMessageV3.Builder builder);
+      Object getRaw(GeneratedMessageV3 message);
+      Object getRaw(GeneratedMessageV3.Builder builder);
+      void set(Builder builder, Object value);
+      Object getRepeated(GeneratedMessageV3 message, int index);
+      Object getRepeated(GeneratedMessageV3.Builder builder, int index);
+      Object getRepeatedRaw(GeneratedMessageV3 message, int index);
+      Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index);
+      void setRepeated(Builder builder,
+                       int index, Object value);
+      void addRepeated(Builder builder, Object value);
+      boolean has(GeneratedMessageV3 message);
+      boolean has(GeneratedMessageV3.Builder builder);
+      int getRepeatedCount(GeneratedMessageV3 message);
+      int getRepeatedCount(GeneratedMessageV3.Builder builder);
+      void clear(Builder builder);
+      Message.Builder newBuilder();
+      Message.Builder getBuilder(GeneratedMessageV3.Builder builder);
+      Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder,
+                                         int index);
+    }
+
+    /** OneofAccessor provides access to a single oneof. */
+    private static class OneofAccessor {
+      OneofAccessor(
+          final Descriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        this.descriptor = descriptor;
+        caseMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
+        caseMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      private final Descriptor descriptor;
+      private final Method caseMethod;
+      private final Method caseMethodBuilder;
+      private final Method clearMethod;
+
+      public boolean has(final GeneratedMessageV3 message) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
+          return false;
+        }
+        return true;
+      }
+
+      public FieldDescriptor get(final GeneratedMessageV3 message) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public FieldDescriptor get(GeneratedMessageV3.Builder builder) {
+        int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+        if (fieldNumber > 0) {
+          return descriptor.findFieldByNumber(fieldNumber);
+        }
+        return null;
+      }
+
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+    }
+
+    private static boolean supportFieldPresence(FileDescriptor file) {
+      return file.getSyntax() == FileDescriptor.Syntax.PROTO2;
+    }
+
+    // ---------------------------------------------------------------
+
+    private static class SingularFieldAccessor implements FieldAccessor {
+      SingularFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        field = descriptor;
+        isOneofField = descriptor.getContainingOneof() != null;
+        hasHasMethod = supportFieldPresence(descriptor.getFile())
+            || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
+        getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+        getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
+        type = getMethod.getReturnType();
+        setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+        hasMethod =
+            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
+        hasMethodBuilder =
+            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+        caseMethod = isOneofField ? getMethodOrDie(
+            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
+        caseMethodBuilder = isOneofField ? getMethodOrDie(
+            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
+      }
+
+      // Note:  We use Java reflection to call public methods rather than
+      //   access private fields directly as this avoids runtime security
+      //   checks.
+      protected final Class<?> type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method setMethod;
+      protected final Method hasMethod;
+      protected final Method hasMethodBuilder;
+      protected final Method clearMethod;
+      protected final Method caseMethod;
+      protected final Method caseMethodBuilder;
+      protected final FieldDescriptor field;
+      protected final boolean isOneofField;
+      protected final boolean hasHasMethod;
+
+      private int getOneofFieldNumber(final GeneratedMessageV3 message) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+      }
+
+      private int getOneofFieldNumber(final GeneratedMessageV3.Builder builder) {
+        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        invokeOrDie(setMethod, builder, value);
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(final GeneratedMessageV3 message, final int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedField() called on a singular field.");
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldRaw() called on a singular field.");
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        throw new UnsupportedOperationException(
+          "setRepeatedField() called on a singular field.");
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        throw new UnsupportedOperationException(
+          "addRepeatedField() called on a singular field.");
+      }
+      @Override
+      public boolean has(final GeneratedMessageV3 message) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(message) == field.getNumber();
+          }
+          return !get(message).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethod, message);
+      }
+      @Override
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        if (!hasHasMethod) {
+          if (isOneofField) {
+            return getOneofFieldNumber(builder) == field.getNumber();
+          }
+          return !get(builder).equals(field.getDefaultValue());
+        }
+        return (Boolean) invokeOrDie(hasMethodBuilder, builder);
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldSize() called on a singular field.");
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class RepeatedFieldAccessor implements FieldAccessor {
+      protected final Class type;
+      protected final Method getMethod;
+      protected final Method getMethodBuilder;
+      protected final Method getRepeatedMethod;
+      protected final Method getRepeatedMethodBuilder;
+      protected final Method setRepeatedMethod;
+      protected final Method addRepeatedMethod;
+      protected final Method getCountMethod;
+      protected final Method getCountMethodBuilder;
+      protected final Method clearMethod;
+
+      RepeatedFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        getMethod = getMethodOrDie(messageClass,
+                                   "get" + camelCaseName + "List");
+        getMethodBuilder = getMethodOrDie(builderClass,
+                                   "get" + camelCaseName + "List");
+        getRepeatedMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+        getRepeatedMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
+        type = getRepeatedMethod.getReturnType();
+        setRepeatedMethod =
+            getMethodOrDie(builderClass, "set" + camelCaseName,
+                           Integer.TYPE, type);
+        addRepeatedMethod =
+            getMethodOrDie(builderClass, "add" + camelCaseName, type);
+        getCountMethod =
+            getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+        getCountMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
+
+        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        return invokeOrDie(getMethod, message);
+      }
+      @Override
+      public Object get(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getMethodBuilder, builder);
+      }
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return get(message);
+      }
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+      @Override
+      public void set(final Builder builder, final Object value) {
+        // Add all the elements individually.  This serves two purposes:
+        // 1) Verifies that each element has the correct type.
+        // 2) Insures that the caller cannot modify the list later on and
+        //    have the modifications be reflected in the message.
+        clear(builder);
+        for (final Object element : (List<?>) value) {
+          addRepeated(builder, element);
+        }
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message, final int index) {
+        return invokeOrDie(getRepeatedMethod, message, index);
+      }
+      @Override
+      public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
+        return invokeOrDie(getRepeatedMethodBuilder, builder, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
+        return getRepeated(message, index);
+      }
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+      @Override
+      public void setRepeated(final Builder builder, final int index, final Object value) {
+        invokeOrDie(setRepeatedMethod, builder, index, value);
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        invokeOrDie(addRepeatedMethod, builder, value);
+      }
+      @Override
+      public boolean has(final GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public boolean has(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "hasField() called on a repeated field.");
+      }
+      @Override
+      public int getRepeatedCount(final GeneratedMessageV3 message) {
+        return (Integer) invokeOrDie(getCountMethod, message);
+      }
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
+        return (Integer) invokeOrDie(getCountMethodBuilder, builder);
+      }
+      @Override
+      public void clear(final Builder builder) {
+        invokeOrDie(clearMethod, builder);
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        throw new UnsupportedOperationException(
+          "newBuilderForField() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        throw new UnsupportedOperationException(
+          "getFieldBuilder() called on a non-Message type.");
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
+        throw new UnsupportedOperationException(
+          "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+    }
+
+    private static class MapFieldAccessor implements FieldAccessor {
+      MapFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        field = descriptor;
+        Method getDefaultInstanceMethod =
+            getMethodOrDie(messageClass, "getDefaultInstance");
+        MapField defaultMapField = getMapField(
+            (GeneratedMessageV3) invokeOrDie(getDefaultInstanceMethod, null));
+        mapEntryMessageDefaultInstance =
+            defaultMapField.getMapEntryMessageDefaultInstance();
+      }
+
+      private final FieldDescriptor field;
+      private final Message mapEntryMessageDefaultInstance;
+
+      private MapField<?, ?> getMapField(GeneratedMessageV3 message) {
+        return (MapField<?, ?>) message.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMapField(GeneratedMessageV3.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
+      }
+
+      private MapField<?, ?> getMutableMapField(
+          GeneratedMessageV3.Builder builder) {
+        return (MapField<?, ?>) builder.internalGetMutableMapField(
+            field.getNumber());
+      }
+
+      @Override
+      public Object get(GeneratedMessageV3 message) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(message); i++) {
+          result.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      public Object get(Builder builder) {
+        List result = new ArrayList();
+        for (int i = 0; i < getRepeatedCount(builder); i++) {
+          result.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(result);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3 message) {
+        return get(message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return get(builder);
+      }
+
+      @Override
+      public void set(Builder builder, Object value) {
+        clear(builder);
+        for (Object entry : (List) value) {
+          addRepeated(builder, entry);
+        }
+      }
+
+      @Override
+      public Object getRepeated(GeneratedMessageV3 message, int index) {
+        return getMapField(message).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeated(Builder builder, int index) {
+        return getMapField(builder).getList().get(index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
+        return getRepeated(message, index);
+      }
+
+      @Override
+      public Object getRepeatedRaw(Builder builder, int index) {
+        return getRepeated(builder, index);
+      }
+
+      @Override
+      public void setRepeated(Builder builder, int index, Object value) {
+        getMutableMapField(builder).getMutableList().set(index, (Message) value);
+      }
+
+      @Override
+      public void addRepeated(Builder builder, Object value) {
+        getMutableMapField(builder).getMutableList().add((Message) value);
+      }
+
+      @Override
+      public boolean has(GeneratedMessageV3 message) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public boolean has(Builder builder) {
+        throw new UnsupportedOperationException(
+            "hasField() is not supported for repeated fields.");
+      }
+
+      @Override
+      public int getRepeatedCount(GeneratedMessageV3 message) {
+        return getMapField(message).getList().size();
+      }
+
+      @Override
+      public int getRepeatedCount(Builder builder) {
+        return getMapField(builder).getList().size();
+      }
+
+      @Override
+      public void clear(Builder builder) {
+        getMutableMapField(builder).getMutableList().clear();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder newBuilder() {
+        return mapEntryMessageDefaultInstance.newBuilderForType();
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+
+      @Override
+      public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
+        throw new UnsupportedOperationException(
+            "Nested builder not supported for map fields.");
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularEnumFieldAccessor
+        extends SingularFieldAccessor {
+      SingularEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
+          getValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
+          setValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class);
+        }
+      }
+
+      private EnumDescriptor enumDescriptor;
+
+      private Method valueOfMethod;
+      private Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getValueMethod;
+      private Method getValueMethodBuilder;
+      private Method setValueMethod;
+
+      @Override
+      public Object get(final GeneratedMessageV3 message) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethod, message);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(message));
+      }
+
+      @Override
+      public Object get(final GeneratedMessageV3.Builder builder) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getValueMethodBuilder, builder);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod, super.get(builder));
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.set(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    private static final class RepeatedEnumFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedEnumFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        enumDescriptor = descriptor.getEnumType();
+
+        valueOfMethod = getMethodOrDie(type, "valueOf",
+                                       EnumValueDescriptor.class);
+        getValueDescriptorMethod =
+          getMethodOrDie(type, "getValueDescriptor");
+
+        supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+        if (supportUnknownEnumValue) {
+          getRepeatedValueMethod =
+              getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
+          getRepeatedValueMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName + "Value", int.class);
+          setRepeatedValueMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class, int.class);
+          addRepeatedValueMethod =
+              getMethodOrDie(builderClass, "add" + camelCaseName + "Value", int.class);
+        }
+      }
+      private EnumDescriptor enumDescriptor;
+
+      private final Method valueOfMethod;
+      private final Method getValueDescriptorMethod;
+
+      private boolean supportUnknownEnumValue;
+      private Method getRepeatedValueMethod;
+      private Method getRepeatedValueMethodBuilder;
+      private Method setRepeatedValueMethod;
+      private Method addRepeatedValueMethod;
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessageV3 message) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(message);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(message, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      @SuppressWarnings("unchecked")
+      public Object get(final GeneratedMessageV3.Builder builder) {
+        final List newList = new ArrayList();
+        final int size = getRepeatedCount(builder);
+        for (int i = 0; i < size; i++) {
+          newList.add(getRepeated(builder, i));
+        }
+        return Collections.unmodifiableList(newList);
+      }
+
+      @Override
+      public Object getRepeated(final GeneratedMessageV3 message,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(message, index));
+      }
+      @Override
+      public Object getRepeated(final GeneratedMessageV3.Builder builder,
+                                final int index) {
+        if (supportUnknownEnumValue) {
+          int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index);
+          return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
+        }
+        return invokeOrDie(getValueDescriptorMethod,
+          super.getRepeated(builder, index));
+      }
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(setRepeatedValueMethod, builder, index,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
+                          value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        if (supportUnknownEnumValue) {
+          invokeOrDie(addRepeatedValueMethod, builder,
+              ((EnumValueDescriptor) value).getNumber());
+          return;
+        }
+        super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    /**
+     * Field accessor for string fields.
+     *
+     * <p>This class makes getFooBytes() and setFooBytes() available for
+     * reflection API so that reflection based serialize/parse functions can
+     * access the raw bytes of the field to preserve non-UTF8 bytes in the
+     * string.
+     *
+     * <p>This ensures the serialize/parse round-trip safety, which is important
+     * for servers which forward messages.
+     */
+    private static final class SingularStringFieldAccessor
+        extends SingularFieldAccessor {
+      SingularStringFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+        getBytesMethod = getMethodOrDie(messageClass,
+            "get" + camelCaseName + "Bytes");
+        getBytesMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Bytes");
+        setBytesMethodBuilder = getMethodOrDie(builderClass,
+            "set" + camelCaseName + "Bytes", ByteString.class);
+      }
+
+      private final Method getBytesMethod;
+      private final Method getBytesMethodBuilder;
+      private final Method setBytesMethodBuilder;
+
+      @Override
+      public Object getRaw(final GeneratedMessageV3 message) {
+        return invokeOrDie(getBytesMethod, message);
+      }
+
+      @Override
+      public Object getRaw(GeneratedMessageV3.Builder builder) {
+        return invokeOrDie(getBytesMethodBuilder, builder);
+      }
+
+      @Override
+      public void set(GeneratedMessageV3.Builder builder, Object value) {
+        if (value instanceof ByteString) {
+          invokeOrDie(setBytesMethodBuilder, builder, value);
+        } else {
+          super.set(builder, value);
+        }
+      }
+    }
+
+    // ---------------------------------------------------------------
+
+    private static final class SingularMessageFieldAccessor
+        extends SingularFieldAccessor {
+      SingularMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass,
+          final String containingOneofCamelCaseName) {
+        super(descriptor, camelCaseName, messageClass, builderClass,
+            containingOneofCamelCaseName);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder =
+            getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).buildPartial();
+        }
+      }
+
+      @Override
+      public void set(final Builder builder, final Object value) {
+        super.set(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
+        return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
+      }
+    }
+
+    private static final class RepeatedMessageFieldAccessor
+        extends RepeatedFieldAccessor {
+      RepeatedMessageFieldAccessor(
+          final FieldDescriptor descriptor, final String camelCaseName,
+          final Class<? extends GeneratedMessageV3> messageClass,
+          final Class<? extends Builder> builderClass) {
+        super(descriptor, camelCaseName, messageClass, builderClass);
+
+        newBuilderMethod = getMethodOrDie(type, "newBuilder");
+        getBuilderMethodBuilder = getMethodOrDie(builderClass,
+            "get" + camelCaseName + "Builder", Integer.TYPE);
+      }
+
+      private final Method newBuilderMethod;
+      private final Method getBuilderMethodBuilder;
+
+      private Object coerceType(final Object value) {
+        if (type.isInstance(value)) {
+          return value;
+        } else {
+          // The value is not the exact right message type.  However, if it
+          // is an alternative implementation of the same type -- e.g. a
+          // DynamicMessage -- we should accept it.  In this case we can make
+          // a copy of the message.
+          return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+                  .mergeFrom((Message) value).build();
+        }
+      }
+
+      @Override
+      public void setRepeated(final Builder builder,
+                              final int index, final Object value) {
+        super.setRepeated(builder, index, coerceType(value));
+      }
+      @Override
+      public void addRepeated(final Builder builder, final Object value) {
+        super.addRepeated(builder, coerceType(value));
+      }
+      @Override
+      public Message.Builder newBuilder() {
+        return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+      }
+      @Override
+      public Message.Builder getRepeatedBuilder(
+          final GeneratedMessageV3.Builder builder, final int index) {
+        return (Message.Builder) invokeOrDie(
+            getBuilderMethodBuilder, builder, index);
+      }
+    }
+  }
+
+  /**
+   * Replaces this object in the output stream with a serialized form.
+   * Part of Java's serialization magic.  Generated sub-classes must override
+   * this method by calling {@code return super.writeReplace();}
+   * @return a SerializedForm of this message
+   */
+  protected Object writeReplace() throws ObjectStreamException {
+    return new GeneratedMessageLite.SerializedForm(this);
+  }
+
+  /**
+   * Checks that the {@link Extension} is non-Lite and returns it as a
+   * {@link GeneratedExtension}.
+   */
+  private static <MessageType extends ExtendableMessage<MessageType>, T>
+    Extension<MessageType, T> checkNotLite(
+        ExtensionLite<MessageType, T> extension) {
+    if (extension.isLite()) {
+      throw new IllegalArgumentException("Expected non-lite extension.");
+    }
+
+    return (Extension<MessageType, T>) extension;
+  }
+  
+  protected static int computeStringSize(final int fieldNumber, final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
+    } else {
+      return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
+    }
+  }
+  
+  protected static int computeStringSizeNoTag(final Object value) {
+    if (value instanceof String) {
+      return CodedOutputStream.computeStringSizeNoTag((String) value);
+    } else {
+      return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
+    }
+  }
+  
+  protected static void writeString(
+      CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeString(fieldNumber, (String) value);
+    } else {
+      output.writeBytes(fieldNumber, (ByteString) value);
+    }
+  }
+  
+  protected static void writeStringNoTag(
+      CodedOutputStream output, final Object value) throws IOException {
+    if (value instanceof String) {
+      output.writeStringNoTag((String) value);
+    } else {
+      output.writeBytesNoTag((ByteString) value);
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index d1de375..3b4a041 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -611,12 +611,12 @@
     int getInt(int index);
 
     /**
-     * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
+     * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
      */
     void addInt(int element);
 
     /**
-     * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element.
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     int setInt(int index, int element);
 
@@ -639,12 +639,12 @@
     boolean getBoolean(int index);
 
     /**
-     * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
+     * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
      */
     void addBoolean(boolean element);
 
     /**
-     * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element.
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     boolean setBoolean(int index, boolean element);
 
@@ -667,12 +667,12 @@
     long getLong(int index);
 
     /**
-     * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
+     * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
      */
     void addLong(long element);
 
     /**
-     * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element.
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     long setLong(int index, long element);
 
@@ -695,12 +695,12 @@
     double getDouble(int index);
 
     /**
-     * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
+     * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
      */
     void addDouble(double element);
 
     /**
-     * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element.
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     double setDouble(int index, double element);
 
@@ -723,12 +723,12 @@
     float getFloat(int index);
 
     /**
-     * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
+     * Like {@link #add(Object)} but more efficient in that it doesn't box the element.
      */
     void addFloat(float element);
 
     /**
-     * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element.
+     * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element.
      */
     float setFloat(int index, float element);
 
diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
index 6db6924..cfbcb44 100644
--- a/java/core/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -39,7 +39,7 @@
  *
  * <p>All methods may throw {@link InvalidProtocolBufferException}. In the event of invalid data,
  * like an encoding error, the cause of the thrown exception will be {@code null}. However, if an
- * I/O problem occurs, an exception is thrown with an {@link IOException} cause.
+ * I/O problem occurs, an exception is thrown with an {@link java.io.IOException} cause.
  *
  * @author liujisi@google.com (Pherl Liu)
  */
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
index 2ecf912..5c43b2c 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java
@@ -45,7 +45,7 @@
  *
  * <p>The locations of primary fields values are retrieved by {@code getLocation} or
  * {@code getLocations}.  The locations of sub message values are within nested
- * {@code TextFormatParseInfoTree}s and are retrieve by {@getNestedTree} or {code @getNestedTrees}.
+ * {@code TextFormatParseInfoTree}s and are retrieve by {@code getNestedTree} or {@code getNestedTrees}.
  *
  * <p>The {@code TextFormatParseInfoTree} is created by a Builder.
  */
@@ -197,7 +197,7 @@
      * Set for a sub message.
      *
      * <p>A new builder is created for a sub message. The builder that is returned is a new builder.
-     * The return is <emph>not</emph> the invoked {@code builder.getBuilderForSubMessageField}.
+     * The return is <em>not</em> the invoked {@code builder.getBuilderForSubMessageField}.
      *
      * @param fieldDescriptor the field whose value is the submessage
      * @return a new Builder for the sub message
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
index 82f4216..4a42c89 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -31,6 +31,8 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
 import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
@@ -253,6 +255,54 @@
     assertEquals(4, message.getAllFields().size());
   }
 
+  public void testFieldPresenceDynamicMessage() {
+    Descriptor descriptor = TestAllTypes.getDescriptor();
+    FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
+    FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
+    FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
+    FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
+    EnumDescriptor enumDescriptor = optionalNestedEnumField.getEnumType();
+    EnumValueDescriptor defaultEnumValueDescriptor = enumDescriptor.getValues().get(0);
+    EnumValueDescriptor nonDefaultEnumValueDescriptor = enumDescriptor.getValues().get(1);
+
+    DynamicMessage defaultInstance = DynamicMessage.getDefaultInstance(descriptor);
+    // Field not present.
+    DynamicMessage message = defaultInstance.newBuilderForType().build();
+    assertFalse(message.hasField(optionalInt32Field));
+    assertFalse(message.hasField(optionalStringField));
+    assertFalse(message.hasField(optionalBytesField));
+    assertFalse(message.hasField(optionalNestedEnumField));
+    assertEquals(0, message.getAllFields().size());
+
+    // Field set to non-default value is seen as present.
+    message =
+        defaultInstance
+            .newBuilderForType()
+            .setField(optionalInt32Field, 1)
+            .setField(optionalStringField, "x")
+            .setField(optionalBytesField, ByteString.copyFromUtf8("y"))
+            .setField(optionalNestedEnumField, nonDefaultEnumValueDescriptor)
+            .build();
+    assertTrue(message.hasField(optionalInt32Field));
+    assertTrue(message.hasField(optionalStringField));
+    assertTrue(message.hasField(optionalBytesField));
+    assertTrue(message.hasField(optionalNestedEnumField));
+    assertEquals(4, message.getAllFields().size());
+
+    // Field set to default value is seen as not present.
+    message = message.toBuilder()
+            .setField(optionalInt32Field, 0)
+            .setField(optionalStringField, "")
+            .setField(optionalBytesField, ByteString.EMPTY)
+            .setField(optionalNestedEnumField, defaultEnumValueDescriptor)
+            .build();
+    assertFalse(message.hasField(optionalInt32Field));
+    assertFalse(message.hasField(optionalStringField));
+    assertFalse(message.hasField(optionalBytesField));
+    assertFalse(message.hasField(optionalNestedEnumField));
+    assertEquals(0, message.getAllFields().size());
+  }
+
   public void testMessageField() {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     assertFalse(builder.hasOptionalNestedMessage());
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index a9b8b63..127e06f 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -972,7 +972,7 @@
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
 
     TestAllTypes.Builder builder = (TestAllTypes.Builder)
-        ((GeneratedMessage) TestAllTypes.getDefaultInstance()).
+        ((AbstractMessage) TestAllTypes.getDefaultInstance()).
             newBuilderForType(mockParent);
     builder.setOptionalInt32(1);
     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
@@ -1027,7 +1027,7 @@
     TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
 
     TestAllExtensions.Builder builder = (TestAllExtensions.Builder)
-        ((GeneratedMessage) TestAllExtensions.getDefaultInstance()).
+        ((AbstractMessage) TestAllExtensions.getDefaultInstance()).
             newBuilderForType(mockParent);
 
     builder.addExtension(UnittestProto.repeatedInt32Extension, 1);
diff --git a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
index 0f42ac5..497c4df 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -35,6 +35,7 @@
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.List;
@@ -233,7 +234,7 @@
     }
     
     try {
-      list.addAllByteArray(asList(BYTE_STRING_A.toByteArray()));
+      list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray()));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
deleted file mode 100644
index 49d5232..0000000
--- a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
+++ /dev/null
@@ -1,190 +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.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-
-import junit.framework.TestCase;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Tests for {@link RepeatedFieldBuilder}. This tests basic functionality.
- * More extensive testing is provided via other tests that exercise the
- * builder.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class RepeatedFieldBuilderTest extends TestCase {
-
-  public void testBasicUse() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-
-    // Make sure it doesn't change.
-    List<TestAllTypes> list2 = builder.build();
-    assertSame(list, list2);
-    assertEquals(0, mockParent.getInvalidationCount());
-  }
-
-  public void testGoingBackAndForth() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    // Convert to list
-    List<TestAllTypes> list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-
-    // Update 0th item
-    assertEquals(0, mockParent.getInvalidationCount());
-    builder.getBuilder(0).setOptionalString("foo");
-    assertEquals(1, mockParent.getInvalidationCount());
-    list = builder.build();
-    assertEquals(2, list.size());
-    assertEquals(0, list.get(0).getOptionalInt32());
-      assertEquals("foo", list.get(0).getOptionalString());
-    assertEquals(1, list.get(1).getOptionalInt32());
-    assertIsUnmodifiable(list);
-    assertEquals(1, mockParent.getInvalidationCount());
-  }
-
-  public void testVariousMethods() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build());
-    builder.addBuilder(0, TestAllTypes.getDefaultInstance())
-        .setOptionalInt32(0);
-    builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
-
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(2, builder.getMessage(2).getOptionalInt32());
-    assertEquals(3, builder.getMessage(3).getOptionalInt32());
-
-    assertEquals(0, mockParent.getInvalidationCount());
-    List<TestAllTypes> messages = builder.build();
-    assertEquals(4, messages.size());
-    assertSame(messages, builder.build()); // expect same list
-
-    // Remove a message.
-    builder.remove(2);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(3, builder.getCount());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-    assertEquals(3, builder.getMessage(2).getOptionalInt32());
-
-    // Remove a builder.
-    builder.remove(0);
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(2, builder.getCount());
-    assertEquals(1, builder.getMessage(0).getOptionalInt32());
-    assertEquals(3, builder.getMessage(1).getOptionalInt32());
-
-    // Test clear.
-    builder.clear();
-    assertEquals(1, mockParent.getInvalidationCount());
-    assertEquals(0, builder.getCount());
-    assertTrue(builder.isEmpty());
-  }
-
-  public void testLists() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
-    builder.addMessage(0,
-        TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage(0).getOptionalInt32());
-    assertEquals(1, builder.getMessage(1).getOptionalInt32());
-
-    // Use list of builders.
-    List<TestAllTypes.Builder> builders = builder.getBuilderList();
-    assertEquals(0, builders.get(0).getOptionalInt32());
-    assertEquals(1, builders.get(1).getOptionalInt32());
-    builders.get(0).setOptionalInt32(10);
-    builders.get(1).setOptionalInt32(11);
-
-    // Use list of protos
-    List<TestAllTypes> protos = builder.getMessageList();
-    assertEquals(10, protos.get(0).getOptionalInt32());
-    assertEquals(11, protos.get(1).getOptionalInt32());
-
-    // Add an item to the builders and verify it's updated in both
-    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
-    assertEquals(3, builders.size());
-    assertEquals(3, protos.size());
-  }
-
-  private void assertIsUnmodifiable(List<?> list) {
-    if (list == Collections.emptyList()) {
-      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
-    } else {
-      try {
-        list.clear();
-        fail("List wasn't immutable");
-      } catch (UnsupportedOperationException e) {
-        // good
-      }
-    }
-  }
-
-  private RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-      TestAllTypesOrBuilder>
-      newRepeatedFieldBuilder(GeneratedMessage.BuilderParent parent) {
-    return new RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false,
-        parent, false);
-  }
-}
diff --git a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
deleted file mode 100644
index 58b8000..0000000
--- a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
+++ /dev/null
@@ -1,155 +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.
-
-package com.google.protobuf;
-
-import protobuf_unittest.UnittestProto.TestAllTypes;
-import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
-
-import junit.framework.TestCase;
-
-/**
- * Tests for {@link SingleFieldBuilder}. This tests basic functionality.
- * More extensive testing is provided via other tests that exercise the
- * builder.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class SingleFieldBuilderTest extends TestCase {
-
-  public void testBasicUseAndInvalidations() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    assertEquals(TestAllTypes.getDefaultInstance(),
-        builder.getBuilder().buildPartial());
-    assertEquals(0, mockParent.getInvalidationCount());
-
-    builder.getBuilder().setOptionalInt32(10);
-    assertEquals(0, mockParent.getInvalidationCount());
-    TestAllTypes message = builder.build();
-    assertEquals(10, message.getOptionalInt32());
-
-    // Test that we receive invalidations now that build has been called.
-    assertEquals(0, mockParent.getInvalidationCount());
-    builder.getBuilder().setOptionalInt32(20);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-    // Test that we don't keep getting invalidations on every change
-    builder.getBuilder().setOptionalInt32(30);
-    assertEquals(1, mockParent.getInvalidationCount());
-
-  }
-
-  public void testSetMessage() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertEquals(0, builder.getMessage().getOptionalInt32());
-
-    // Update message using the builder
-    builder.getBuilder().setOptionalInt32(1);
-    assertEquals(0, mockParent.getInvalidationCount());
-    assertEquals(1, builder.getBuilder().getOptionalInt32());
-    assertEquals(1, builder.getMessage().getOptionalInt32());
-    builder.build();
-    builder.getBuilder().setOptionalInt32(2);
-    assertEquals(2, builder.getBuilder().getOptionalInt32());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
-
-    // Make sure message stays cached
-    assertSame(builder.getMessage(), builder.getMessage());
-  }
-
-  public void testClear() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-
-    builder.getBuilder().setOptionalInt32(1);
-    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-    builder.clear();
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-  }
-
-  public void testMerge() {
-    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
-    SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-        TestAllTypesOrBuilder> builder =
-        new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
-            TestAllTypesOrBuilder>(
-            TestAllTypes.getDefaultInstance(),
-            mockParent,
-            false);
-
-    // Merge into default field.
-    builder.mergeFrom(TestAllTypes.getDefaultInstance());
-    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
-
-    // Merge into non-default field on existing builder.
-    builder.getBuilder().setOptionalInt32(2);
-    builder.mergeFrom(TestAllTypes.newBuilder()
-        .setOptionalDouble(4.0)
-        .buildPartial());
-    assertEquals(2, builder.getMessage().getOptionalInt32());
-    assertEquals(4.0, builder.getMessage().getOptionalDouble());
-
-    // Merge into non-default field on existing message
-    builder.setMessage(TestAllTypes.newBuilder()
-        .setOptionalInt32(10)
-        .buildPartial());
-    builder.mergeFrom(TestAllTypes.newBuilder()
-        .setOptionalDouble(5.0)
-        .buildPartial());
-    assertEquals(10, builder.getMessage().getOptionalInt32());
-    assertEquals(5.0, builder.getMessage().getOptionalDouble());
-  }
-}
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index c403dc0..9862cd9 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-3</version>
+    <version>3.0.0</version>
   </parent>
 
   <artifactId>protobuf-lite</artifactId>
diff --git a/java/pom.xml b/java/pom.xml
index 7a1a91f..3a91a0b 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -11,7 +11,7 @@
 
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-parent</artifactId>
-  <version>3.0.0-beta-3</version>
+  <version>3.0.0</version>
   <packaging>pom</packaging>
 
   <name>Protocol Buffers [Parent]</name>
@@ -152,6 +152,32 @@
       <build>
         <plugins>
           <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.2.1</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar-no-fork</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.9.1</version>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
             <artifactId>maven-gpg-plugin</artifactId>
             <version>1.6</version>
             <executions>
@@ -182,7 +208,7 @@
 
   <modules>
     <module>core</module>
-    <module>lite</module>
+    <!-- <module>lite</module> -->
     <module>util</module>
   </modules>
 
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 9236f90..0d5e8e3 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.0.0-beta-3</version>
+    <version>3.0.0</version>
   </parent>
 
   <artifactId>protobuf-java-util</artifactId>
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 297545e..d4db9c8 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -116,7 +116,8 @@
     private Printer(
         TypeRegistry registry,
         boolean includingDefaultValueFields,
-        boolean preservingProtoFieldNames, boolean omittingInsignificantWhitespace) {
+        boolean preservingProtoFieldNames,
+        boolean omittingInsignificantWhitespace) {
       this.registry = registry;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
@@ -133,7 +134,11 @@
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames, omittingInsignificantWhitespace);
+      return new Printer(
+          registry,
+          includingDefaultValueFields,
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace);
     }
 
     /**
@@ -143,7 +148,8 @@
      * {@link Printer}.
      */
     public Printer includingDefaultValueFields() {
-      return new Printer(registry, true, preservingProtoFieldNames, omittingInsignificantWhitespace);
+      return new Printer(
+          registry, true, preservingProtoFieldNames, omittingInsignificantWhitespace);
     }
 
     /**
@@ -153,7 +159,8 @@
      * current {@link Printer}.
      */
     public Printer preservingProtoFieldNames() {
-      return new Printer(registry, includingDefaultValueFields, true, omittingInsignificantWhitespace);
+      return new Printer(
+          registry, includingDefaultValueFields, true, omittingInsignificantWhitespace);
     }
 
 
@@ -172,7 +179,7 @@
      * See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/html/rfc7159</a>
      * current {@link Printer}.
      */
-    public Printer omittingInsignificantWhitespace(){
+    public Printer omittingInsignificantWhitespace() {
       return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames, true);
     }
 
@@ -186,7 +193,12 @@
     public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output, omittingInsignificantWhitespace)
+      new PrinterImpl(
+              registry,
+              includingDefaultValueFields,
+              preservingProtoFieldNames,
+              output,
+              omittingInsignificantWhitespace)
           .print(message);
     }
 
@@ -212,7 +224,7 @@
    * Creates a {@link Parser} with default configuration.
    */
   public static Parser parser() {
-    return new Parser(TypeRegistry.getEmptyTypeRegistry());
+    return new Parser(TypeRegistry.getEmptyTypeRegistry(), false);
   }
 
   /**
@@ -220,9 +232,11 @@
    */
   public static class Parser {
     private final TypeRegistry registry;
+    private final boolean ignoringUnknownFields;
 
-    private Parser(TypeRegistry registry) {
+    private Parser(TypeRegistry registry, boolean ignoreUnknownFields) {
       this.registry = registry;
+      this.ignoringUnknownFields = ignoreUnknownFields;
     }
 
     /**
@@ -235,7 +249,16 @@
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Parser(registry);
+      return new Parser(registry, this.ignoringUnknownFields);
+    }
+
+    /**
+     * Creates a new {@link Parser} configured to not throw an exception
+     * when an unknown field is encountered. The new Parser clones all other
+     * configurations from this Parser.
+     */
+    public Parser ignoringUnknownFields() {
+      return new Parser(this.registry, true);
     }
 
     /**
@@ -247,7 +270,7 @@
     public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields).merge(json, builder);
     }
 
     /**
@@ -260,7 +283,7 @@
     public void merge(Reader json, Message.Builder builder) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new ParserImpl(registry).merge(json, builder);
+      new ParserImpl(registry, ignoringUnknownFields).merge(json, builder);
     }
   }
 
@@ -379,18 +402,18 @@
    */
   interface TextGenerator {
     void indent();
+
     void outdent();
+
     void print(final CharSequence text) throws IOException;
   }
 
-
   /**
    * Format the json without indentation
    */
-  private static final class CompactTextGenerator implements TextGenerator{
+  private static final class CompactTextGenerator implements TextGenerator {
     private final Appendable output;
 
-
     private CompactTextGenerator(final Appendable output) {
       this.output = output;
     }
@@ -411,12 +434,11 @@
     public void print(final CharSequence text) throws IOException {
       output.append(text);
     }
-
   }
   /**
    * A TextGenerator adds indentation when writing formatted text.
    */
-  private static final class PrettyTextGenerator implements TextGenerator{
+  private static final class PrettyTextGenerator implements TextGenerator {
     private final Appendable output;
     private final StringBuilder indent = new StringBuilder();
     private boolean atStartOfLine = true;
@@ -496,7 +518,8 @@
         TypeRegistry registry,
         boolean includingDefaultValueFields,
         boolean preservingProtoFieldNames,
-        Appendable jsonOutput, boolean omittingInsignificantWhitespace) {
+        Appendable jsonOutput,
+        boolean omittingInsignificantWhitespace) {
       this.registry = registry;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
@@ -734,9 +757,7 @@
     }
 
     /** Prints a regular message with an optional type URL. */
-
-    private void print(MessageOrBuilder message, String typeUrl)
-        throws IOException {
+    private void print(MessageOrBuilder message, String typeUrl) throws IOException {
       generator.print("{" + blankOrNewLine);
       generator.indent();
 
@@ -1014,9 +1035,11 @@
   private static class ParserImpl {
     private final TypeRegistry registry;
     private final JsonParser jsonParser;
+    private final boolean ignoringUnknownFields;
 
-    ParserImpl(TypeRegistry registry) {
+    ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields) {
       this.registry = registry;
+      this.ignoringUnknownFields = ignoreUnknownFields;
       this.jsonParser = new JsonParser();
     }
 
@@ -1181,6 +1204,9 @@
         }
         FieldDescriptor field = fieldNameMap.get(entry.getKey());
         if (field == null) {
+          if (ignoringUnknownFields) {
+            continue;
+          }
           throw new InvalidProtocolBufferException(
               "Cannot find field: "
                   + entry.getKey()
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index e68c7be..c11114c 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -140,7 +140,7 @@
   private String toJsonString(Message message) throws IOException {
     return JsonFormat.printer().print(message);
   }
-  private String toCompactJsonString(Message message) throws IOException{
+  private String toCompactJsonString(Message message) throws IOException {
     return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
   }
 
@@ -1030,6 +1030,22 @@
     }
   }
 
+  public void testParserUnknownFields() throws Exception {
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
+      JsonFormat.parser().merge(json, builder);
+      fail("Exception is expected.");
+    } catch (InvalidProtocolBufferException e) {
+      // Expected.
+    }
+  }
+  public void testParserIgnoringUnknownFields() throws Exception {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    String json = "{\n" + "  \"unknownField\": \"XXX\"\n" + "}";
+    JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
+  }
+
   public void testCustomJsonName() throws Exception {
     TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
     assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
@@ -1172,7 +1188,9 @@
 
   public void testOmittingInsignificantWhiteSpace() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
-    assertEquals("{" + "\"optionalInt32\":12345" + "}", JsonFormat.printer().omittingInsignificantWhitespace().print(message));
+    assertEquals(
+        "{" + "\"optionalInt32\":12345" + "}",
+        JsonFormat.printer().omittingInsignificantWhitespace().print(message));
     TestAllTypes message1 = TestAllTypes.getDefaultInstance();
     assertEquals("{}", JsonFormat.printer().omittingInsignificantWhitespace().print(message1));
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
@@ -1224,4 +1242,20 @@
         toCompactJsonString(message2));
   }
 
+  // Regression test for b/29892357
+  public void testEmptyWrapperTypesInAny() throws Exception {
+    JsonFormat.TypeRegistry registry =
+        JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
+    JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry);
+
+    Any.Builder builder = Any.newBuilder();
+    parser.merge(
+        "{\n"
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+            + "  \"value\": false\n"
+            + "}\n",
+        builder);
+    Any any = builder.build();
+    assertEquals(0, any.getValue().size());
+  }
 }
diff --git a/javanano/pom.xml b/javanano/pom.xml
index a2eca09..6ebba3c 100644
--- a/javanano/pom.xml
+++ b/javanano/pom.xml
@@ -10,7 +10,7 @@
   </parent>
   <groupId>com.google.protobuf.nano</groupId>
   <artifactId>protobuf-javanano</artifactId>
-  <version>3.0.0-alpha-6</version>
+  <version>3.0.0-alpha-7</version>
   <packaging>bundle</packaging>
   <name>Protocol Buffer JavaNano API</name>
   <description>
@@ -164,8 +164,8 @@
         <configuration>
           <instructions>
             <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
-            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
-            <Export-Package>com.google.protobuf;version=3.0.0-alpha-5</Export-Package>
+            <Bundle-SymbolicName>com.google.protobuf.nano</Bundle-SymbolicName>
+            <Export-Package>com.google.protobuf.nano;version=3.0.0-alpha-7</Export-Package>
           </instructions>
         </configuration>
       </plugin>
diff --git a/jenkins/docker/Dockerfile b/jenkins/docker/Dockerfile
index 8467aef..53ac38f 100644
--- a/jenkins/docker/Dockerfile
+++ b/jenkins/docker/Dockerfile
@@ -23,6 +23,13 @@
   echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list && \
   apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
 
+# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
+# (Ubuntu instructions need apt to support https)
+RUN apt-get update && apt-get install -y curl libunwind8 gettext && \
+  curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130 && \
+  mkdir -p /opt/dotnet && tar zxf dotnet.tar.gz -C /opt/dotnet && \
+  ln -s /opt/dotnet/dotnet /usr/local/bin
+
 # Install dependencies.  We start with the basic ones require to build protoc
 # and the C++ build
 RUN apt-get update && apt-get install -y \
@@ -80,7 +87,6 @@
 RUN pip install pip --upgrade
 RUN pip install virtualenv tox yattag
 
-
 ##################
 # Ruby dependencies
 
@@ -88,12 +94,12 @@
 RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
 RUN \curl -sSL https://get.rvm.io | bash -s stable
 
-# Install Ruby 2.1
+# Install Ruby 2.1, Ruby 2.2 and JRuby 1.7
 RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "rvm install ruby-2.2"
+RUN /bin/bash -l -c "rvm install jruby-1.7"
 RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
 RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
 
 ##################
@@ -111,12 +117,29 @@
   ./configure && \
   make -j6 && \
   cd java && \
-  $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO -P lite && \
   $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO && \
   cd ../javanano && \
   $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO
 
 ##################
+# Go dependencies.
+RUN apt-get install -y  \
+  # -- For go -- \
+  golang
+
+##################
+# Javascript dependencies.
+Run apt-get install -y \
+  # -- For javascript -- \
+  npm
+
+# On Debian/Ubuntu, nodejs binary is named 'nodejs' because the name 'node'
+# is taken by another legacy binary. We don't have that legacy binary and
+# npm expects the binary to be named 'node', so we just create a symbol
+# link here.
+RUN ln -s `which nodejs` /usr/bin/node
+
+##################
 # Prepare ccache
 
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/jenkins/pull_request_in_docker.sh b/jenkins/pull_request_in_docker.sh
index 887f97c..78a9253 100755
--- a/jenkins/pull_request_in_docker.sh
+++ b/jenkins/pull_request_in_docker.sh
@@ -55,7 +55,9 @@
   javanano_oracle7 \
   python \
   python_cpp \
-  ruby21 \
+  ruby_all \
+  javascript \
+  golang \
   || true  # Process test results even if tests fail.
 
 cat $OUTPUT_DIR/joblog
diff --git a/js/README.md b/js/README.md
index 15d48c8..f418462 100644
--- a/js/README.md
+++ b/js/README.md
@@ -152,8 +152,7 @@
     // Serializes to a UInt8Array.
     bytes = message.serializeBinary();
 
-    var message2 = new MyMessage();
-    message2.deserializeBinary(bytes);
+    var message2 = MyMessage.deserializeBinary(bytes);
 
 For more examples, see the tests.  You can also look at the generated code
 to see what methods are defined for your generated messages.
diff --git a/js/commonjs/export.js b/js/commonjs/export.js
index a3cfbd6..2403b1a 100644
--- a/js/commonjs/export.js
+++ b/js/commonjs/export.js
@@ -8,13 +8,17 @@
 goog.require('goog.object');
 goog.require('jspb.BinaryReader');
 goog.require('jspb.BinaryWriter');
+goog.require('jspb.ExtensionFieldBinaryInfo');
 goog.require('jspb.ExtensionFieldInfo');
 goog.require('jspb.Message');
+goog.require('jspb.Map');
 
+exports.Map = jspb.Map;
 exports.Message = jspb.Message;
 exports.BinaryReader = jspb.BinaryReader;
 exports.BinaryWriter = jspb.BinaryWriter;
 exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
+exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo;
 
 // These are used by generated code but should not be used directly by clients.
 exports.exportSymbol = goog.exportSymbol;
diff --git a/js/debug.js b/js/debug.js
index 3701a09..3c1ada0 100644
--- a/js/debug.js
+++ b/js/debug.js
@@ -94,8 +94,10 @@
     var match = /^get([A-Z]\w*)/.exec(name);
     if (match && name != 'getExtension' &&
         name != 'getJsPbMessageId') {
-      var val = thing[name]();
-      if (val != null) {
+      var has = 'has' + match[1];
+      if (!thing[has] || thing[has]())
+      {
+        var val = thing[name]();
         object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val);
       }
     }
diff --git a/js/map.js b/js/map.js
index 821765e..e6406a6 100644
--- a/js/map.js
+++ b/js/map.js
@@ -44,65 +44,23 @@
  * on ES6 itself.
  *
  * This constructor should only be called from generated message code. It is not
- * intended for general use by library consumers. The callback function
- * arguments are references to methods in `BinaryReader` and `BinaryWriter`, as
- * well as constructors and reader/writer methods in submessage types if
- * appropriate, that are used for binary serialization and parsing.
+ * intended for general use by library consumers.
  *
  * @template K, V
  *
  * @param {!Array<!Array<!Object>>} arr
  *
- * @param {function(this:jspb.BinaryWriter,number,K)=} opt_keyWriterFn
- *     The method on BinaryWriter that writes type K to the stream.
- *
- * @param {function(this:jspb.BinaryReader):K=} opt_keyReaderFn
- *     The method on BinaryReader that reads type K from the stream.
- *
- * @param {function(this:jspb.BinaryWriter,number,V)|
- *         function(this:jspb.BinaryReader,V,?)=} opt_valueWriterFn
- *     The method on BinaryWriter that writes type V to the stream.  May be
- *     writeMessage, in which case the second callback arg form is used.
- *
- * @param {function(this:jspb.BinaryReader):V|
- *         function(this:jspb.BinaryReader,V,
- *                  function(V,!jspb.BinaryReader))=} opt_valueReaderFn
- *    The method on BinaryReader that reads type V from the stream. May be
- *    readMessage, in which case the second callback arg form is used.
- *
  * @param {?function(new:V)|function(new:V,?)=} opt_valueCtor
  *    The constructor for type V, if type V is a message type.
  *
- * @param {?function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
- *    The BinaryWriter serialization callback for type V, if V is a message
- *    type.
- *
- * @param {?function(V,!jspb.BinaryReader)=} opt_valueReaderCallback
- *    The BinaryReader parsing callback for type V, if V is a message type.
- *
  * @constructor
  * @struct
  */
-jspb.Map = function(
-    arr, opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn, opt_valueReaderFn,
-    opt_valueCtor, opt_valueWriterCallback, opt_valueReaderCallback) {
-
+jspb.Map = function(arr, opt_valueCtor) {
   /** @const @private */
   this.arr_ = arr;
   /** @const @private */
-  this.keyWriterFn_ = opt_keyWriterFn;
-  /** @const @private */
-  this.keyReaderFn_ = opt_keyReaderFn;
-  /** @const @private */
-  this.valueWriterFn_ = opt_valueWriterFn;
-  /** @const @private */
-  this.valueReaderFn_ = opt_valueReaderFn;
-  /** @const @private */
   this.valueCtor_ = opt_valueCtor;
-  /** @const @private */
-  this.valueWriterCallback_ = opt_valueWriterCallback;
-  /** @const @private */
-  this.valueReaderCallback_ = opt_valueReaderCallback;
 
   /** @type {!Object<string, !jspb.Map.Entry_<K,V>>} @private */
   this.map_ = {};
@@ -385,19 +343,29 @@
  * number.
  * @param {number} fieldNumber
  * @param {!jspb.BinaryWriter} writer
+ * @param {function(this:jspb.BinaryWriter,number,K)=} keyWriterFn
+ *     The method on BinaryWriter that writes type K to the stream.
+ * @param {function(this:jspb.BinaryWriter,number,V)|
+ *         function(this:jspb.BinaryReader,V,?)=} valueWriterFn
+ *     The method on BinaryWriter that writes type V to the stream.  May be
+ *     writeMessage, in which case the second callback arg form is used.
+ * @param {?function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
+ *    The BinaryWriter serialization callback for type V, if V is a message
+ *    type.
  */
-jspb.Map.prototype.serializeBinary = function(fieldNumber, writer) {
+jspb.Map.prototype.serializeBinary = function(
+    fieldNumber, writer, keyWriterFn, valueWriterFn, opt_valueWriterCallback) {
   var strKeys = this.stringKeys_();
   strKeys.sort();
   for (var i = 0; i < strKeys.length; i++) {
     var entry = this.map_[strKeys[i]];
     writer.beginSubMessage(fieldNumber);
-    this.keyWriterFn_.call(writer, 1, entry.key);
+    keyWriterFn.call(writer, 1, entry.key);
     if (this.valueCtor_) {
-      this.valueWriterFn_.call(writer, 2, this.wrapEntry_(entry),
-                               this.valueWriterCallback_);
+      valueWriterFn.call(writer, 2, this.wrapEntry_(entry),
+                         opt_valueWriterCallback);
     } else {
-      this.valueWriterFn_.call(writer, 2, entry.value);
+      valueWriterFn.call(writer, 2, entry.value);
     }
     writer.endSubMessage();
   }
@@ -410,8 +378,21 @@
  * when a key/value pair submessage is encountered.
  * @param {!jspb.Map} map
  * @param {!jspb.BinaryReader} reader
+ * @param {function(this:jspb.BinaryReader):K=} keyReaderFn
+ *     The method on BinaryReader that reads type K from the stream.
+ *
+ * @param {function(this:jspb.BinaryReader):V|
+ *         function(this:jspb.BinaryReader,V,
+ *                  function(V,!jspb.BinaryReader))=} valueReaderFn
+ *    The method on BinaryReader that reads type V from the stream. May be
+ *    readMessage, in which case the second callback arg form is used.
+ *
+ * @param {?function(V,!jspb.BinaryReader)=} opt_valueReaderCallback
+ *    The BinaryReader parsing callback for type V, if V is a message type.
+ *
  */
-jspb.Map.deserializeBinary = function(map, reader) {
+jspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,
+                                      opt_valueReaderCallback) {
   var key = undefined;
   var value = undefined;
 
@@ -422,14 +403,14 @@
     var field = reader.getFieldNumber();
     if (field == 1) {
       // Key.
-      key = map.keyReaderFn_.call(reader);
+      key = keyReaderFn.call(reader);
     } else if (field == 2) {
       // Value.
       if (map.valueCtor_) {
         value = new map.valueCtor_();
-        map.valueReaderFn_.call(reader, value, map.valueReaderCallback_);
+        valueReaderFn.call(reader, value, opt_valueReaderCallback);
       } else {
-        value = map.valueReaderFn_.call(reader);
+        value = valueReaderFn.call(reader);
       }
     }
   }
diff --git a/js/message.js b/js/message.js
index 3863bac..631ebe6 100644
--- a/js/message.js
+++ b/js/message.js
@@ -34,6 +34,7 @@
  * @author mwr@google.com (Mark Rawling)
  */
 
+goog.provide('jspb.ExtensionFieldBinaryInfo');
 goog.provide('jspb.ExtensionFieldInfo');
 goog.provide('jspb.Message');
 
@@ -84,19 +85,12 @@
  * @param {?function(new: jspb.Message, Array=)} ctor
  * @param {?function((boolean|undefined),!jspb.Message):!Object} toObjectFn
  * @param {number} isRepeated
- * @param {?function(number,?)=} opt_binaryReaderFn
- * @param {?function(number,?)|function(number,?,?,?,?,?)=} opt_binaryWriterFn
- * @param {?function(?,?)=} opt_binaryMessageSerializeFn
- * @param {?function(?,?)=} opt_binaryMessageDeserializeFn
- * @param {?boolean=} opt_isPacked
  * @constructor
  * @struct
  * @template T
  */
 jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
-    isRepeated, opt_binaryReaderFn, opt_binaryWriterFn,
-    opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn,
-    opt_isPacked) {
+    isRepeated) {
   /** @const */
   this.fieldIndex = fieldNumber;
   /** @const */
@@ -106,19 +100,36 @@
   /** @const */
   this.toObjectFn = toObjectFn;
   /** @const */
-  this.binaryReaderFn = opt_binaryReaderFn;
-  /** @const */
-  this.binaryWriterFn = opt_binaryWriterFn;
-  /** @const */
-  this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn;
-  /** @const */
-  this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn;
-  /** @const */
   this.isRepeated = isRepeated;
-  /** @const */
-  this.isPacked = opt_isPacked;
 };
 
+/**
+ * Stores binary-related information for a single extension field.
+ * @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
+ * @param {?function(number,?)=} binaryReaderFn
+ * @param {?function(number,?)|function(number,?,?,?,?,?)=} binaryWriterFn
+ * @param {?function(?,?)=} opt_binaryMessageSerializeFn
+ * @param {?function(?,?)=} opt_binaryMessageDeserializeFn
+ * @param {?boolean=} opt_isPacked
+ * @constructor
+ * @struct
+ * @template T
+ */
+jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriterFn,
+    binaryMessageSerializeFn, binaryMessageDeserializeFn, isPacked) {
+  /** @const */
+  this.fieldInfo = fieldInfo;
+  /** @const */
+  this.binaryReaderFn = binaryReaderFn;
+  /** @const */
+  this.binaryWriterFn = binaryWriterFn;
+  /** @const */
+  this.binaryMessageSerializeFn = binaryMessageSerializeFn;
+  /** @const */
+  this.binaryMessageDeserializeFn = binaryMessageDeserializeFn;
+  /** @const */
+  this.isPacked = isPacked;
+};
 
 /**
  * @return {boolean} Does this field represent a sub Message?
@@ -491,11 +502,13 @@
 jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
     getExtensionFn) {
   for (var fieldNumber in extensions) {
-    var fieldInfo = extensions[fieldNumber];
+    var binaryFieldInfo = extensions[fieldNumber];
+    var fieldInfo = binaryFieldInfo.fieldInfo;
+
     // The old codegen doesn't add the extra fields to ExtensionFieldInfo, so we
     // need to gracefully error-out here rather than produce a null dereference
     // below.
-    if (!fieldInfo.binaryWriterFn) {
+    if (!binaryFieldInfo.binaryWriterFn) {
       throw new Error('Message extension present that was generated ' +
                       'without binary serialization support');
     }
@@ -508,16 +521,17 @@
         // message may require binary support, so we can *only* catch this error
         // here, at runtime (and this decoupled codegen is the whole point of
         // extensions!).
-        if (fieldInfo.binaryMessageSerializeFn) {
-          fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
-              value, fieldInfo.binaryMessageSerializeFn);
+        if (binaryFieldInfo.binaryMessageSerializeFn) {
+          binaryFieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
+              value, binaryFieldInfo.binaryMessageSerializeFn);
         } else {
           throw new Error('Message extension present holding submessage ' +
                           'without binary support enabled, and message is ' +
                           'being serialized to binary format');
         }
       } else {
-        fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex, value);
+        binaryFieldInfo.binaryWriterFn.call(
+            writer, fieldInfo.fieldIndex, value);
       }
     }
   }
@@ -535,12 +549,13 @@
  */
 jspb.Message.readBinaryExtension = function(msg, reader, extensions,
     getExtensionFn, setExtensionFn) {
-  var fieldInfo = extensions[reader.getFieldNumber()];
-  if (!fieldInfo) {
+  var binaryFieldInfo = extensions[reader.getFieldNumber()];
+  var fieldInfo = binaryFieldInfo.fieldInfo;
+  if (!binaryFieldInfo) {
     reader.skipField();
     return;
   }
-  if (!fieldInfo.binaryReaderFn) {
+  if (!binaryFieldInfo.binaryReaderFn) {
     throw new Error('Deserializing extension whose generated code does not ' +
                     'support binary format');
   }
@@ -548,14 +563,14 @@
   var value;
   if (fieldInfo.isMessageType()) {
     value = new fieldInfo.ctor();
-    fieldInfo.binaryReaderFn.call(
-        reader, value, fieldInfo.binaryMessageDeserializeFn);
+    binaryFieldInfo.binaryReaderFn.call(
+        reader, value, binaryFieldInfo.binaryMessageDeserializeFn);
   } else {
     // All other types.
-    value = fieldInfo.binaryReaderFn.call(reader);
+    value = binaryFieldInfo.binaryReaderFn.call(reader);
   }
 
-  if (fieldInfo.isRepeated && !fieldInfo.isPacked) {
+  if (fieldInfo.isRepeated && !binaryFieldInfo.isPacked) {
     var currentList = getExtensionFn.call(msg, fieldInfo);
     if (!currentList) {
       setExtensionFn.call(msg, fieldInfo, [value]);
@@ -747,29 +762,16 @@
  * of serialization/parsing callbacks (which are required by the map at
  * construction time, and the map may be constructed here).
  *
- * The below callbacks are used to allow the map to serialize and parse its
- * binary wire format data. Their purposes are described in more detail in
- * `jspb.Map`'s constructor documentation.
- *
  * @template K, V
  * @param {!jspb.Message} msg
  * @param {number} fieldNumber
  * @param {boolean|undefined} noLazyCreate
  * @param {?=} opt_valueCtor
- * @param {function(number,K)=} opt_keyWriterFn
- * @param {function():K=} opt_keyReaderFn
- * @param {function(number,V)|function(number,V,?)|
- *         function(number,V,?,?,?,?)=} opt_valueWriterFn
- * @param {function():V|
- *         function(V,function(?,?))=} opt_valueReaderFn
- * @param {function(?,?)|function(?,?,?,?,?)=} opt_valueWriterCallback
- * @param {function(?,?)=} opt_valueReaderCallback
  * @return {!jspb.Map<K, V>|undefined}
  * @protected
  */
 jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
-    opt_valueCtor, opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
-    opt_valueReaderFn, opt_valueWriterCallback, opt_valueReaderCallback) {
+    opt_valueCtor) {
   if (!msg.wrappers_) {
     msg.wrappers_ = {};
   }
@@ -787,10 +789,7 @@
     }
     return msg.wrappers_[fieldNumber] =
         new jspb.Map(
-            /** @type {!Array<!Array<!Object>>} */ (arr),
-            opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
-            opt_valueReaderFn, opt_valueCtor, opt_valueWriterCallback,
-            opt_valueReaderCallback);
+            /** @type {!Array<!Array<!Object>>} */ (arr), opt_valueCtor);
   }
 };
 
diff --git a/js/message_test.js b/js/message_test.js
index 0b0c017..b779143 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -215,6 +215,10 @@
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
     assertEquals(13, response.getEnumField());
+    assertFalse(response.hasStringField());
+    assertFalse(response.hasBoolField());
+    assertFalse(response.hasIntField());
+    assertFalse(response.hasEnumField());
 
     // Test with null values, as would be returned by a JSON serializer.
     response = makeDefault([null, null, null, null]);
@@ -222,6 +226,10 @@
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
     assertEquals(13, response.getEnumField());
+    assertFalse(response.hasStringField());
+    assertFalse(response.hasBoolField());
+    assertFalse(response.hasIntField());
+    assertFalse(response.hasEnumField());
 
     // Test with false-like values.
     response = makeDefault(['', false, 0, 0]);
@@ -229,6 +237,10 @@
     assertEquals(false, response.getBoolField());
     assertEquals(true, response.getIntField() == 0);
     assertEquals(true, response.getEnumField() == 0);
+    assertTrue(response.hasStringField());
+    assertTrue(response.hasBoolField());
+    assertTrue(response.hasIntField());
+    assertTrue(response.hasEnumField());
 
     // Test that clearing the values reverts them to the default state.
     response = makeDefault(['blah', false, 111, 77]);
@@ -238,6 +250,10 @@
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
     assertEquals(13, response.getEnumField());
+    assertFalse(response.hasStringField());
+    assertFalse(response.hasBoolField());
+    assertFalse(response.hasIntField());
+    assertFalse(response.hasEnumField());
 
     // Test that setFoo(null) clears the values.
     response = makeDefault(['blah', false, 111, 77]);
@@ -247,6 +263,10 @@
     assertEquals(true, response.getBoolField());
     assertEquals(11, response.getIntField());
     assertEquals(13, response.getEnumField());
+    assertFalse(response.hasStringField());
+    assertFalse(response.hasBoolField());
+    assertFalse(response.hasIntField());
+    assertFalse(response.hasEnumField());
   });
 
   it('testMessageRegistration', function() {
@@ -256,9 +276,6 @@
   });
 
   it('testClearFields', function() {
-    // We don't set 'proper' defaults, rather, bools, strings,
-    // etc, are cleared to undefined or null and take on the Javascript
-    // meaning for that value. Repeated fields are set to [] when cleared.
     var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
     var foo = new proto.jspb.test.OptionalFields(data);
     foo.clearAString();
@@ -266,9 +283,11 @@
     foo.clearANestedMessage();
     foo.clearARepeatedMessageList();
     foo.clearARepeatedStringList();
-    assertUndefined(foo.getAString());
-    assertUndefined(foo.getABool());
+    assertEquals('', foo.getAString());
+    assertEquals(false, foo.getABool());
     assertUndefined(foo.getANestedMessage());
+    assertFalse(foo.hasAString());
+    assertFalse(foo.hasABool());
     assertObjectEquals([], foo.getARepeatedMessageList());
     assertObjectEquals([], foo.getARepeatedStringList());
     // NOTE: We want the missing fields in 'expected' to be undefined,
@@ -288,9 +307,11 @@
     foo.setANestedMessage(null);
     foo.setARepeatedMessageList(null);
     foo.setARepeatedStringList(null);
-    assertNull(foo.getAString());
-    assertNull(foo.getABool());
+    assertEquals('', foo.getAString());
+    assertEquals(false, foo.getABool());
     assertNull(foo.getANestedMessage());
+    assertFalse(foo.hasAString());
+    assertFalse(foo.hasABool());
     assertObjectEquals([], foo.getARepeatedMessageList());
     assertObjectEquals([], foo.getARepeatedStringList());
     assertObjectEquals([null, null, null, [], []], foo.toArray());
@@ -304,9 +325,11 @@
     foo.setANestedMessage(undefined);
     foo.setARepeatedMessageList(undefined);
     foo.setARepeatedStringList(undefined);
-    assertUndefined(foo.getAString());
-    assertUndefined(foo.getABool());
+    assertEquals('', foo.getAString());
+    assertEquals(false, foo.getABool());
     assertUndefined(foo.getANestedMessage());
+    assertFalse(foo.hasAString());
+    assertFalse(foo.hasABool());
     assertObjectEquals([], foo.getARepeatedMessageList());
     assertObjectEquals([], foo.getARepeatedStringList());
     expected = [,,, [], []];
@@ -320,9 +343,9 @@
                                                {1000: 'unique'}]);
     var diff = /** @type {proto.jspb.test.HasExtensions} */
         (jspb.Message.difference(p1, p2));
-    assertUndefined(diff.getStr1());
+    assertEquals('', diff.getStr1());
     assertEquals('what', diff.getStr2());
-    assertUndefined(diff.getStr3());
+    assertEquals('', diff.getStr3());
     assertEquals('unique', diff.extensionObject_[1000]);
   });
 
@@ -780,7 +803,7 @@
     var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
 
     assertEquals('x', message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPthree());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
         message.getPartialOneofCase());
@@ -789,7 +812,7 @@
   it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
     var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
 
-    assertUndefined('x', message.getPone());
+    assertEquals('', message.getPone());
     assertEquals('y', message.getPthree());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
@@ -798,35 +821,47 @@
 
   it('testSettingOneofFieldClearsOthers', function() {
     var message = new proto.jspb.test.TestMessageWithOneof;
-    assertUndefined(message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPone());
+    assertEquals('', message.getPthree());
+    assertFalse(message.hasPone());
+    assertFalse(message.hasPthree());
 
     message.setPone('hi');
     assertEquals('hi', message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPthree());
+    assertTrue(message.hasPone());
+    assertFalse(message.hasPthree());
 
     message.setPthree('bye');
-    assertUndefined(message.getPone());
+    assertEquals('', message.getPone());
     assertEquals('bye', message.getPthree());
+    assertFalse(message.hasPone());
+    assertTrue(message.hasPthree());
   });
 
   it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
     var other = new proto.jspb.test.TestMessageWithOneof;
     var message = new proto.jspb.test.TestMessageWithOneof;
-    assertUndefined(message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPone());
+    assertEquals('', message.getPthree());
     assertUndefined(message.getRone());
+    assertFalse(message.hasPone());
+    assertFalse(message.hasPthree());
 
     message.setPone('hi');
     message.setRone(other);
     assertEquals('hi', message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPthree());
     assertEquals(other, message.getRone());
+    assertTrue(message.hasPone());
+    assertFalse(message.hasPthree());
 
     message.setPthree('bye');
-    assertUndefined(message.getPone());
+    assertEquals('', message.getPone());
     assertEquals('bye', message.getPthree());
     assertEquals(other, message.getRone());
+    assertFalse(message.hasPone());
+    assertTrue(message.hasPthree());
   });
 
   it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
@@ -851,7 +886,7 @@
   it('testMessageWithDefaultOneofValues', function() {
     var message = new proto.jspb.test.TestMessageWithOneof;
     assertEquals(1234, message.getAone());
-    assertUndefined(message.getAtwo());
+    assertEquals(0, message.getAtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
             .DEFAULT_ONEOF_A_NOT_SET,
@@ -859,7 +894,7 @@
 
     message.setAone(567);
     assertEquals(567, message.getAone());
-    assertUndefined(message.getAtwo());
+    assertEquals(0, message.getAtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
         message.getDefaultOneofACase());
@@ -873,7 +908,7 @@
 
     message.clearAtwo();
     assertEquals(1234, message.getAone());
-    assertUndefined(message.getAtwo());
+    assertEquals(0, message.getAtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
             .DEFAULT_ONEOF_A_NOT_SET,
@@ -882,8 +917,10 @@
 
   it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
     var message = new proto.jspb.test.TestMessageWithOneof;
-    assertUndefined(message.getBone());
+    assertEquals(0, message.getBone());
     assertEquals(1234, message.getBtwo());
+    assertFalse(message.hasBone());
+    assertFalse(message.hasBtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
             .DEFAULT_ONEOF_B_NOT_SET,
@@ -892,19 +929,25 @@
     message.setBone(2);
     assertEquals(2, message.getBone());
     assertEquals(1234, message.getBtwo());
+    assertTrue(message.hasBone());
+    assertFalse(message.hasBtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
         message.getDefaultOneofBCase());
 
     message.setBtwo(3);
-    assertUndefined(message.getBone());
+    assertEquals(0, message.getBone());
+    assertFalse(message.hasBone());
+    assertTrue(message.hasBtwo());
     assertEquals(3, message.getBtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
         message.getDefaultOneofBCase());
 
     message.clearBtwo();
-    assertUndefined(message.getBone());
+    assertEquals(0, message.getBone());
+    assertFalse(message.hasBone());
+    assertFalse(message.hasBtwo());
     assertEquals(1234, message.getBtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
@@ -916,7 +959,7 @@
     var message =
         new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567));
     assertEquals(567, message.getAone());
-    assertUndefined(message.getAtwo());
+    assertEquals(0, message.getAtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
         message.getDefaultOneofACase());
@@ -952,7 +995,7 @@
 
         message =
             new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890));
-        assertUndefined(message.getBone());
+        assertEquals(0, message.getBone());
         assertEquals(890, message.getBtwo());
         assertEquals(
             proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
@@ -960,7 +1003,7 @@
 
         message = new proto.jspb.test.TestMessageWithOneof(
             new Array(11).concat(567, 890));
-        assertUndefined(message.getBone());
+        assertEquals(0, message.getBone());
         assertEquals(890, message.getBtwo());
         assertEquals(
             proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
@@ -977,7 +1020,7 @@
     var other = new proto.jspb.test.TestMessageWithOneof;
     message.setRone(other);
     assertEquals(other, message.getRone());
-    assertUndefined(message.getRtwo());
+    assertEquals('', message.getRtwo());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
         message.getRecursiveOneofCase());
@@ -995,7 +1038,7 @@
     var message = new proto.jspb.test.TestMessageWithOneof;
     message.setPone('x');
     assertEquals('x', message.getPone());
-    assertUndefined(message.getPthree());
+    assertEquals('', message.getPthree());
     assertEquals(
         proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
         message.getPartialOneofCase());
diff --git a/js/package.json b/js/package.json
index 657b08b..3f51d96 100644
--- a/js/package.json
+++ b/js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "google-protobuf",
-  "version": "3.0.0-alpha.6.2",
+  "version": "3.0.0",
   "description": "Protocol Buffers for JavaScript",
   "main": "google-protobuf.js",
   "files": [
diff --git a/js/proto3_test.js b/js/proto3_test.js
index 4dd7790..fab0fd4 100644
--- a/js/proto3_test.js
+++ b/js/proto3_test.js
@@ -221,37 +221,52 @@
   it('testOneofs', function() {
     var msg = new proto.jspb.test.TestProto3();
 
-    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofUint32(), 0);
     assertEquals(msg.getOneofForeignMessage(), undefined);
-    assertEquals(msg.getOneofString(), undefined);
-    assertEquals(msg.getOneofBytes(), undefined);
+    assertEquals(msg.getOneofString(), '');
+    assertEquals(msg.getOneofBytes(), '');
+    assertFalse(msg.hasOneofUint32());
+    assertFalse(msg.hasOneofString());
+    assertFalse(msg.hasOneofBytes());
 
     msg.setOneofUint32(42);
     assertEquals(msg.getOneofUint32(), 42);
     assertEquals(msg.getOneofForeignMessage(), undefined);
-    assertEquals(msg.getOneofString(), undefined);
-    assertEquals(msg.getOneofBytes(), undefined);
+    assertEquals(msg.getOneofString(), '');
+    assertEquals(msg.getOneofBytes(), '');
+    assertTrue(msg.hasOneofUint32());
+    assertFalse(msg.hasOneofString());
+    assertFalse(msg.hasOneofBytes());
 
 
     var submsg = new proto.jspb.test.ForeignMessage();
     msg.setOneofForeignMessage(submsg);
-    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofUint32(), 0);
     assertEquals(msg.getOneofForeignMessage(), submsg);
-    assertEquals(msg.getOneofString(), undefined);
-    assertEquals(msg.getOneofBytes(), undefined);
+    assertEquals(msg.getOneofString(), '');
+    assertEquals(msg.getOneofBytes(), '');
+    assertFalse(msg.hasOneofUint32());
+    assertFalse(msg.hasOneofString());
+    assertFalse(msg.hasOneofBytes());
 
     msg.setOneofString('hello');
-    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofUint32(), 0);
     assertEquals(msg.getOneofForeignMessage(), undefined);
     assertEquals(msg.getOneofString(), 'hello');
-    assertEquals(msg.getOneofBytes(), undefined);
+    assertEquals(msg.getOneofBytes(), '');
+    assertFalse(msg.hasOneofUint32());
+    assertTrue(msg.hasOneofString());
+    assertFalse(msg.hasOneofBytes());
 
     msg.setOneofBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
-    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofUint32(), 0);
     assertEquals(msg.getOneofForeignMessage(), undefined);
-    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofString(), '');
     assertEquals(msg.getOneofBytes_asB64(),
         goog.crypt.base64.encodeString('\u00FF\u00FF'));
+    assertFalse(msg.hasOneofUint32());
+    assertFalse(msg.hasOneofString());
+    assertTrue(msg.hasOneofBytes());
   });
 
 
diff --git a/js/test.proto b/js/test.proto
index cf2eafe..937ffb8 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -233,3 +233,4 @@
   optional int32 value = 1;
   optional bytes data = 2;
 }
+
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh
index 8295313..6cc32da 100755
--- a/objectivec/DevTools/compile_testing_protos.sh
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -1,17 +1,16 @@
-#!/bin/bash
-
+#!/bin/bash -eu
 # Invoked by the Xcode projects to build the protos needed for the unittests.
 
-set -eu
-
 readonly OUTPUT_DIR="${PROJECT_DERIVED_FILE_DIR}/protos"
 
+# -----------------------------------------------------------------------------
 # Helper for bailing.
 die() {
   echo "Error: $1"
   exit 2
 }
 
+# -----------------------------------------------------------------------------
 # What to do.
 case "${ACTION}" in
   "")
@@ -26,12 +25,19 @@
     ;;
 esac
 
-# Move to the top of the protobuf directories.
-cd "${SRCROOT}/.."
+# -----------------------------------------------------------------------------
+# Ensure the output dir exists
+mkdir -p "${OUTPUT_DIR}/google/protobuf"
 
+# -----------------------------------------------------------------------------
+# Move to the top of the protobuf directories and ensure there is a protoc
+# binary to use.
+cd "${SRCROOT}/.."
 [[ -x src/protoc ]] || \
   die "Could not find the protoc binary; make sure you have built it (objectivec/DevTools/full_mac_build.sh -h)."
 
+# -----------------------------------------------------------------------------
+# See the compiler or proto files have changed.
 RUN_PROTOC=no
 if [[ ! -d "${OUTPUT_DIR}" ]] ; then
   RUN_PROTOC=yes
@@ -50,7 +56,7 @@
   # Find the oldest output file.
   readonly OldestOutput=$(find \
         "${OUTPUT_DIR}" \
-        -type f -print0 \
+        -type f -name "*pbobjc.[hm]" -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.
@@ -64,10 +70,30 @@
   exit 0
 fi
 
-# Ensure the output dir exists
-mkdir -p "${OUTPUT_DIR}/google/protobuf"
+# -----------------------------------------------------------------------------
+# Prune out all the files from previous generations to ensure we only have
+# current ones.
+find "${OUTPUT_DIR}" \
+    -type f -name "*pbobjc.[hm]" -print0 \
+    | xargs -0 rm -rf
+
+# -----------------------------------------------------------------------------
+# Helper to invoke protoc
+compile_protos() {
+  src/protoc                                   \
+    --objc_out="${OUTPUT_DIR}/google/protobuf" \
+    --proto_path=src/google/protobuf/          \
+    --proto_path=src                           \
+    "$@"
+}
+
+# -----------------------------------------------------------------------------
+# Generate most of the proto files that exist in the C++ src tree.  Several
+# are used in the tests, but the extra don't hurt in that they ensure ObjC
+# sources can be generated from them.
 
 CORE_PROTO_FILES=(
+  src/google/protobuf/any_test.proto
   src/google/protobuf/unittest_arena.proto
   src/google/protobuf/unittest_custom_options.proto
   src/google/protobuf/unittest_enormous_descriptor.proto
@@ -90,35 +116,32 @@
   src/google/protobuf/map_lite_unittest.proto
   src/google/protobuf/map_proto2_unittest.proto
   src/google/protobuf/map_unittest.proto
-)
-
-# The unittest_custom_options.proto extends the messages in descriptor.proto
-# so we build it in to test extending in general. The library doesn't provide
-# a descriptor as it doesn't use the classes/enums.
-CORE_PROTO_FILES+=(
+  # The unittest_custom_options.proto extends the messages in descriptor.proto
+  # so we build it in to test extending in general. The library doesn't provide
+  # a descriptor as it doesn't use the classes/enums.
   src/google/protobuf/descriptor.proto
 )
 
-compile_proto() {
-  src/protoc                                   \
-    --objc_out="${OUTPUT_DIR}/google/protobuf" \
-    --proto_path=src/google/protobuf/          \
-    --proto_path=src                           \
-    $*
-}
-
+# Note: there is overlap in package.Message names between some of the test
+# files, so they can't be generated all at once. This works because the overlap
+# isn't linked into a single binary.
 for a_proto in "${CORE_PROTO_FILES[@]}" ; do
-  compile_proto "${a_proto}"
+  compile_protos "${a_proto}"
 done
 
-OBJC_PROTO_FILES=(
-  objectivec/Tests/unittest_cycle.proto
-  objectivec/Tests/unittest_runtime_proto2.proto
-  objectivec/Tests/unittest_runtime_proto3.proto
-  objectivec/Tests/unittest_objc.proto
+# -----------------------------------------------------------------------------
+# Generate the Objective C specific testing protos.
+compile_protos \
+  --proto_path="objectivec/Tests" \
+  objectivec/Tests/unittest_cycle.proto \
+  objectivec/Tests/unittest_extension_chain_a.proto \
+  objectivec/Tests/unittest_extension_chain_b.proto \
+  objectivec/Tests/unittest_extension_chain_c.proto \
+  objectivec/Tests/unittest_extension_chain_d.proto \
+  objectivec/Tests/unittest_extension_chain_e.proto \
+  objectivec/Tests/unittest_extension_chain_f.proto \
+  objectivec/Tests/unittest_extension_chain_g.proto \
+  objectivec/Tests/unittest_runtime_proto2.proto \
+  objectivec/Tests/unittest_runtime_proto3.proto \
+  objectivec/Tests/unittest_objc.proto \
   objectivec/Tests/unittest_objc_startup.proto
-)
-
-for a_proto in "${OBJC_PROTO_FILES[@]}" ; do
-  compile_proto --proto_path="objectivec/Tests" "${a_proto}"
-done
diff --git a/objectivec/GPBArray.h b/objectivec/GPBArray.h
index afda57f..781cfb6 100644
--- a/objectivec/GPBArray.h
+++ b/objectivec/GPBArray.h
@@ -32,11 +32,6 @@
 
 #import "GPBRuntimeTypes.h"
 
-// These classes are used for repeated fields of basic data types. They are used because
-// they perform better than boxing into NSNumbers in NSArrays.
-
-// Note: These are not meant to be subclassed.
-
 NS_ASSUME_NONNULL_BEGIN
 
 //%PDDM-EXPAND DECLARE_ARRAYS()
@@ -44,39 +39,171 @@
 
 #pragma mark - Int32
 
+/**
+ * Class used for repeated fields of int32_t values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32Array : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBInt32Array.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBInt32Array with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBInt32Array with value in it.
+ **/
 + (instancetype)arrayWithValue:(int32_t)value;
+
+/**
+ * Creates and initializes a GPBInt32Array with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBInt32Array with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBInt32Array *)array;
+
+/**
+ * Creates and initializes a GPBInt32Array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBInt32Array with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBInt32Array.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBInt32Array with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const int32_t [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBInt32Array with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBInt32Array *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBInt32Array with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (int32_t)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(int32_t)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const int32_t [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBInt32Array *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(int32_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -84,39 +211,171 @@
 
 #pragma mark - UInt32
 
+/**
+ * Class used for repeated fields of uint32_t values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32Array : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBUInt32Array.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBUInt32Array with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBUInt32Array with value in it.
+ **/
 + (instancetype)arrayWithValue:(uint32_t)value;
+
+/**
+ * Creates and initializes a GPBUInt32Array with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBUInt32Array with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBUInt32Array *)array;
+
+/**
+ * Creates and initializes a GPBUInt32Array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBUInt32Array with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBUInt32Array.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBUInt32Array with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const uint32_t [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBUInt32Array with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBUInt32Array *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBUInt32Array with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (uint32_t)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(uint32_t)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const uint32_t [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBUInt32Array *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(uint32_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint32_t)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -124,39 +383,171 @@
 
 #pragma mark - Int64
 
+/**
+ * Class used for repeated fields of int64_t values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64Array : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBInt64Array.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBInt64Array with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBInt64Array with value in it.
+ **/
 + (instancetype)arrayWithValue:(int64_t)value;
+
+/**
+ * Creates and initializes a GPBInt64Array with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBInt64Array with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBInt64Array *)array;
+
+/**
+ * Creates and initializes a GPBInt64Array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBInt64Array with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBInt64Array.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBInt64Array with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const int64_t [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBInt64Array with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBInt64Array *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBInt64Array with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (int64_t)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(int64_t)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const int64_t [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBInt64Array *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(int64_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(int64_t)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -164,39 +555,171 @@
 
 #pragma mark - UInt64
 
+/**
+ * Class used for repeated fields of uint64_t values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64Array : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBUInt64Array.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBUInt64Array with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBUInt64Array with value in it.
+ **/
 + (instancetype)arrayWithValue:(uint64_t)value;
+
+/**
+ * Creates and initializes a GPBUInt64Array with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBUInt64Array with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBUInt64Array *)array;
+
+/**
+ * Creates and initializes a GPBUInt64Array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBUInt64Array with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBUInt64Array.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBUInt64Array with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const uint64_t [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBUInt64Array with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBUInt64Array *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBUInt64Array with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (uint64_t)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(uint64_t)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const uint64_t [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBUInt64Array *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(uint64_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(uint64_t)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -204,39 +727,171 @@
 
 #pragma mark - Float
 
+/**
+ * Class used for repeated fields of float values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBFloatArray : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBFloatArray.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBFloatArray with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBFloatArray with value in it.
+ **/
 + (instancetype)arrayWithValue:(float)value;
+
+/**
+ * Creates and initializes a GPBFloatArray with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBFloatArray with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBFloatArray *)array;
+
+/**
+ * Creates and initializes a GPBFloatArray with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBFloatArray with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBFloatArray.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBFloatArray with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const float [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBFloatArray with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBFloatArray *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBFloatArray with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (float)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(float)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const float [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBFloatArray *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(float)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(float)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -244,39 +899,171 @@
 
 #pragma mark - Double
 
+/**
+ * Class used for repeated fields of double values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBDoubleArray : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBDoubleArray.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBDoubleArray with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBDoubleArray with value in it.
+ **/
 + (instancetype)arrayWithValue:(double)value;
+
+/**
+ * Creates and initializes a GPBDoubleArray with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBDoubleArray with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBDoubleArray *)array;
+
+/**
+ * Creates and initializes a GPBDoubleArray with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBDoubleArray with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBDoubleArray.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBDoubleArray with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const double [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBDoubleArray with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBDoubleArray *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBDoubleArray with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (double)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(double)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const double [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBDoubleArray *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(double)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(double)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -284,39 +1071,171 @@
 
 #pragma mark - Bool
 
+/**
+ * Class used for repeated fields of BOOL values. This performs better than
+ * boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolArray : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty GPBBoolArray.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBBoolArray with the single element given.
+ *
+ * @param value The value to be placed in the array.
+ *
+ * @return A newly instanced GPBBoolArray with value in it.
+ **/
 + (instancetype)arrayWithValue:(BOOL)value;
+
+/**
+ * Creates and initializes a GPBBoolArray with the contents of the given
+ * array.
+ *
+ * @param array Array with the contents to be put into the new array.
+ *
+ * @return A newly instanced GPBBoolArray with the contents of array.
+ **/
 + (instancetype)arrayWithValueArray:(GPBBoolArray *)array;
+
+/**
+ * Creates and initializes a GPBBoolArray with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBBoolArray with a capacity of count.
+ **/
 + (instancetype)arrayWithCapacity:(NSUInteger)count;
 
+/**
+ * @return A newly initialized and empty GPBBoolArray.
+ **/
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
-// Initializes the array, copying the values.
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBBoolArray with a copy of the values.
+ **/
 - (instancetype)initWithValues:(const BOOL [])values
                          count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBBoolArray with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBBoolArray *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBBoolArray with a capacity of count.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)count;
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (BOOL)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block;
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(BOOL)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const BOOL [])values count:(NSUInteger)count;
+
+/**
+ * Adds the values from the given array to this array.
+ *
+ * @param array The array containing the elements to add to this array.
+ **/
 - (void)addValuesFromArray:(GPBBoolArray *)array;
 
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(BOOL)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(BOOL)value;
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -324,27 +1243,108 @@
 
 #pragma mark - Enum
 
+/**
+ * This class is used for repeated fields of int32_t values. This performs
+ * better than boxing into NSNumbers in NSArrays.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBEnumArray : NSObject <NSCopying>
 
+/** The number of elements contained in the array. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty GPBEnumArray.
+ **/
 + (instancetype)array;
+
+/**
+ * Creates and initializes a GPBEnumArray with the enum validation function
+ * given.
+ *
+ * @param func The enum validation function for the array.
+ *
+ * @return A newly instanced GPBEnumArray.
+ **/
 + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a GPBEnumArray with the enum validation function
+ * given and the single raw value given.
+ *
+ * @param func  The enum validation function for the array.
+ * @param value The raw value to add to this array.
+ *
+ * @return A newly instanced GPBEnumArray.
+ **/
 + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                    rawValue:(int32_t)value;
+
+/**
+ * Creates and initializes a GPBEnumArray that adds the elements from the
+ * given array.
+ *
+ * @param array Array containing the values to add to the new array.
+ *
+ * @return A newly instanced GPBEnumArray.
+ **/
 + (instancetype)arrayWithValueArray:(GPBEnumArray *)array;
+
+/**
+ * Creates and initializes a GPBEnumArray with the given enum validation
+ * function and with the givencapacity.
+ *
+ * @param func  The enum validation function for the array.
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly instanced GPBEnumArray with a capacity of count.
+ **/
 + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                    capacity:(NSUInteger)count;
 
+/**
+ * Initializes the array with the given enum validation function.
+ *
+ * @param func The enum validation function for the array.
+ *
+ * @return A newly initialized GPBEnumArray with a copy of the values.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
     NS_DESIGNATED_INITIALIZER;
 
-// Initializes the array, copying the values.
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param func   The enum validation function for the array.
+ * @param values An array with the values to put inside this array.
+ * @param count  The number of elements to copy into the array.
+ *
+ * @return A newly initialized GPBEnumArray with a copy of the values.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                      count:(NSUInteger)count;
+
+/**
+ * Initializes the array, copying the given values.
+ *
+ * @param array An array with the values to put inside this array.
+ *
+ * @return A newly initialized GPBEnumArray with a copy of the values.
+ **/
 - (instancetype)initWithValueArray:(GPBEnumArray *)array;
+
+/**
+ * Initializes the array with the given capacity.
+ *
+ * @param func  The enum validation function for the array.
+ * @param count The capacity needed for the array.
+ *
+ * @return A newly initialized GPBEnumArray with a capacity of count.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)count;
 
@@ -352,18 +1352,68 @@
 // valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
+/**
+ * Gets the value at the given index.
+ *
+ * @param index The index of the value to get.
+ *
+ * @return The value at the given index.
+ **/
 - (int32_t)valueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
                         usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
 
 // These methods bypass the validationFunc to provide access to values that were not
 // known at the time the binary was compiled.
 
+/**
+ * Gets the raw enum value at the given index.
+ *
+ * @param index The index of the raw enum value to get.
+ *
+ * @return The raw enum value at the given index.
+ **/
 - (int32_t)rawValueAtIndex:(NSUInteger)index;
 
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
+
+/**
+ * Enumerates the values on this array with the given block.
+ *
+ * @param opts  Options to control the enumeration.
+ * @param block The block to enumerate with.
+ *   **value**: The current value being enumerated.
+ *   **idx**:   The index of the current value.
+ *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
                            usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
 
@@ -372,29 +1422,114 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Adds a value to this array.
+ *
+ * @param value The value to add to this array.
+ **/
 - (void)addValue:(int32_t)value;
+
+/**
+ * Adds values to this array.
+ *
+ * @param values The values to add to this array.
+ * @param count  The number of elements to add.
+ **/
 - (void)addValues:(const int32_t [])values count:(NSUInteger)count;
 
+
+/**
+ * Inserts a value into the given position.
+ *
+ * @param value The value to add to this array.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertValue:(int32_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the value at the given index with the given value.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;
 
 // These methods bypass the validationFunc to provide setting of values that were not
 // known at the time the binary was compiled.
 
+/**
+ * Adds a raw enum value to this array.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param value The raw enum value to add to the array.
+ **/
 - (void)addRawValue:(int32_t)value;
+
+/**
+ * Adds raw enum values to this array.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param array Array containing the raw enum values to add to this array.
+ **/
 - (void)addRawValuesFromArray:(GPBEnumArray *)array;
+
+/**
+ * Adds raw enum values to this array.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param values Array containing the raw enum values to add to this array.
+ * @param count  The number of raw values to add.
+ **/
 - (void)addRawValues:(const int32_t [])values count:(NSUInteger)count;
 
+/**
+ * Inserts a raw enum value at the given index.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param value Raw enum value to add.
+ * @param index The index into which to insert the value.
+ **/
 - (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)index;
 
+/**
+ * Replaces the raw enum value at the given index with the given value.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param index The index for which to replace the value.
+ * @param value The raw enum value to replace with.
+ **/
 - (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)value;
 
 // No validation applies to these methods.
 
+/**
+ * Removes the value at the given index.
+ *
+ * @param index The index of the value to remove.
+ **/
 - (void)removeValueAtIndex:(NSUInteger)index;
+
+/**
+ * Removes all the values from this array.
+ **/
 - (void)removeAll;
 
+/**
+ * Exchanges the values between the given indexes.
+ *
+ * @param idx1 The index of the first element to exchange.
+ * @param idx2 The index of the second element to exchange.
+ **/
 - (void)exchangeValueAtIndex:(NSUInteger)idx1
             withValueAtIndex:(NSUInteger)idx2;
 
@@ -421,20 +1556,82 @@
 //%PDDM-DEFINE ARRAY_INTERFACE_SIMPLE(NAME, TYPE)
 //%#pragma mark - NAME
 //%
+//%/**
+//% * Class used for repeated fields of ##TYPE## values. This performs better than
+//% * boxing into NSNumbers in NSArrays.
+//% *
+//% * @note This class is not meant to be subclassed.
+//% **/
 //%@interface GPB##NAME##Array : NSObject <NSCopying>
 //%
+//%/** The number of elements contained in the array. */
 //%@property(nonatomic, readonly) NSUInteger count;
 //%
+//%/**
+//% * @return A newly instanced and empty GPB##NAME##Array.
+//% **/
 //%+ (instancetype)array;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the single element given.
+//% * 
+//% * @param value The value to be placed in the array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array with value in it.
+//% **/
 //%+ (instancetype)arrayWithValue:(TYPE)value;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the contents of the given
+//% * array.
+//% *
+//% * @param array Array with the contents to be put into the new array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array with the contents of array.
+//% **/
 //%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the given capacity.
+//% *
+//% * @param count The capacity needed for the array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array with a capacity of count.
+//% **/
 //%+ (instancetype)arrayWithCapacity:(NSUInteger)count;
 //%
+//%/** 
+//% * @return A newly initialized and empty GPB##NAME##Array.
+//% **/
 //%- (instancetype)init NS_DESIGNATED_INITIALIZER;
-//%// Initializes the array, copying the values.
+//%
+//%/**
+//% * Initializes the array, copying the given values.
+//% *
+//% * @param values An array with the values to put inside this array.
+//% * @param count  The number of elements to copy into the array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a copy of the values.
+//% **/
 //%- (instancetype)initWithValues:(const TYPE [])values
 //%                         count:(NSUInteger)count;
+//%
+//%/**
+//% * Initializes the array, copying the given values.
+//% *
+//% * @param array An array with the values to put inside this array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a copy of the values.
+//% **/
 //%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array;
+//%
+//%/**
+//% * Initializes the array with the given capacity.
+//% *
+//% * @param count The capacity needed for the array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a capacity of count.
+//% **/
 //%- (instancetype)initWithCapacity:(NSUInteger)count;
 //%
 //%ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, Basic)
@@ -451,27 +1648,108 @@
 //%PDDM-DEFINE ARRAY_INTERFACE_ENUM(NAME, TYPE)
 //%#pragma mark - NAME
 //%
+//%/**
+//% * This class is used for repeated fields of ##TYPE## values. This performs
+//% * better than boxing into NSNumbers in NSArrays.
+//% *
+//% * @note This class is not meant to be subclassed.
+//% **/
 //%@interface GPB##NAME##Array : NSObject <NSCopying>
 //%
+//%/** The number of elements contained in the array. */
 //%@property(nonatomic, readonly) NSUInteger count;
+//%/** The validation function to check if the enums are valid. */
 //%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 //%
+//%/**
+//% * @return A newly instanced and empty GPB##NAME##Array.
+//% **/
 //%+ (instancetype)array;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the enum validation function
+//% * given.
+//% *
+//% * @param func The enum validation function for the array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array.
+//% **/
 //%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the enum validation function
+//% * given and the single raw value given.
+//% *
+//% * @param func  The enum validation function for the array.
+//% * @param value The raw value to add to this array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array.
+//% **/
 //%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                   rawValue:(TYPE)value;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array that adds the elements from the
+//% * given array.
+//% *
+//% * @param array Array containing the values to add to the new array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array.
+//% **/
 //%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array;
+//%
+//%/**
+//% * Creates and initializes a GPB##NAME##Array with the given enum validation
+//% * function and with the givencapacity.
+//% *
+//% * @param func  The enum validation function for the array.
+//% * @param count The capacity needed for the array.
+//% *
+//% * @return A newly instanced GPB##NAME##Array with a capacity of count.
+//% **/
 //%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                   capacity:(NSUInteger)count;
 //%
+//%/**
+//% * Initializes the array with the given enum validation function.
+//% *
+//% * @param func The enum validation function for the array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a copy of the values.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%    NS_DESIGNATED_INITIALIZER;
 //%
-//%// Initializes the array, copying the values.
+//%/**
+//% * Initializes the array, copying the given values.
+//% *
+//% * @param func   The enum validation function for the array.
+//% * @param values An array with the values to put inside this array.
+//% * @param count  The number of elements to copy into the array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a copy of the values.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                 rawValues:(const TYPE [])values
 //%                                     count:(NSUInteger)count;
+//%
+//%/**
+//% * Initializes the array, copying the given values.
+//% *
+//% * @param array An array with the values to put inside this array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a copy of the values.
+//% **/
 //%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array;
+//%
+//%/**
+//% * Initializes the array with the given capacity.
+//% *
+//% * @param func  The enum validation function for the array.
+//% * @param count The capacity needed for the array.
+//% *
+//% * @return A newly initialized GPB##NAME##Array with a capacity of count.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                  capacity:(NSUInteger)count;
 //%
@@ -484,9 +1762,34 @@
 //%// These methods bypass the validationFunc to provide access to values that were not
 //%// known at the time the binary was compiled.
 //%
+//%/**
+//% * Gets the raw enum value at the given index.
+//% *
+//% * @param index The index of the raw enum value to get.
+//% *
+//% * @return The raw enum value at the given index.
+//% **/
 //%- (TYPE)rawValueAtIndex:(NSUInteger)index;
 //%
+//%/**
+//% * Enumerates the values on this array with the given block.
+//% * 
+//% * @param block The block to enumerate with.
+//% *   **value**: The current value being enumerated.
+//% *   **idx**:   The index of the current value.
+//% *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateRawValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+//%
+//%/**
+//% * Enumerates the values on this array with the given block.
+//% *
+//% * @param opts  Options to control the enumeration.
+//% * @param block The block to enumerate with.
+//% *   **value**: The current value being enumerated.
+//% *   **idx**:   The index of the current value.
+//% *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
 //%                           usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
 //%
@@ -501,23 +1804,88 @@
 //%
 
 //%PDDM-DEFINE ARRAY_IMMUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME)
+//%/**
+//% * Gets the value at the given index.
+//% *
+//% * @param index The index of the value to get.
+//% *
+//% * @return The value at the given index.
+//% **/
 //%- (TYPE)valueAtIndex:(NSUInteger)index;
 //%
+//%/**
+//% * Enumerates the values on this array with the given block.
+//% *
+//% * @param block The block to enumerate with.
+//% *   **value**: The current value being enumerated.
+//% *   **idx**:   The index of the current value.
+//% *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
+//%
+//%/**
+//% * Enumerates the values on this array with the given block.
+//% *
+//% * @param opts  Options to control the enumeration.
+//% * @param block The block to enumerate with. 
+//% *   **value**: The current value being enumerated.
+//% *   **idx**:   The index of the current value.
+//% *   **stop**:  A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
 //%                        usingBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block;
 
 //%PDDM-DEFINE ARRAY_MUTABLE_INTERFACE(NAME, TYPE, HELPER_NAME)
+//%/**
+//% * Adds a value to this array.
+//% *
+//% * @param value The value to add to this array.
+//% **/
 //%- (void)addValue:(TYPE)value;
+//%
+//%/**
+//% * Adds values to this array.
+//% *
+//% * @param values The values to add to this array.
+//% * @param count  The number of elements to add.
+//% **/
 //%- (void)addValues:(const TYPE [])values count:(NSUInteger)count;
+//%
 //%ARRAY_EXTRA_MUTABLE_METHODS1_##HELPER_NAME(NAME, TYPE)
+//%/**
+//% * Inserts a value into the given position.
+//% *
+//% * @param value The value to add to this array.
+//% * @param index The index into which to insert the value.
+//% **/
 //%- (void)insertValue:(TYPE)value atIndex:(NSUInteger)index;
 //%
+//%/**
+//% * Replaces the value at the given index with the given value.
+//% *
+//% * @param index The index for which to replace the value.
+//% * @param value The value to replace with.
+//% **/
 //%- (void)replaceValueAtIndex:(NSUInteger)index withValue:(TYPE)value;
 //%ARRAY_EXTRA_MUTABLE_METHODS2_##HELPER_NAME(NAME, TYPE)
+//%/**
+//% * Removes the value at the given index.
+//% *
+//% * @param index The index of the value to remove.
+//% **/
 //%- (void)removeValueAtIndex:(NSUInteger)index;
+//%
+//%/**
+//% * Removes all the values from this array.
+//% **/
 //%- (void)removeAll;
 //%
+//%/**
+//% * Exchanges the values between the given indexes.
+//% *
+//% * @param idx1 The index of the first element to exchange.
+//% * @param idx2 The index of the second element to exchange.
+//% **/
 //%- (void)exchangeValueAtIndex:(NSUInteger)idx1
 //%            withValueAtIndex:(NSUInteger)idx2;
 
@@ -526,6 +1894,11 @@
 //
 
 //%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS1_Basic(NAME, TYPE)
+//%/**
+//% * Adds the values from the given array to this array.
+//% *
+//% * @param array The array containing the elements to add to this array.
+//% **/
 //%- (void)addValuesFromArray:(GPB##NAME##Array *)array;
 //%
 //%PDDM-DEFINE ARRAY_EXTRA_MUTABLE_METHODS2_Basic(NAME, TYPE)
@@ -537,12 +1910,57 @@
 //%// These methods bypass the validationFunc to provide setting of values that were not
 //%// known at the time the binary was compiled.
 //%
+//%/**
+//% * Adds a raw enum value to this array.
+//% *
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% *
+//% * @param value The raw enum value to add to the array.
+//% **/
 //%- (void)addRawValue:(TYPE)value;
+//%
+//%/**
+//% * Adds raw enum values to this array.
+//% *
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% *
+//% * @param array Array containing the raw enum values to add to this array.
+//% **/
 //%- (void)addRawValuesFromArray:(GPB##NAME##Array *)array;
+//%
+//%/**
+//% * Adds raw enum values to this array.
+//% *
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% *
+//% * @param values Array containing the raw enum values to add to this array.
+//% * @param count  The number of raw values to add.
+//% **/
 //%- (void)addRawValues:(const TYPE [])values count:(NSUInteger)count;
 //%
+//%/**
+//% * Inserts a raw enum value at the given index.
+//% *
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% *
+//% * @param value Raw enum value to add.
+//% * @param index The index into which to insert the value.
+//% **/
 //%- (void)insertRawValue:(TYPE)value atIndex:(NSUInteger)index;
 //%
+//%/**
+//% * Replaces the raw enum value at the given index with the given value.
+//% *
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% *
+//% * @param index The index for which to replace the value.
+//% * @param value The raw enum value to replace with.
+//% **/
 //%- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(TYPE)value;
 //%
 //%// No validation applies to these methods.
diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m
index 64869bb..ae57747 100644
--- a/objectivec/GPBArray.m
+++ b/objectivec/GPBArray.m
@@ -195,7 +195,7 @@
 //%}
 //%
 //%- (void)enumerate##ACCESSOR_NAME##ValuesWithBlock:(void (^)(TYPE value, NSUInteger idx, BOOL *stop))block {
-//%  [self enumerate##ACCESSOR_NAME##ValuesWithOptions:0 usingBlock:block];
+//%  [self enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 //%}
 //%
 //%- (void)enumerate##ACCESSOR_NAME##ValuesWithOptions:(NSEnumerationOptions)opts
@@ -406,7 +406,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -654,7 +654,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(uint32_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -902,7 +902,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(int64_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1150,7 +1150,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(uint64_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1398,7 +1398,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(float value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1646,7 +1646,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(double value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -1894,7 +1894,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(BOOL value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
@@ -2166,7 +2166,7 @@
 }
 
 - (void)enumerateRawValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateRawValuesWithOptions:0 usingBlock:block];
+  [self enumerateRawValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
@@ -2218,7 +2218,7 @@
 }
 
 - (void)enumerateValuesWithBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block {
-  [self enumerateValuesWithOptions:0 usingBlock:block];
+  [self enumerateValuesWithOptions:(NSEnumerationOptions)0 usingBlock:block];
 }
 
 - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 4db08e8..7dc943d 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -28,11 +28,13 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// The Objective C runtime has complete enough info that most protos don’t end
-// up using this, so leaving it on is no cost or very little cost.  If you
-// happen to see it causing bloat, this is the way to disable it. If you do
-// need to disable it, try only disabling it for Release builds as having
-// full TextFormat can be useful for debugging.
+/**
+ * The Objective C runtime has complete enough info that most protos don’t end
+ * up using this, so leaving it on is no cost or very little cost.  If you
+ * happen to see it causing bloat, this is the way to disable it. If you do
+ * need to disable it, try only disabling it for Release builds as having
+ * full TextFormat can be useful for debugging.
+ **/
 #ifndef GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
 #define GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS 0
 #endif
@@ -42,6 +44,7 @@
 #if !__has_feature(objc_fixed_enum)
  #error All supported Xcode versions should support objc_fixed_enum.
 #endif
+
 // If the headers are imported into Objective-C++, we can run into an issue
 // where the defintion of NS_ENUM (really CF_ENUM) changes based on the C++
 // standard that is in effect.  If it isn't C++11 or higher, the definition
@@ -53,19 +56,29 @@
 #else
  #define GPB_ENUM(X) NS_ENUM(int32_t, X)
 #endif
-// GPB_ENUM_FWD_DECLARE is used for forward declaring enums, ex:
-//   GPB_ENUM_FWD_DECLARE(Foo_Enum)
-//   @property (nonatomic) Foo_Enum value;
+
+/**
+ * GPB_ENUM_FWD_DECLARE is used for forward declaring enums, for example:
+ *
+ * ```
+ * GPB_ENUM_FWD_DECLARE(Foo_Enum)
+ * @property (nonatomic) Foo_Enum value;
+ * ```
+ **/
 #define GPB_ENUM_FWD_DECLARE(X) enum X : int32_t
 
-// Based upon CF_INLINE. Forces inlining in release.
+/**
+ * Based upon CF_INLINE. Forces inlining in non DEBUG builds.
+ **/
 #if !defined(DEBUG)
 #define GPB_INLINE static __inline__ __attribute__((always_inline))
 #else
 #define GPB_INLINE static __inline__
 #endif
 
-// For use in public headers that might need to deal with ARC.
+/**
+ * For use in public headers that might need to deal with ARC.
+ **/
 #ifndef GPB_UNSAFE_UNRETAINED
 #if __has_feature(objc_arc)
 #define GPB_UNSAFE_UNRETAINED __unsafe_unretained
@@ -76,10 +89,14 @@
 
 // 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
+//
+// Meant to be used internally by generated code.
 #define GPB_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
 
 // The protoc-gen-objc version which works with the current version of the
 // generated Objective C sources.  In general we don't want to change the
 // runtime interfaces (or this version) as it means everything has to be
 // regenerated.
-#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
+//
+// Meant to be used internally by generated code.
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002
diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h
index df9d97b..de27b18 100644
--- a/objectivec/GPBCodedInputStream.h
+++ b/objectivec/GPBCodedInputStream.h
@@ -37,125 +37,194 @@
 
 CF_EXTERN_C_BEGIN
 
-/// GPBCodedInputStream exception name. Exceptions raised from
-/// GPBCodedInputStream contain an underlying error in the userInfo dictionary
-/// under the GPBCodedInputStreamUnderlyingErrorKey key.
+/**
+ * @c GPBCodedInputStream exception name. Exceptions raised from
+ * @c GPBCodedInputStream contain an underlying error in the userInfo dictionary
+ * under the GPBCodedInputStreamUnderlyingErrorKey key.
+ **/
 extern NSString *const GPBCodedInputStreamException;
 
-/// The key under which the underlying NSError from the exception is stored.
+/** The key under which the underlying NSError from the exception is stored. */
 extern NSString *const GPBCodedInputStreamUnderlyingErrorKey;
 
-/// NSError domain used for GPBCodedInputStream errors.
+/** NSError domain used for @c GPBCodedInputStream errors. */
 extern NSString *const GPBCodedInputStreamErrorDomain;
 
-/// Error code for NSError with GPBCodedInputStreamErrorDomain.
+/**
+ * Error code for NSError with @c GPBCodedInputStreamErrorDomain.
+ **/
 typedef NS_ENUM(NSInteger, GPBCodedInputStreamErrorCode) {
-  /// The size does not fit in the remaining bytes to be read.
+  /** The size does not fit in the remaining bytes to be read. */
   GPBCodedInputStreamErrorInvalidSize = -100,
-  /// Attempted to read beyond the subsection limit.
+  /** Attempted to read beyond the subsection limit. */
   GPBCodedInputStreamErrorSubsectionLimitReached = -101,
-  /// The requested subsection limit is invalid.
+  /** The requested subsection limit is invalid. */
   GPBCodedInputStreamErrorInvalidSubsectionLimit = -102,
-  /// Invalid tag read.
+  /** Invalid tag read. */
   GPBCodedInputStreamErrorInvalidTag = -103,
-  /// Invalid UTF-8 character in a string.
+  /** Invalid UTF-8 character in a string. */
   GPBCodedInputStreamErrorInvalidUTF8 = -104,
-  /// Invalid VarInt read.
+  /** Invalid VarInt read. */
   GPBCodedInputStreamErrorInvalidVarInt = -105,
-  /// The maximum recursion depth of messages was exceeded.
+  /** The maximum recursion depth of messages was exceeded. */
   GPBCodedInputStreamErrorRecursionDepthExceeded = -106,
 };
 
 CF_EXTERN_C_END
 
-/// Reads and decodes protocol message fields.
-///
-/// The common uses of protocol buffers shouldn't need to use this class.
-/// @c GPBMessage's provide a @c +parseFromData:error: and @c
-/// +parseFromData:extensionRegistry:error: method that will decode a
-/// message for you.
-///
-/// @note Subclassing of GPBCodedInputStream is NOT supported.
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * The common uses of protocol buffers shouldn't need to use this class.
+ * @c GPBMessage's provide a @c +parseFromData:error: and
+ * @c +parseFromData:extensionRegistry:error: method that will decode a
+ * message for you.
+ *
+ * @note Subclassing of @c GPBCodedInputStream is NOT supported.
+ **/
 @interface GPBCodedInputStream : NSObject
 
-/// Creates a new stream wrapping some data.
+/**
+ * Creates a new stream wrapping some data.
+ *
+ * @param data The data to wrap inside the stream.
+ *
+ * @return A newly instanced GPBCodedInputStream.
+ **/
 + (instancetype)streamWithData:(NSData *)data;
 
-/// Initializes a stream wrapping some data.
+/**
+ * Initializes a stream wrapping some data.
+ *
+ * @param data The data to wrap inside the stream.
+ *
+ * @return A newly initialized GPBCodedInputStream.
+ **/
 - (instancetype)initWithData:(NSData *)data;
 
-/// Attempt to read a field tag, returning zero if we have reached EOF.
-/// Protocol message parsers use this to read tags, since a protocol message
-/// may legally end wherever a tag occurs, and zero is not a valid tag number.
+/**
+ * Attempts to read a field tag, returning zero if we have reached EOF.
+ * Protocol message parsers use this to read tags, since a protocol message
+ * may legally end wherever a tag occurs, and zero is not a valid tag number.
+ *
+ * @return The field tag, or zero if EOF was reached.
+ **/
 - (int32_t)readTag;
 
-/// Read and return a double.
+/**
+ * @return A double read from the stream.
+ **/
 - (double)readDouble;
-/// Read and return a float.
+/**
+ * @return A float read from the stream.
+ **/
 - (float)readFloat;
-/// Read and return a uint64.
+/**
+ * @return A uint64 read from the stream.
+ **/
 - (uint64_t)readUInt64;
-/// Read and return a uint32.
+/**
+ * @return A uint32 read from the stream.
+ **/
 - (uint32_t)readUInt32;
-/// Read and return an int64.
+/**
+ * @return An int64 read from the stream.
+ **/
 - (int64_t)readInt64;
-/// Read and return an int32.
+/**
+ * @return An int32 read from the stream.
+ **/
 - (int32_t)readInt32;
-/// Read and return a fixed64.
+/**
+ * @return A fixed64 read from the stream.
+ **/
 - (uint64_t)readFixed64;
-/// Read and return a fixed32.
+/**
+ * @return A fixed32 read from the stream.
+ **/
 - (uint32_t)readFixed32;
-/// Read and return an enum (int).
+/**
+ * @return An enum read from the stream.
+ **/
 - (int32_t)readEnum;
-/// Read and return a sfixed32.
+/**
+ * @return A sfixed32 read from the stream.
+ **/
 - (int32_t)readSFixed32;
-/// Read and return a sfixed64.
+/**
+ * @return A fixed64 read from the stream.
+ **/
 - (int64_t)readSFixed64;
-/// Read and return a sint32.
+/**
+ * @return A sint32 read from the stream.
+ **/
 - (int32_t)readSInt32;
-/// Read and return a sint64.
+/**
+ * @return A sint64 read from the stream.
+ **/
 - (int64_t)readSInt64;
-/// Read and return a boolean.
+/**
+ * @return A boolean read from the stream.
+ **/
 - (BOOL)readBool;
-/// Read and return a string.
+/**
+ * @return A string read from the stream.
+ **/
 - (NSString *)readString;
-/// Read and return length delimited data.
+/**
+ * @return Data read from the stream.
+ **/
 - (NSData *)readBytes;
 
-/// Read an embedded message field value from the stream.
-///
-/// @param message           The message to set fields on as they are read.
-/// @param extensionRegistry An optional extension registry to use to lookup
-///                          extensions for @c message.
+/**
+ * Read an embedded message field value from the stream.
+ *
+ * @param message           The message to set fields on as they are read.
+ * @param extensionRegistry An optional extension registry to use to lookup
+ *                          extensions for message.
+ **/
 - (void)readMessage:(GPBMessage *)message
   extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry;
 
-/// Reads and discards a single field, given its tag value.
-///
-/// @param tag The tag number of the field to skip.
-///
-/// @return NO if the tag is an endgroup tag (in which case nothing is skipped),
-///         YES in all other cases.
+/**
+ * Reads and discards a single field, given its tag value.
+ *
+ * @param tag The tag number of the field to skip.
+ *
+ * @return NO if the tag is an endgroup tag (in which case nothing is skipped),
+ *         YES in all other cases.
+ **/
 - (BOOL)skipField:(int32_t)tag;
 
-/// Reads and discards an entire message.  This will read either until EOF
-/// or until an endgroup tag, whichever comes first.
+/**
+ * Reads and discards an entire message. This will read either until EOF or
+ * until an endgroup tag, whichever comes first.
+ **/
 - (void)skipMessage;
 
-/// Check to see if the logical end of the stream has been reached.
-///
-/// This can return NO when there is no more data, but the current parsing
-/// expected more data.
+/**
+ * Check to see if the logical end of the stream has been reached.
+ *
+ * @note This can return NO when there is no more data, but the current parsing
+ *       expected more data.
+ *
+ * @return YES if the logical end of the stream has been reached, NO otherwise.
+ **/
 - (BOOL)isAtEnd;
 
-/// The offset into the stream.
+/**
+ * @return The offset into the stream.
+ **/
 - (size_t)position;
 
-/// Verifies that the last call to @c -readTag returned the given tag value.
-/// This is used to verify that a nested group ended with the correct end tag.
-/// Throws @c NSParseErrorException if value does not match the last tag.
-///
-/// @param expected The tag that was expected.
+/**
+ * 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.
+ *
+ * @exception NSParseErrorException If the value does not match the last tag.
+ *
+ * @param expected The tag that was expected.
+ **/
 - (void)checkLastTagWas:(int32_t)expected;
 
 @end
diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h
index 8272880..d6fff3d 100644
--- a/objectivec/GPBCodedOutputStream.h
+++ b/objectivec/GPBCodedOutputStream.h
@@ -46,63 +46,122 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/// Writes out protocol message fields.
-///
-/// The common uses of protocol buffers shouldn't need to use this class.
-/// @c GPBMessage's provide a @c -data method that will serialize the message
-/// for you.
-///
-/// @note Subclassing of GPBCodedOutputStream is NOT supported.
+/**
+ * Writes out protocol message fields.
+ *
+ * The common uses of protocol buffers shouldn't need to use this class.
+ * GPBMessage's provide a -data method that will serialize the message for you.
+ *
+ * @note Subclassing of GPBCodedOutputStream is NOT supported.
+ **/
 @interface GPBCodedOutputStream : NSObject
 
-/// Creates a stream to fill in the given data. Data must be sized to fit or
-/// an error will be raised when out of space.
+/**
+ * Creates a stream to fill in the given data. Data must be sized to fit or
+ * an error will be raised when out of space.
+ *
+ * @param data The data where the stream will be written to.
+ *
+ * @return A newly instanced GPBCodedOutputStream.
+ **/
 + (instancetype)streamWithData:(NSMutableData *)data;
 
-/// Creates a stream to write into the given @c NSOutputStream.
+/**
+ * Creates a stream to write into the given NSOutputStream.
+ *
+ * @param output The output stream where the stream will be written to.
+ *
+ * @return A newly instanced GPBCodedOutputStream.
+ **/
 + (instancetype)streamWithOutputStream:(NSOutputStream *)output;
 
-/// Initializes a stream to fill in the given data. Data must be sized to fit
-/// or an error will be raised when out of space.
+/**
+ * Initializes a stream to fill in the given data. Data must be sized to fit
+ * or an error will be raised when out of space.
+ *
+ * @param data The data where the stream will be written to.
+ *
+ * @return A newly initialized GPBCodedOutputStream.
+ **/
 - (instancetype)initWithData:(NSMutableData *)data;
 
-/// Initializes a stream to write into the given @c NSOutputStream.
+/**
+ * Initializes a stream to write into the given @c NSOutputStream.
+ *
+ * @param output The output stream where the stream will be written to.
+ *
+ * @return A newly initialized GPBCodedOutputStream.
+ **/
 - (instancetype)initWithOutputStream:(NSOutputStream *)output;
 
-/// Flush any buffered data out.
+/**
+ * Flush any buffered data out.
+ **/
 - (void)flush;
 
-/// Write the raw byte out.
+/**
+ * Write the raw byte out.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawByte:(uint8_t)value;
 
-/// Write the tag for the given field number and wire format.
-///
-/// @param fieldNumber The field number.
-/// @param format      The wire format the data for the field will be in.
+/**
+ * Write the tag for the given field number and wire format.
+ *
+ * @param fieldNumber The field number.
+ * @param format      The wire format the data for the field will be in.
+ **/
 - (void)writeTag:(uint32_t)fieldNumber format:(GPBWireFormat)format;
 
-/// Write a 32bit value out in little endian format.
+/**
+ * Write a 32bit value out in little endian format.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawLittleEndian32:(int32_t)value;
-/// Write a 64bit value out in little endian format.
+/**
+ * Write a 64bit value out in little endian format.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawLittleEndian64:(int64_t)value;
 
-/// Write a 32bit value out in varint format.
+/**
+ * Write a 32bit value out in varint format.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawVarint32:(int32_t)value;
-/// Write a 64bit value out in varint format.
+/**
+ * Write a 64bit value out in varint format.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawVarint64:(int64_t)value;
 
-/// Write a size_t out as a 32bit varint value.
-///
-/// @note This will truncate 64 bit values to 32.
+/**
+ * Write a size_t out as a 32bit varint value.
+ *
+ * @note This will truncate 64 bit values to 32.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeRawVarintSizeTAs32:(size_t)value;
 
-/// Writes the contents of an @c NSData out.
+/**
+ * Writes the contents of an NSData out.
+ *
+ * @param data The data to write out.
+ **/
 - (void)writeRawData:(NSData *)data;
-/// Writes out the given data.
-///
-/// @param data   The data blob to write out.
-/// @param offset The offset into the blob to start writing out.
-/// @param length The number of bytes from the blob to write out.
+/**
+ * Writes out the given data.
+ *
+ * @param data   The data blob to write out.
+ * @param offset The offset into the blob to start writing out.
+ * @param length The number of bytes from the blob to write out.
+ **/
 - (void)writeRawPtr:(const void *)data
              offset:(size_t)offset
              length:(size_t)length;
@@ -110,179 +169,471 @@
 //%PDDM-EXPAND _WRITE_DECLS()
 // This block of code is generated, do not edit it directly.
 
-/// Write a double for the given field number.
+/**
+ * Write a double for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeDouble:(int32_t)fieldNumber value:(double)value;
-/// Write a packed array of double for the given field number.
+/**
+ * Write a packed array of double for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeDoubleArray:(int32_t)fieldNumber
                   values:(GPBDoubleArray *)values
                      tag:(uint32_t)tag;
-/// Write a double without any tag.
+/**
+ * Write a double without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeDoubleNoTag:(double)value;
 
-/// Write a float for the given field number.
+/**
+ * Write a float for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeFloat:(int32_t)fieldNumber value:(float)value;
-/// Write a packed array of float for the given field number.
+/**
+ * Write a packed array of float for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeFloatArray:(int32_t)fieldNumber
                  values:(GPBFloatArray *)values
                     tag:(uint32_t)tag;
-/// Write a float without any tag.
+/**
+ * Write a float without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeFloatNoTag:(float)value;
 
-/// Write a uint64_t for the given field number.
+/**
+ * Write a uint64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value;
-/// Write a packed array of uint64_t for the given field number.
+/**
+ * Write a packed array of uint64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeUInt64Array:(int32_t)fieldNumber
                   values:(GPBUInt64Array *)values
                      tag:(uint32_t)tag;
-/// Write a uint64_t without any tag.
+/**
+ * Write a uint64_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeUInt64NoTag:(uint64_t)value;
 
-/// Write a int64_t for the given field number.
+/**
+ * Write a int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value;
-/// Write a packed array of int64_t for the given field number.
+/**
+ * Write a packed array of int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeInt64Array:(int32_t)fieldNumber
                  values:(GPBInt64Array *)values
                     tag:(uint32_t)tag;
-/// Write a int64_t without any tag.
+/**
+ * Write a int64_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeInt64NoTag:(int64_t)value;
 
-/// Write a int32_t for the given field number.
+/**
+ * Write a int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value;
-/// Write a packed array of int32_t for the given field number.
+/**
+ * Write a packed array of int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeInt32Array:(int32_t)fieldNumber
                  values:(GPBInt32Array *)values
                     tag:(uint32_t)tag;
-/// Write a int32_t without any tag.
+/**
+ * Write a int32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeInt32NoTag:(int32_t)value;
 
-/// Write a uint32_t for the given field number.
+/**
+ * Write a uint32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value;
-/// Write a packed array of uint32_t for the given field number.
+/**
+ * Write a packed array of uint32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeUInt32Array:(int32_t)fieldNumber
                   values:(GPBUInt32Array *)values
                      tag:(uint32_t)tag;
-/// Write a uint32_t without any tag.
+/**
+ * Write a uint32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeUInt32NoTag:(uint32_t)value;
 
-/// Write a uint64_t for the given field number.
+/**
+ * Write a uint64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value;
-/// Write a packed array of uint64_t for the given field number.
+/**
+ * Write a packed array of uint64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeFixed64Array:(int32_t)fieldNumber
                    values:(GPBUInt64Array *)values
                       tag:(uint32_t)tag;
-/// Write a uint64_t without any tag.
+/**
+ * Write a uint64_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeFixed64NoTag:(uint64_t)value;
 
-/// Write a uint32_t for the given field number.
+/**
+ * Write a uint32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value;
-/// Write a packed array of uint32_t for the given field number.
+/**
+ * Write a packed array of uint32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeFixed32Array:(int32_t)fieldNumber
                    values:(GPBUInt32Array *)values
                       tag:(uint32_t)tag;
-/// Write a uint32_t without any tag.
+/**
+ * Write a uint32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeFixed32NoTag:(uint32_t)value;
 
-/// Write a int32_t for the given field number.
+/**
+ * Write a int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value;
-/// Write a packed array of int32_t for the given field number.
+/**
+ * Write a packed array of int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeSInt32Array:(int32_t)fieldNumber
                   values:(GPBInt32Array *)values
                      tag:(uint32_t)tag;
-/// Write a int32_t without any tag.
+/**
+ * Write a int32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeSInt32NoTag:(int32_t)value;
 
-/// Write a int64_t for the given field number.
+/**
+ * Write a int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value;
-/// Write a packed array of int64_t for the given field number.
+/**
+ * Write a packed array of int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeSInt64Array:(int32_t)fieldNumber
                   values:(GPBInt64Array *)values
                      tag:(uint32_t)tag;
-/// Write a int64_t without any tag.
+/**
+ * Write a int64_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeSInt64NoTag:(int64_t)value;
 
-/// Write a int64_t for the given field number.
+/**
+ * Write a int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value;
-/// Write a packed array of int64_t for the given field number.
+/**
+ * Write a packed array of int64_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeSFixed64Array:(int32_t)fieldNumber
                     values:(GPBInt64Array *)values
                        tag:(uint32_t)tag;
-/// Write a int64_t without any tag.
+/**
+ * Write a int64_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeSFixed64NoTag:(int64_t)value;
 
-/// Write a int32_t for the given field number.
+/**
+ * Write a int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value;
-/// Write a packed array of int32_t for the given field number.
+/**
+ * Write a packed array of int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeSFixed32Array:(int32_t)fieldNumber
                     values:(GPBInt32Array *)values
                        tag:(uint32_t)tag;
-/// Write a int32_t without any tag.
+/**
+ * Write a int32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeSFixed32NoTag:(int32_t)value;
 
-/// Write a BOOL for the given field number.
+/**
+ * Write a BOOL for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeBool:(int32_t)fieldNumber value:(BOOL)value;
-/// Write a packed array of BOOL for the given field number.
+/**
+ * Write a packed array of BOOL for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeBoolArray:(int32_t)fieldNumber
                 values:(GPBBoolArray *)values
                    tag:(uint32_t)tag;
-/// Write a BOOL without any tag.
+/**
+ * Write a BOOL without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeBoolNoTag:(BOOL)value;
 
-/// Write a int32_t for the given field number.
+/**
+ * Write a int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value;
-/// Write a packed array of int32_t for the given field number.
+/**
+ * Write a packed array of int32_t for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ * @param tag         The tag assigned to the values.
+ **/
 - (void)writeEnumArray:(int32_t)fieldNumber
                 values:(GPBEnumArray *)values
                    tag:(uint32_t)tag;
-/// Write a int32_t without any tag.
+/**
+ * Write a int32_t without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeEnumNoTag:(int32_t)value;
 
-/// Write a NSString for the given field number.
+/**
+ * Write a NSString for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeString:(int32_t)fieldNumber value:(NSString *)value;
-/// Write an array of NSString for the given field number.
+/**
+ * Write an array of NSString for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ **/
 - (void)writeStringArray:(int32_t)fieldNumber values:(NSArray<NSString*> *)values;
-/// Write a NSString without any tag.
+/**
+ * Write a NSString without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeStringNoTag:(NSString *)value;
 
-/// Write a GPBMessage for the given field number.
+/**
+ * Write a GPBMessage for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value;
-/// Write an array of GPBMessage for the given field number.
+/**
+ * Write an array of GPBMessage for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ **/
 - (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
-/// Write a GPBMessage without any tag.
+/**
+ * Write a GPBMessage without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeMessageNoTag:(GPBMessage *)value;
 
-/// Write a NSData for the given field number.
+/**
+ * Write a NSData for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeBytes:(int32_t)fieldNumber value:(NSData *)value;
-/// Write an array of NSData for the given field number.
+/**
+ * Write an array of NSData for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ **/
 - (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray<NSData*> *)values;
-/// Write a NSData without any tag.
+/**
+ * Write a NSData without any tag.
+ *
+ * @param value The value to write out.
+ **/
 - (void)writeBytesNoTag:(NSData *)value;
 
-/// Write a GPBMessage for the given field number.
+/**
+ * Write a GPBMessage for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeGroup:(int32_t)fieldNumber
              value:(GPBMessage *)value;
-/// Write an array of GPBMessage for the given field number.
+/**
+ * Write an array of GPBMessage for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ **/
 - (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
-/// Write a GPBMessage without any tag (but does write the endGroup tag).
+/**
+ * Write a GPBMessage without any tag (but does write the endGroup tag).
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeGroupNoTag:(int32_t)fieldNumber
                   value:(GPBMessage *)value;
 
-/// Write a GPBUnknownFieldSet for the given field number.
+/**
+ * Write a GPBUnknownFieldSet for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeUnknownGroup:(int32_t)fieldNumber
                     value:(GPBUnknownFieldSet *)value;
-/// Write an array of GPBUnknownFieldSet for the given field number.
+/**
+ * Write an array of GPBUnknownFieldSet for the given field number.
+ *
+ * @param fieldNumber The field number assigned to the values.
+ * @param values      The values to write out.
+ **/
 - (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray<GPBUnknownFieldSet*> *)values;
-/// Write a GPBUnknownFieldSet without any tag (but does write the endGroup tag).
+/**
+ * Write a GPBUnknownFieldSet without any tag (but does write the endGroup tag).
+ *
+ * @param fieldNumber The field number assigned to the value.
+ * @param value       The value to write out.
+ **/
 - (void)writeUnknownGroupNoTag:(int32_t)fieldNumber
                          value:(GPBUnknownFieldSet *)value;
 
 //%PDDM-EXPAND-END _WRITE_DECLS()
 
-/// Write a MessageSet extension field to the stream. For historical reasons,
-/// the wire format differs from normal fields.
+/**
+Write a MessageSet extension field to the stream. For historical reasons,
+the wire format differs from normal fields.
+
+@param fieldNumber The extension field number to write out.
+@param value       The message from where to get the extension.
+*/
 - (void)writeMessageSetExtension:(int32_t)fieldNumber value:(GPBMessage *)value;
 
-/// Write an unparsed MessageSet extension field to the stream. For
-/// historical reasons, the wire format differs from normal fields.
+/**
+Write an unparsed MessageSet extension field to the stream. For historical
+reasons, the wire format differs from normal fields.
+
+@param fieldNumber The extension field number to write out.
+@param value       The raw message from where to get the extension.
+*/
 - (void)writeRawMessageSetExtension:(int32_t)fieldNumber value:(NSData *)value;
 
 @end
@@ -291,32 +642,76 @@
 
 // Write methods for types that can be in packed arrays.
 //%PDDM-DEFINE _WRITE_PACKABLE_DECLS(NAME, ARRAY_TYPE, TYPE)
-//%/// Write a TYPE for the given field number.
+//%/**
+//% * Write a TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the value.
+//% * @param value       The value to write out.
+//% **/
 //%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value;
-//%/// Write a packed array of TYPE for the given field number.
+//%/**
+//% * Write a packed array of TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the values.
+//% * @param values      The values to write out.
+//% * @param tag         The tag assigned to the values.
+//% **/
 //%- (void)write##NAME##Array:(int32_t)fieldNumber
 //%       NAME$S     values:(GPB##ARRAY_TYPE##Array *)values
 //%       NAME$S        tag:(uint32_t)tag;
-//%/// Write a TYPE without any tag.
+//%/**
+//% * Write a TYPE without any tag.
+//% *
+//% * @param value The value to write out.
+//% **/
 //%- (void)write##NAME##NoTag:(TYPE)value;
 //%
 // Write methods for types that aren't in packed arrays.
 //%PDDM-DEFINE _WRITE_UNPACKABLE_DECLS(NAME, TYPE)
-//%/// Write a TYPE for the given field number.
+//%/**
+//% * Write a TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the value.
+//% * @param value       The value to write out.
+//% **/
 //%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE *)value;
-//%/// Write an array of TYPE for the given field number.
+//%/**
+//% * Write an array of TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the values.
+//% * @param values      The values to write out.
+//% **/
 //%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
-//%/// Write a TYPE without any tag.
+//%/**
+//% * Write a TYPE without any tag.
+//% *
+//% * @param value The value to write out.
+//% **/
 //%- (void)write##NAME##NoTag:(TYPE *)value;
 //%
 // Special write methods for Groups.
 //%PDDM-DEFINE _WRITE_GROUP_DECLS(NAME, TYPE)
-//%/// Write a TYPE for the given field number.
+//%/**
+//% * Write a TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the value.
+//% * @param value       The value to write out.
+//% **/
 //%- (void)write##NAME:(int32_t)fieldNumber
 //%       NAME$S value:(TYPE *)value;
-//%/// Write an array of TYPE for the given field number.
+//%/**
+//% * Write an array of TYPE for the given field number.
+//% *
+//% * @param fieldNumber The field number assigned to the values.
+//% * @param values      The values to write out.
+//% **/
 //%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
-//%/// Write a TYPE without any tag (but does write the endGroup tag).
+//%/**
+//% * Write a TYPE without any tag (but does write the endGroup tag).
+//% *
+//% * @param fieldNumber The field number assigned to the value.
+//% * @param value       The value to write out.
+//% **/
 //%- (void)write##NAME##NoTag:(int32_t)fieldNumber
 //%            NAME$S value:(TYPE *)value;
 //%
diff --git a/objectivec/GPBCodedOutputStream.m b/objectivec/GPBCodedOutputStream.m
index 63ba806..7c3ab44 100644
--- a/objectivec/GPBCodedOutputStream.m
+++ b/objectivec/GPBCodedOutputStream.m
@@ -144,22 +144,6 @@
   GPBWriteRawByte(state, (int32_t)(value >> 56) & 0xFF);
 }
 
-#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
-+ (void)load {
-  // This test exists to verify that CFStrings with embedded NULLs will work
-  // for us. If this Assert fails, all code below that depends on
-  // CFStringGetCStringPtr will NOT work properly on strings that contain
-  // embedded NULLs, and we do get that in some protobufs.
-  // Note that this will not be compiled in release.
-  // We didn't feel that just keeping it in a unit test was sufficient because
-  // the Protobuf unit tests are only run when somebody is actually working
-  // on protobufs.
-  CFStringRef zeroTest = CFSTR("Test\0String");
-  const char *cString = CFStringGetCStringPtr(zeroTest, kCFStringEncodingUTF8);
-  NSAssert(cString == NULL, @"Serious Error");
-}
-#endif  // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
-
 - (void)dealloc {
   [self flush];
   [state_.output close];
@@ -282,19 +266,15 @@
 }
 
 - (void)writeStringNoTag:(const NSString *)value {
-  // If you are concerned about embedded NULLs see the test in
-  // +load above.
-  const char *quickString =
-      CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8);
-  size_t length = (quickString != NULL)
-                      ? strlen(quickString)
-                      : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+  size_t length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
   GPBWriteRawVarint32(&state_, (int32_t)length);
-
   if (length == 0) {
     return;
   }
 
+  const char *quickString =
+      CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8);
+
   // Fast path: Most strings are short, if the buffer already has space,
   // add to it directly.
   NSUInteger bufferBytesLeft = state_.size - state_.position;
@@ -310,7 +290,7 @@
                      maxLength:bufferBytesLeft
                     usedLength:&usedBufferLength
                       encoding:NSUTF8StringEncoding
-                       options:0
+                       options:(NSStringEncodingConversionOptions)0
                          range:NSMakeRange(0, [value length])
                 remainingRange:NULL];
     }
@@ -1038,14 +1018,7 @@
 }
 
 size_t GPBComputeStringSizeNoTag(NSString *value) {
-  // If you are concerned about embedded NULLs see the test in
-  // +load above.
-  const char *quickString =
-      CFStringGetCStringPtr((CFStringRef)value, kCFStringEncodingUTF8);
-  NSUInteger length =
-      (quickString != NULL)
-          ? strlen(quickString)
-          : [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+  NSUInteger length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
   return GPBComputeRawVarint32SizeForInteger(length) + length;
 }
 
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index fe4ff39..651f4de 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -39,104 +39,250 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+/** Syntax used in the proto file. */
 typedef NS_ENUM(uint8_t, GPBFileSyntax) {
+  /** Unknown syntax. */
   GPBFileSyntaxUnknown = 0,
+  /** Proto2 syntax. */
   GPBFileSyntaxProto2 = 2,
+  /** Proto3 syntax. */
   GPBFileSyntaxProto3 = 3,
 };
 
+/** Type of proto field. */
 typedef NS_ENUM(uint8_t, GPBFieldType) {
-  GPBFieldTypeSingle,    // optional/required
-  GPBFieldTypeRepeated,  // repeated
-  GPBFieldTypeMap,       // map<K,V>
+  /** Optional/required field. Only valid for proto2 fields. */
+  GPBFieldTypeSingle,
+  /** Repeated field. */
+  GPBFieldTypeRepeated,
+  /** Map field. */
+  GPBFieldTypeMap,
 };
 
+/**
+ * Describes a proto message.
+ **/
 @interface GPBDescriptor : NSObject<NSCopying>
 
+/** Name of the message. */
 @property(nonatomic, readonly, copy) NSString *name;
+/** Fields declared in the message. */
 @property(nonatomic, readonly, strong, nullable) NSArray<GPBFieldDescriptor*> *fields;
+/** Oneofs declared in the message. */
 @property(nonatomic, readonly, strong, nullable) NSArray<GPBOneofDescriptor*> *oneofs;
+/** Extension range declared for the message. */
 @property(nonatomic, readonly, nullable) const GPBExtensionRange *extensionRanges;
+/** Number of extension ranges declared for the message. */
 @property(nonatomic, readonly) uint32_t extensionRangesCount;
+/** Descriptor for the file where the message was defined. */
 @property(nonatomic, readonly, assign) GPBFileDescriptor *file;
 
+/** Whether the message is in wire format or not. */
 @property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
+/** The class of this message. */
 @property(nonatomic, readonly) Class messageClass;
+/** Containing message descriptor if this message is nested, or nil otherwise. */
+@property(readonly, nullable) GPBDescriptor *containingType;
+/**
+ * Fully qualified name for this message (package.message). Can be nil if the
+ * value is unable to be computed.
+ */
+@property(readonly, nullable) NSString *fullName;
 
+/**
+ * Gets the field for the given number.
+ *
+ * @param fieldNumber The number for the field to get.
+ *
+ * @return The field descriptor for the given number, or nil if not found.
+ **/
 - (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber;
+
+/**
+ * Gets the field for the given name.
+ *
+ * @param name The name for the field to get.
+ *
+ * @return The field descriptor for the given name, or nil if not found.
+ **/
 - (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name;
+
+/**
+ * Gets the oneof for the given name.
+ *
+ * @param name The name for the oneof to get.
+ *
+ * @return The oneof descriptor for the given name, or nil if not found.
+ **/
 - (nullable GPBOneofDescriptor *)oneofWithName:(NSString *)name;
 
 @end
 
+/**
+ * Describes a proto file.
+ **/
 @interface GPBFileDescriptor : NSObject
 
+/** The package declared in the proto file. */
 @property(nonatomic, readonly, copy) NSString *package;
+/** The objc prefix declared in the proto file. */
+@property(nonatomic, readonly, copy, nullable) NSString *objcPrefix;
+/** The syntax of the proto file. */
 @property(nonatomic, readonly) GPBFileSyntax syntax;
 
 @end
 
+/**
+ * Describes a oneof field.
+ **/
 @interface GPBOneofDescriptor : NSObject
+/** Name of the oneof field. */
 @property(nonatomic, readonly) NSString *name;
+/** Fields declared in the oneof. */
 @property(nonatomic, readonly) NSArray<GPBFieldDescriptor*> *fields;
 
+/**
+ * Gets the field for the given number.
+ *
+ * @param fieldNumber The number for the field to get.
+ *
+ * @return The field descriptor for the given number, or nil if not found.
+ **/
 - (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber;
+
+/**
+ * Gets the field for the given name.
+ *
+ * @param name The name for the field to get.
+ *
+ * @return The field descriptor for the given name, or nil if not found.
+ **/
 - (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name;
+
 @end
 
+/**
+ * Describes a proto field.
+ **/
 @interface GPBFieldDescriptor : NSObject
 
+/** Name of the field. */
 @property(nonatomic, readonly, copy) NSString *name;
+/** Number associated with the field. */
 @property(nonatomic, readonly) uint32_t number;
+/** Data type contained in the field. */
 @property(nonatomic, readonly) GPBDataType dataType;
+/** Whether it has a default value or not. */
 @property(nonatomic, readonly) BOOL hasDefaultValue;
+/** Default value for the field. */
 @property(nonatomic, readonly) GPBGenericValue defaultValue;
+/** Whether this field is required. Only valid for proto2 fields. */
 @property(nonatomic, readonly, getter=isRequired) BOOL required;
+/** Whether this field is optional. */
 @property(nonatomic, readonly, getter=isOptional) BOOL optional;
+/** Type of field (single, repeated, map). */
 @property(nonatomic, readonly) GPBFieldType fieldType;
-// If it is a map, the value type is in -type.
+/** Type of the key if the field is a map. The value's type is -fieldType. */
 @property(nonatomic, readonly) GPBDataType mapKeyDataType;
+/** Whether the field is packable. */
 @property(nonatomic, readonly, getter=isPackable) BOOL packable;
 
+/** The containing oneof if this field is part of one, nil otherwise. */
 @property(nonatomic, readonly, assign, nullable) GPBOneofDescriptor *containingOneof;
 
-// Message properties
+/** Class of the message if the field is of message type. */
 @property(nonatomic, readonly, assign, nullable) Class msgClass;
 
-// Enum properties
+/** Descriptor for the enum if this field is an enum. */
 @property(nonatomic, readonly, strong, nullable) GPBEnumDescriptor *enumDescriptor;
 
+/**
+ * Checks whether the given enum raw value is a valid enum value.
+ *
+ * @param value The raw enum value to check.
+ *
+ * @return YES if value is a valid enum raw value.
+ **/
 - (BOOL)isValidEnumValue:(int32_t)value;
 
-// For now, this will return nil if it doesn't know the name to use for
-// TextFormat.
+/** @return Name for the text format, or nil if not known. */
 - (nullable NSString *)textFormatName;
 
 @end
 
+/**
+ * Describes a proto enum.
+ **/
 @interface GPBEnumDescriptor : NSObject
 
+/** Name of the enum. */
 @property(nonatomic, readonly, copy) NSString *name;
+/** Function that validates that raw values are valid enum values. */
 @property(nonatomic, readonly) GPBEnumValidationFunc enumVerifier;
 
+/**
+ * Returns the enum value name for the given raw enum.
+ *
+ * @param number The raw enum value.
+ *
+ * @return The name of the enum value passed, or nil if not valid.
+ **/
 - (nullable NSString *)enumNameForValue:(int32_t)number;
+
+/**
+ * Gets the enum raw value for the given enum name.
+ *
+ * @param outValue A pointer where the value will be set.
+ * @param name     The enum name for which to get the raw value.
+ *
+ * @return YES if a value was copied into the pointer, NO otherwise.
+ **/
 - (BOOL)getValue:(nullable int32_t *)outValue forEnumName:(NSString *)name;
 
+/**
+ * Returns the text format for the given raw enum value.
+ *
+ * @param number The raw enum value.
+ *
+ * @return The text format name for the raw enum value, or nil if not valid.
+ **/
 - (nullable NSString *)textFormatNameForValue:(int32_t)number;
+
+/**
+ * Gets the enum raw value for the given text format name.
+ *
+ * @param outValue       A pointer where the value will be set.
+ * @param textFormatName The text format name for which to get the raw value.
+ *
+ * @return YES if a value was copied into the pointer, NO otherwise.
+ **/
 - (BOOL)getValue:(nullable int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName;
 
 @end
 
+/**
+ * Describes a proto extension.
+ **/
 @interface GPBExtensionDescriptor : NSObject<NSCopying>
+/** Field number under which the extension is stored. */
 @property(nonatomic, readonly) uint32_t fieldNumber;
+/** The containing message class, i.e. the class extended by this extension. */
 @property(nonatomic, readonly) Class containingMessageClass;
+/** Data type contained in the extension. */
 @property(nonatomic, readonly) GPBDataType dataType;
+/** Whether the extension is repeated. */
 @property(nonatomic, readonly, getter=isRepeated) BOOL repeated;
+/** Whether the extension is packable. */
 @property(nonatomic, readonly, getter=isPackable) BOOL packable;
+/** The class of the message if the extension is of message type. */
 @property(nonatomic, readonly, assign) Class msgClass;
+/** The singleton name for the extension. */
 @property(nonatomic, readonly) NSString *singletonName;
+/** The enum descriptor if the extension is of enum type. */
 @property(nonatomic, readonly, strong, nullable) GPBEnumDescriptor *enumDescriptor;
+/** The default value for the extension. */
 @property(nonatomic, readonly, nullable) id defaultValue;
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
index dccb9bc..0753a94 100644
--- a/objectivec/GPBDescriptor.m
+++ b/objectivec/GPBDescriptor.m
@@ -42,8 +42,10 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
 
-// The address of this variable is used as a key for obj_getAssociatedObject.
+// The addresses of these variables are used as keys for objc_getAssociatedObject.
 static const char kTextFormatExtraValueKey = 0;
+static const char kParentClassNameValueKey = 0;
+static const char kClassNameSuffixKey = 0;
 
 // Utility function to generate selectors on the fly.
 static SEL SelFromStrings(const char *prefix, const char *middle,
@@ -215,10 +217,102 @@
   extensionRangesCount_ = count;
 }
 
+- (void)setupContainingMessageClassName:(const char *)msgClassName {
+  // Note: Only fetch the class here, can't send messages to it because
+  // that could cause cycles back to this class within +initialize if
+  // two messages have each other in fields (i.e. - they build a graph).
+  NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName);
+  NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName];
+  objc_setAssociatedObject(self, &kParentClassNameValueKey,
+                           parentNameValue,
+                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setupMessageClassNameSuffix:(NSString *)suffix {
+  if (suffix.length) {
+    objc_setAssociatedObject(self, &kClassNameSuffixKey,
+                             suffix,
+                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+  }
+}
+
 - (NSString *)name {
   return NSStringFromClass(messageClass_);
 }
 
+- (GPBDescriptor *)containingType {
+  NSValue *parentNameValue =
+      objc_getAssociatedObject(self, &kParentClassNameValueKey);
+  if (!parentNameValue) {
+    return nil;
+  }
+  const char *parentName = [parentNameValue pointerValue];
+  Class parentClass = objc_getClass(parentName);
+  NSAssert(parentClass, @"Class %s not defined", parentName);
+  return [parentClass descriptor];
+}
+
+- (NSString *)fullName {
+  NSString *className = NSStringFromClass(self.messageClass);
+  GPBFileDescriptor *file = self.file;
+  NSString *objcPrefix = file.objcPrefix;
+  if (objcPrefix && ![className hasPrefix:objcPrefix]) {
+    NSAssert(0,
+             @"Class didn't have correct prefix? (%@ - %@)",
+             className, objcPrefix);
+    return nil;
+  }
+  GPBDescriptor *parent = self.containingType;
+
+  NSString *name = nil;
+  if (parent) {
+    NSString *parentClassName = NSStringFromClass(parent.messageClass);
+    // The generator will add _Class to avoid reserved words, drop it.
+    NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
+    if (suffix) {
+      if (![parentClassName hasSuffix:suffix]) {
+        NSAssert(0,
+                 @"ParentMessage class didn't have correct suffix? (%@ - %@)",
+                 className, suffix);
+        return nil;
+      }
+      parentClassName =
+          [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
+    }
+    NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
+    if (![className hasPrefix:parentPrefix]) {
+      NSAssert(0,
+               @"Class didn't have the correct parent name prefix? (%@ - %@)",
+               parentPrefix, className);
+      return nil;
+    }
+    name = [className substringFromIndex:parentPrefix.length];
+  } else {
+    name = [className substringFromIndex:objcPrefix.length];
+  }
+
+  // The generator will add _Class to avoid reserved words, drop it.
+  NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
+  if (suffix) {
+    if (![name hasSuffix:suffix]) {
+      NSAssert(0,
+               @"Message class didn't have correct suffix? (%@ - %@)",
+               name, suffix);
+      return nil;
+    }
+    name = [name substringToIndex:(name.length - suffix.length)];
+  }
+
+  NSString *prefix = (parent != nil ? parent.fullName : file.package);
+  NSString *result;
+  if (prefix.length > 0) {
+    result = [NSString stringWithFormat:@"%@.%@", prefix, name];
+  } else {
+    result = name;
+  }
+  return result;
+}
+
 - (id)copyWithZone:(NSZone *)zone {
 #pragma unused(zone)
   return [self retain];
@@ -255,13 +349,27 @@
 
 @implementation GPBFileDescriptor {
   NSString *package_;
+  NSString *objcPrefix_;
   GPBFileSyntax syntax_;
 }
 
 @synthesize package = package_;
+@synthesize objcPrefix = objcPrefix_;
 @synthesize syntax = syntax_;
 
 - (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax {
+  self = [super init];
+  if (self) {
+    package_ = [package copy];
+    objcPrefix_ = [objcPrefix copy];
+    syntax_ = syntax;
+  }
+  return self;
+}
+
+- (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax {
   self = [super init];
   if (self) {
@@ -273,6 +381,7 @@
 
 - (void)dealloc {
   [package_ release];
+  [objcPrefix_ release];
   [super dealloc];
 }
 
@@ -416,6 +525,9 @@
     // Extra type specific data.
     if (isMessage) {
       const char *className = coreDesc->dataTypeSpecific.className;
+      // Note: Only fetch the class here, can't send messages to it because
+      // that could cause cycles back to this class within +initialize if
+      // two messages have each other in fields (i.e. - they build a graph).
       msgClass_ = objc_getClass(className);
       NSAssert(msgClass_, @"Class %s not defined", className);
     } else if (dataType == GPBDataTypeEnum) {
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
index c20ff6b..9173e7a 100644
--- a/objectivec/GPBDescriptor_PackagePrivate.h
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -37,6 +37,7 @@
 
 // Describes attributes of the field.
 typedef NS_OPTIONS(uint16_t, GPBFieldFlags) {
+  GPBFieldNone            = 0,
   // These map to standard protobuf concepts.
   GPBFieldRequired        = 1 << 0,
   GPBFieldRepeated        = 1 << 1,
@@ -111,6 +112,7 @@
 
 // Describes attributes of the extension.
 typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) {
+  GPBExtensionNone          = 0,
   // These map to standard protobuf concepts.
   GPBExtensionRepeated      = 1 << 0,
   GPBExtensionPacked        = 1 << 1,
@@ -130,6 +132,7 @@
 } GPBExtensionDescription;
 
 typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) {
+  GPBDescriptorInitializationFlag_None              = 0,
   GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0,
   GPBDescriptorInitializationFlag_WireFormat        = 1 << 1,
 };
@@ -165,11 +168,16 @@
       firstHasIndex:(int32_t)firstHasIndex;
 - (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
 - (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+- (void)setupContainingMessageClassName:(const char *)msgClassName;
+- (void)setupMessageClassNameSuffix:(NSString *)suffix;
 
 @end
 
 @interface GPBFileDescriptor ()
 - (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax;
+- (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax;
 @end
 
diff --git a/objectivec/GPBDictionary.h b/objectivec/GPBDictionary.h
index f795996..4b2b9ff 100644
--- a/objectivec/GPBDictionary.h
+++ b/objectivec/GPBDictionary.h
@@ -32,11 +32,6 @@
 
 #import "GPBRuntimeTypes.h"
 
-// These classes are used for map fields of basic data types. They are used because
-// they perform better than boxing into NSNumbers in NSDictionaries.
-
-// Note: These are not meant to be subclassed.
-
 // Note on naming: for the classes holding numeric values, a more natural
 // naming of the method might be things like "-valueForKey:",
 // "-setValue:forKey:"; etc. But those selectors are also defined by Key Value
@@ -53,289 +48,1134 @@
 
 #pragma mark - UInt32 -> UInt32
 
+/**
+ * Class used for map fields of <uint32_t, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32UInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const uint32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const uint32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(uint32_t key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32UInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Int32
 
+/**
+ * Class used for map fields of <uint32_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32Int32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const uint32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const uint32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32Int32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(uint32_t key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32Int32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> UInt64
 
+/**
+ * Class used for map fields of <uint32_t, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32UInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const uint32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const uint32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(uint32_t key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32UInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Int64
 
+/**
+ * Class used for map fields of <uint32_t, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32Int64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const uint32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const uint32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32Int64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(uint32_t key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32Int64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Bool
 
+/**
+ * Class used for map fields of <uint32_t, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32BoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const uint32_t [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const uint32_t [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32BoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(uint32_t key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32BoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Float
 
+/**
+ * Class used for map fields of <uint32_t, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32FloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const uint32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const uint32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32FloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(uint32_t key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32FloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Double
 
+/**
+ * Class used for map fields of <uint32_t, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32DoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const uint32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const uint32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32DoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(uint32_t key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32DoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Enum
 
+/**
+ * Class used for map fields of <uint32_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32EnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const uint32_t [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32EnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const uint32_t [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32EnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -343,23 +1183,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(uint32_t key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(uint32_t key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBUInt32EnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -367,339 +1247,1312 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(uint32_t)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(uint32_t)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt32 -> Object
 
+/**
+ * Class used for map fields of <uint32_t, ObjectType>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param object     The value to be placed in the dictionary.
+ * @param key        The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithObject:(ObjectType)object
                               forKey:(uint32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param objects      The values to be placed in the dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                               forKeys:(const uint32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param objects      The values to be placed in this dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                         forKeys:(const uint32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Fetches the object stored under the given key.
+ *
+ * @param key Key under which the value is stored, if present.
+ *
+ * @return The object if found, nil otherwise.
+ **/
 - (ObjectType)objectForKey:(uint32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:         The key for the current entry.
+ *   **object**:      The value for the current entry
+ *   **stop**:        A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndObjectsUsingBlock:
     (void (^)(uint32_t key, ObjectType object, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param object     The value to set.
+ * @param key        The key under which to store the value.
+ **/
 - (void)setObject:(ObjectType)object forKey:(uint32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeObjectForKey:(uint32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> UInt32
 
+/**
+ * Class used for map fields of <int32_t, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32UInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const int32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const int32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32UInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(int32_t key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32UInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Int32
 
+/**
+ * Class used for map fields of <int32_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32Int32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const int32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const int32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32Int32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(int32_t key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32Int32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> UInt64
 
+/**
+ * Class used for map fields of <int32_t, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32UInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const int32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const int32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32UInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(int32_t key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32UInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Int64
 
+/**
+ * Class used for map fields of <int32_t, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32Int64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const int32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const int32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32Int64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(int32_t key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32Int64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Bool
 
+/**
+ * Class used for map fields of <int32_t, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32BoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const int32_t [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const int32_t [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32BoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(int32_t key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32BoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Float
 
+/**
+ * Class used for map fields of <int32_t, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32FloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const int32_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const int32_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32FloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(int32_t key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32FloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Double
 
+/**
+ * Class used for map fields of <int32_t, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32DoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const int32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const int32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32DoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(int32_t key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32DoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Enum
 
+/**
+ * Class used for map fields of <int32_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32EnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const int32_t [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32EnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const int32_t [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32EnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -707,23 +2560,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(int32_t key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(int32_t key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBInt32EnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -731,339 +2624,1312 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(int32_t)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(int32_t)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int32 -> Object
 
+/**
+ * Class used for map fields of <int32_t, ObjectType>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param object     The value to be placed in the dictionary.
+ * @param key        The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithObject:(ObjectType)object
                               forKey:(int32_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param objects      The values to be placed in the dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                               forKeys:(const int32_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param objects      The values to be placed in this dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                         forKeys:(const int32_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Fetches the object stored under the given key.
+ *
+ * @param key Key under which the value is stored, if present.
+ *
+ * @return The object if found, nil otherwise.
+ **/
 - (ObjectType)objectForKey:(int32_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:         The key for the current entry.
+ *   **object**:      The value for the current entry
+ *   **stop**:        A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndObjectsUsingBlock:
     (void (^)(int32_t key, ObjectType object, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param object     The value to set.
+ * @param key        The key under which to store the value.
+ **/
 - (void)setObject:(ObjectType)object forKey:(int32_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeObjectForKey:(int32_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> UInt32
 
+/**
+ * Class used for map fields of <uint64_t, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64UInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const uint64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const uint64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(uint64_t key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64UInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Int32
 
+/**
+ * Class used for map fields of <uint64_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64Int32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const uint64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const uint64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64Int32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(uint64_t key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64Int32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> UInt64
 
+/**
+ * Class used for map fields of <uint64_t, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64UInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const uint64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const uint64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(uint64_t key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64UInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Int64
 
+/**
+ * Class used for map fields of <uint64_t, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64Int64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const uint64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const uint64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64Int64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(uint64_t key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64Int64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Bool
 
+/**
+ * Class used for map fields of <uint64_t, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64BoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const uint64_t [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const uint64_t [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64BoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(uint64_t key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64BoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Float
 
+/**
+ * Class used for map fields of <uint64_t, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64FloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const uint64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const uint64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64FloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(uint64_t key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64FloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Double
 
+/**
+ * Class used for map fields of <uint64_t, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64DoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const uint64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const uint64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64DoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(uint64_t key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64DoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Enum
 
+/**
+ * Class used for map fields of <uint64_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64EnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const uint64_t [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64EnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const uint64_t [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64EnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -1071,23 +3937,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(uint64_t key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(uint64_t key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBUInt64EnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -1095,339 +4001,1312 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(uint64_t)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(uint64_t)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - UInt64 -> Object
 
+/**
+ * Class used for map fields of <uint64_t, ObjectType>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBUInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param object     The value to be placed in the dictionary.
+ * @param key        The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithObject:(ObjectType)object
                               forKey:(uint64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param objects      The values to be placed in the dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                               forKeys:(const uint64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param objects      The values to be placed in this dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                         forKeys:(const uint64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Fetches the object stored under the given key.
+ *
+ * @param key Key under which the value is stored, if present.
+ *
+ * @return The object if found, nil otherwise.
+ **/
 - (ObjectType)objectForKey:(uint64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:         The key for the current entry.
+ *   **object**:      The value for the current entry
+ *   **stop**:        A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndObjectsUsingBlock:
     (void (^)(uint64_t key, ObjectType object, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param object     The value to set.
+ * @param key        The key under which to store the value.
+ **/
 - (void)setObject:(ObjectType)object forKey:(uint64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeObjectForKey:(uint64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> UInt32
 
+/**
+ * Class used for map fields of <int64_t, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64UInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const int64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const int64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64UInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(int64_t key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64UInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Int32
 
+/**
+ * Class used for map fields of <int64_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64Int32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const int64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const int64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64Int32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(int64_t key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64Int32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> UInt64
 
+/**
+ * Class used for map fields of <int64_t, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64UInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const int64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const int64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64UInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(int64_t key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64UInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Int64
 
+/**
+ * Class used for map fields of <int64_t, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64Int64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const int64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const int64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64Int64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(int64_t key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64Int64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Bool
 
+/**
+ * Class used for map fields of <int64_t, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64BoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const int64_t [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const int64_t [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64BoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(int64_t key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64BoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Float
 
+/**
+ * Class used for map fields of <int64_t, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64FloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const int64_t [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const int64_t [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64FloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(int64_t key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64FloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Double
 
+/**
+ * Class used for map fields of <int64_t, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64DoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const int64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const int64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64DoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(int64_t key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64DoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Enum
 
+/**
+ * Class used for map fields of <int64_t, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64EnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const int64_t [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64EnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const int64_t [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64EnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -1435,23 +5314,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(int64_t key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(int64_t key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBInt64EnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -1459,339 +5378,1312 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(int64_t)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(int64_t)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Int64 -> Object
 
+/**
+ * Class used for map fields of <int64_t, ObjectType>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param object     The value to be placed in the dictionary.
+ * @param key        The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithObject:(ObjectType)object
                               forKey:(int64_t)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param objects      The values to be placed in the dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                               forKeys:(const int64_t [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param objects      The values to be placed in this dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                         forKeys:(const int64_t [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Fetches the object stored under the given key.
+ *
+ * @param key Key under which the value is stored, if present.
+ *
+ * @return The object if found, nil otherwise.
+ **/
 - (ObjectType)objectForKey:(int64_t)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:         The key for the current entry.
+ *   **object**:      The value for the current entry
+ *   **stop**:        A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndObjectsUsingBlock:
     (void (^)(int64_t key, ObjectType object, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param object     The value to set.
+ * @param key        The key under which to store the value.
+ **/
 - (void)setObject:(ObjectType)object forKey:(int64_t)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeObjectForKey:(int64_t)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> UInt32
 
+/**
+ * Class used for map fields of <BOOL, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolUInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const BOOL [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const BOOL [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolUInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(BOOL key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolUInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Int32
 
+/**
+ * Class used for map fields of <BOOL, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const BOOL [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const BOOL [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(BOOL key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> UInt64
 
+/**
+ * Class used for map fields of <BOOL, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolUInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const BOOL [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const BOOL [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolUInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(BOOL key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolUInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Int64
 
+/**
+ * Class used for map fields of <BOOL, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const BOOL [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const BOOL [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(BOOL key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Bool
 
+/**
+ * Class used for map fields of <BOOL, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolBoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const BOOL [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const BOOL [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolBoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(BOOL key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolBoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Float
 
+/**
+ * Class used for map fields of <BOOL, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolFloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const BOOL [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const BOOL [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolFloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(BOOL key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolFloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Double
 
+/**
+ * Class used for map fields of <BOOL, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolDoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const BOOL [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const BOOL [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolDoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(BOOL key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolDoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Enum
 
+/**
+ * Class used for map fields of <BOOL, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolEnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const BOOL [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolEnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const BOOL [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolEnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -1799,23 +6691,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(BOOL key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(BOOL key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBBoolEnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -1823,339 +6755,1312 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(BOOL)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(BOOL)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - Bool -> Object
 
+/**
+ * Class used for map fields of <BOOL, ObjectType>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBBoolObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param object     The value to be placed in the dictionary.
+ * @param key        The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithObject:(ObjectType)object
                               forKey:(BOOL)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param objects      The values to be placed in the dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                               forKeys:(const BOOL [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param objects      The values to be placed in this dictionary.
+ * @param keys         The keys under which to store the values.
+ * @param count        The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
                         forKeys:(const BOOL [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Fetches the object stored under the given key.
+ *
+ * @param key Key under which the value is stored, if present.
+ *
+ * @return The object if found, nil otherwise.
+ **/
 - (ObjectType)objectForKey:(BOOL)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:         The key for the current entry.
+ *   **object**:      The value for the current entry
+ *   **stop**:        A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndObjectsUsingBlock:
     (void (^)(BOOL key, ObjectType object, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param object     The value to set.
+ * @param key        The key under which to store the value.
+ **/
 - (void)setObject:(ObjectType)object forKey:(BOOL)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeObjectForKey:(BOOL)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> UInt32
 
+/**
+ * Class used for map fields of <NSString, uint32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringUInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt32:(uint32_t)value
                               forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt32s:(const uint32_t [])values
                               forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt32s:(const uint32_t [])values
                         forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringUInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt32:(nullable uint32_t *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt32sUsingBlock:
     (void (^)(NSString *key, uint32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringUInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt32:(uint32_t)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt32ForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Int32
 
+/**
+ * Class used for map fields of <NSString, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringInt32Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt32:(int32_t)value
                              forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt32s:(const int32_t [])values
                              forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt32s:(const int32_t [])values
                        forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringInt32Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt32:(nullable int32_t *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt32sUsingBlock:
     (void (^)(NSString *key, int32_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringInt32Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt32:(int32_t)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt32ForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> UInt64
 
+/**
+ * Class used for map fields of <NSString, uint64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringUInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithUInt64:(uint64_t)value
                               forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithUInt64s:(const uint64_t [])values
                               forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithUInt64s:(const uint64_t [])values
                         forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringUInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getUInt64:(nullable uint64_t *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndUInt64sUsingBlock:
     (void (^)(NSString *key, uint64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringUInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setUInt64:(uint64_t)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeUInt64ForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Int64
 
+/**
+ * Class used for map fields of <NSString, int64_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringInt64Dictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithInt64:(int64_t)value
                              forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithInt64s:(const int64_t [])values
                              forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithInt64s:(const int64_t [])values
                        forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringInt64Dictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getInt64:(nullable int64_t *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndInt64sUsingBlock:
     (void (^)(NSString *key, int64_t value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringInt64Dictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setInt64:(int64_t)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeInt64ForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Bool
 
+/**
+ * Class used for map fields of <NSString, BOOL>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringBoolDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithBool:(BOOL)value
                             forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithBools:(const BOOL [])values
                             forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                               count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithBools:(const BOOL [])values
                       forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringBoolDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getBool:(nullable BOOL *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndBoolsUsingBlock:
     (void (^)(NSString *key, BOOL value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringBoolDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setBool:(BOOL)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeBoolForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Float
 
+/**
+ * Class used for map fields of <NSString, float>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringFloatDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithFloat:(float)value
                              forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithFloats:(const float [])values
                              forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithFloats:(const float [])values
                        forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringFloatDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getFloat:(nullable float *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndFloatsUsingBlock:
     (void (^)(NSString *key, float value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringFloatDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setFloat:(float)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeFloatForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Double
 
+/**
+ * Class used for map fields of <NSString, double>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringDoubleDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param value     The value to be placed in the dictionary.
+ * @param key       The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithDouble:(double)value
                               forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param values      The values to be placed in the dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithDoubles:(const double [])values
                               forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                 count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
+/**
+ * Initializes this dictionary, copying the given values and keys.
+ *
+ * @param values      The values to be placed in this dictionary.
+ * @param keys        The keys under which to store the values.
+ * @param count       The number of elements to copy into the dictionary.
+ *
+ * @return A newly initialized dictionary with a copy of the values and keys.
+ **/
 - (instancetype)initWithDoubles:(const double [])values
                         forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                           count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes this dictionary, copying the entries from the given dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to this dictionary.
+ *
+ * @return A newly initialized dictionary with the entries of the given dictionary.
+ **/
 - (instancetype)initWithDictionary:(GPBStringDoubleDictionary *)dictionary;
+
+/**
+ * Initializes this dictionary with the requested capacity.
+ *
+ * @param numItems Number of items needed for this dictionary.
+ *
+ * @return A newly initialized dictionary with the requested capacity.
+ **/
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getDouble:(nullable double *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndDoublesUsingBlock:
     (void (^)(NSString *key, double value, BOOL *stop))block;
 
+/**
+ * Adds the keys and values from another dictionary.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addEntriesFromDictionary:(GPBStringDoubleDictionary *)otherDictionary;
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setDouble:(double)value forKey:(NSString *)key;
 
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeDoubleForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
 
 #pragma mark - String -> Enum
 
+/**
+ * Class used for map fields of <NSString, int32_t>
+ * values. This performs better than boxing into NSNumbers in NSDictionaries.
+ *
+ * @note This class is not meant to be subclassed.
+ **/
 @interface GPBStringEnumDictionary : NSObject <NSCopying>
 
+/** Number of entries stored in this dictionary. */
 @property(nonatomic, readonly) NSUInteger count;
+/** The validation function to check if the enums are valid. */
 @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 
+/**
+ * @return A newly instanced and empty dictionary.
+ **/
 + (instancetype)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly instanced dictionary.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Creates and initializes a dictionary with the single entry given.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param rawValue The raw enum value to be placed in the dictionary.
+ * @param key      The key under which to store the value.
+ *
+ * @return A newly instanced dictionary with the key and value in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         rawValue:(int32_t)rawValue
                                           forKey:(NSString *)key;
+
+/**
+ * Creates and initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly instanced dictionary with the keys and values in it.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValues:(const int32_t [])values
                                          forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                            count:(NSUInteger)count;
+
+/**
+ * Creates and initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly instanced dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 + (instancetype)dictionaryWithDictionary:(GPBStringEnumDictionary *)dictionary;
+
+/**
+ * Creates and initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly instanced dictionary with the given capacity.
+ **/
 + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                         capacity:(NSUInteger)numItems;
 
+/**
+ * Initializes a dictionary with the given validation function.
+ *
+ * @param func The enum validation function for the dictionary.
+ *
+ * @return A newly initialized dictionary.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+
+/**
+ * Initializes a dictionary with the entries given.
+ *
+ * @param func   The enum validation function for the dictionary.
+ * @param values The raw enum values values to be placed in the dictionary.
+ * @param keys   The keys under which to store the values.
+ * @param count  The number of entries to store in the dictionary.
+ *
+ * @return A newly initialized dictionary with the keys and values in it.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  rawValues:(const int32_t [])values
                                    forKeys:(const NSString * GPB_UNSAFE_UNRETAINED [])keys
                                      count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Initializes a dictionary with the entries from the given.
+ * dictionary.
+ *
+ * @param dictionary Dictionary containing the entries to add to the dictionary.
+ *
+ * @return A newly initialized dictionary with the entries from the given
+ *         dictionary in it.
+ **/
 - (instancetype)initWithDictionary:(GPBStringEnumDictionary *)dictionary;
+
+/**
+ * Initializes a dictionary with the given capacity.
+ *
+ * @param func     The enum validation function for the dictionary.
+ * @param numItems Capacity needed for the dictionary.
+ *
+ * @return A newly initialized dictionary with the given capacity.
+ **/
 - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)numItems;
 
@@ -2163,23 +8068,63 @@
 // is not a valid enumerator as defined by validationFunc. If the actual value is
 // desired, use "raw" version of the method.
 
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the value for the given key.
+ *
+ * @param value Pointer into which the value will be set, if found.
+ * @param key   Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getEnum:(nullable int32_t *)value forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:        The key for the current entry.
+ *   **value**:      The value for the current entry
+ *   **stop**:       A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndEnumsUsingBlock:
     (void (^)(NSString *key, int32_t value, BOOL *stop))block;
 
-// These methods bypass the validationFunc to provide access to values that were not
-// known at the time the binary was compiled.
-
-// Returns YES/NO to indicate if the key was found or not, filling in the value
-// only when the key was found.
+/**
+ * Gets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue Pointer into which the value will be set, if found.
+ * @param key      Key under which the value is stored, if present.
+ *
+ * @return YES if the key was found and the value was copied, NO otherwise.
+ **/
 - (BOOL)getRawValue:(nullable int32_t *)rawValue forKey:(NSString *)key;
 
+/**
+ * Enumerates the keys and values on this dictionary with the given block.
+ *
+ * @note This method bypass the validationFunc to enable the access of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param block The block to enumerate with.
+ *   **key**:      The key for the current entry.
+ *   **rawValue**: The value for the current entry
+ *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+ **/
 - (void)enumerateKeysAndRawValuesUsingBlock:
     (void (^)(NSString *key, int32_t rawValue, BOOL *stop))block;
 
+/**
+ * Adds the keys and raw enum values from another dictionary.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param otherDictionary Dictionary containing entries to be added to this
+ *                        dictionary.
+ **/
 - (void)addRawEntriesFromDictionary:(GPBStringEnumDictionary *)otherDictionary;
 
 // If value is not a valid enumerator as defined by validationFunc, these
@@ -2187,15 +8132,35 @@
 // to the default value. Use the rawValue methods below to assign non enumerator
 // values.
 
+/**
+ * Sets the value for the given key.
+ *
+ * @param value     The value to set.
+ * @param key       The key under which to store the value.
+ **/
 - (void)setEnum:(int32_t)value forKey:(NSString *)key;
 
-// This method bypass the validationFunc to provide setting of values that were not
-// known at the time the binary was compiled.
+/**
+ * Sets the raw enum value for the given key.
+ *
+ * @note This method bypass the validationFunc to enable the setting of values that
+ *       were not known at the time the binary was compiled.
+ *
+ * @param rawValue The raw enum value to set.
+ * @param key      The key under which to store the raw enum value.
+ **/
 - (void)setRawValue:(int32_t)rawValue forKey:(NSString *)key;
 
-// No validation applies to these methods.
-
+/**
+ * Removes the entry for the given key.
+ *
+ * @param aKey Key to be removed from this dictionary.
+ **/
 - (void)removeEnumForKey:(NSString *)aKey;
+
+/**
+ * Removes all entries in this dictionary.
+ **/
 - (void)removeAll;
 
 @end
@@ -2228,10 +8193,23 @@
 //%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE)
 //%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, , POD, VALUE_NAME, VALUE_TYPE, OBJECT, Object, object)
 //%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE, VNAME)
-//%// Returns YES/NO to indicate if the key was found or not, filling in the value
-//%// only when the key was found.
+//%/**
+//% * Gets the value for the given key.
+//% * 
+//% * @param value Pointer into which the value will be set, if found.
+//% * @param key   Key under which the value is stored, if present.
+//% * 
+//% * @return YES if the key was found and the value was copied, NO otherwise.
+//% **/
 //%- (BOOL)get##VNAME##:(nullable VALUE_TYPE *)value forKey:(KEY_TYPE)key;
 //%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_TYPE, VNAME)
+//%/**
+//% * Fetches the object stored under the given key.
+//% * 
+//% * @param key Key under which the value is stored, if present.
+//% * 
+//% * @return The object if found, nil otherwise.
+//% **/
 //%- (VALUE_TYPE)objectForKey:(KEY_TYPE)key;
 //%PDDM-DEFINE VALUE_FOR_KEY_Enum(KEY_TYPE, VALUE_TYPE, VNAME)
 //%VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE, VNAME)
@@ -2250,27 +8228,105 @@
 //%PDDM-DEFINE DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME, VNAME_VAR)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
+//%/**
+//% * Class used for map fields of <##KEY_TYPE##, ##VALUE_TYPE##>
+//% * values. This performs better than boxing into NSNumbers in NSDictionaries.
+//% * 
+//% * @note This class is not meant to be subclassed.
+//% **/
 //%@interface DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) : NSObject <NSCopying>
 //%
+//%/** Number of entries stored in this dictionary. */
 //%@property(nonatomic, readonly) NSUInteger count;
 //%
+//%/**
+//% * @return A newly instanced and empty dictionary.
+//% **/
 //%+ (instancetype)dictionary;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the single entry given.
+//% * 
+//% * @param ##VNAME_VAR     The value to be placed in the dictionary.
+//% * @param key ##VNAME_VAR$S## The key under which to store the value.
+//% * 
+//% * @return A newly instanced dictionary with the key and value in it.
+//% **/
 //%+ (instancetype)dictionaryWith##VNAME##:(VALUE_TYPE)##VNAME_VAR
 //%                       ##VNAME$S## forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the entries given.
+//% * 
+//% * @param ##VNAME_VAR##s      The values to be placed in the dictionary.
+//% * @param keys ##VNAME_VAR$S##  The keys under which to store the values.
+//% * @param count ##VNAME_VAR$S## The number of entries to store in the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the keys and values in it.
+//% **/
 //%+ (instancetype)dictionaryWith##VNAME##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME_VAR##s
 //%                      ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
 //%                      ##VNAME$S##    count:(NSUInteger)count;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the entries from the given.
+//% * dictionary.
+//% * 
+//% * @param dictionary Dictionary containing the entries to add to the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the entries from the given
+//% *         dictionary in it.
+//% **/
 //%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the given capacity.
+//% * 
+//% * @param numItems Capacity needed for the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the given capacity.
+//% **/
 //%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 //%
+//%/**
+//% * Initializes this dictionary, copying the given values and keys.
+//% * 
+//% * @param ##VNAME_VAR##s      The values to be placed in this dictionary.
+//% * @param keys ##VNAME_VAR$S##  The keys under which to store the values.
+//% * @param count ##VNAME_VAR$S## The number of elements to copy into the dictionary.
+//% * 
+//% * @return A newly initialized dictionary with a copy of the values and keys.
+//% **/
 //%- (instancetype)initWith##VNAME##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME_VAR##s
 //%                ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
 //%                ##VNAME$S##    count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%
+//%/**
+//% * Initializes this dictionary, copying the entries from the given dictionary.
+//% * 
+//% * @param dictionary Dictionary containing the entries to add to this dictionary.
+//% * 
+//% * @return A newly initialized dictionary with the entries of the given dictionary.
+//% **/
 //%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%
+//%/**
+//% * Initializes this dictionary with the requested capacity.
+//% * 
+//% * @param numItems Number of items needed for this dictionary.
+//% * 
+//% * @return A newly initialized dictionary with the requested capacity.
+//% **/
 //%- (instancetype)initWithCapacity:(NSUInteger)numItems;
 //%
 //%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME, VNAME_VAR)
 //%
+//%/**
+//% * Adds the keys and values from another dictionary.
+//% * 
+//% * @param otherDictionary Dictionary containing entries to be added to this
+//% *                        dictionary.
+//% **/
 //%- (void)addEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary;
 //%
 //%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME, VNAME_VAR)
@@ -2283,30 +8339,126 @@
 //%PDDM-DEFINE DICTIONARY_KEY_TO_ENUM_INTERFACE2(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
+//%/**
+//% * Class used for map fields of <##KEY_TYPE##, ##VALUE_TYPE##>
+//% * values. This performs better than boxing into NSNumbers in NSDictionaries.
+//% * 
+//% * @note This class is not meant to be subclassed.
+//% **/
 //%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : NSObject <NSCopying>
 //%
+//%/** Number of entries stored in this dictionary. */
 //%@property(nonatomic, readonly) NSUInteger count;
+//%/** The validation function to check if the enums are valid. */
 //%@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;
 //%
+//%/**
+//% * @return A newly instanced and empty dictionary.
+//% **/
 //%+ (instancetype)dictionary;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the given validation function.
+//% * 
+//% * @param func The enum validation function for the dictionary.
+//% * 
+//% * @return A newly instanced dictionary.
+//% **/
 //%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the single entry given.
+//% * 
+//% * @param func     The enum validation function for the dictionary.
+//% * @param rawValue The raw enum value to be placed in the dictionary.
+//% * @param key      The key under which to store the value.
+//% * 
+//% * @return A newly instanced dictionary with the key and value in it.
+//% **/
 //%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                        rawValue:(VALUE_TYPE)rawValue
 //%                                          forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the entries given.
+//% * 
+//% * @param func   The enum validation function for the dictionary.
+//% * @param values The raw enum values values to be placed in the dictionary.
+//% * @param keys   The keys under which to store the values.
+//% * @param count  The number of entries to store in the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the keys and values in it.
+//% **/
 //%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                       rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values
 //%                                         forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
 //%                                           count:(NSUInteger)count;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the entries from the given.
+//% * dictionary.
+//% * 
+//% * @param dictionary Dictionary containing the entries to add to the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the entries from the given
+//% *         dictionary in it.
+//% **/
 //%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%
+//%/**
+//% * Creates and initializes a dictionary with the given capacity.
+//% * 
+//% * @param func     The enum validation function for the dictionary.
+//% * @param numItems Capacity needed for the dictionary.
+//% * 
+//% * @return A newly instanced dictionary with the given capacity.
+//% **/
 //%+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                        capacity:(NSUInteger)numItems;
 //%
+//%/**
+//% * Initializes a dictionary with the given validation function.
+//% * 
+//% * @param func The enum validation function for the dictionary.
+//% * 
+//% * @return A newly initialized dictionary.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+//%
+//%/**
+//% * Initializes a dictionary with the entries given.
+//% * 
+//% * @param func   The enum validation function for the dictionary.
+//% * @param values The raw enum values values to be placed in the dictionary.
+//% * @param keys   The keys under which to store the values.
+//% * @param count  The number of entries to store in the dictionary.
+//% * 
+//% * @return A newly initialized dictionary with the keys and values in it.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                 rawValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values
 //%                                   forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
 //%                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+//%
+//%/**
+//% * Initializes a dictionary with the entries from the given.
+//% * dictionary.
+//% * 
+//% * @param dictionary Dictionary containing the entries to add to the dictionary.
+//% * 
+//% * @return A newly initialized dictionary with the entries from the given
+//% *         dictionary in it.
+//% **/
 //%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
+//%
+//%/**
+//% * Initializes a dictionary with the given capacity.
+//% * 
+//% * @param func     The enum validation function for the dictionary.
+//% * @param numItems Capacity needed for the dictionary.
+//% * 
+//% * @return A newly initialized dictionary with the given capacity.
+//% **/
 //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
 //%                                  capacity:(NSUInteger)numItems;
 //%
@@ -2316,16 +8468,42 @@
 //%
 //%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, Enum, value)
 //%
-//%// These methods bypass the validationFunc to provide access to values that were not
-//%// known at the time the binary was compiled.
-//%
-//%// Returns YES/NO to indicate if the key was found or not, filling in the value
-//%// only when the key was found.
+//%/**
+//% * Gets the raw enum value for the given key.
+//% * 
+//% * @note This method bypass the validationFunc to enable the access of values that
+//% *       were not known at the time the binary was compiled.
+//% * 
+//% * @param rawValue Pointer into which the value will be set, if found.
+//% * @param key      Key under which the value is stored, if present.
+//% * 
+//% * @return YES if the key was found and the value was copied, NO otherwise.
+//% **/
 //%- (BOOL)getRawValue:(nullable VALUE_TYPE *)rawValue forKey:(KEY_TYPE##KisP$S##KisP)key;
 //%
+//%/**
+//% * Enumerates the keys and values on this dictionary with the given block.
+//% * 
+//% * @note This method bypass the validationFunc to enable the access of values that
+//% *       were not known at the time the binary was compiled.
+//% * 
+//% * @param block The block to enumerate with.
+//% *   **key**:      The key for the current entry.
+//% *   **rawValue**: The value for the current entry
+//% *   **stop**:     A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateKeysAndRawValuesUsingBlock:
 //%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE rawValue, BOOL *stop))block;
 //%
+//%/**
+//% * Adds the keys and raw enum values from another dictionary.
+//% * 
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% * 
+//% * @param otherDictionary Dictionary containing entries to be added to this
+//% *                        dictionary.
+//% **/
 //%- (void)addRawEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary;
 //%
 //%// If value is not a valid enumerator as defined by validationFunc, these
@@ -2341,13 +8519,36 @@
 //%PDDM-DEFINE DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME, VNAME_VAR)
 //%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_TYPE, VNAME)
 //%
+//%/**
+//% * Enumerates the keys and values on this dictionary with the given block.
+//% * 
+//% * @param block The block to enumerate with.
+//% *   **key**: ##VNAME_VAR$S##  The key for the current entry.
+//% *   **VNAME_VAR**:      The value for the current entry
+//% *   **stop**: ##VNAME_VAR$S## A pointer to a boolean that when set stops the enumeration.
+//% **/
 //%- (void)enumerateKeysAnd##VNAME##sUsingBlock:
 //%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE VNAME_VAR, BOOL *stop))block;
 
 //%PDDM-DEFINE DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME, VNAME_VAR)
+//%/**
+//% * Sets the value for the given key.
+//% * 
+//% * @param ##VNAME_VAR     The value to set.
+//% * @param key ##VNAME_VAR$S## The key under which to store the value.
+//% **/
 //%- (void)set##VNAME##:(VALUE_TYPE)##VNAME_VAR forKey:(KEY_TYPE##KisP$S##KisP)key;
 //%DICTIONARY_EXTRA_MUTABLE_METHODS_##VHELPER(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
+//%/**
+//% * Removes the entry for the given key.
+//% * 
+//% * @param aKey Key to be removed from this dictionary.
+//% **/
 //%- (void)remove##VNAME##ForKey:(KEY_TYPE##KisP$S##KisP)aKey;
+//%
+//%/**
+//% * Removes all entries in this dictionary.
+//% **/
 //%- (void)removeAll;
 
 //%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_POD(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
@@ -2356,9 +8557,14 @@
 // Empty
 //%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_Enum(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
 //%
-//%// This method bypass the validationFunc to provide setting of values that were not
-//%// known at the time the binary was compiled.
+//%/**
+//% * Sets the raw enum value for the given key.
+//% * 
+//% * @note This method bypass the validationFunc to enable the setting of values that
+//% *       were not known at the time the binary was compiled.
+//% * 
+//% * @param rawValue The raw enum value to set.
+//% * @param key      The key under which to store the raw enum value.
+//% **/
 //%- (void)setRawValue:(VALUE_TYPE)rawValue forKey:(KEY_TYPE##KisP$S##KisP)key;
 //%
-//%// No validation applies to these methods.
-//%
diff --git a/objectivec/GPBExtensionRegistry.h b/objectivec/GPBExtensionRegistry.h
index 08a6472..d79632d 100644
--- a/objectivec/GPBExtensionRegistry.h
+++ b/objectivec/GPBExtensionRegistry.h
@@ -35,45 +35,50 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/// A table of known extensions, searchable by name or field number.  When
-/// parsing a protocol message that might have extensions, you must provide a
-/// @c GPBExtensionRegistry 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.
-///
-/// The @c *Root classes provide @c +extensionRegistry for the extensions defined
-/// in a given file *and* all files it imports. You can also create a
-/// @c GPBExtensionRegistry, and merge those registries to handle parsing
-/// extensions defined from non overlapping files.
-///
-/// @code
-/// 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];
-/// @endcode
+/**
+ * A table of known extensions, searchable by name or field number.  When
+ * parsing a protocol message that might have extensions, you must provide a
+ * GPBExtensionRegistry 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.
+ *
+ * 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];
+ * [registry addExtension:[OtherMessage neededExtension]]; // Not in MyProtoFile
+ * NSError *parseError;
+ * MyMessage *msg = [MyMessage parseData:data extensionRegistry:registry error:&parseError];
+ * ```
+ **/
 @interface GPBExtensionRegistry : NSObject<NSCopying>
 
-/// Add the given @c GPBExtensionDescriptor to this registry.
-///
-/// @param extension The extension description to add.
+/**
+ * Adds the given GPBExtensionDescriptor to this registry.
+ *
+ * @param extension The extension description to add.
+ **/
 - (void)addExtension:(GPBExtensionDescriptor *)extension;
 
-/// Adds all the extensions from another registry to this registry.
-///
-/// @param registry The registry to merge into this registry.
+/**
+ * Adds all the extensions from another registry to this registry.
+ *
+ * @param registry The registry to merge into this registry.
+ **/
 - (void)addExtensions:(GPBExtensionRegistry *)registry;
 
-/// Looks for the extension registered for the given field number on a given
-/// @c GPBDescriptor.
-///
-/// @param descriptor  The descriptor to look for a registered extension on.
-/// @param fieldNumber The field number of an extension to look for.
-///
-/// @return The registered @c GPBExtensionDescripto or nil if none was found.
+/**
+ * Looks for the extension registered for the given field number on a given
+ * GPBDescriptor.
+ *
+ * @param descriptor  The descriptor to look for a registered extension on.
+ * @param fieldNumber The field number of the extension to look for.
+ *
+ * @return The registered GPBExtensionDescriptor or nil if none was found.
+ **/
 - (nullable GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
                                                 fieldNumber:(NSInteger)fieldNumber;
 
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index 9608cdb..0cb74f9 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -44,282 +44,404 @@
 
 CF_EXTERN_C_BEGIN
 
-/// NSError domain used for errors.
+/** NSError domain used for errors. */
 extern NSString *const GPBMessageErrorDomain;
 
-/// Error code for NSError with GPBMessageErrorDomain.
+/** Error codes for NSErrors originated in GPBMessage. */
 typedef NS_ENUM(NSInteger, GPBMessageErrorCode) {
-  /// Uncategorized error.
+  /** Uncategorized error. */
   GPBMessageErrorCodeOther = -100,
-  /// A message can't be serialized because it is missing required fields.
+  /** Message couldn't be serialized because it is missing required fields. */
   GPBMessageErrorCodeMissingRequiredField = -101,
 };
 
-/// Key under which the error's reason is stored inside the userInfo dictionary.
+/**
+ * Key under which the GPBMessage error's reason is stored inside the userInfo
+ * dictionary.
+ **/
 extern NSString *const GPBErrorReasonKey;
 
 CF_EXTERN_C_END
 
-/// Base class for all of the generated message classes.
+/**
+ * Base class that each generated message subclasses from.
+ **/
 @interface GPBMessage : NSObject<NSSecureCoding, NSCopying>
+ 
+// If you add an instance method/property to this class that may conflict with
+// fields declared in protos, you need to update objective_helpers.cc. The main
+// cases are methods that take no arguments, or setFoo:/hasFoo: type methods.
 
-// 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.
-
-/// The unknown fields for this message.
-///
-/// Only messages from proto files declared with "proto2" syntax support unknown
-/// fields. For "proto3" syntax, any unknown fields found while parsing are
-/// dropped.
+/**
+ * The set of unknown fields for this message.
+ *
+ * Only messages from proto files declared with "proto2" syntax support unknown
+ * fields. For "proto3" syntax, any unknown fields found while parsing are
+ * dropped.
+ **/
 @property(nonatomic, copy, nullable) GPBUnknownFieldSet *unknownFields;
 
-/// Are all required fields set in the message and all embedded messages.
+/**
+ * Whether the message, along with all submessages, have the required fields
+ * set. This is only applicable for files declared with "proto2" syntax, as
+ * there are no required fields for "proto3" syntax.
+ **/
 @property(nonatomic, readonly, getter=isInitialized) BOOL initialized;
 
-/// Returns an autoreleased instance.
+/**
+ * @return An autoreleased message with the default values set.
+ **/
 + (instancetype)message;
 
-/// Creates a new instance by parsing the data. This method should be sent to
-/// the generated message class that the data should be interpreted as. If
-/// there is an error the method returns nil and the error is returned in
-/// errorPtr (when provided).
-///
-/// @note In DEBUG builds, the parsed message is checked to be sure all required
-///       fields were provided, and the parse will fail if some are missing.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param data     The data to parse.
-/// @param errorPtr An optional error pointer to fill in with a failure reason if
-///                 the data can not be parsed.
-///
-/// @return A new instance of the class messaged.
+/**
+ * Creates a new instance by parsing the provided data. This method should be
+ * sent to the generated message class that the data should be interpreted as.
+ * If there is an error the method returns nil and the error is returned in
+ * errorPtr (when provided).
+ *
+ * @note In DEBUG builds, the parsed message is checked to be sure all required
+ *       fields were provided, and the parse will fail if some are missing.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param data     The data to parse.
+ * @param errorPtr An optional error pointer to fill in with a failure reason if
+ *                 the data can not be parsed.
+ *
+ * @return A new instance of the generated class.
+ **/
 + (nullable instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr;
 
-/// Creates a new instance by parsing the data. This method should be sent to
-/// the generated message class that the data should be interpreted as. If
-/// there is an error the method returns nil and the error is returned in
-/// errorPtr (when provided).
-///
-/// @note In DEBUG builds, the parsed message is checked to be sure all required
-///       fields were provided, and the parse will fail if some are missing.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param data              The data to parse.
-/// @param extensionRegistry The extension registry to use to look up extensions.
-/// @param errorPtr          An optional error pointer to fill in with a failure
-///                          reason if the data can not be parsed.
-///
-/// @return A new instance of the class messaged.
+/**
+ * Creates a new instance by parsing the data. This method should be sent to
+ * the generated message class that the data should be interpreted as. If
+ * there is an error the method returns nil and the error is returned in
+ * errorPtr (when provided).
+ *
+ * @note In DEBUG builds, the parsed message is checked to be sure all required
+ *       fields were provided, and the parse will fail if some are missing.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param data              The data to parse.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr          An optional error pointer to fill in with a failure
+ *                          reason if the data can not be parsed.
+ *
+ * @return A new instance of the generated class.
+ **/
 + (nullable instancetype)parseFromData:(NSData *)data
                      extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
                                  error:(NSError **)errorPtr;
 
-/// Creates a new instance by parsing the data from the given input stream. This
-/// method should be sent to the generated message class that the data should
-/// be interpreted as. If there is an error the method returns nil and the error
-/// is returned in errorPtr (when provided).
-///
-/// @note In DEBUG builds, the parsed message is checked to be sure all required
-///       fields were provided, and the parse will fail if some are missing.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param input             The stream to read data from.
-/// @param extensionRegistry The extension registry to use to look up extensions.
-/// @param errorPtr          An optional error pointer to fill in with a failure
-///                          reason if the data can not be parsed.
-///
-/// @return A new instance of the class messaged.
+/**
+ * Creates a new instance by parsing the data from the given input stream. This
+ * method should be sent to the generated message class that the data should
+ * be interpreted as. If there is an error the method returns nil and the error
+ * is returned in errorPtr (when provided).
+ *
+ * @note In DEBUG builds, the parsed message is checked to be sure all required
+ *       fields were provided, and the parse will fail if some are missing.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param input             The stream to read data from.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr          An optional error pointer to fill in with a failure
+ *                          reason if the data can not be parsed.
+ *
+ * @return A new instance of the generated class.
+ **/
 + (nullable instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
                                  extensionRegistry:
                                      (nullable GPBExtensionRegistry *)extensionRegistry
                                              error:(NSError **)errorPtr;
 
-/// Creates a new instance by parsing the data from the given input stream. This
-/// method should be sent to the generated message class that the data should
-/// be interpreted as. If there is an error the method returns nil and the error
-/// is returned in errorPtr (when provided).
-///
-/// @note Unlike the parseFrom... methods, this never checks to see if all of
-///       the required fields are set. So this method can be used to reload
-///       messages that may not be complete.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param input             The stream to read data from.
-/// @param extensionRegistry The extension registry to use to look up extensions.
-/// @param errorPtr          An optional error pointer to fill in with a failure
-///                          reason if the data can not be parsed.
-///
-/// @return A new instance of the class messaged.
+/**
+ * Creates a new instance by parsing the data from the given input stream. This
+ * method should be sent to the generated message class that the data should
+ * be interpreted as. If there is an error the method returns nil and the error
+ * is returned in errorPtr (when provided).
+ *
+ * @note Unlike the parseFrom... methods, this never checks to see if all of
+ *       the required fields are set. So this method can be used to reload
+ *       messages that may not be complete.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param input             The stream to read data from.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr          An optional error pointer to fill in with a failure
+ *                          reason if the data can not be parsed.
+ *
+ * @return A new instance of the generated class.
+ **/
 + (nullable instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
                                           extensionRegistry:
                                               (nullable GPBExtensionRegistry *)extensionRegistry
                                                       error:(NSError **)errorPtr;
 
-/// Initializes an instance by parsing the data. This method should be sent to
-/// the generated message class that the data should be interpreted as. If
-/// there is an error the method returns nil and the error is returned in
-/// errorPtr (when provided).
-///
-/// @note In DEBUG builds, the parsed message is checked to be sure all required
-///       fields were provided, and the parse will fail if some are missing.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param data     The data to parse.
-/// @param errorPtr An optional error pointer to fill in with a failure reason if
-///                 the data can not be parsed.
+/**
+ * Initializes an instance by parsing the data. This method should be sent to
+ * the generated message class that the data should be interpreted as. If
+ * there is an error the method returns nil and the error is returned in
+ * errorPtr (when provided).
+ *
+ * @note In DEBUG builds, the parsed message is checked to be sure all required
+ *       fields were provided, and the parse will fail if some are missing.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param data     The data to parse.
+ * @param errorPtr An optional error pointer to fill in with a failure reason if
+ *                 the data can not be parsed.
+ *
+ * @return An initialized instance of the generated class.
+ **/
 - (nullable instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr;
 
-/// Initializes an instance by parsing the data. This method should be sent to
-/// the generated message class that the data should be interpreted as. If
-/// there is an error the method returns nil and the error is returned in
-/// errorPtr (when provided).
-///
-/// @note In DEBUG builds, the parsed message is checked to be sure all required
-///       fields were provided, and the parse will fail if some are missing.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param data              The data to parse.
-/// @param extensionRegistry The extension registry to use to look up extensions.
-/// @param errorPtr          An optional error pointer to fill in with a failure
-///                          reason if the data can not be parsed.
+/**
+ * Initializes an instance by parsing the data. This method should be sent to
+ * the generated message class that the data should be interpreted as. If
+ * there is an error the method returns nil and the error is returned in
+ * errorPtr (when provided).
+ *
+ * @note In DEBUG builds, the parsed message is checked to be sure all required
+ *       fields were provided, and the parse will fail if some are missing.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param data              The data to parse.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr          An optional error pointer to fill in with a failure
+ *                          reason if the data can not be parsed.
+ *
+ * @return An initialized instance of the generated class.
+ **/
 - (nullable instancetype)initWithData:(NSData *)data
                     extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry
                                 error:(NSError **)errorPtr;
 
-/// Initializes an instance by parsing the data from the given input stream. This
-/// method should be sent to the generated message class that the data should
-/// be interpreted as. If there is an error the method returns nil and the error
-/// is returned in errorPtr (when provided).
-///
-/// @note Unlike the parseFrom... methods, this never checks to see if all of
-///       the required fields are set. So this method can be used to reload
-///       messages that may not be complete.
-///
-/// @note The errors returned are likely coming from the domain and codes listed
-///       at the top of this file and GPBCodedInputStream.h.
-///
-/// @param input             The stream to read data from.
-/// @param extensionRegistry The extension registry to use to look up extensions.
-/// @param errorPtr          An optional error pointer to fill in with a failure
-///                          reason if the data can not be parsed.
+/**
+ * Initializes an instance by parsing the data from the given input stream. This
+ * method should be sent to the generated message class that the data should
+ * be interpreted as. If there is an error the method returns nil and the error
+ * is returned in errorPtr (when provided).
+ *
+ * @note Unlike the parseFrom... methods, this never checks to see if all of
+ *       the required fields are set. So this method can be used to reload
+ *       messages that may not be complete.
+ *
+ * @note The errors returned are likely coming from the domain and codes listed
+ *       at the top of this file and GPBCodedInputStream.h.
+ *
+ * @param input             The stream to read data from.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr          An optional error pointer to fill in with a failure
+ *                          reason if the data can not be parsed.
+ *
+ * @return An initialized instance of the generated class.
+ **/
 - (nullable instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
                                 extensionRegistry:
                                     (nullable GPBExtensionRegistry *)extensionRegistry
                                             error:(NSError **)errorPtr;
 
-/// Writes out the message to the given output stream.
+/**
+ * Parses the given data as this message's class, and merges those values into
+ * this message.
+ *
+ * @param data              The binary representation of the message to merge.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ *
+ * @exception GPBCodedInputStreamException Exception thrown when parsing was
+ *                                         unsuccessful.
+ **/
+- (void)mergeFromData:(NSData *)data
+    extensionRegistry:(nullable GPBExtensionRegistry *)extensionRegistry;
+
+/**
+ * Merges the fields from another message (of the same type) into this
+ * message.
+ *
+ * @param other Message to merge into this message.
+ **/
+- (void)mergeFrom:(GPBMessage *)other;
+
+/**
+ * Writes out the message to the given coded output stream.
+ *
+ * @param output The coded output stream into which to write the message.
+ **/
 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
-/// Writes out the message to the given output stream.
+
+/**
+ * Writes out the message to the given output stream.
+ *
+ * @param output The output stream into which to write the message.
+ **/
 - (void)writeToOutputStream:(NSOutputStream *)output;
 
-/// Writes out a varint for the message size followed by the the message to
-/// the given output stream.
+/**
+ * Writes out a varint for the message size followed by the the message to
+ * the given output stream.
+ *
+ * @param output The coded output stream into which to write the message.
+ **/
 - (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
-/// Writes out a varint for the message size followed by the the message to
-/// the given output stream.
+
+/**
+ * Writes out a varint for the message size followed by the the message to
+ * the given output stream.
+ *
+ * @param output The output stream into which to write the message.
+ **/
 - (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
 
-/// Serializes the message to a @c NSData.
-///
-/// If there is an error while generating the data, nil is returned.
-///
-/// @note This value is not cached, so if you are using it repeatedly, cache
-///       it yourself.
-///
-/// @note In DEBUG ONLY, the message is also checked for all required field,
-///       if one is missing, nil will be returned.
+/**
+ * Serializes the message to an NSData.
+ *
+ * If there is an error while generating the data, nil is returned.
+ *
+ * @note This value is not cached, so if you are using it repeatedly, cache
+ *       it yourself.
+ *
+ * @note In DEBUG ONLY, the message is also checked for all required field,
+ *       if one is missing, nil will be returned.
+ *
+ * @return The binary representation of the message.
+ **/
 - (nullable NSData *)data;
 
-/// Serializes a varint with the message size followed by the message data,
-/// returning that as a @c NSData.
-///
-/// @note This value is not cached, so if you are using it repeatedly, cache
-///       it yourself.
+/**
+ * Serializes a varint with the message size followed by the message data,
+ * returning that as an NSData.
+ *
+ * @note This value is not cached, so if you are using it repeatedly, it is
+ *       recommended to keep a local copy.
+ *
+ * @return The binary representation of the size along with the message.
+ **/
 - (NSData *)delimitedData;
 
-/// Calculates the size of the object if it were serialized.
-///
-/// This is not a cached value. If you are following a pattern like this:
-/// @code
-///   size_t size = [aMsg serializedSize];
-///   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
-///   [foo writeSize:size];
-///   [foo appendData:[aMsg data]];
-/// @endcode
-/// you would be better doing:
-/// @code
-///   NSData *data = [aMsg data];
-///   NSUInteger size = [aMsg length];
-///   NSMutableData *foo = [NSMutableData dataWithCapacity:size + sizeof(size)];
-///   [foo writeSize:size];
-///   [foo appendData:data];
-/// @endcode
+/**
+ * Calculates 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]];
+ * ```
+ *
+ * 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];
+ * ```
+ *
+ * @return The size of the message in it's binary representation.
+ **/
 - (size_t)serializedSize;
 
-/// Return the descriptor for the message class.
+/**
+ * @return The descriptor for the message class.
+ **/
 + (GPBDescriptor *)descriptor;
-/// Return the descriptor for the message.
+
+/**
+ * Return the descriptor for the message.
+ **/
 - (GPBDescriptor *)descriptor;
 
-/// Test to see if the given extension is set on the message.
+/**
+ * @return An array with the extension descriptors that are currently set on the
+ * message.
+ **/
+- (NSArray *)extensionsCurrentlySet;
+
+/**
+ * Checks whether there is an extension set on the message which matches the
+ * given extension descriptor.
+ *
+ * @param extension Extension descriptor to check if it's set on the message.
+ *
+ * @return Whether the extension is currently set on the message.
+ **/
 - (BOOL)hasExtension:(GPBExtensionDescriptor *)extension;
 
-/// Fetches the given extension's value for this message.
-///
-/// Extensions use boxed values (NSNumbers) for PODs and NSMutableArrays for
-/// repeated fields. If the extension is a Message one will be auto created for you
-/// and returned similar to fields.
+/*
+ * Fetches the given extension's value for this message.
+ *
+ * Extensions use boxed values (NSNumbers) for PODs and NSMutableArrays for
+ * repeated fields. If the extension is a Message one will be auto created for
+ * you and returned similar to fields.
+ *
+ * @param extension The extension descriptor of the extension to fetch.
+ *
+ * @return The extension matching the given descriptor, or nil if none found.
+ **/
 - (nullable id)getExtension:(GPBExtensionDescriptor *)extension;
 
-/// Sets the given extension's value for this message. This is only for single
-/// field extensions (i.e. - not repeated fields).
-///
-/// Extensions use boxed values (@c NSNumbers).
-- (void)setExtension:(GPBExtensionDescriptor *)extension value:(nullable id)value;
+/**
+ * Sets the given extension's value for this message. This only applies for
+ * single field extensions (i.e. - not repeated fields).
+ *
+ * Extensions use boxed values (NSNumbers).
+ *
+ * @param extension The extension descriptor under which to set the value.
+ * @param value     The value to be set as the extension.
+ **/
+- (void)setExtension:(GPBExtensionDescriptor *)extension
+               value:(nullable id)value;
 
-/// Adds the given value to the extension for this message. This is only for
-/// repeated field extensions. If the field is a repeated POD type the @c value
-/// is a @c NSNumber.
+/**
+ * Adds the given value to the extension for this message. This only applies
+ * to repeated field extensions. If the field is a repeated POD type, the value
+ * should be an NSNumber.
+ *
+ * @param extension The extension descriptor under which to add the value.
+ * @param value     The value to be added to the repeated extension.
+ **/
 - (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value;
 
-/// Replaces the given value at an index for the extension on this message. This
-/// is only for repeated field extensions. If the field is a repeated POD type
-/// the @c value is a @c NSNumber.
+/**
+ * Replaces the value at the given index with the given value for the extension
+ * on this message. This only applies to repeated field extensions. If the field
+ * is a repeated POD type, the value is should be an NSNumber.
+ *
+ * @param extension The extension descriptor under which to replace the value.
+ * @param index     The index of the extension to be replaced.
+ * @param value     The value to be replaced in the repeated extension.
+ **/
 - (void)setExtension:(GPBExtensionDescriptor *)extension
                index:(NSUInteger)index
                value:(id)value;
 
-/// Clears the given extension for this message.
+/**
+ * Clears the given extension for this message.
+ *
+ * @param extension The extension descriptor to be cleared from this message.
+ **/
 - (void)clearExtension:(GPBExtensionDescriptor *)extension;
 
-/// Resets all of the fields of this message to their default values.
+/**
+ * Resets all of the fields of this message to their default values.
+ **/
 - (void)clear;
 
-/// 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:(nullable GPBExtensionRegistry *)extensionRegistry;
-
-/// Merges the fields from another message (of the same type) into this
-/// message.
-- (void)mergeFrom:(GPBMessage *)other;
-
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index b9566bd..4a6f061 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -1777,11 +1777,6 @@
   }
 }
 
-- (NSArray *)sortedExtensionsInUse {
-  return [[extensionMap_ allKeys]
-      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
-}
-
 - (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
   if (!value) {
     [self clearExtension:extension];
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
index ff3cd6e..02d0e16 100644
--- a/objectivec/GPBMessage_PackagePrivate.h
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -78,10 +78,6 @@
 // returns nil if the extension is not set)
 - (id)getExistingExtension:(GPBExtensionDescriptor *)extension;
 
-// Returns an array of GPBExtensionDescriptor* for all the extensions currently
-// in use on the message.  They are sorted by field number.
-- (NSArray *)sortedExtensionsInUse;
-
 // Parses a message of this type from the input and merges it with this
 // message.
 //
diff --git a/objectivec/GPBRootObject.h b/objectivec/GPBRootObject.h
index c05b5c6..d2e2aeb 100644
--- a/objectivec/GPBRootObject.h
+++ b/objectivec/GPBRootObject.h
@@ -34,12 +34,17 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/// Every generated proto file defines a local "Root" class that exposes a
-/// @c GPBExtensionRegistry for all the extensions defined by that file and
-/// the files it depends on.
+/**
+ * Every generated proto file defines a local "Root" class that exposes a
+ * GPBExtensionRegistry for all the extensions defined by that file and
+ * the files it depends on.
+ **/
 @interface GPBRootObject : NSObject
 
-/// An extension registry for the given file and all the files it depends on.
+/**
+ * @return An extension registry for the given file and all the files it depends
+ * on.
+ **/
 + (GPBExtensionRegistry *)extensionRegistry;
 
 @end
diff --git a/objectivec/GPBRuntimeTypes.h b/objectivec/GPBRuntimeTypes.h
index 0a38b11..4d55206 100644
--- a/objectivec/GPBRuntimeTypes.h
+++ b/objectivec/GPBRuntimeTypes.h
@@ -36,21 +36,28 @@
 @class GPBMessage;
 @class GPBInt32Array;
 
-// Function used to verify that a given value can be represented by an
-// enum type.
+/**
+ * Verifies that a given value can be represented by an enum type.
+ * */
 typedef BOOL (*GPBEnumValidationFunc)(int32_t);
 
-// Function used to fetch an EnumDescriptor.
+/**
+ * Fetches an EnumDescriptor.
+ * */
 typedef GPBEnumDescriptor *(*GPBEnumDescriptorFunc)(void);
 
-// Magic values used for when an the at runtime to indicate an enum value
-// that wasn't know at compile time.
+/**
+ * Magic value used at runtime to indicate an enum value that wasn't know at
+ * compile time.
+ * */
 enum {
   kGPBUnrecognizedEnumeratorValue = (int32_t)0xFBADBEEF,
 };
 
-// A union for storing all possible Protobuf values.
-// Note that owner is responsible for memory management of object types.
+/**
+ * A union for storing all possible Protobuf values. Note that owner is
+ * responsible for memory management of object types.
+ * */
 typedef union {
   BOOL valueBool;
   int32_t valueInt32;
@@ -65,38 +72,73 @@
   int32_t valueEnum;
 } GPBGenericValue;
 
-// Do not change the order of this enum (or add things to it) without thinking
-// about it very carefully. There are several things that depend on the order.
+/**
+ * Enum listing the possible data types that a field can contain.
+ * 
+ * @note Do not change the order of this enum (or add things to it) without
+ *       thinking about it very carefully. There are several things that depend
+ *       on the order.
+ * */
 typedef NS_ENUM(uint8_t, GPBDataType) {
+  /** Field contains boolean value(s). */
   GPBDataTypeBool = 0,
+  /** Field contains unsigned 4 byte value(s). */
   GPBDataTypeFixed32,
+  /** Field contains signed 4 byte value(s). */
   GPBDataTypeSFixed32,
+  /** Field contains float value(s). */
   GPBDataTypeFloat,
+  /** Field contains unsigned 8 byte value(s). */
   GPBDataTypeFixed64,
+  /** Field contains signed 8 byte value(s). */
   GPBDataTypeSFixed64,
+  /** Field contains double value(s). */
   GPBDataTypeDouble,
+  /**
+   * Field contains variable length value(s). Inefficient for encoding negative
+   * numbers – if your field is likely to have negative values, use
+   * GPBDataTypeSInt32 instead.
+   **/
   GPBDataTypeInt32,
+  /**
+   * Field contains variable length value(s). Inefficient for encoding negative
+   * numbers – if your field is likely to have negative values, use
+   * GPBDataTypeSInt64 instead.
+   **/
   GPBDataTypeInt64,
+  /** Field contains signed variable length integer value(s). */
   GPBDataTypeSInt32,
+  /** Field contains signed variable length integer value(s). */
   GPBDataTypeSInt64,
+  /** Field contains unsigned variable length integer value(s). */
   GPBDataTypeUInt32,
+  /** Field contains unsigned variable length integer value(s). */
   GPBDataTypeUInt64,
+  /** Field contains an arbitrary sequence of bytes. */
   GPBDataTypeBytes,
+  /** Field contains UTF-8 encoded or 7-bit ASCII text. */
   GPBDataTypeString,
+  /** Field contains message type(s). */
   GPBDataTypeMessage,
+  /** Field contains message type(s). */
   GPBDataTypeGroup,
+  /** Field contains enum value(s). */
   GPBDataTypeEnum,
 };
 
 enum {
-  // A count of the number of types in GPBDataType. Separated out from the
-  // GPBDataType enum to avoid warnings regarding not handling
-  // GPBDataType_Count in switch statements.
+  /**
+   * A count of the number of types in GPBDataType. Separated out from the
+   * GPBDataType enum to avoid warnings regarding not handling GPBDataType_Count
+   * in switch statements.
+   **/
   GPBDataType_Count = GPBDataTypeEnum + 1
 };
 
-// An extension range.
+/** An extension range. */
 typedef struct GPBExtensionRange {
-  uint32_t start;  // inclusive
-  uint32_t end;    // exclusive
+  /** Inclusive. */
+  uint32_t start;
+  /** Exclusive. */
+  uint32_t end;
 } GPBExtensionRange;
diff --git a/objectivec/GPBUnknownField.h b/objectivec/GPBUnknownField.h
index 0f301e4..a135cc2 100644
--- a/objectivec/GPBUnknownField.h
+++ b/objectivec/GPBUnknownField.h
@@ -36,52 +36,59 @@
 @class GPBUnknownFieldSet;
 
 NS_ASSUME_NONNULL_BEGIN
-
-/// Store an unknown field. These are used in conjunction with @c GPBUnknownFieldSet
+/**
+ * Store an unknown field. These are used in conjunction with
+ * GPBUnknownFieldSet.
+ **/
 @interface GPBUnknownField : NSObject<NSCopying>
 
-/// The field number the data is stored under.
+/** The field number the data is stored under. */
 @property(nonatomic, readonly, assign) int32_t number;
 
-/// An array of varint values for this field.
+/** An array of varint values for this field. */
 @property(nonatomic, readonly, strong) GPBUInt64Array *varintList;
 
-/// An array of fixed32 values for this field.
+/** An array of fixed32 values for this field. */
 @property(nonatomic, readonly, strong) GPBUInt32Array *fixed32List;
 
-/// An array of fixed64 values for this field.
+/** An array of fixed64 values for this field. */
 @property(nonatomic, readonly, strong) GPBUInt64Array *fixed64List;
 
-/// An array of data values for this field.
+/** An array of data values for this field. */
 @property(nonatomic, readonly, strong) NSArray<NSData*> *lengthDelimitedList;
 
-/// An array of groups of values for this field.
+/** An array of groups of values for this field. */
 @property(nonatomic, readonly, strong) NSArray<GPBUnknownFieldSet*> *groupList;
 
-
-/// Add a value to the varintList.
-///
-/// @param value The value to add.
+/**
+ * Add a value to the varintList.
+ *
+ * @param value The value to add.
+ **/
 - (void)addVarint:(uint64_t)value;
-
-/// Add a value to the fixed32List.
-///
-/// @param value The value to add.
+/**
+ * Add a value to the fixed32List.
+ *
+ * @param value The value to add.
+ **/
 - (void)addFixed32:(uint32_t)value;
-
-/// Add a value to the fixed64List.
-///
-/// @param value The value to add.
+/**
+ * Add a value to the fixed64List.
+ *
+ * @param value The value to add.
+ **/
 - (void)addFixed64:(uint64_t)value;
-
-/// Add a value to the lengthDelimitedList.
-///
-/// @param value The value to add.
+/**
+ * Add a value to the lengthDelimitedList.
+ *
+ * @param value The value to add.
+ **/
 - (void)addLengthDelimited:(NSData *)value;
-
-/// Add a value to the groupList.
-///
-/// @param value The value to add.
+/**
+ * Add a value to the groupList.
+ *
+ * @param value The value to add.
+ **/
 - (void)addGroup:(GPBUnknownFieldSet *)value;
 
 @end
diff --git a/objectivec/GPBUnknownFieldSet.h b/objectivec/GPBUnknownFieldSet.h
index cf61299..1b5f24f 100644
--- a/objectivec/GPBUnknownFieldSet.h
+++ b/objectivec/GPBUnknownFieldSet.h
@@ -34,31 +34,48 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/// A collection of unknown fields.
+/**
+ * A collection of unknown fields. Fields parsed from the binary representation
+ * of a message that are unknown end up in an instance of this set. This only
+ * applies for files declared with the "proto2" syntax. Files declared with the
+ * "proto3" syntax discard the unknown values.
+ **/
 @interface GPBUnknownFieldSet : NSObject<NSCopying>
 
-/// Tests to see if the given field number has a value.
-///
-/// @param number The field number to check.
-///
-/// @return YES if there is an unknown field for the given field number.
+/**
+ * Tests to see if the given field number has a value.
+ *
+ * @param number The field number to check.
+ *
+ * @return YES if there is an unknown field for the given field number.
+ **/
 - (BOOL)hasField:(int32_t)number;
 
-/// Fetches the @c GPBUnknownField for the given field number.
-///
-/// @param number The field number to look up.
-///
-/// @return The @c GPBUnknownField or nil.
+/**
+ * Fetches the GPBUnknownField for the given field number.
+ *
+ * @param number The field number to look up.
+ *
+ * @return The GPBUnknownField or nil if none found.
+ **/
 - (nullable GPBUnknownField *)getField:(int32_t)number;
 
-/// Returns the number of fields in this set.
+/**
+ * @return The number of fields in this set.
+ **/
 - (NSUInteger)countOfFields;
 
-/// Adds the given field to the set.
+/**
+ * Adds the given field to the set.
+ *
+ * @param field The field to add to the set.
+ **/
 - (void)addField:(GPBUnknownField *)field;
 
-/// Returns an NSArray of the @c GPBUnknownFields sorted by the field numbers.
-- (NSArray<GPBUnknownField*> *)sortedFields;
+/**
+ * @return An array of the GPBUnknownFields sorted by the field numbers.
+ **/
+- (NSArray<GPBUnknownField *> *)sortedFields;
 
 @end
 
diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h
index b720932..52e7d2e 100644
--- a/objectivec/GPBUtilities.h
+++ b/objectivec/GPBUtilities.h
@@ -38,34 +38,58 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
-/// Generates a string that should be a valid "Text Format" for the C++ version
-/// of Protocol Buffers.
-///
-///  @param message    The message to generate from.
-///  @param lineIndent A string to use as the prefix for all lines generated. Can
-///                    be nil if no extra indent is needed.
-///
-/// @return A @c NSString with the Text Format of the message.
+/**
+ * Generates a string that should be a valid "TextFormat" for the C++ version
+ * of Protocol Buffers.
+ *
+ * @param message    The message to generate from.
+ * @param lineIndent A string to use as the prefix for all lines generated. Can
+ *                   be nil if no extra indent is needed.
+ *
+ * @return An NSString with the TextFormat of the message.
+ **/
 NSString *GPBTextFormatForMessage(GPBMessage *message,
                                   NSString * __nullable lineIndent);
 
-/// Generates a string that should be a valid "Text Format" for the C++ version
-/// of Protocol Buffers.
-///
-///  @param unknownSet The unknown field set to generate from.
-///  @param lineIndent A string to use as the prefix for all lines generated. Can
-///                    be nil if no extra indent is needed.
-///
-/// @return A @c NSString with the Text Format of the unknown field set.
+/**
+ * Generates a string that should be a valid "TextFormat" for the C++ version
+ * of Protocol Buffers.
+ *
+ * @param unknownSet The unknown field set to generate from.
+ * @param lineIndent A string to use as the prefix for all lines generated. Can
+ *                   be nil if no extra indent is needed.
+ *
+ * @return An NSString with the TextFormat of the unknown field set.
+ **/
 NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet * __nullable unknownSet,
                                           NSString * __nullable lineIndent);
 
-/// Test if the given field is set on a message.
+/**
+ * Checks if the given field number is set on a message.
+ *
+ * @param self        The message to check.
+ * @param fieldNumber The field number to check.
+ *
+ * @return YES if the field number is set on the given message.
+ **/
 BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber);
-/// Test if the given field is set on a message.
+
+/**
+ * Checks if the given field is set on a message.
+ *
+ * @param self  The message to check.
+ * @param field The field to check.
+ *
+ * @return YES if the field is set on the given message.
+ **/
 BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field);
 
-/// Clear the given field of a message.
+/**
+ * Clears the given field for the given message.
+ *
+ * @param self  The message for which to clear the field.
+ * @param field The field to clear.
+ **/
 void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field);
 
 //%PDDM-EXPAND GPB_ACCESSORS()
@@ -73,112 +97,299 @@
 
 
 //
-// Get/Set the given field of a message.
+// Get/Set a given field from/to a message.
 //
 
 // Single Fields
 
-/// Gets the value of a bytes field.
+/**
+ * Gets the value of a bytes field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 NSData *GPBGetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a bytes field.
+
+/**
+ * Sets the value of a bytes field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageBytesField(GPBMessage *self, GPBFieldDescriptor *field, NSData *value);
 
-/// Gets the value of a string field.
+/**
+ * Gets the value of a string field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 NSString *GPBGetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a string field.
+
+/**
+ * Sets the value of a string field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageStringField(GPBMessage *self, GPBFieldDescriptor *field, NSString *value);
 
-/// Gets the value of a message field.
+/**
+ * Gets the value of a message field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 GPBMessage *GPBGetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a message field.
+
+/**
+ * Sets the value of a message field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageMessageField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
 
-/// Gets the value of a group field.
+/**
+ * Gets the value of a group field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 GPBMessage *GPBGetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a group field.
+
+/**
+ * Sets the value of a group field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageGroupField(GPBMessage *self, GPBFieldDescriptor *field, GPBMessage *value);
 
-/// Gets the value of a bool field.
+/**
+ * Gets the value of a bool field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 BOOL GPBGetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a bool field.
+
+/**
+ * Sets the value of a bool field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field, BOOL value);
 
-/// Gets the value of an int32 field.
+/**
+ * Gets the value of an int32 field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 int32_t GPBGetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of an int32 field.
+
+/**
+ * Sets the value of an int32 field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageInt32Field(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
 
-/// Gets the value of an uint32 field.
+/**
+ * Gets the value of an uint32 field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 uint32_t GPBGetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of an uint32 field.
+
+/**
+ * Sets the value of an uint32 field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageUInt32Field(GPBMessage *self, GPBFieldDescriptor *field, uint32_t value);
 
-/// Gets the value of an int64 field.
+/**
+ * Gets the value of an int64 field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 int64_t GPBGetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of an int64 field.
+
+/**
+ * Sets the value of an int64 field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageInt64Field(GPBMessage *self, GPBFieldDescriptor *field, int64_t value);
 
-/// Gets the value of an uint64 field.
+/**
+ * Gets the value of an uint64 field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 uint64_t GPBGetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of an uint64 field.
+
+/**
+ * Sets the value of an uint64 field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageUInt64Field(GPBMessage *self, GPBFieldDescriptor *field, uint64_t value);
 
-/// Gets the value of a float field.
+/**
+ * Gets the value of a float field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 float GPBGetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a float field.
+
+/**
+ * Sets the value of a float field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageFloatField(GPBMessage *self, GPBFieldDescriptor *field, float value);
 
-/// Gets the value of a double field.
+/**
+ * Gets the value of a double field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ **/
 double GPBGetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a double field.
+
+/**
+ * Sets the value of a double field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The to set in the field.
+ **/
 void GPBSetMessageDoubleField(GPBMessage *self, GPBFieldDescriptor *field, double value);
 
-/// Get the given enum field of a message. For proto3, if the value isn't a
-/// member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
-/// GPBGetMessageRawEnumField will bypass the check and return whatever value
-/// was set.
+/**
+ * Gets the given enum field of a message. For proto3, if the value isn't a
+ * member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
+ * GPBGetMessageRawEnumField will bypass the check and return whatever value
+ * was set.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ *
+ * @return The enum value for the given field.
+ **/
 int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Set the given enum field of a message. You can only set values that are
-/// members of the enum.
-void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
-/// Get the given enum field of a message. No check is done to ensure the value
-/// was defined in the enum.
+
+/**
+ * Set the given enum field of a message. You can only set values that are
+ * members of the enum.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The enum value to set in the field.
+ **/
+void GPBSetMessageEnumField(GPBMessage *self,
+                            GPBFieldDescriptor *field,
+                            int32_t value);
+
+/**
+ * Get the given enum field of a message. No check is done to ensure the value
+ * was defined in the enum.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The field to get.
+ *
+ * @return The raw enum value for the given field.
+ **/
 int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Set the given enum field of a message. You can set the value to anything,
-/// even a value that is not a member of the enum.
-void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+
+/**
+ * Set the given enum field of a message. You can set the value to anything,
+ * even a value that is not a member of the enum.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param value The raw enum value to set in the field.
+ **/
+void GPBSetMessageRawEnumField(GPBMessage *self,
+                               GPBFieldDescriptor *field,
+                               int32_t value);
 
 // Repeated Fields
 
-/// Gets the value of a repeated field.
-///
-/// The result will be @c GPB*Array or @c NSMutableArray based on the
-/// field's type.
+/**
+ * Gets the value of a repeated field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The repeated field to get.
+ *
+ * @return A GPB*Array or an NSMutableArray based on the field's type.
+ **/
 id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a repeated field.
-///
-/// The value should be @c GPB*Array or @c NSMutableArray based on the
-/// field's type.
-void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+
+/**
+ * Sets the value of a repeated field.
+ *
+ * @param self  The message into which to set the field.
+ * @param field The field to set.
+ * @param array A GPB*Array or NSMutableArray based on the field's type.
+ **/
+void GPBSetMessageRepeatedField(GPBMessage *self,
+                                GPBFieldDescriptor *field,
+                                id array);
 
 // Map Fields
 
-/// Gets the value of a map<> field.
-///
-/// The result will be @c GPB*Dictionary or @c NSMutableDictionary based on
-/// the field's type.
+/**
+ * Gets the value of a map<> field.
+ *
+ * @param self  The message from which to get the field.
+ * @param field The repeated field to get.
+ *
+ * @return A GPB*Dictionary or NSMutableDictionary based on the field's type.
+ **/
 id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
-/// Sets the value of a map<> field.
-///
-/// The object should be @c GPB*Dictionary or @c NSMutableDictionary based
-/// on the field's type.
-void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary);
+
+/**
+ * Sets the value of a map<> field.
+ *
+ * @param self       The message into which to set the field.
+ * @param field      The field to set.
+ * @param dictionary A GPB*Dictionary or NSMutableDictionary based on the
+ *                   field's type.
+ **/
+void GPBSetMessageMapField(GPBMessage *self,
+                           GPBFieldDescriptor *field,
+                           id dictionary);
 
 //%PDDM-EXPAND-END GPB_ACCESSORS()
 
-// Returns an empty NSData to assign to byte fields when you wish
-// to assign them to empty. Prevents allocating a lot of little [NSData data]
-// objects.
+/**
+ * Returns an empty NSData to assign to byte fields when you wish to assign them
+ * to empty. Prevents allocating a lot of little [NSData data] objects.
+ **/
 NSData *GPBEmptyNSData(void) __attribute__((pure));
 
 NS_ASSUME_NONNULL_END
@@ -189,7 +400,7 @@
 //%PDDM-DEFINE GPB_ACCESSORS()
 //%
 //%//
-//%// Get/Set the given field of a message.
+//%// Get/Set a given field from/to a message.
 //%//
 //%
 //%// Single Fields
@@ -205,53 +416,119 @@
 //%GPB_ACCESSOR_SINGLE(UInt64, uint64_t, n)
 //%GPB_ACCESSOR_SINGLE(Float, float, )
 //%GPB_ACCESSOR_SINGLE(Double, double, )
-//%/// Get the given enum field of a message. For proto3, if the value isn't a
-//%/// member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
-//%/// GPBGetMessageRawEnumField will bypass the check and return whatever value
-//%/// was set.
+//%/**
+//% * Gets the given enum field of a message. For proto3, if the value isn't a
+//% * member of the enum, @c kGPBUnrecognizedEnumeratorValue will be returned.
+//% * GPBGetMessageRawEnumField will bypass the check and return whatever value
+//% * was set.
+//% *
+//% * @param self  The message from which to get the field.
+//% * @param field The field to get.
+//% *
+//% * @return The enum value for the given field.
+//% **/
 //%int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field);
-//%/// Set the given enum field of a message. You can only set values that are
-//%/// members of the enum.
-//%void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
-//%/// Get the given enum field of a message. No check is done to ensure the value
-//%/// was defined in the enum.
+//%
+//%/**
+//% * Set the given enum field of a message. You can only set values that are
+//% * members of the enum.
+//% *
+//% * @param self  The message into which to set the field.
+//% * @param field The field to set.
+//% * @param value The enum value to set in the field.
+//% **/
+//%void GPBSetMessageEnumField(GPBMessage *self,
+//%                            GPBFieldDescriptor *field,
+//%                            int32_t value);
+//%
+//%/**
+//% * Get the given enum field of a message. No check is done to ensure the value
+//% * was defined in the enum.
+//% *
+//% * @param self  The message from which to get the field.
+//% * @param field The field to get.
+//% *
+//% * @return The raw enum value for the given field.
+//% **/
 //%int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field);
-//%/// Set the given enum field of a message. You can set the value to anything,
-//%/// even a value that is not a member of the enum.
-//%void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value);
+//%
+//%/**
+//% * Set the given enum field of a message. You can set the value to anything,
+//% * even a value that is not a member of the enum.
+//% *
+//% * @param self  The message into which to set the field.
+//% * @param field The field to set.
+//% * @param value The raw enum value to set in the field.
+//% **/
+//%void GPBSetMessageRawEnumField(GPBMessage *self,
+//%                               GPBFieldDescriptor *field,
+//%                               int32_t value);
 //%
 //%// Repeated Fields
 //%
-//%/// Gets the value of a repeated field.
-//%///
-//%/// The result will be @c GPB*Array or @c NSMutableArray based on the
-//%/// field's type.
+//%/**
+//% * Gets the value of a repeated field.
+//% *
+//% * @param self  The message from which to get the field.
+//% * @param field The repeated field to get.
+//% *
+//% * @return A GPB*Array or an NSMutableArray based on the field's type.
+//% **/
 //%id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field);
-//%/// Sets the value of a repeated field.
-//%///
-//%/// The value should be @c GPB*Array or @c NSMutableArray based on the
-//%/// field's type.
-//%void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array);
+//%
+//%/**
+//% * Sets the value of a repeated field.
+//% *
+//% * @param self  The message into which to set the field.
+//% * @param field The field to set.
+//% * @param array A GPB*Array or NSMutableArray based on the field's type.
+//% **/
+//%void GPBSetMessageRepeatedField(GPBMessage *self,
+//%                                GPBFieldDescriptor *field,
+//%                                id array);
 //%
 //%// Map Fields
 //%
-//%/// Gets the value of a map<> field.
-//%///
-//%/// The result will be @c GPB*Dictionary or @c NSMutableDictionary based on
-//%/// the field's type.
+//%/**
+//% * Gets the value of a map<> field.
+//% *
+//% * @param self  The message from which to get the field.
+//% * @param field The repeated field to get.
+//% *
+//% * @return A GPB*Dictionary or NSMutableDictionary based on the field's type.
+//% **/
 //%id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field);
-//%/// Sets the value of a map<> field.
-//%///
-//%/// The object should be @c GPB*Dictionary or @c NSMutableDictionary based
-//%/// on the field's type.
-//%void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary);
+//%
+//%/**
+//% * Sets the value of a map<> field.
+//% *
+//% * @param self       The message into which to set the field.
+//% * @param field      The field to set.
+//% * @param dictionary A GPB*Dictionary or NSMutableDictionary based on the
+//% *                   field's type.
+//% **/
+//%void GPBSetMessageMapField(GPBMessage *self,
+//%                           GPBFieldDescriptor *field,
+//%                           id dictionary);
 //%
 
 //%PDDM-DEFINE GPB_ACCESSOR_SINGLE(NAME, TYPE, AN)
 //%GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, AN, )
 //%PDDM-DEFINE GPB_ACCESSOR_SINGLE_FULL(NAME, TYPE, AN, TisP)
-//%/// Gets the value of a##AN NAME$L field.
+//%/**
+//% * Gets the value of a##AN NAME$L field.
+//% *
+//% * @param self  The message from which to get the field.
+//% * @param field The field to get.
+//% **/
 //%TYPE TisP##GPBGetMessage##NAME##Field(GPBMessage *self, GPBFieldDescriptor *field);
-//%/// Sets the value of a##AN NAME$L field.
+//%
+//%/**
+//% * Sets the value of a##AN NAME$L field.
+//% *
+//% * @param self  The message into which to set the field.
+//% * @param field The field to set.
+//% * @param value The to set in the field.
+//% **/
 //%void GPBSetMessage##NAME##Field(GPBMessage *self, GPBFieldDescriptor *field, TYPE TisP##value);
 //%
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 0537508..80b85d0 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -218,9 +218,10 @@
 //%  TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
 //%  *typePtr = value;
 //%  // proto2: any value counts as having been set; proto3, it
-//%  // has to be a non zero value.
-//%  BOOL hasValue =
-//%    (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0);
+//%  // has to be a non zero value or be in a oneof.
+//%  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+//%                   || (value != (TYPE)0)
+//%                   || (field->containingOneof_ != NULL));
 //%  GPBSetHasIvarField(self, field, hasValue);
 //%  GPBBecomeVisibleToAutocreator(self);
 //%}
@@ -337,8 +338,19 @@
     // zero, they are being cleared.
     if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
         ([value length] == 0)) {
-      setHasValue = NO;
-      value = nil;
+      // Except, if the field was in a oneof, then it still gets recorded as
+      // having been set so the state of the oneof can be serialized back out.
+      if (!oneof) {
+        setHasValue = NO;
+      }
+      if (setHasValue) {
+        NSCAssert(value != nil, @"Should never be setting has for nil");
+      } else {
+        // The value passed in was retained, it must be released since we
+        // aren't saving anything in the field.
+        [value release];
+        value = nil;
+      }
     }
     GPBSetHasIvarField(self, field, setHasValue);
   }
@@ -524,9 +536,10 @@
   GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
 
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (BOOL)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -573,9 +586,10 @@
   int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (int32_t)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -622,9 +636,10 @@
   uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (uint32_t)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -671,9 +686,10 @@
   int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (int64_t)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -720,9 +736,10 @@
   uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (uint64_t)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -769,9 +786,10 @@
   float *typePtr = (float *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (float)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (float)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -818,9 +836,10 @@
   double *typePtr = (double *)&storage[field->description_->offset];
   *typePtr = value;
   // proto2: any value counts as having been set; proto3, it
-  // has to be a non zero value.
-  BOOL hasValue =
-    (syntax == GPBFileSyntaxProto2) || (value != (double)0);
+  // has to be a non zero value or be in a oneof.
+  BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
+                   || (value != (double)0)
+                   || (field->containingOneof_ != NULL));
   GPBSetHasIvarField(self, field, hasValue);
   GPBBecomeVisibleToAutocreator(self);
 }
@@ -1052,7 +1071,15 @@
       case '\'': [destStr appendString:@"\\\'"]; break;
       case '\\': [destStr appendString:@"\\\\"]; break;
       default:
-        [destStr appendFormat:@"%C", aChar];
+        // This differs slightly from the C++ code in that the C++ doesn't
+        // generate UTF8; it looks at the string in UTF8, but escapes every
+        // byte > 0x7E.
+        if (aChar < 0x20) {
+          [destStr appendFormat:@"\\%d%d%d",
+                                (aChar / 64), ((aChar % 64) / 8), (aChar % 8)];
+        } else {
+          [destStr appendFormat:@"%C", aChar];
+        }
         break;
     }
   }
@@ -1472,7 +1499,8 @@
   NSUInteger fieldCount = fieldsArray.count;
   const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
   NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
-  NSArray *activeExtensions = [message sortedExtensionsInUse];
+  NSArray *activeExtensions = [[message extensionsCurrentlySet]
+      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
   for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
     if (i == fieldCount) {
       AppendTextFormatForMessageExtensionRange(
diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h
index c02493b..a41ee2a 100644
--- a/objectivec/GPBUtilities_PackagePrivate.h
+++ b/objectivec/GPBUtilities_PackagePrivate.h
@@ -96,7 +96,7 @@
 // negative values must be sign-extended to 64 bits to be varint encoded,
 // thus always taking 10 bytes on the wire.)
 GPB_INLINE int32_t GPBDecodeZigZag32(uint32_t n) {
-  return GPBLogicalRightShift32(n, 1) ^ -(n & 1);
+  return (int32_t)(GPBLogicalRightShift32((int32_t)n, 1) ^ -((int32_t)(n) & 1));
 }
 
 // Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
@@ -104,7 +104,7 @@
 // negative values must be sign-extended to 64 bits to be varint encoded,
 // thus always taking 10 bytes on the wire.)
 GPB_INLINE int64_t GPBDecodeZigZag64(uint64_t n) {
-  return GPBLogicalRightShift64(n, 1) ^ -(n & 1);
+  return (int64_t)(GPBLogicalRightShift64((int64_t)n, 1) ^ -((int64_t)(n) & 1));
 }
 
 // Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
@@ -113,7 +113,7 @@
 // thus always taking 10 bytes on the wire.)
 GPB_INLINE uint32_t GPBEncodeZigZag32(int32_t n) {
   // Note:  the right-shift must be arithmetic
-  return (n << 1) ^ (n >> 31);
+  return (uint32_t)((n << 1) ^ (n >> 31));
 }
 
 // Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
@@ -122,7 +122,7 @@
 // thus always taking 10 bytes on the wire.)
 GPB_INLINE uint64_t GPBEncodeZigZag64(int64_t n) {
   // Note:  the right-shift must be arithmetic
-  return (n << 1) ^ (n >> 63);
+  return (uint64_t)((n << 1) ^ (n >> 63));
 }
 
 #pragma clang diagnostic push
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 311ac58..90d96c6 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -37,27 +37,198 @@
 #endif
 
 #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
+ #import <Protobuf/Any.pbobjc.h>
  #import <Protobuf/Duration.pbobjc.h>
  #import <Protobuf/Timestamp.pbobjc.h>
 #else
+ #import "google/protobuf/Any.pbobjc.h"
  #import "google/protobuf/Duration.pbobjc.h"
  #import "google/protobuf/Timestamp.pbobjc.h"
 #endif
 
 NS_ASSUME_NONNULL_BEGIN
 
-// Extension to GPBTimestamp to work with standard Foundation time/date types.
+#pragma mark - Errors
+
+/** NSError domain used for errors. */
+extern NSString *const GPBWellKnownTypesErrorDomain;
+
+/** Error code for NSError with GPBWellKnownTypesErrorDomain. */
+typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
+  /** The type_url could not be computed for the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeFailedToComputeTypeURL = -100,
+  /** type_url in a Any doesn’t match that of the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeTypeURLMismatch = -101,
+};
+
+#pragma mark - GPBTimestamp
+
+/**
+ * Category for GPBTimestamp to work with standard Foundation time/date types.
+ **/
 @interface GPBTimestamp (GBPWellKnownTypes)
+
+/** The NSDate representation of this GPBTimestamp. */
 @property(nonatomic, readwrite, strong) NSDate *date;
+
+/**
+ * The NSTimeInterval representation of this GPBTimestamp.
+ *
+ * @note: Not all second/nanos combinations can be represented in a
+ * NSTimeInterval, so getting this could be a lossy transform.
+ **/
 @property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
+
+/**
+ * Initializes a GPBTimestamp with the given NSDate.
+ *
+ * @param date The date to configure the GPBTimestamp with.
+ *
+ * @return A newly initialized GPBTimestamp.
+ **/
 - (instancetype)initWithDate:(NSDate *)date;
+
+/**
+ * Initializes a GPBTimestamp with the given NSTimeInterval.
+ *
+ * @param timeIntervalSince1970 Time interval to configure the GPBTimestamp with.
+ *
+ * @return A newly initialized GPBTimestamp.
+ **/
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
+
 @end
 
-// Extension to GPBDuration to work with standard Foundation time type.
+#pragma mark - GPBDuration
+
+/**
+ * Category for GPBDuration to work with standard Foundation time type.
+ **/
 @interface GPBDuration (GBPWellKnownTypes)
+
+/**
+ * The NSTimeInterval representation of this GPBDuration.
+ *
+ * @note: Not all second/nanos combinations can be represented in a
+ * NSTimeInterval, so getting this could be a lossy transform.
+ **/
 @property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
+
+/**
+ * Initializes a GPBDuration with the given NSTimeInterval.
+ *
+ * @param timeIntervalSince1970 Time interval to configure the GPBDuration with.
+ *
+ * @return A newly initialized GPBDuration.
+ **/
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
+
+@end
+
+#pragma mark - GPBAny
+
+/**
+ * Category for GPBAny to help work with the message within the object.
+ **/
+@interface GPBAny (GBPWellKnownTypes)
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ * This uses type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                           typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+                  error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                  error:(NSError **)errorPtr;
+
+/**
+ * Unpacks the serialized message as if it was an instance of the given class.
+ *
+ * @note When checking type_url, the base URL is not checked, only the fully
+ *       qualified name.
+ *
+ * @param messageClass The class to use to deserialize the contained message.
+ * @param errorPtr     Pointer to an error that will be populated if something
+ *                     goes wrong.
+ *
+ * @return An instance of the given class populated with the contained data, or
+ *         nil on failure.
+ */
+- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
+                                      error:(NSError **)errorPtr;
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index 5cdd62d..ed798a2 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -34,6 +34,13 @@
 
 #import "GPBWellKnownTypes.h"
 
+#import "GPBUtilities_PackagePrivate.h"
+
+NSString *const GPBWellKnownTypesErrorDomain =
+    GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
+
+static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
+
 static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
                                                                int32_t nanos) {
   return seconds + (NSTimeInterval)nanos / 1e9;
@@ -48,6 +55,30 @@
   return (int32_t)nanos;
 }
 
+static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
+  if (typeURLPrefix.length == 0) {
+    return fullName;
+  }
+
+  if ([typeURLPrefix hasSuffix:@"/"]) {
+    return [typeURLPrefix stringByAppendingString:fullName];
+  }
+
+  return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
+}
+
+static NSString *ParseTypeFromURL(NSString *typeURLString) {
+  NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
+  if ((range.location == NSNotFound) ||
+      (NSMaxRange(range) == typeURLString.length)) {
+    return nil;
+  }
+  NSString *result = [typeURLString substringFromIndex:range.location + 1];
+  return result;
+}
+
+#pragma mark - GPBTimestamp
+
 @implementation GPBTimestamp (GBPWellKnownTypes)
 
 - (instancetype)initWithDate:(NSDate *)date {
@@ -87,6 +118,8 @@
 
 @end
 
+#pragma mark - GPBDuration
+
 @implementation GPBDuration (GBPWellKnownTypes)
 
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
@@ -113,3 +146,105 @@
 }
 
 @end
+
+#pragma mark - GPBAny
+
+@implementation GPBAny (GBPWellKnownTypes)
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+                         error:(NSError **)errorPtr {
+  return [self anyWithMessage:message
+                typeURLPrefix:kTypePrefixGoogleApisCom
+                        error:errorPtr];
+}
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+                 typeURLPrefix:(NSString *)typeURLPrefix
+                         error:(NSError **)errorPtr {
+  return [[[self alloc] initWithMessage:message
+                          typeURLPrefix:typeURLPrefix
+                                  error:errorPtr] autorelease];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+                          error:(NSError **)errorPtr {
+  return [self initWithMessage:message
+                 typeURLPrefix:kTypePrefixGoogleApisCom
+                         error:errorPtr];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+                  typeURLPrefix:(NSString *)typeURLPrefix
+                          error:(NSError **)errorPtr {
+  self = [self init];
+  if (self) {
+    if (![self packWithMessage:message
+                 typeURLPrefix:typeURLPrefix
+                         error:errorPtr]) {
+      [self release];
+      self = nil;
+    }
+  }
+  return self;
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+                  error:(NSError **)errorPtr {
+  return [self packWithMessage:message
+                 typeURLPrefix:kTypePrefixGoogleApisCom
+                         error:errorPtr];
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+          typeURLPrefix:(NSString *)typeURLPrefix
+                  error:(NSError **)errorPtr {
+  NSString *fullName = [message descriptor].fullName;
+  if (fullName.length == 0) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+                          userInfo:nil];
+    }
+    return NO;
+  }
+  if (errorPtr) {
+    *errorPtr = nil;
+  }
+  self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
+  self.value = message.data;
+  return YES;
+}
+
+- (GPBMessage *)unpackMessageClass:(Class)messageClass
+                             error:(NSError **)errorPtr {
+  NSString *fullName = [messageClass descriptor].fullName;
+  if (fullName.length == 0) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+                      userInfo:nil];
+    }
+    return nil;
+  }
+
+  NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
+  if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeTypeURLMismatch
+                          userInfo:nil];
+    }
+    return nil;
+  }
+
+  // Any is proto3, which means no extensions, so this assumes anything put
+  // within an any also won't need extensions. A second helper could be added
+  // if needed.
+  return [messageClass parseFromData:self.value
+                               error:errorPtr];
+}
+
+@end
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
index 3206791..1585dbe 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -65,6 +65,7 @@
 		F4E675A11B21D0000054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675911B21D0000054530B /* Struct.pbobjc.m */; };
 		F4E675A31B21D0000054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675931B21D0000054530B /* Type.pbobjc.m */; };
 		F4E675A51B21D0000054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675951B21D0000054530B /* Wrappers.pbobjc.m */; };
+		F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -211,6 +212,7 @@
 		F4E675AB1B21D05C0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
 		F4E675AC1B21D05C0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
 		F4E675AD1B21D05C0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+		F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -408,6 +410,7 @@
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
 				8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+				F4F8D8811D789FCE002CE128 /* GPBUnittestProtos2.m */,
 				7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
 				7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
 				8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */,
@@ -659,6 +662,7 @@
 				F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
 				F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */,
 				8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
+				F4F8D8831D789FD9002CE128 /* GPBUnittestProtos2.m in Sources */,
 				F4353D1D1AB8822D005A6198 /* GPBDescriptorTests.m in Sources */,
 				8B4248BB1A8C256A00BC1EC6 /* GPBSwiftTests.swift in Sources */,
 				5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
@@ -778,6 +782,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_ASSIGN_ENUM = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
@@ -838,6 +843,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_ASSIGN_ENUM = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
index 9f688f8..b6bc95a 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -73,6 +73,7 @@
 		F4E675D51B21D1620054530B /* Struct.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C21B21D1440054530B /* Struct.pbobjc.m */; };
 		F4E675D61B21D1620054530B /* Type.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C51B21D1440054530B /* Type.pbobjc.m */; };
 		F4E675D71B21D1620054530B /* Wrappers.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675C71B21D1440054530B /* Wrappers.pbobjc.m */; };
+		F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -234,6 +235,7 @@
 		F4E675DD1B21D1DE0054530B /* struct.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = struct.proto; path = ../src/google/protobuf/struct.proto; sourceTree = "<group>"; };
 		F4E675DE1B21D1DE0054530B /* type.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = type.proto; path = ../src/google/protobuf/type.proto; sourceTree = "<group>"; };
 		F4E675DF1B21D1DE0054530B /* wrappers.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrappers.proto; path = ../src/google/protobuf/wrappers.proto; sourceTree = "<group>"; };
+		F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos2.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -446,6 +448,7 @@
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
 				8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */,
+				F4F8D8841D78A186002CE128 /* GPBUnittestProtos2.m */,
 				7461B6B80F94FDF900A0C422 /* GPBUnknownFieldSetTest.m */,
 				7461B6BA0F94FDF900A0C422 /* GPBUtilitiesTests.m */,
 				8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */,
@@ -755,6 +758,7 @@
 				F4487C811AAF62FC00531423 /* GPBMessageTests+Serialization.m in Sources */,
 				8B4248E61A929C9900BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
 				F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */,
+				F4F8D8861D78A193002CE128 /* GPBUnittestProtos2.m in Sources */,
 				F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
 				8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */,
 				5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
@@ -940,6 +944,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_ASSIGN_ENUM = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
@@ -1001,6 +1006,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
+				CLANG_WARN_ASSIGN_ENUM = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m
index 0723b64..2ad326b 100644
--- a/objectivec/Tests/GPBCodedOuputStreamTests.m
+++ b/objectivec/Tests/GPBCodedOuputStreamTests.m
@@ -193,6 +193,32 @@
   }
 }
 
+- (void)assertWriteStringNoTag:(NSData*)data
+                         value:(NSString *)value
+                       context:(NSString *)contextMessage {
+  NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
+  GPBCodedOutputStream* output =
+      [GPBCodedOutputStream streamWithOutputStream:rawOutput];
+  [output writeStringNoTag:value];
+  [output flush];
+
+  NSData* actual =
+      [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+  XCTAssertEqualObjects(data, actual, @"%@", contextMessage);
+
+  // Try different block sizes.
+  for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+    rawOutput = [NSOutputStream outputStreamToMemory];
+    output = [GPBCodedOutputStream streamWithOutputStream:rawOutput
+                                               bufferSize:blockSize];
+    [output writeStringNoTag:value];
+    [output flush];
+
+    actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
+    XCTAssertEqualObjects(data, actual, @"%@", contextMessage);
+  }
+}
+
 - (void)testWriteVarint1 {
   [self assertWriteVarint:bytes(0x00) value:0];
 }
@@ -337,4 +363,64 @@
   XCTAssertEqualObjects(rawBytes, goldenData);
 }
 
+- (void)testCFStringGetCStringPtrAndStringsWithNullChars {
+  // This test exists to verify that CFStrings with embedded NULLs still expose
+  // their raw buffer if they are backed by UTF8 storage. If this fails, the
+  // quick/direct access paths in GPBCodedOutputStream that depend on
+  // CFStringGetCStringPtr need to be re-evalutated (maybe just removed).
+  // And yes, we do get NULLs in strings from some servers.
+
+  char zeroTest[] = "\0Test\0String";
+  // Note: there is a \0 at the end of this since it is a c-string.
+  NSString *asNSString = [[NSString alloc] initWithBytes:zeroTest
+                                                  length:sizeof(zeroTest)
+                                                encoding:NSUTF8StringEncoding];
+  const char *cString =
+      CFStringGetCStringPtr((CFStringRef)asNSString, kCFStringEncodingUTF8);
+  XCTAssertTrue(cString != NULL);
+  // Again, if the above assert fails, then it means NSString no longer exposes
+  // the raw utf8 storage of a string created from utf8 input, so the code using
+  // CFStringGetCStringPtr in GPBCodedOutputStream will still work (it will take
+  // a different code path); but the optimizations for when
+  // CFStringGetCStringPtr does work could possibly go away.
+
+  XCTAssertEqual(sizeof(zeroTest),
+                 [asNSString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
+  XCTAssertTrue(0 == memcmp(cString, zeroTest, sizeof(zeroTest)));
+  [asNSString release];
+}
+
+- (void)testWriteStringsWithZeroChar {
+  // Unicode allows `\0` as a character, and NSString is a class cluster, so
+  // there are a few different classes that could end up beind a given string.
+  // Historically, we've seen differences based on constant strings in code and
+  // strings built via the NSString apis. So this round trips them to ensure
+  // they are acting as expected.
+
+  NSArray<NSString *> *strs = @[
+    @"\0at start",
+    @"in\0middle",
+    @"at end\0",
+  ];
+  int i = 0;
+  for (NSString *str in strs) {
+    NSData *asUTF8 = [str dataUsingEncoding:NSUTF8StringEncoding];
+    NSMutableData *expected = [NSMutableData data];
+    uint8_t lengthByte = (uint8_t)asUTF8.length;
+    [expected appendBytes:&lengthByte length:1];
+    [expected appendData:asUTF8];
+
+    NSString *context = [NSString stringWithFormat:@"Loop %d - Literal", i];
+    [self assertWriteStringNoTag:expected value:str context:context];
+
+    // Force a new string to be built which gets a different class from the
+    // NSString class cluster than the literal did.
+    NSString *str2 = [NSString stringWithFormat:@"%@", str];
+    context = [NSString stringWithFormat:@"Loop %d - Built", i];
+    [self assertWriteStringNoTag:expected value:str2 context:context];
+
+    ++i;
+  }
+}
+
 @end
diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m
index 74e3172..1e1c3de 100644
--- a/objectivec/Tests/GPBDescriptorTests.m
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -34,12 +34,41 @@
 
 #import "GPBDescriptor.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
 
 @interface DescriptorTests : GPBTestCase
 @end
 
 @implementation DescriptorTests
 
+- (void)testDescriptor_containingType {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertNil(testAllTypesDesc.containingType);
+  XCTAssertNotNil(nestedMessageDesc.containingType);
+  XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc);  // Ptr comparison
+}
+
+- (void)testDescriptor_fullName {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  XCTAssertEqualObjects(testAllTypesDesc.fullName, @"protobuf_unittest.TestAllTypes");
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertEqualObjects(nestedMessageDesc.fullName, @"protobuf_unittest.TestAllTypes.NestedMessage");
+
+  // Prefixes removed.
+  GPBDescriptor *descDesc = [GPBDescriptorProto descriptor];
+  XCTAssertEqualObjects(descDesc.fullName, @"google.protobuf.DescriptorProto");
+  GPBDescriptor *descExtRngDesc = [GPBDescriptorProto_ExtensionRange descriptor];
+  XCTAssertEqualObjects(descExtRngDesc.fullName, @"google.protobuf.DescriptorProto.ExtensionRange");
+
+  // Things that get "_Class" added.
+  GPBDescriptor *pointDesc = [Point_Class descriptor];
+  XCTAssertEqualObjects(pointDesc.fullName, @"protobuf_unittest.Point");
+  GPBDescriptor *pointRectDesc = [Point_Rect descriptor];
+  XCTAssertEqualObjects(pointRectDesc.fullName, @"protobuf_unittest.Point.Rect");
+}
+
 - (void)testFieldDescriptor {
   GPBDescriptor *descriptor = [TestAllTypes descriptor];
 
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m
index 1520381..0058311 100644
--- a/objectivec/Tests/GPBMessageTests+Runtime.m
+++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -36,6 +36,7 @@
 
 #import "google/protobuf/MapUnittest.pbobjc.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestCycle.pbobjc.h"
 #import "google/protobuf/UnittestObjcStartup.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"
 #import "google/protobuf/UnittestRuntimeProto3.pbobjc.h"
@@ -49,11 +50,24 @@
 // specific.
 
 - (void)testStartupOrdering {
-  // Just have to create a message.  Nothing else uses the classes from
-  // this file, so the first selector invoked on the class will initialize
-  // it, which also initializes the root.
+  // Message class/Root class initialization is a little tricky, so these just
+  // create some possible patterns that can be a problem. The messages don't
+  // have to be exercised, just creating them is enough to test.  If there
+  // is a problem, the runtime should assert or hang.
+  //
+  // Note: the messages from these proto files should not be used in any other
+  // tests, that way when they are referenced here it will be the first use and
+  // initialization will take place now.
+
   TestObjCStartupMessage *message = [TestObjCStartupMessage message];
   XCTAssertNotNil(message);
+
+  CycleBaz *baz = [CycleBaz message];
+  CycleBar *bar = [CycleBar message];
+  CycleFoo *foo = [CycleFoo message];
+  XCTAssertNotNil(baz);
+  XCTAssertNotNil(bar);
+  XCTAssertNotNil(foo);
 }
 
 - (void)testProto2HasMethodSupport {
@@ -326,6 +340,17 @@
 //%    [msg release];
 //%  }
 //%
+//%PDDM-DEFINE PROTO2_TEST_CLEAR_FIELD_WITH_NIL(FIELD, VALUE)
+//%  {  // optional##FIELD
+//%    Message2 *msg = [[Message2 alloc] init];
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = VALUE;
+//%    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = nil;
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD));
+//%    [msg release];
+//%  }
+//%
 //%PDDM-DEFINE PROTO2_TEST_HAS_FIELDS()
 //%PROTO2_TEST_HAS_FIELD(Int32, 1, 0)
 //%PROTO2_TEST_HAS_FIELD(Int64, 1, 0)
@@ -347,6 +372,14 @@
 //%  //
 //%
 //%PROTO2_TEST_HAS_FIELD(Enum, Message2_Enum_Bar, Message2_Enum_Foo)
+//%  //
+//%  // Nil can also be used to clear strings, bytes, groups, and messages.
+//%  //
+//%
+//%PROTO2_TEST_CLEAR_FIELD_WITH_NIL(String, @"foo")
+//%PROTO2_TEST_CLEAR_FIELD_WITH_NIL(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding])
+//%PROTO2_TEST_CLEAR_FIELD_WITH_NIL(Group, [Message2_OptionalGroup message])
+//%PROTO2_TEST_CLEAR_FIELD_WITH_NIL(Message, [Message2 message])
 //%PDDM-EXPAND PROTO2_TEST_HAS_FIELDS()
 // This block of code is generated, do not edit it directly.
 
@@ -658,13 +691,57 @@
     [msg release];
   }
 
+  //
+  // Nil can also be used to clear strings, bytes, groups, and messages.
+  //
+
+  {  // optionalString
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    msg.optionalString = @"foo";
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    msg.optionalString = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString));
+    [msg release];
+  }
+
+  {  // optionalBytes
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    msg.optionalBytes = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes));
+    [msg release];
+  }
+
+  {  // optionalGroup
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalGroup));
+    msg.optionalGroup = [Message2_OptionalGroup message];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalGroup));
+    msg.optionalGroup = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalGroup));
+    [msg release];
+  }
+
+  {  // optionalMessage
+    Message2 *msg = [[Message2 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalMessage));
+    msg.optionalMessage = [Message2 message];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalMessage));
+    msg.optionalMessage = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalMessage));
+    [msg release];
+  }
+
 //%PDDM-EXPAND-END PROTO2_TEST_HAS_FIELDS()
 }
 
 - (void)testProto3SingleFieldHasBehavior {
   //
-  // Setting to any value including the default value (0) should result has*
-  // being true.
+  // Setting to any value but the default value (0) should result has*
+  // being true.  When set to the default, shouldn't be true.
   //
 
 //%PDDM-DEFINE PROTO3_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE)
@@ -678,6 +755,17 @@
 //%    [msg release];
 //%  }
 //%
+//%PDDM-DEFINE PROTO3_TEST_CLEAR_FIELD_WITH_NIL(FIELD, VALUE)
+//%  {  // optional##FIELD
+//%    Message3 *msg = [[Message3 alloc] init];
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = VALUE;
+//%    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    msg.optional##FIELD = nil;
+//%    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD));
+//%    [msg release];
+//%  }
+//%
 //%PDDM-DEFINE PROTO3_TEST_HAS_FIELDS()
 //%PROTO3_TEST_HAS_FIELD(Int32, 1, 0)
 //%PROTO3_TEST_HAS_FIELD(Int64, 1, 0)
@@ -695,10 +783,17 @@
 //%PROTO3_TEST_HAS_FIELD(String, @"foo", @"")
 //%PROTO3_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data])
 //%  //
-//%  // Test doesn't apply to optionalGroup/optionalMessage.
+//%  // Test doesn't apply to optionalMessage (no groups in proto3).
 //%  //
 //%
 //%PROTO3_TEST_HAS_FIELD(Enum, Message3_Enum_Bar, Message3_Enum_Foo)
+//%  //
+//%  // Nil can also be used to clear strings, bytes, and messages (no groups in proto3).
+//%  //
+//%
+//%PROTO3_TEST_CLEAR_FIELD_WITH_NIL(String, @"foo")
+//%PROTO3_TEST_CLEAR_FIELD_WITH_NIL(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding])
+//%PROTO3_TEST_CLEAR_FIELD_WITH_NIL(Message, [Message3 message])
 //%PDDM-EXPAND PROTO3_TEST_HAS_FIELDS()
 // This block of code is generated, do not edit it directly.
 
@@ -853,7 +948,7 @@
   }
 
   //
-  // Test doesn't apply to optionalGroup/optionalMessage.
+  // Test doesn't apply to optionalMessage (no groups in proto3).
   //
 
   {  // optionalEnum
@@ -866,6 +961,40 @@
     [msg release];
   }
 
+  //
+  // Nil can also be used to clear strings, bytes, and messages (no groups in proto3).
+  //
+
+  {  // optionalString
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    msg.optionalString = @"foo";
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    msg.optionalString = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString));
+    [msg release];
+  }
+
+  {  // optionalBytes
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    msg.optionalBytes = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes));
+    [msg release];
+  }
+
+  {  // optionalMessage
+    Message3 *msg = [[Message3 alloc] init];
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalMessage));
+    msg.optionalMessage = [Message3 message];
+    XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalMessage));
+    msg.optionalMessage = nil;
+    XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalMessage));
+    [msg release];
+  }
+
 //%PDDM-EXPAND-END PROTO3_TEST_HAS_FIELDS()
 }
 
@@ -1972,6 +2101,262 @@
   [msg release];
 }
 
+- (void)testProto2OneofSetToDefault {
+
+  // proto3 doesn't normally write out zero (default) fields, but if they are
+  // in a oneof it does.  proto2 doesn't have this special behavior, but we
+  // still confirm setting to the explicit default does set the case to be
+  // sure the runtime is working correctly.
+
+  NSString *oneofStringDefault = @"string";
+  NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding];
+
+  Message2 *msg = [[Message2 alloc] init];
+
+  uint32_t values[] = {
+    Message2_O_OneOfCase_OneofInt32,
+    Message2_O_OneOfCase_OneofInt64,
+    Message2_O_OneOfCase_OneofUint32,
+    Message2_O_OneOfCase_OneofUint64,
+    Message2_O_OneOfCase_OneofSint32,
+    Message2_O_OneOfCase_OneofSint64,
+    Message2_O_OneOfCase_OneofFixed32,
+    Message2_O_OneOfCase_OneofFixed64,
+    Message2_O_OneOfCase_OneofSfixed32,
+    Message2_O_OneOfCase_OneofSfixed64,
+    Message2_O_OneOfCase_OneofFloat,
+    Message2_O_OneOfCase_OneofDouble,
+    Message2_O_OneOfCase_OneofBool,
+    Message2_O_OneOfCase_OneofString,
+    Message2_O_OneOfCase_OneofBytes,
+    // Skip group
+    // Skip message
+    Message2_O_OneOfCase_OneofEnum,
+  };
+
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+    switch (values[i]) {
+      case Message2_O_OneOfCase_OneofInt32:
+        msg.oneofInt32 = 100;
+        break;
+      case Message2_O_OneOfCase_OneofInt64:
+        msg.oneofInt64 = 101;
+        break;
+      case Message2_O_OneOfCase_OneofUint32:
+        msg.oneofUint32 = 102;
+        break;
+      case Message2_O_OneOfCase_OneofUint64:
+        msg.oneofUint64 = 103;
+        break;
+      case Message2_O_OneOfCase_OneofSint32:
+        msg.oneofSint32 = 104;
+        break;
+      case Message2_O_OneOfCase_OneofSint64:
+        msg.oneofSint64 = 105;
+        break;
+      case Message2_O_OneOfCase_OneofFixed32:
+        msg.oneofFixed32 = 106;
+        break;
+      case Message2_O_OneOfCase_OneofFixed64:
+        msg.oneofFixed64 = 107;
+        break;
+      case Message2_O_OneOfCase_OneofSfixed32:
+        msg.oneofSfixed32 = 108;
+        break;
+      case Message2_O_OneOfCase_OneofSfixed64:
+        msg.oneofSfixed64 = 109;
+        break;
+      case Message2_O_OneOfCase_OneofFloat:
+        msg.oneofFloat = 110.0f;
+        break;
+      case Message2_O_OneOfCase_OneofDouble:
+        msg.oneofDouble = 111.0;
+        break;
+      case Message2_O_OneOfCase_OneofBool:
+        msg.oneofBool = YES;
+        break;
+      case Message2_O_OneOfCase_OneofString:
+        msg.oneofString = oneofStringDefault;
+        break;
+      case Message2_O_OneOfCase_OneofBytes:
+        msg.oneofBytes = oneofBytesDefault;
+        break;
+      case Message2_O_OneOfCase_OneofEnum:
+        msg.oneofEnum = Message3_Enum_Baz;
+        break;
+      default:
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
+        break;
+    }
+
+    // Should be set to the correct case.
+    XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i);
+
+    // Confirm everything is the defaults.
+    XCTAssertEqual(msg.oneofInt32, 100, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofInt64, 101, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint32, 102U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint64, 103U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint32, 104, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint64, 105, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed32, 106U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed64, 107U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed32, 108, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed64, 109, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFloat, 110.0f, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofDouble, 111.0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofBool, YES, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i);
+    // Skip group, no default to consider.
+    // Skip message, no default to consider.
+    XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz, "Loop: %zd", i);
+  }
+
+  // We special case nil on string, data, group, and message, ensure they work
+  // as expected. i.e. - it clears the case.
+  msg.oneofString = nil;
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase);
+  msg.oneofBytes = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  msg.oneofGroup = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertNotNil(msg.oneofGroup);
+  msg.oneofMessage = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertNotNil(msg.oneofMessage);
+
+  [msg release];
+}
+
+- (void)testProto3OneofSetToZero {
+
+  // Normally setting a proto3 field to the zero value should result in it being
+  // reset/cleared.  But in a oneof, it still gets recored so it can go out
+  // over the wire and the other side can see what was set in the oneof.
+
+  NSString *oneofStringDefault = @"";
+  NSData *oneofBytesDefault = [NSData data];
+
+  Message3 *msg = [[Message3 alloc] init];
+
+  uint32_t values[] = {
+    Message3_O_OneOfCase_OneofInt32,
+    Message3_O_OneOfCase_OneofInt64,
+    Message3_O_OneOfCase_OneofUint32,
+    Message3_O_OneOfCase_OneofUint64,
+    Message3_O_OneOfCase_OneofSint32,
+    Message3_O_OneOfCase_OneofSint64,
+    Message3_O_OneOfCase_OneofFixed32,
+    Message3_O_OneOfCase_OneofFixed64,
+    Message3_O_OneOfCase_OneofSfixed32,
+    Message3_O_OneOfCase_OneofSfixed64,
+    Message3_O_OneOfCase_OneofFloat,
+    Message3_O_OneOfCase_OneofDouble,
+    Message3_O_OneOfCase_OneofBool,
+    Message3_O_OneOfCase_OneofString,
+    Message3_O_OneOfCase_OneofBytes,
+    Message3_O_OneOfCase_OneofMessage,
+    Message3_O_OneOfCase_OneofEnum,
+  };
+
+  for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
+    switch (values[i]) {
+      case Message3_O_OneOfCase_OneofInt32:
+        msg.oneofInt32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofInt64:
+        msg.oneofInt64 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofUint32:
+        msg.oneofUint32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofUint64:
+        msg.oneofUint64 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofSint32:
+        msg.oneofSint32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofSint64:
+        msg.oneofSint64 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofFixed32:
+        msg.oneofFixed32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofFixed64:
+        msg.oneofFixed64 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofSfixed32:
+        msg.oneofSfixed32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofSfixed64:
+        msg.oneofSfixed64 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofFloat:
+        msg.oneofFloat = 0.0f;
+        break;
+      case Message3_O_OneOfCase_OneofDouble:
+        msg.oneofDouble = 0.0;
+        break;
+      case Message3_O_OneOfCase_OneofBool:
+        msg.oneofBool = NO;
+        break;
+      case Message3_O_OneOfCase_OneofString:
+        msg.oneofString = oneofStringDefault;
+        break;
+      case Message3_O_OneOfCase_OneofBytes:
+        msg.oneofBytes = oneofBytesDefault;
+        break;
+      case Message3_O_OneOfCase_OneofMessage:
+        msg.oneofMessage.optionalInt32 = 0;
+        break;
+      case Message3_O_OneOfCase_OneofEnum:
+        msg.oneofEnum = Message3_Enum_Foo;
+        break;
+      default:
+        XCTFail(@"shouldn't happen, loop: %zd, value: %d", i, values[i]);
+        break;
+    }
+
+    // Should be set to the correct case.
+    XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i);
+
+    // Confirm everything is still zeros.
+    XCTAssertEqual(msg.oneofInt32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofInt64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint32, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofUint64, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSint64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed32, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFixed64, 0U, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed32, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofSfixed64, 0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofFloat, 0.0f, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofDouble, 0.0, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofBool, NO, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i);
+    XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i);
+    XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i);
+    XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo, "Loop: %zd", i);
+  }
+
+  // We special case nil on string, data, message, ensure they work as expected.
+  msg.oneofString = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertEqualObjects(msg.oneofString, oneofStringDefault);
+  msg.oneofBytes = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault);
+  msg.oneofMessage = nil;
+  XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase);
+  XCTAssertNotNil(msg.oneofMessage);
+
+  [msg release];
+}
+
 - (void)testCopyingMakesUniqueObjects {
   const int repeatCount = 5;
   TestAllTypes *msg1 = [TestAllTypes message];
diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m
index d19beee..8d2948b 100644
--- a/objectivec/Tests/GPBUnittestProtos.m
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -36,6 +36,7 @@
 // a descriptor as it doesn't use the classes/enums.
 #import "google/protobuf/Descriptor.pbobjc.m"
 
+#import "google/protobuf/AnyTest.pbobjc.m"
 #import "google/protobuf/MapProto2Unittest.pbobjc.m"
 #import "google/protobuf/MapUnittest.pbobjc.m"
 #import "google/protobuf/Unittest.pbobjc.m"
@@ -62,3 +63,11 @@
 #import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m"
 #import "google/protobuf/UnittestRuntimeProto2.pbobjc.m"
 #import "google/protobuf/UnittestRuntimeProto3.pbobjc.m"
+
+#import "google/protobuf/UnittestExtensionChainA.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainB.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainC.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainD.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainE.pbobjc.m"
+// See GPBUnittestProtos2.m for for "UnittestExtensionChainF.pbobjc.m"
+#import "google/protobuf/UnittestExtensionChainG.pbobjc.m"
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/GPBUnittestProtos2.m
similarity index 67%
rename from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
rename to objectivec/Tests/GPBUnittestProtos2.m
index d22e90f..ef9f070 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/GPBUnittestProtos2.m
@@ -1,6 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
+// Copyright 2016 Google Inc.  All rights reserved.
 // https://developers.google.com/protocol-buffers/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,21 +27,8 @@
 // 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.
-#endregion
 
-using System.Reflection;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+// This one file in the chain tests is compiled by itself to ensure if was
+// generated with the extra #imports needed to pull in the indirect Root class
+// used in its Root registry.
+#import "google/protobuf/UnittestExtensionChainF.pbobjc.m"
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 78f4e63..041841d 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -32,6 +32,8 @@
 
 #import <XCTest/XCTest.h>
 
+#import "google/protobuf/AnyTest.pbobjc.h"
+
 // A basically random interval into the future for testing with.
 static const NSTimeInterval kFutureOffsetInterval = 15000;
 
@@ -99,4 +101,58 @@
   [duration2 release];
 }
 
+- (void)testAnyHelpers {
+
+  // Set and extract covers most of the code.
+
+  TestAny *subMessage = [TestAny message];
+  subMessage.int32Value = 12345;
+  TestAny *message = [TestAny message];
+  NSError *err = nil;
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:&err];
+  XCTAssertNil(err);
+
+  NSData *data = message.data;
+  XCTAssertNotNil(data);
+
+  TestAny *message2 = [TestAny parseFromData:data error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(message2);
+  XCTAssertTrue(message2.hasAnyValue);
+
+  TestAny *subMessage2 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(subMessage2);
+  XCTAssertEqual(subMessage2.int32Value, 12345);
+
+  // NULL errorPtr in the two calls.
+
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:NULL];
+  NSData *data2 = message.data;
+  XCTAssertEqualObjects(data2, data);
+
+  TestAny *subMessage3 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:NULL];
+  XCTAssertNotNil(subMessage3);
+  XCTAssertEqualObjects(subMessage2, subMessage3);
+
+  // Try to extract wrong type.
+
+  GPBTimestamp *wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:&err];
+  XCTAssertNotNil(err);
+  XCTAssertNil(wrongMessage);
+  XCTAssertEqualObjects(err.domain, GPBWellKnownTypesErrorDomain);
+  XCTAssertEqual(err.code, GPBWellKnownTypesErrorCodeTypeURLMismatch);
+
+  wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:NULL];
+  XCTAssertNil(wrongMessage);
+}
+
 @end
diff --git a/objectivec/Tests/unittest_cycle.proto b/objectivec/Tests/unittest_cycle.proto
index 5f6f56a..afc1b0f 100644
--- a/objectivec/Tests/unittest_cycle.proto
+++ b/objectivec/Tests/unittest_cycle.proto
@@ -31,10 +31,8 @@
 
 package protobuf_unittest;
 
-// Cycles in the Message graph can cause problems for the mutable classes
-// since the properties on the mutable class change types. This file just
-// needs to generate source, and that source must compile, to ensure the
-// generated source works for this sort of case.
+// Cycles in the Message graph can cause problems for message class
+// initialization order.
 
 // You can't make a object graph that spans files, so this can only be done
 // within a single proto file.
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_a.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_a.proto
index d22e90f..6a227eb 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_a.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,26 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_b.proto";
+import "unittest_extension_chain_c.proto";
+import "unittest_extension_chain_d.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from D's Root (unittest and C will come via D's).
+
+message ChainAMessage {
+  optional ChainBMessage b = 1;
+  optional ChainCMessage c = 2;
+  optional ChainDMessage d = 3;
+}
+
+extend TestAllExtensions {
+  optional int32 chain_a_extension = 10001;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_b.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_b.proto
index d22e90f..0da7ed3 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_b.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,22 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_c.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from C's Root (unittest will come via C's).
+
+message ChainBMessage {
+  optional ChainCMessage c = 1;
+}
+
+extend TestAllExtensions {
+  optional int32 chain_b_extension = 10002;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_c.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_c.proto
index d22e90f..c702900 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_c.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,20 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "google/protobuf/unittest.proto";
+
+// The Root for this file should end up adding the local extension and merging
+// in the extensions from unittest.proto's Root.
+
+message ChainCMessage {
+  optional int32 my_field = 1;
+}
+
+extend TestAllExtensions {
+  optional int32 chain_c_extension = 10003;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_d.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_d.proto
index d22e90f..f9abe3b 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_d.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,24 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "google/protobuf/unittest.proto";
+
+import "unittest_extension_chain_b.proto";
+import "unittest_extension_chain_c.proto";
+
+// The root should end up needing to merge B (C will be merged into B, so it
+// doesn't need to be directly merged).
+
+message ChainDMessage {
+  optional ChainBMessage b = 1;
+  optional ChainCMessage c = 2;
+}
+
+extend TestAllExtensions {
+  optional int32 chain_d_extension = 10004;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_e.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_e.proto
index d22e90f..fe11663 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_e.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,15 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "google/protobuf/unittest.proto";
+
+// The Root for this file should end up just merging in unittest's Root.
+
+message ChainEMessage {
+  optional TestAllTypes my_field = 1;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_f.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_f.proto
index d22e90f..b9bed72 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_f.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,19 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "unittest_extension_chain_g.proto";
+
+// The Root for this file should just be merging in the extensions from C's
+// Root (because G doens't define anything itself).
+
+// The generated source will also have to directly import C's .h file so it can
+// compile the reference to C's Root class.
+
+message ChainFMessage {
+  optional ChainGMessage g = 1;
+}
diff --git a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs b/objectivec/Tests/unittest_extension_chain_g.proto
similarity index 65%
copy from csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
copy to objectivec/Tests/unittest_extension_chain_g.proto
index d22e90f..aee827b 100644
--- a/csharp/src/Google.Protobuf.Conformance/Properties/AssemblyInfo.cs
+++ b/objectivec/Tests/unittest_extension_chain_g.proto
@@ -1,7 +1,5 @@
-#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2016 Google Inc.  All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -28,21 +26,16 @@
 // 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.
-#endregion
 
-using System.Reflection;
+syntax = "proto2";
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Google.Protobuf.Conformance")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Google.Protobuf.Conformance")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
+package protobuf_unittest;
 
-[assembly: AssemblyVersion("3.0.0.0")]
-[assembly: AssemblyFileVersion("3.0.0.0")]
+import "unittest_extension_chain_c.proto";
+
+// The Root for this file should just be merging in the extensions from C's
+// Root.
+
+message ChainGMessage {
+  optional ChainCMessage c = 1;
+}
diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto
index 914945e..e5577fa 100644
--- a/objectivec/Tests/unittest_objc.proto
+++ b/objectivec/Tests/unittest_objc.proto
@@ -34,6 +34,15 @@
 
 package protobuf_unittest;
 
+// Used to check that Headerdocs and appledoc work correctly. If these comments
+// are not handled correctly, Xcode will fail to build the tests.
+message TestGeneratedComments {
+  // This is a string that could contain stuff like
+  // mime types as image/* or */plain. Maybe twitter usernames
+  // like @protobuf, @google or @something.
+  optional string string_field = 1;
+}
+
 // Using the messages in unittest.proto, setup for recursive cases for testing
 // extensions at various depths.
 extend TestAllExtensions {
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
index 4253b60..b88b786 100644
--- a/objectivec/google/protobuf/Any.pbobjc.h
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBAnyRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBAnyRoot : GPBRootObject
 @end
 
@@ -46,101 +48,105 @@
   GPBAny_FieldNumber_Value = 2,
 };
 
-/// `Any` contains an arbitrary serialized protocol buffer message along with a
-/// URL that describes the type of the serialized message.
-///
-/// Protobuf library provides support to pack/unpack Any values in the form
-/// of utility functions or additional generated methods of the Any type.
-///
-/// Example 1: Pack and unpack a message in C++.
-///
-///     Foo foo = ...;
-///     Any any;
-///     any.PackFrom(foo);
-///     ...
-///     if (any.UnpackTo(&foo)) {
-///       ...
-///     }
-///
-/// Example 2: Pack and unpack a message in Java.
-///
-///     Foo foo = ...;
-///     Any any = Any.pack(foo);
-///     ...
-///     if (any.is(Foo.class)) {
-///       foo = any.unpack(Foo.class);
-///     }
-///
-///  Example 3: Pack and unpack a message in Python.
-///
-///     foo = Foo(...)
-///     any = Any()
-///     any.Pack(foo)
-///     ...
-///     if any.Is(Foo.DESCRIPTOR):
-///       any.Unpack(foo)
-///       ...
-///
-/// The pack methods provided by protobuf library will by default use
-/// 'type.googleapis.com/full.type.name' as the type URL and the unpack
-/// methods only use the fully qualified type name after the last '/'
-/// in the type URL, for example "foo.bar.com/x/y.z" will yield type
-/// name "y.z".
-///
-///
-/// 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 `\@type`
-/// field. Example (for message [google.protobuf.Duration][]):
-///
-///     {
-///       "\@type": "type.googleapis.com/google.protobuf.Duration",
-///       "value": "1.212s"
-///     }
+/**
+ * `Any` contains an arbitrary serialized protocol buffer message along with a
+ * URL that describes the type of the serialized message.
+ *
+ * Protobuf library provides support to pack/unpack Any values in the form
+ * of utility functions or additional generated methods of the Any type.
+ *
+ * Example 1: Pack and unpack a message in C++.
+ *
+ *     Foo foo = ...;
+ *     Any any;
+ *     any.PackFrom(foo);
+ *     ...
+ *     if (any.UnpackTo(&foo)) {
+ *       ...
+ *     }
+ *
+ * Example 2: Pack and unpack a message in Java.
+ *
+ *     Foo foo = ...;
+ *     Any any = Any.pack(foo);
+ *     ...
+ *     if (any.is(Foo.class)) {
+ *       foo = any.unpack(Foo.class);
+ *     }
+ *
+ *  Example 3: Pack and unpack a message in Python.
+ *
+ *     foo = Foo(...)
+ *     any = Any()
+ *     any.Pack(foo)
+ *     ...
+ *     if any.Is(Foo.DESCRIPTOR):
+ *       any.Unpack(foo)
+ *       ...
+ *
+ * The pack methods provided by protobuf library will by default use
+ * 'type.googleapis.com/full.type.name' as the type URL and the unpack
+ * methods only use the fully qualified type name after the last '/'
+ * in the type URL, for example "foo.bar.com/x/y.z" will yield type
+ * name "y.z".
+ *
+ *
+ * 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 `\@type`
+ * field. Example (for message [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 protocol buffer message.
-///
-/// For URLs which use the scheme `http`, `https`, or no scheme, the
-/// following restrictions and interpretations apply:
-///
-/// * If no scheme 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`).
-///   The name should be in a canonical form (e.g., leading "." is
-///   not accepted).
-/// * An HTTP GET on the URL must yield a [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.)
-///
-/// Schemes other than `http`, `https` (or the empty scheme) might be
-/// used with implementation specific semantics.
+/**
+ * A URL/resource name whose content describes the type of the
+ * serialized protocol buffer message.
+ *
+ * For URLs which use the scheme `http`, `https`, or no scheme, the
+ * following restrictions and interpretations apply:
+ *
+ * * If no scheme 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`).
+ *   The name should be in a canonical form (e.g., leading "." is
+ *   not accepted).
+ * * An HTTP GET on the URL must yield a [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.)
+ *
+ * Schemes other than `http`, `https` (or the empty scheme) might be
+ * used with implementation specific semantics.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL;
 
-/// Must be a valid serialized protocol buffer of the above specified type.
+/** Must be a valid serialized protocol buffer of the above specified type. */
 @property(nonatomic, readwrite, copy, null_resettable) NSData *value;
 
 @end
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
index 25e5b4c..e105492 100644
--- a/objectivec/google/protobuf/Any.pbobjc.m
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBAnyRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBAnyRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -68,7 +72,7 @@
         .number = GPBAny_FieldNumber_TypeURL,
         .hasIndex = 0,
         .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL),
-        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
         .dataType = GPBDataTypeString,
       },
       {
@@ -88,7 +92,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBAny__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
 #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
     static const char *extraTextFormatInfo =
         "\001\001\004\241!!\000";
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
index 04341f4..3750e09 100644
--- a/objectivec/google/protobuf/Api.pbobjc.h
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -34,14 +34,16 @@
 
 #pragma mark - GPBApiRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBApiRoot : GPBRootObject
 @end
 
@@ -57,67 +59,79 @@
   GPBApi_FieldNumber_Syntax = 7,
 };
 
-/// Api is a light-weight descriptor for a protocol buffer service.
+/**
+ * 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.
+/**
+ * The fully qualified name of this api, including package name
+ * followed by the api's simple name.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// The methods of this api, in unspecified order.
+/** The methods of this api, in unspecified order. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethod*> *methodsArray;
-/// The number of items in @c methodsArray without causing the array to be created.
+/** The number of items in @c methodsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger methodsArray_Count;
 
-/// Any metadata attached to the API.
+/** Any metadata attached to the API. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-/// 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.
+/**
+ * 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.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *version;
 
-/// Source context for the protocol buffer service represented by this
-/// message.
+/**
+ * Source context for the protocol buffer service represented by this
+ * message.
+ **/
 @property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
-/// Test to see if @c sourceContext has been set.
+/** Test to see if @c sourceContext has been set. */
 @property(nonatomic, readwrite) BOOL hasSourceContext;
 
-/// Included APIs. See [Mixin][].
+/** Included APIs. See [Mixin][]. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMixin*> *mixinsArray;
-/// The number of items in @c mixinsArray without causing the array to be created.
+/** The number of items in @c mixinsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger mixinsArray_Count;
 
-/// The source syntax of the service.
+/** The source syntax of the service. */
 @property(nonatomic, readwrite) enum GPBSyntax syntax;
 
 @end
 
-/// Fetches the raw value of a @c GPBApi's @c syntax property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBApi's @c syntax property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBApi_Syntax_RawValue(GPBApi *message);
-/// Sets the raw value of an @c GPBApi's @c syntax property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBApi's @c syntax property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value);
 
 #pragma mark - GPBMethod
@@ -132,40 +146,46 @@
   GPBMethod_FieldNumber_Syntax = 7,
 };
 
-/// Method represents a method of an api.
+/**
+ * Method represents a method of an api.
+ **/
 @interface GPBMethod : GPBMessage
 
-/// The simple name of this method.
+/** The simple name of this method. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// A URL of the input message type.
+/** A URL of the input message type. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *requestTypeURL;
 
-/// If true, the request is streamed.
+/** If true, the request is streamed. */
 @property(nonatomic, readwrite) BOOL requestStreaming;
 
-/// The URL of the output message type.
+/** The URL of the output message type. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *responseTypeURL;
 
-/// If true, the response is streamed.
+/** If true, the response is streamed. */
 @property(nonatomic, readwrite) BOOL responseStreaming;
 
-/// Any metadata attached to the method.
+/** Any metadata attached to the method. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-/// The source syntax of this method.
+/** The source syntax of this method. */
 @property(nonatomic, readwrite) enum GPBSyntax syntax;
 
 @end
 
-/// Fetches the raw value of a @c GPBMethod's @c syntax property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBMethod's @c syntax property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBMethod_Syntax_RawValue(GPBMethod *message);
-/// Sets the raw value of an @c GPBMethod's @c syntax property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBMethod's @c syntax property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value);
 
 #pragma mark - GPBMixin
@@ -175,90 +195,94 @@
   GPBMixin_FieldNumber_Root = 2,
 };
 
-/// Declares an API to be included in this API. The including API must
-/// redeclare all the methods from the included API, but documentation
-/// and options are inherited as follows:
-///
-/// - If after comment and whitespace stripping, the documentation
-///   string of the redeclared method is empty, it will be inherited
-///   from the original method.
-///
-/// - Each annotation belonging to the service config (http,
-///   visibility) which is not set in the redeclared method will be
-///   inherited.
-///
-/// - If an http annotation is inherited, the path pattern will be
-///   modified as follows. Any version prefix will be replaced by the
-///   version of the including API plus the [root][] path if specified.
-///
-/// Example of a simple mixin:
-///
-///     package google.acl.v1;
-///     service AccessControl {
-///       // Get the underlying ACL object.
-///       rpc GetAcl(GetAclRequest) returns (Acl) {
-///         option (google.api.http).get = "/v1/{resource=**}:getAcl";
-///       }
-///     }
-///
-///     package google.storage.v2;
-///     service Storage {
-///       rpc GetAcl(GetAclRequest) returns (Acl);
-///
-///       // Get a data record.
-///       rpc GetData(GetDataRequest) returns (Data) {
-///         option (google.api.http).get = "/v2/{resource=**}";
-///       }
-///     }
-///
-/// Example of a mixin configuration:
-///
-///     apis:
-///     - name: google.storage.v2.Storage
-///       mixins:
-///       - name: google.acl.v1.AccessControl
-///
-/// The mixin construct implies that all methods in `AccessControl` are
-/// also declared with same name and request/response types in
-/// `Storage`. A documentation generator or annotation processor will
-/// see the effective `Storage.GetAcl` method after inherting
-/// documentation and annotations as follows:
-///
-///     service Storage {
-///       // Get the underlying ACL object.
-///       rpc GetAcl(GetAclRequest) returns (Acl) {
-///         option (google.api.http).get = "/v2/{resource=**}:getAcl";
-///       }
-///       ...
-///     }
-///
-/// Note how the version in the path pattern changed from `v1` to `v2`.
-///
-/// If the `root` field in the mixin is specified, it should be a
-/// relative path under which inherited HTTP paths are placed. Example:
-///
-///     apis:
-///     - name: google.storage.v2.Storage
-///       mixins:
-///       - name: google.acl.v1.AccessControl
-///         root: acls
-///
-/// This implies the following inherited HTTP annotation:
-///
-///     service Storage {
-///       // Get the underlying ACL object.
-///       rpc GetAcl(GetAclRequest) returns (Acl) {
-///         option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
-///       }
-///       ...
-///     }
+/**
+ * Declares an API to be included in this API. The including API must
+ * redeclare all the methods from the included API, but documentation
+ * and options are inherited as follows:
+ *
+ * - If after comment and whitespace stripping, the documentation
+ *   string of the redeclared method is empty, it will be inherited
+ *   from the original method.
+ *
+ * - Each annotation belonging to the service config (http,
+ *   visibility) which is not set in the redeclared method will be
+ *   inherited.
+ *
+ * - If an http annotation is inherited, the path pattern will be
+ *   modified as follows. Any version prefix will be replaced by the
+ *   version of the including API plus the [root][] path if specified.
+ *
+ * Example of a simple mixin:
+ *
+ *     package google.acl.v1;
+ *     service AccessControl {
+ *       // Get the underlying ACL object.
+ *       rpc GetAcl(GetAclRequest) returns (Acl) {
+ *         option (google.api.http).get = "/v1/{resource=**}:getAcl";
+ *       }
+ *     }
+ *
+ *     package google.storage.v2;
+ *     service Storage {
+ *       rpc GetAcl(GetAclRequest) returns (Acl);
+ *
+ *       // Get a data record.
+ *       rpc GetData(GetDataRequest) returns (Data) {
+ *         option (google.api.http).get = "/v2/{resource=**}";
+ *       }
+ *     }
+ *
+ * Example of a mixin configuration:
+ *
+ *     apis:
+ *     - name: google.storage.v2.Storage
+ *       mixins:
+ *       - name: google.acl.v1.AccessControl
+ *
+ * The mixin construct implies that all methods in `AccessControl` are
+ * also declared with same name and request/response types in
+ * `Storage`. A documentation generator or annotation processor will
+ * see the effective `Storage.GetAcl` method after inherting
+ * documentation and annotations as follows:
+ *
+ *     service Storage {
+ *       // Get the underlying ACL object.
+ *       rpc GetAcl(GetAclRequest) returns (Acl) {
+ *         option (google.api.http).get = "/v2/{resource=**}:getAcl";
+ *       }
+ *       ...
+ *     }
+ *
+ * Note how the version in the path pattern changed from `v1` to `v2`.
+ *
+ * If the `root` field in the mixin is specified, it should be a
+ * relative path under which inherited HTTP paths are placed. Example:
+ *
+ *     apis:
+ *     - name: google.storage.v2.Storage
+ *       mixins:
+ *       - name: google.acl.v1.AccessControl
+ *         root: acls
+ *
+ * This implies the following inherited HTTP annotation:
+ *
+ *     service Storage {
+ *       // Get the underlying ACL object.
+ *       rpc GetAcl(GetAclRequest) returns (Acl) {
+ *         option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
+ *       }
+ *       ...
+ *     }
+ **/
 @interface GPBMixin : GPBMessage
 
-/// The fully qualified name of the API which is included.
+/** The fully qualified name of the API which is included. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// If non-empty specifies a path under which inherited HTTP paths
-/// are rooted.
+/**
+ * If non-empty specifies a path under which inherited HTTP paths
+ * are rooted.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *root;
 
 @end
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
index cd37eda..70437d4 100644
--- a/objectivec/google/protobuf/Api.pbobjc.m
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -31,18 +31,8 @@
 
 @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) {
-    GPBDebugCheckRuntimeVersion();
-    registry = [[GPBExtensionRegistry alloc] init];
-    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
-    [registry addExtensions:[GPBTypeRoot extensionRegistry]];
-  }
-  return registry;
-}
+// No extensions in the file and none of the imports (direct or indirect)
+// defined extensions, so no need to generate +extensionRegistry.
 
 @end
 
@@ -55,6 +45,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -149,7 +140,7 @@
         .number = GPBApi_FieldNumber_Syntax,
         .hasIndex = 3,
         .offset = (uint32_t)offsetof(GPBApi__storage_, syntax),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
     };
@@ -160,7 +151,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBApi__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -223,7 +214,7 @@
         .number = GPBMethod_FieldNumber_RequestTypeURL,
         .hasIndex = 1,
         .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL),
-        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
         .dataType = GPBDataTypeString,
       },
       {
@@ -241,7 +232,7 @@
         .number = GPBMethod_FieldNumber_ResponseTypeURL,
         .hasIndex = 4,
         .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL),
-        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
         .dataType = GPBDataTypeString,
       },
       {
@@ -268,7 +259,7 @@
         .number = GPBMethod_FieldNumber_Syntax,
         .hasIndex = 7,
         .offset = (uint32_t)offsetof(GPBMethod__storage_, syntax),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
     };
@@ -279,7 +270,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBMethod__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
 #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
     static const char *extraTextFormatInfo =
         "\002\002\007\244\241!!\000\004\010\244\241!!\000";
@@ -350,7 +341,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBMixin__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index 4c3173d..090eb00 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBDurationRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBDurationRoot : GPBRootObject
 @end
 
@@ -46,58 +48,64 @@
   GPBDuration_FieldNumber_Nanos = 2,
 };
 
-/// A Duration represents a signed, fixed-length span of time represented
-/// as a count of seconds and fractions of seconds at nanosecond
-/// resolution. It is independent of any calendar and concepts like "day"
-/// or "month". It is related to Timestamp in that the difference between
-/// two Timestamp values is a Duration and it can be added or subtracted
-/// from a Timestamp. Range is approximately +-10,000 years.
-///
-/// Example 1: Compute Duration from two Timestamps in pseudo code.
-///
-///     Timestamp start = ...;
-///     Timestamp end = ...;
-///     Duration duration = ...;
-///
-///     duration.seconds = end.seconds - start.seconds;
-///     duration.nanos = end.nanos - start.nanos;
-///
-///     if (duration.seconds < 0 && duration.nanos > 0) {
-///       duration.seconds += 1;
-///       duration.nanos -= 1000000000;
-///     } else if (durations.seconds > 0 && duration.nanos < 0) {
-///       duration.seconds -= 1;
-///       duration.nanos += 1000000000;
-///     }
-///
-/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
-///
-///     Timestamp start = ...;
-///     Duration duration = ...;
-///     Timestamp end = ...;
-///
-///     end.seconds = start.seconds + duration.seconds;
-///     end.nanos = start.nanos + duration.nanos;
-///
-///     if (end.nanos < 0) {
-///       end.seconds -= 1;
-///       end.nanos += 1000000000;
-///     } else if (end.nanos >= 1000000000) {
-///       end.seconds += 1;
-///       end.nanos -= 1000000000;
-///     }
+/**
+ * A Duration represents a signed, fixed-length span of time represented
+ * as a count of seconds and fractions of seconds at nanosecond
+ * resolution. It is independent of any calendar and concepts like "day"
+ * or "month". It is related to Timestamp in that the difference between
+ * two Timestamp values is a Duration and it can be added or subtracted
+ * from a Timestamp. Range is approximately +-10,000 years.
+ *
+ * Example 1: Compute Duration from two Timestamps in pseudo code.
+ *
+ *     Timestamp start = ...;
+ *     Timestamp end = ...;
+ *     Duration duration = ...;
+ *
+ *     duration.seconds = end.seconds - start.seconds;
+ *     duration.nanos = end.nanos - start.nanos;
+ *
+ *     if (duration.seconds < 0 && duration.nanos > 0) {
+ *       duration.seconds += 1;
+ *       duration.nanos -= 1000000000;
+ *     } else if (durations.seconds > 0 && duration.nanos < 0) {
+ *       duration.seconds -= 1;
+ *       duration.nanos += 1000000000;
+ *     }
+ *
+ * Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
+ *
+ *     Timestamp start = ...;
+ *     Duration duration = ...;
+ *     Timestamp end = ...;
+ *
+ *     end.seconds = start.seconds + duration.seconds;
+ *     end.nanos = start.nanos + duration.nanos;
+ *
+ *     if (end.nanos < 0) {
+ *       end.seconds -= 1;
+ *       end.nanos += 1000000000;
+ *     } else if (end.nanos >= 1000000000) {
+ *       end.seconds += 1;
+ *       end.nanos -= 1000000000;
+ *     }
+ **/
 @interface GPBDuration : GPBMessage
 
-/// Signed seconds of the span of time. Must be from -315,576,000,000
-/// to +315,576,000,000 inclusive.
+/**
+ * Signed seconds of the span of time. Must be from -315,576,000,000
+ * to +315,576,000,000 inclusive.
+ **/
 @property(nonatomic, readwrite) int64_t seconds;
 
-/// Signed fractions of a second at nanosecond resolution of the span
-/// of time. Durations less than one second are represented with a 0
-/// `seconds` field and a positive or negative `nanos` field. For durations
-/// of one second or more, a non-zero value for the `nanos` field must be
-/// of the same sign as the `seconds` field. Must be from -999,999,999
-/// to +999,999,999 inclusive.
+/**
+ * Signed fractions of a second at nanosecond resolution of the span
+ * of time. Durations less than one second are represented with a 0
+ * `seconds` field and a positive or negative `nanos` field. For durations
+ * of one second or more, a non-zero value for the `nanos` field must be
+ * of the same sign as the `seconds` field. Must be from -999,999,999
+ * to +999,999,999 inclusive.
+ **/
 @property(nonatomic, readwrite) int32_t nanos;
 
 @end
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
index 35daa3d..f87d35d 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.m
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBDurationRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBDurationRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -88,7 +92,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBDuration__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
index 2d2a86b..e0ed3e1 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.h
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,28 +28,32 @@
 
 #pragma mark - GPBEmptyRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBEmptyRoot : GPBRootObject
 @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);
-///     }
-///
-/// The JSON representation for `Empty` is empty JSON object `{}`.
+/**
+ * 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);
+ *     }
+ *
+ * The JSON representation for `Empty` is empty JSON object `{}`.
+ **/
 @interface GPBEmpty : GPBMessage
 
 @end
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
index 1bdd494..9b60f36 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.m
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBEmptyRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBEmptyRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -64,7 +68,7 @@
                                         fields:NULL
                                     fieldCount:0
                                    storageSize:sizeof(GPBEmpty__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
index 06053f1..14ed537 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.h
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBFieldMaskRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBFieldMaskRoot : GPBRootObject
 @end
 
@@ -45,212 +47,214 @@
   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
-/// (their 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 apply 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.
-///
-/// If a repeated field is specified for an update operation, the existing
-/// repeated values in the target resource will be overwritten by the new values.
-/// Note that a repeated field is only allowed in the last position of a field
-/// mask.
-///
-/// If a sub-message is specified in the last position of the field mask for an
-/// update operation, then the existing sub-message in the target resource is
-/// overwritten. Given the target message:
-///
-///     f {
-///       b {
-///         d : 1
-///         x : 2
-///       }
-///       c : 1
-///     }
-///
-/// And an update message:
-///
-///     f {
-///       b {
-///         d : 10
-///       }
-///     }
-///
-/// then if the field mask is:
-///
-///  paths: "f.b"
-///
-/// then the result will be:
-///
-///     f {
-///       b {
-///         d : 10
-///       }
-///       c : 1
-///     }
-///
-/// However, if the update mask was:
-///
-///  paths: "f.b.d"
-///
-/// then the result would be:
-///
-///     f {
-///       b {
-///         d : 10
-///         x : 2
-///       }
-///       c : 1
-///     }
-///
-/// 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"
-///     }
-///
-/// # Field Masks and Oneof Fields
-///
-/// Field masks treat fields in oneofs just as regular fields. Consider the
-/// following message:
-///
-///     message SampleMessage {
-///       oneof test_oneof {
-///         string name = 4;
-///         SubMessage sub_message = 9;
-///       }
-///     }
-///
-/// The field mask can be:
-///
-///     mask {
-///       paths: "name"
-///     }
-///
-/// Or:
-///
-///     mask {
-///       paths: "sub_message"
-///     }
-///
-/// Note that oneof type names ("test_oneof" in this case) cannot be used in
-/// paths.
+/**
+ * `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
+ * (their 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 apply 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.
+ *
+ * If a repeated field is specified for an update operation, the existing
+ * repeated values in the target resource will be overwritten by the new values.
+ * Note that a repeated field is only allowed in the last position of a field
+ * mask.
+ *
+ * If a sub-message is specified in the last position of the field mask for an
+ * update operation, then the existing sub-message in the target resource is
+ * overwritten. Given the target message:
+ *
+ *     f {
+ *       b {
+ *         d : 1
+ *         x : 2
+ *       }
+ *       c : 1
+ *     }
+ *
+ * And an update message:
+ *
+ *     f {
+ *       b {
+ *         d : 10
+ *       }
+ *     }
+ *
+ * then if the field mask is:
+ *
+ *  paths: "f.b"
+ *
+ * then the result will be:
+ *
+ *     f {
+ *       b {
+ *         d : 10
+ *       }
+ *       c : 1
+ *     }
+ *
+ * However, if the update mask was:
+ *
+ *  paths: "f.b.d"
+ *
+ * then the result would be:
+ *
+ *     f {
+ *       b {
+ *         d : 10
+ *         x : 2
+ *       }
+ *       c : 1
+ *     }
+ *
+ * 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"
+ *     }
+ *
+ * # Field Masks and Oneof Fields
+ *
+ * Field masks treat fields in oneofs just as regular fields. Consider the
+ * following message:
+ *
+ *     message SampleMessage {
+ *       oneof test_oneof {
+ *         string name = 4;
+ *         SubMessage sub_message = 9;
+ *       }
+ *     }
+ *
+ * The field mask can be:
+ *
+ *     mask {
+ *       paths: "name"
+ *     }
+ *
+ * Or:
+ *
+ *     mask {
+ *       paths: "sub_message"
+ *     }
+ *
+ * Note that oneof type names ("test_oneof" in this case) cannot be used in
+ * paths.
+ **/
 @interface GPBFieldMask : GPBMessage
 
-/// The set of field mask paths.
+/** The set of field mask paths. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *pathsArray;
-/// The number of items in @c pathsArray without causing the array to be created.
+/** The number of items in @c pathsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger pathsArray_Count;
 
 @end
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
index 2721fdf..4dc8409 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.m
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBFieldMaskRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBFieldMaskRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -77,7 +81,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBFieldMask__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
index 4514fa9..417562c 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.h
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBSourceContextRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBSourceContextRoot : GPBRootObject
 @end
 
@@ -45,12 +47,16 @@
   GPBSourceContext_FieldNumber_FileName = 1,
 };
 
-/// `SourceContext` represents information about the source of a
-/// protobuf element, like the file in which it is defined.
+/**
+ * `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_context.proto"`.
+/**
+ * The path-qualified name of the .proto file that contained the associated
+ * protobuf element.  For example: `"google/protobuf/source_context.proto"`.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *fileName;
 
 @end
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
index 6e3c9c0..648d736 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.m
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBSourceContextRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBSourceContextRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -77,7 +81,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBSourceContext__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
index 3e2d55f..163b39b 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.h
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -32,35 +32,43 @@
 
 #pragma mark - Enum GPBNullValue
 
-/// `NullValue` is a singleton enumeration to represent the null value for the
-/// `Value` type union.
-///
-///  The JSON representation for `NullValue` is JSON `null`.
+/**
+ * `NullValue` is a singleton enumeration to represent the null value for the
+ * `Value` type union.
+ *
+ *  The JSON representation for `NullValue` is JSON `null`.
+ **/
 typedef GPB_ENUM(GPBNullValue) {
-  /// Value used if any message's field encounters a value that is not defined
-  /// by this enum. The message will also have C functions to get/set the rawValue
-  /// of the field.
+  /**
+   * Value used if any message's field encounters a value that is not defined
+   * by this enum. The message will also have C functions to get/set the rawValue
+   * of the field.
+   **/
   GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  /// Null value.
+  /** Null value. */
   GPBNullValue_NullValue = 0,
 };
 
 GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void);
 
-/// Checks to see if the given value is defined by the enum or was not known at
-/// the time this source was generated.
+/**
+ * Checks to see if the given value is defined by the enum or was not known at
+ * the time this source was generated.
+ **/
 BOOL GPBNullValue_IsValidValue(int32_t value);
 
 #pragma mark - GPBStructRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBStructRoot : GPBRootObject
 @end
 
@@ -70,19 +78,21 @@
   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.
-///
-/// The JSON representation for `Struct` is JSON object.
+/**
+ * `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.
+ *
+ * The JSON representation for `Struct` is JSON object.
+ **/
 @interface GPBStruct : GPBMessage
 
-/// Unordered map of dynamically typed values.
+/** Unordered map of dynamically typed values. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, GPBValue*> *fields;
-/// The number of items in @c fields without causing the array to be created.
+/** The number of items in @c fields without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger fields_Count;
 
 @end
@@ -108,46 +118,54 @@
   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.
-///
-/// The JSON representation for `Value` is JSON value.
+/**
+ * `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.
+ *
+ * The JSON representation for `Value` is JSON value.
+ **/
 @interface GPBValue : GPBMessage
 
-/// The kind of value.
+/** The kind of value. */
 @property(nonatomic, readonly) GPBValue_Kind_OneOfCase kindOneOfCase;
 
-/// Represents a null value.
+/** Represents a null value. */
 @property(nonatomic, readwrite) GPBNullValue nullValue;
 
-/// Represents a double value.
+/** Represents a double value. */
 @property(nonatomic, readwrite) double numberValue;
 
-/// Represents a string value.
+/** Represents a string value. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;
 
-/// Represents a boolean value.
+/** Represents a boolean value. */
 @property(nonatomic, readwrite) BOOL boolValue;
 
-/// Represents a structured value.
+/** Represents a structured value. */
 @property(nonatomic, readwrite, strong, null_resettable) GPBStruct *structValue;
 
-/// Represents a repeated `Value`.
+/** Represents a repeated `Value`. */
 @property(nonatomic, readwrite, strong, null_resettable) GPBListValue *listValue;
 
 @end
 
-/// Fetches the raw value of a @c GPBValue's @c nullValue property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBValue's @c nullValue property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBValue_NullValue_RawValue(GPBValue *message);
-/// Sets the raw value of an @c GPBValue's @c nullValue property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBValue's @c nullValue property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value);
 
-/// Clears whatever value was set for the oneof 'kind'.
+/**
+ * Clears whatever value was set for the oneof 'kind'.
+ **/
 void GPBValue_ClearKindOneOfCase(GPBValue *message);
 
 #pragma mark - GPBListValue
@@ -156,14 +174,16 @@
   GPBListValue_FieldNumber_ValuesArray = 1,
 };
 
-/// `ListValue` is a wrapper around a repeated field of values.
-///
-/// The JSON representation for `ListValue` is JSON array.
+/**
+ * `ListValue` is a wrapper around a repeated field of values.
+ *
+ * The JSON representation for `ListValue` is JSON array.
+ **/
 @interface GPBListValue : GPBMessage
 
-/// Repeated field of dynamically typed values.
+/** Repeated field of dynamically typed values. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBValue*> *valuesArray;
-/// The number of items in @c valuesArray without causing the array to be created.
+/** The number of items in @c valuesArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger valuesArray_Count;
 
 @end
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
index 538faab..bc9f23f 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.m
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -28,6 +28,9 @@
 
 @implementation GPBStructRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBStructRoot_FileDescriptor
@@ -39,6 +42,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -110,7 +114,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBStruct__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -152,7 +156,7 @@
         .number = GPBValue_FieldNumber_NullValue,
         .hasIndex = -1,
         .offset = (uint32_t)offsetof(GPBValue__storage_, nullValue),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
       {
@@ -208,7 +212,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     static const char *oneofs[] = {
       "kind",
     };
@@ -237,7 +241,7 @@
 
 void GPBValue_ClearKindOneOfCase(GPBValue *message) {
   GPBDescriptor *descriptor = [message descriptor];
-  GPBOneofDescriptor *oneof = descriptor->oneofs_[0];
+  GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0];
   GPBMaybeClearOneof(message, oneof, -1, 0);
 }
 #pragma mark - GPBListValue
@@ -274,7 +278,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBListValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index d15de7c..094e9b6 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBTimestampRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBTimestampRoot : GPBRootObject
 @end
 
@@ -46,70 +48,76 @@
   GPBTimestamp_FieldNumber_Nanos = 2,
 };
 
-/// A Timestamp represents a point in time independent of any time zone
-/// or calendar, represented as seconds and fractions of seconds at
-/// nanosecond resolution in UTC Epoch time. It is encoded using the
-/// Proleptic Gregorian Calendar which extends the Gregorian calendar
-/// backwards to year one. It is encoded assuming all minutes are 60
-/// seconds long, i.e. leap seconds are "smeared" so that no leap second
-/// table is needed for interpretation. Range is from
-/// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
-/// By restricting to that range, we ensure that we can convert to
-/// and from  RFC 3339 date strings.
-/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
-///
-/// Example 1: Compute Timestamp from POSIX `time()`.
-///
-///     Timestamp timestamp;
-///     timestamp.set_seconds(time(NULL));
-///     timestamp.set_nanos(0);
-///
-/// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
-///
-///     struct timeval tv;
-///     gettimeofday(&tv, NULL);
-///
-///     Timestamp timestamp;
-///     timestamp.set_seconds(tv.tv_sec);
-///     timestamp.set_nanos(tv.tv_usec * 1000);
-///
-/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
-///
-///     FILETIME ft;
-///     GetSystemTimeAsFileTime(&ft);
-///     UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
-///
-///     // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
-///     // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
-///     Timestamp timestamp;
-///     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
-///     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
-///
-/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
-///
-///     long millis = System.currentTimeMillis();
-///
-///     Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
-///         .setNanos((int) ((millis % 1000) * 1000000)).build();
-///
-///
-/// Example 5: Compute Timestamp from current time in Python.
-///
-///     now = time.time()
-///     seconds = int(now)
-///     nanos = int((now - seconds) * 10**9)
-///     timestamp = Timestamp(seconds=seconds, nanos=nanos)
+/**
+ * A Timestamp represents a point in time independent of any time zone
+ * or calendar, represented as seconds and fractions of seconds at
+ * nanosecond resolution in UTC Epoch time. It is encoded using the
+ * Proleptic Gregorian Calendar which extends the Gregorian calendar
+ * backwards to year one. It is encoded assuming all minutes are 60
+ * seconds long, i.e. leap seconds are "smeared" so that no leap second
+ * table is needed for interpretation. Range is from
+ * 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
+ * By restricting to that range, we ensure that we can convert to
+ * and from  RFC 3339 date strings.
+ * See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+ *
+ * Example 1: Compute Timestamp from POSIX `time()`.
+ *
+ *     Timestamp timestamp;
+ *     timestamp.set_seconds(time(NULL));
+ *     timestamp.set_nanos(0);
+ *
+ * Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+ *
+ *     struct timeval tv;
+ *     gettimeofday(&tv, NULL);
+ *
+ *     Timestamp timestamp;
+ *     timestamp.set_seconds(tv.tv_sec);
+ *     timestamp.set_nanos(tv.tv_usec * 1000);
+ *
+ * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+ *
+ *     FILETIME ft;
+ *     GetSystemTimeAsFileTime(&ft);
+ *     UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+ *
+ *     // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+ *     // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+ *     Timestamp timestamp;
+ *     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+ *     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+ *
+ * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+ *
+ *     long millis = System.currentTimeMillis();
+ *
+ *     Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+ *         .setNanos((int) ((millis % 1000) * 1000000)).build();
+ *
+ *
+ * Example 5: Compute Timestamp from current time in Python.
+ *
+ *     now = time.time()
+ *     seconds = int(now)
+ *     nanos = int((now - seconds) * 10**9)
+ *     timestamp = Timestamp(seconds=seconds, nanos=nanos)
+ **/
 @interface GPBTimestamp : GPBMessage
 
-/// Represents seconds of UTC time since Unix epoch
-/// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
-/// 9999-12-31T23:59:59Z inclusive.
+/**
+ * Represents seconds of UTC time since Unix epoch
+ * 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
+ * 9999-12-31T23:59:59Z inclusive.
+ **/
 @property(nonatomic, readwrite) int64_t seconds;
 
-/// Non-negative fractions of a second at nanosecond resolution. Negative
-/// second values with fractions must still have non-negative nanos values
-/// that count forward in time. Must be from 0 to 999,999,999
-/// inclusive.
+/**
+ * Non-negative fractions of a second at nanosecond resolution. Negative
+ * second values with fractions must still have non-negative nanos values
+ * that count forward in time. Must be from 0 to 999,999,999
+ * inclusive.
+ **/
 @property(nonatomic, readwrite) int32_t nanos;
 
 @end
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
index 06e3ef9..1506dff 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.m
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBTimestampRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBTimestampRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -88,7 +92,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBTimestamp__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
index 93ee3ce..da923c3 100644
--- a/objectivec/google/protobuf/Type.pbobjc.h
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -34,134 +34,148 @@
 
 #pragma mark - Enum GPBSyntax
 
-/// The syntax in which a protocol buffer element is defined.
+/** The syntax in which a protocol buffer element is defined. */
 typedef GPB_ENUM(GPBSyntax) {
-  /// Value used if any message's field encounters a value that is not defined
-  /// by this enum. The message will also have C functions to get/set the rawValue
-  /// of the field.
+  /**
+   * Value used if any message's field encounters a value that is not defined
+   * by this enum. The message will also have C functions to get/set the rawValue
+   * of the field.
+   **/
   GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  /// Syntax `proto2`.
+  /** Syntax `proto2`. */
   GPBSyntax_SyntaxProto2 = 0,
 
-  /// Syntax `proto3`.
+  /** Syntax `proto3`. */
   GPBSyntax_SyntaxProto3 = 1,
 };
 
 GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void);
 
-/// Checks to see if the given value is defined by the enum or was not known at
-/// the time this source was generated.
+/**
+ * Checks to see if the given value is defined by the enum or was not known at
+ * the time this source was generated.
+ **/
 BOOL GPBSyntax_IsValidValue(int32_t value);
 
 #pragma mark - Enum GPBField_Kind
 
-/// Basic field types.
+/** Basic field types. */
 typedef GPB_ENUM(GPBField_Kind) {
-  /// Value used if any message's field encounters a value that is not defined
-  /// by this enum. The message will also have C functions to get/set the rawValue
-  /// of the field.
+  /**
+   * Value used if any message's field encounters a value that is not defined
+   * by this enum. The message will also have C functions to get/set the rawValue
+   * of the field.
+   **/
   GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  /// Field type unknown.
+  /** Field type unknown. */
   GPBField_Kind_TypeUnknown = 0,
 
-  /// Field type double.
+  /** Field type double. */
   GPBField_Kind_TypeDouble = 1,
 
-  /// Field type float.
+  /** Field type float. */
   GPBField_Kind_TypeFloat = 2,
 
-  /// Field type int64.
+  /** Field type int64. */
   GPBField_Kind_TypeInt64 = 3,
 
-  /// Field type uint64.
+  /** Field type uint64. */
   GPBField_Kind_TypeUint64 = 4,
 
-  /// Field type int32.
+  /** Field type int32. */
   GPBField_Kind_TypeInt32 = 5,
 
-  /// Field type fixed64.
+  /** Field type fixed64. */
   GPBField_Kind_TypeFixed64 = 6,
 
-  /// Field type fixed32.
+  /** Field type fixed32. */
   GPBField_Kind_TypeFixed32 = 7,
 
-  /// Field type bool.
+  /** Field type bool. */
   GPBField_Kind_TypeBool = 8,
 
-  /// Field type string.
+  /** Field type string. */
   GPBField_Kind_TypeString = 9,
 
-  /// Field type group. Proto2 syntax only, and deprecated.
+  /** Field type group. Proto2 syntax only, and deprecated. */
   GPBField_Kind_TypeGroup = 10,
 
-  /// Field type message.
+  /** Field type message. */
   GPBField_Kind_TypeMessage = 11,
 
-  /// Field type bytes.
+  /** Field type bytes. */
   GPBField_Kind_TypeBytes = 12,
 
-  /// Field type uint32.
+  /** Field type uint32. */
   GPBField_Kind_TypeUint32 = 13,
 
-  /// Field type enum.
+  /** Field type enum. */
   GPBField_Kind_TypeEnum = 14,
 
-  /// Field type sfixed32.
+  /** Field type sfixed32. */
   GPBField_Kind_TypeSfixed32 = 15,
 
-  /// Field type sfixed64.
+  /** Field type sfixed64. */
   GPBField_Kind_TypeSfixed64 = 16,
 
-  /// Field type sint32.
+  /** Field type sint32. */
   GPBField_Kind_TypeSint32 = 17,
 
-  /// Field type sint64.
+  /** Field type sint64. */
   GPBField_Kind_TypeSint64 = 18,
 };
 
 GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void);
 
-/// Checks to see if the given value is defined by the enum or was not known at
-/// the time this source was generated.
+/**
+ * Checks to see if the given value is defined by the enum or was not known at
+ * the time this source was generated.
+ **/
 BOOL GPBField_Kind_IsValidValue(int32_t value);
 
 #pragma mark - Enum GPBField_Cardinality
 
-/// Whether a field is optional, required, or repeated.
+/** Whether a field is optional, required, or repeated. */
 typedef GPB_ENUM(GPBField_Cardinality) {
-  /// Value used if any message's field encounters a value that is not defined
-  /// by this enum. The message will also have C functions to get/set the rawValue
-  /// of the field.
+  /**
+   * Value used if any message's field encounters a value that is not defined
+   * by this enum. The message will also have C functions to get/set the rawValue
+   * of the field.
+   **/
   GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  /// For fields with unknown cardinality.
+  /** For fields with unknown cardinality. */
   GPBField_Cardinality_CardinalityUnknown = 0,
 
-  /// For optional fields.
+  /** For optional fields. */
   GPBField_Cardinality_CardinalityOptional = 1,
 
-  /// For required fields. Proto2 syntax only.
+  /** For required fields. Proto2 syntax only. */
   GPBField_Cardinality_CardinalityRequired = 2,
 
-  /// For repeated fields.
+  /** For repeated fields. */
   GPBField_Cardinality_CardinalityRepeated = 3,
 };
 
 GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void);
 
-/// Checks to see if the given value is defined by the enum or was not known at
-/// the time this source was generated.
+/**
+ * Checks to see if the given value is defined by the enum or was not known at
+ * the time this source was generated.
+ **/
 BOOL GPBField_Cardinality_IsValidValue(int32_t value);
 
 #pragma mark - GPBTypeRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBTypeRoot : GPBRootObject
 @end
 
@@ -176,43 +190,49 @@
   GPBType_FieldNumber_Syntax = 6,
 };
 
-/// A protocol buffer message type.
+/**
+ * A protocol buffer message type.
+ **/
 @interface GPBType : GPBMessage
 
-/// The fully qualified message name.
+/** The fully qualified message name. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// The list of fields.
+/** The list of fields. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBField*> *fieldsArray;
-/// The number of items in @c fieldsArray without causing the array to be created.
+/** The number of items in @c fieldsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger fieldsArray_Count;
 
-/// The list of types appearing in `oneof` definitions in this type.
+/** The list of types appearing in `oneof` definitions in this type. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *oneofsArray;
-/// The number of items in @c oneofsArray without causing the array to be created.
+/** The number of items in @c oneofsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger oneofsArray_Count;
 
-/// The protocol buffer options.
+/** The protocol buffer options. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-/// The source context.
+/** The source context. */
 @property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
-/// Test to see if @c sourceContext has been set.
+/** Test to see if @c sourceContext has been set. */
 @property(nonatomic, readwrite) BOOL hasSourceContext;
 
-/// The source syntax.
+/** The source syntax. */
 @property(nonatomic, readwrite) GPBSyntax syntax;
 
 @end
 
-/// Fetches the raw value of a @c GPBType's @c syntax property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBType's @c syntax property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBType_Syntax_RawValue(GPBType *message);
-/// Sets the raw value of an @c GPBType's @c syntax property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBType's @c syntax property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value);
 
 #pragma mark - GPBField
@@ -230,59 +250,73 @@
   GPBField_FieldNumber_DefaultValue = 11,
 };
 
-/// A single field of a message type.
+/**
+ * A single field of a message type.
+ **/
 @interface GPBField : GPBMessage
 
-/// The field type.
+/** The field type. */
 @property(nonatomic, readwrite) GPBField_Kind kind;
 
-/// The field cardinality.
+/** The field cardinality. */
 @property(nonatomic, readwrite) GPBField_Cardinality cardinality;
 
-/// The field number.
+/** The field number. */
 @property(nonatomic, readwrite) int32_t number;
 
-/// The field name.
+/** The field name. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// The field type URL, without the scheme, for message or enumeration
-/// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+/**
+ * The field type URL, without the scheme, for message or enumeration
+ * types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+ **/
 @property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL;
 
-/// The index of the field type in `Type.oneofs`, for message or enumeration
-/// types. The first type has index 1; zero means the type is not in the list.
+/**
+ * The index of the field type in `Type.oneofs`, for message or enumeration
+ * types. The first type has index 1; zero means the type is not in the list.
+ **/
 @property(nonatomic, readwrite) int32_t oneofIndex;
 
-/// Whether to use alternative packed wire representation.
+/** Whether to use alternative packed wire representation. */
 @property(nonatomic, readwrite) BOOL packed;
 
-/// The protocol buffer options.
+/** The protocol buffer options. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-/// The field JSON name.
+/** The field JSON name. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName;
 
-/// The string value of the default value of this field. Proto2 syntax only.
+/** The string value of the default value of this field. Proto2 syntax only. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue;
 
 @end
 
-/// Fetches the raw value of a @c GPBField's @c kind property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBField's @c kind property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBField_Kind_RawValue(GPBField *message);
-/// Sets the raw value of an @c GPBField's @c kind property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBField's @c kind property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBField_Kind_RawValue(GPBField *message, int32_t value);
 
-/// Fetches the raw value of a @c GPBField's @c cardinality property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBField's @c cardinality property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBField_Cardinality_RawValue(GPBField *message);
-/// Sets the raw value of an @c GPBField's @c cardinality property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBField's @c cardinality property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value);
 
 #pragma mark - GPBEnum
@@ -295,38 +329,44 @@
   GPBEnum_FieldNumber_Syntax = 5,
 };
 
-/// Enum type definition.
+/**
+ * Enum type definition.
+ **/
 @interface GPBEnum : GPBMessage
 
-/// Enum type name.
+/** Enum type name. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// Enum value definitions.
+/** Enum value definitions. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValue*> *enumvalueArray;
-/// The number of items in @c enumvalueArray without causing the array to be created.
+/** The number of items in @c enumvalueArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
 
-/// Protocol buffer options.
+/** Protocol buffer options. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-/// The source context.
+/** The source context. */
 @property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
-/// Test to see if @c sourceContext has been set.
+/** Test to see if @c sourceContext has been set. */
 @property(nonatomic, readwrite) BOOL hasSourceContext;
 
-/// The source syntax.
+/** The source syntax. */
 @property(nonatomic, readwrite) GPBSyntax syntax;
 
 @end
 
-/// Fetches the raw value of a @c GPBEnum's @c syntax property, even
-/// if the value was not defined by the enum at the time the code was generated.
+/**
+ * Fetches the raw value of a @c GPBEnum's @c syntax property, even
+ * if the value was not defined by the enum at the time the code was generated.
+ **/
 int32_t GPBEnum_Syntax_RawValue(GPBEnum *message);
-/// Sets the raw value of an @c GPBEnum's @c syntax property, allowing
-/// it to be set to a value that was not defined by the enum at the time the code
-/// was generated.
+/**
+ * Sets the raw value of an @c GPBEnum's @c syntax property, allowing
+ * it to be set to a value that was not defined by the enum at the time the code
+ * was generated.
+ **/
 void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value);
 
 #pragma mark - GPBEnumValue
@@ -337,18 +377,20 @@
   GPBEnumValue_FieldNumber_OptionsArray = 3,
 };
 
-/// Enum value definition.
+/**
+ * Enum value definition.
+ **/
 @interface GPBEnumValue : GPBMessage
 
-/// Enum value name.
+/** Enum value name. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// Enum value number.
+/** Enum value number. */
 @property(nonatomic, readwrite) int32_t number;
 
-/// Protocol buffer options.
+/** Protocol buffer options. */
 @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
-/// The number of items in @c optionsArray without causing the array to be created.
+/** The number of items in @c optionsArray without causing the array to be created. */
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 @end
@@ -360,16 +402,18 @@
   GPBOption_FieldNumber_Value = 2,
 };
 
-/// A protocol buffer option, which can be attached to a message, field,
-/// enumeration, etc.
+/**
+ * A protocol buffer option, which can be attached to a message, field,
+ * enumeration, etc.
+ **/
 @interface GPBOption : GPBMessage
 
-/// The option's name. For example, `"java_package"`.
+/** The option's name. For example, `"java_package"`. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-/// The option's value. For example, `"com.google.protobuf"`.
+/** The option's value. For example, `"com.google.protobuf"`. */
 @property(nonatomic, readwrite, strong, null_resettable) GPBAny *value;
-/// Test to see if @c value has been set.
+/** Test to see if @c value has been set. */
 @property(nonatomic, readwrite) BOOL hasValue;
 
 @end
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
index 6c7b4ef..a36f1cd 100644
--- a/objectivec/google/protobuf/Type.pbobjc.m
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -31,18 +31,8 @@
 
 @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) {
-    GPBDebugCheckRuntimeVersion();
-    registry = [[GPBExtensionRegistry alloc] init];
-    [registry addExtensions:[GPBAnyRoot extensionRegistry]];
-    [registry addExtensions:[GPBSourceContextRoot extensionRegistry]];
-  }
-  return registry;
-}
+// No extensions in the file and none of the imports (direct or indirect)
+// defined extensions, so no need to generate +extensionRegistry.
 
 @end
 
@@ -55,6 +45,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -172,7 +163,7 @@
         .number = GPBType_FieldNumber_Syntax,
         .hasIndex = 2,
         .offset = (uint32_t)offsetof(GPBType__storage_, syntax),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
     };
@@ -183,7 +174,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBType__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -244,7 +235,7 @@
         .number = GPBField_FieldNumber_Kind,
         .hasIndex = 0,
         .offset = (uint32_t)offsetof(GPBField__storage_, kind),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
       {
@@ -253,7 +244,7 @@
         .number = GPBField_FieldNumber_Cardinality,
         .hasIndex = 1,
         .offset = (uint32_t)offsetof(GPBField__storage_, cardinality),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
       {
@@ -280,7 +271,7 @@
         .number = GPBField_FieldNumber_TypeURL,
         .hasIndex = 4,
         .offset = (uint32_t)offsetof(GPBField__storage_, typeURL),
-        .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldTextFormatNameCustom),
         .dataType = GPBDataTypeString,
       },
       {
@@ -336,7 +327,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBField__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
 #if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
     static const char *extraTextFormatInfo =
         "\001\006\004\241!!\000";
@@ -553,7 +544,7 @@
         .number = GPBEnum_FieldNumber_Syntax,
         .hasIndex = 2,
         .offset = (uint32_t)offsetof(GPBEnum__storage_, syntax),
-        .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor,
+        .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor),
         .dataType = GPBDataTypeEnum,
       },
     };
@@ -564,7 +555,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBEnum__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -641,7 +632,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBEnumValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -695,7 +686,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBOption__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
index 5593d34..2bf6fd2 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.h
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
@@ -28,14 +28,16 @@
 
 #pragma mark - GPBWrappersRoot
 
-/// Exposes the extension registry for this file.
-///
-/// The base class provides:
-/// @code
-///   + (GPBExtensionRegistry *)extensionRegistry;
-/// @endcode
-/// which is a @c GPBExtensionRegistry that includes all the extensions defined by
-/// this file and all files that it depends on.
+/**
+ * Exposes the extension registry for this file.
+ *
+ * The base class provides:
+ * @code
+ *   + (GPBExtensionRegistry *)extensionRegistry;
+ * @endcode
+ * which is a @c GPBExtensionRegistry that includes all the extensions defined by
+ * this file and all files that it depends on.
+ **/
 @interface GPBWrappersRoot : GPBRootObject
 @end
 
@@ -45,12 +47,14 @@
   GPBDoubleValue_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `double`.
-///
-/// The JSON representation for `DoubleValue` is JSON number.
+/**
+ * Wrapper message for `double`.
+ *
+ * The JSON representation for `DoubleValue` is JSON number.
+ **/
 @interface GPBDoubleValue : GPBMessage
 
-/// The double value.
+/** The double value. */
 @property(nonatomic, readwrite) double value;
 
 @end
@@ -61,12 +65,14 @@
   GPBFloatValue_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `float`.
-///
-/// The JSON representation for `FloatValue` is JSON number.
+/**
+ * Wrapper message for `float`.
+ *
+ * The JSON representation for `FloatValue` is JSON number.
+ **/
 @interface GPBFloatValue : GPBMessage
 
-/// The float value.
+/** The float value. */
 @property(nonatomic, readwrite) float value;
 
 @end
@@ -77,12 +83,14 @@
   GPBInt64Value_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `int64`.
-///
-/// The JSON representation for `Int64Value` is JSON string.
+/**
+ * Wrapper message for `int64`.
+ *
+ * The JSON representation for `Int64Value` is JSON string.
+ **/
 @interface GPBInt64Value : GPBMessage
 
-/// The int64 value.
+/** The int64 value. */
 @property(nonatomic, readwrite) int64_t value;
 
 @end
@@ -93,12 +101,14 @@
   GPBUInt64Value_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `uint64`.
-///
-/// The JSON representation for `UInt64Value` is JSON string.
+/**
+ * Wrapper message for `uint64`.
+ *
+ * The JSON representation for `UInt64Value` is JSON string.
+ **/
 @interface GPBUInt64Value : GPBMessage
 
-/// The uint64 value.
+/** The uint64 value. */
 @property(nonatomic, readwrite) uint64_t value;
 
 @end
@@ -109,12 +119,14 @@
   GPBInt32Value_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `int32`.
-///
-/// The JSON representation for `Int32Value` is JSON number.
+/**
+ * Wrapper message for `int32`.
+ *
+ * The JSON representation for `Int32Value` is JSON number.
+ **/
 @interface GPBInt32Value : GPBMessage
 
-/// The int32 value.
+/** The int32 value. */
 @property(nonatomic, readwrite) int32_t value;
 
 @end
@@ -125,12 +137,14 @@
   GPBUInt32Value_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `uint32`.
-///
-/// The JSON representation for `UInt32Value` is JSON number.
+/**
+ * Wrapper message for `uint32`.
+ *
+ * The JSON representation for `UInt32Value` is JSON number.
+ **/
 @interface GPBUInt32Value : GPBMessage
 
-/// The uint32 value.
+/** The uint32 value. */
 @property(nonatomic, readwrite) uint32_t value;
 
 @end
@@ -141,12 +155,14 @@
   GPBBoolValue_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `bool`.
-///
-/// The JSON representation for `BoolValue` is JSON `true` and `false`.
+/**
+ * Wrapper message for `bool`.
+ *
+ * The JSON representation for `BoolValue` is JSON `true` and `false`.
+ **/
 @interface GPBBoolValue : GPBMessage
 
-/// The bool value.
+/** The bool value. */
 @property(nonatomic, readwrite) BOOL value;
 
 @end
@@ -157,12 +173,14 @@
   GPBStringValue_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `string`.
-///
-/// The JSON representation for `StringValue` is JSON string.
+/**
+ * Wrapper message for `string`.
+ *
+ * The JSON representation for `StringValue` is JSON string.
+ **/
 @interface GPBStringValue : GPBMessage
 
-/// The string value.
+/** The string value. */
 @property(nonatomic, readwrite, copy, null_resettable) NSString *value;
 
 @end
@@ -173,12 +191,14 @@
   GPBBytesValue_FieldNumber_Value = 1,
 };
 
-/// Wrapper message for `bytes`.
-///
-/// The JSON representation for `BytesValue` is JSON string.
+/**
+ * Wrapper message for `bytes`.
+ *
+ * The JSON representation for `BytesValue` is JSON string.
+ **/
 @interface GPBBytesValue : GPBMessage
 
-/// The bytes value.
+/** The bytes value. */
 @property(nonatomic, readwrite, copy, null_resettable) NSData *value;
 
 @end
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
index b5405a7..c8fdeb0 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.m
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -27,6 +27,9 @@
 
 @implementation GPBWrappersRoot
 
+// No extensions in the file and no imports, so no need to generate
+// +extensionRegistry.
+
 @end
 
 #pragma mark - GPBWrappersRoot_FileDescriptor
@@ -38,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
@@ -77,7 +81,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBDoubleValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -120,7 +124,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBFloatValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -163,7 +167,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBInt64Value__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -206,7 +210,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBUInt64Value__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -249,7 +253,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBInt32Value__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -292,7 +296,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBUInt32Value__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -334,7 +338,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBBoolValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -377,7 +381,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBStringValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
@@ -420,7 +424,7 @@
                                         fields:fields
                                     fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
                                    storageSize:sizeof(GPBBytesValue__storage_)
-                                         flags:0];
+                                         flags:GPBDescriptorInitializationFlag_None];
     NSAssert(descriptor == nil, @"Startup recursed!");
     descriptor = localDescriptor;
   }
diff --git a/protobuf.bzl b/protobuf.bzl
index c5555fd..e356f53 100644
--- a/protobuf.bzl
+++ b/protobuf.bzl
@@ -62,9 +62,19 @@
   if ctx.attr.gen_py:
     args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
 
-  if ctx.executable.grpc_cpp_plugin:
-    args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path]
-    args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+  if ctx.executable.plugin:
+    plugin = ctx.executable.plugin
+    lang = ctx.attr.plugin_language
+    if not lang and plugin.basename.startswith('protoc-gen-'):
+      lang = plugin.basename[len('protoc-gen-'):]
+    if not lang:
+      fail("cannot infer the target language of plugin", "plugin_language")
+
+    outdir = ctx.var["GENDIR"] + "/" + gen_dir
+    if ctx.attr.plugin_options:
+      outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
+    args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)]
+    args += ["--%s_out=%s" % (lang, outdir)]
 
   if args:
     ctx.action(
@@ -72,6 +82,7 @@
         outputs=ctx.outputs.outs,
         arguments=args + import_flags + [s.path for s in srcs],
         executable=ctx.executable.protoc,
+        mnemonic="ProtoCompile",
     )
 
   return struct(
@@ -82,22 +93,24 @@
       ),
   )
 
-_proto_gen = rule(
+proto_gen = rule(
     attrs = {
         "srcs": attr.label_list(allow_files = True),
         "deps": attr.label_list(providers = ["proto"]),
         "includes": attr.string_list(),
         "protoc": attr.label(
-            cfg = HOST_CFG,
+            cfg = "host",
             executable = True,
             single_file = True,
             mandatory = True,
         ),
-        "grpc_cpp_plugin": attr.label(
-            cfg = HOST_CFG,
+        "plugin": attr.label(
+            cfg = "host",
+            allow_files = True,
             executable = True,
-            single_file = True,
         ),
+        "plugin_language": attr.string(),
+        "plugin_options": attr.string_list(),
         "gen_cc": attr.bool(),
         "gen_py": attr.bool(),
         "outs": attr.output_list(),
@@ -105,6 +118,26 @@
     output_to_genfiles = True,
     implementation = _proto_gen_impl,
 )
+"""Generates codes from Protocol Buffers definitions.
+
+This rule helps you to implement Skylark macros specific to the target
+language. You should prefer more specific `cc_proto_library `,
+`py_proto_library` and others unless you are adding such wrapper macros.
+
+Args:
+  srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
+    against.
+  deps: a list of dependency labels; must be other proto libraries.
+  includes: a list of include paths to .proto files.
+  protoc: the label of the protocol compiler to generate the sources.
+  plugin: the label of the protocol compiler plugin to be passed to the protocol
+    compiler.
+  plugin_language: the language of the generated sources
+  plugin_options: a list of options to be passed to the plugin
+  gen_cc: generates C++ sources in addition to the ones from the plugin. 
+  gen_py: generates Python sources in addition to the ones from the plugin.
+  outs: a list of labels of the expected outputs from the protocol compiler.
+"""
 
 def cc_proto_library(
         name,
@@ -150,7 +183,7 @@
   if internal_bootstrap_hack:
     # For pre-checked-in generated files, we add the internal_bootstrap_hack
     # which will skip the codegen action.
-    _proto_gen(
+    proto_gen(
         name=name + "_genproto",
         srcs=srcs,
         deps=[s + "_genproto" for s in deps],
@@ -170,13 +203,14 @@
 
   outs = _CcOuts(srcs, use_grpc_plugin)
 
-  _proto_gen(
+  proto_gen(
       name=name + "_genproto",
       srcs=srcs,
       deps=[s + "_genproto" for s in deps],
       includes=includes,
       protoc=protoc,
-      grpc_cpp_plugin=grpc_cpp_plugin,
+      plugin=grpc_cpp_plugin,
+      plugin_language="grpc",
       gen_cc=1,
       outs=outs,
       visibility=["//visibility:public"],
@@ -286,7 +320,7 @@
   if include != None:
     includes = [include]
 
-  _proto_gen(
+  proto_gen(
       name=name + "_genproto",
       srcs=srcs,
       deps=[s + "_genproto" for s in deps],
diff --git a/protoc-artifacts/Dockerfile b/protoc-artifacts/Dockerfile
index fd35b89..5143b02 100644
--- a/protoc-artifacts/Dockerfile
+++ b/protoc-artifacts/Dockerfile
@@ -21,9 +21,9 @@
 ENV PATH $JAVA_HOME/bin:$PATH
 
 # Install Maven
-RUN wget -q http://apache.cs.utah.edu/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz -O - | \
+RUN wget -q http://apache.cs.utah.edu/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz -O - | \
     tar xz -C /var/local
-ENV PATH /var/local/apache-maven-3.3.3/bin:$PATH
+ENV PATH /var/local/apache-maven-3.3.9/bin:$PATH
 
 # Install GCC 4.7 to support -static-libstdc++
 RUN wget http://people.centos.org/tru/devtools-1.1/devtools-1.1.repo -P /etc/yum.repos.d
diff --git a/protoc-artifacts/README.md b/protoc-artifacts/README.md
index a910fe0..5062920 100644
--- a/protoc-artifacts/README.md
+++ b/protoc-artifacts/README.md
@@ -102,6 +102,25 @@
 https://oss.sonatype.org/#stagingRepositories, verify that the staging
 repository has all the binaries, close and release this repository.
 
+## Upload zip packages to github release page.
+After uploading protoc artifacts to Maven Central repository, run the
+build-zip.sh script to bulid zip packages for these protoc binaries
+and upload these zip packages to the download section of the github
+release. For example:
+```
+$ ./build-zip.sh 3.0.0-beta-4
+```
+The above command will create 5 zip files:
+```
+dist/protoc-3.0.0-beta-4-win32.zip
+dist/protoc-3.0.0-beta-4-osx-x86_32.zip
+dist/protoc-3.0.0-beta-4-osx-x86_64.zip
+dist/protoc-3.0.0-beta-4-linux-x86_32.zip
+dist/protoc-3.0.0-beta-4-linux-x86_64.zip
+```
+Before running the script, make sure the artifacts are accessible from:
+http://repo1.maven.org/maven2/com/google/protobuf/protoc/
+
 ### Tips for deploying on Linux
 We build on Centos 6.6 to provide a good compatibility for not very new
 systems. We have provided a ``Dockerfile`` under this directory to build the
diff --git a/protoc-artifacts/build-protoc.sh b/protoc-artifacts/build-protoc.sh
index 88e6ae5..e31948e 100755
--- a/protoc-artifacts/build-protoc.sh
+++ b/protoc-artifacts/build-protoc.sh
@@ -1,17 +1,30 @@
 #!/bin/bash
 
-# Builds protoc executable into target/protoc.exe
+# Builds protoc executable into target/protoc.exe; optionally build protoc
+# plugins into target/protoc-gen-*.exe
 # To be run from Maven.
-# Usage: build-protoc.sh <OS> <ARCH>
+# Usage: build-protoc.sh <OS> <ARCH> <TARGET>
 # <OS> and <ARCH> are ${os.detected.name} and ${os.detected.arch} from os-maven-plugin
+# <TARGET> can be "protoc" or "protoc-gen-javalite"
 OS=$1
 ARCH=$2
+MAKE_TARGET=$3
 
-if [[ $# < 2 ]]; then
+if [[ $# < 3 ]]; then
   echo "No arguments provided. This script is intended to be run from Maven."
   exit 1
 fi
 
+case $MAKE_TARGET in
+  protoc-gen-javalite)
+    ;;
+  protoc)
+    ;;
+  *)
+    echo "Target ""$TARGET"" invalid."
+    exit 1
+esac
+
 # Under Cygwin, bash doesn't have these in PATH when called from Maven which
 # runs in Windows version of Java.
 export PATH="/bin:/usr/bin:$PATH"
@@ -126,7 +139,7 @@
 }
 ############################################################################
 
-echo "Building protoc, OS=$OS ARCH=$ARCH"
+echo "Building protoc, OS=$OS ARCH=$ARCH TARGET=$TARGET"
 
 # Nested double quotes are unintuitive, but it works.
 cd "$(dirname "$0")"
@@ -134,7 +147,7 @@
 WORKING_DIR=$(pwd)
 CONFIGURE_ARGS="--disable-shared"
 
-MAKE_TARGET="protoc"
+TARGET_FILE=target/$MAKE_TARGET.exe
 if [[ "$OS" == windows ]]; then
   MAKE_TARGET="${MAKE_TARGET}.exe"
 fi
@@ -209,12 +222,10 @@
 
 export CXXFLAGS LDFLAGS
 
-TARGET_FILE=target/protoc.exe
-
 cd "$WORKING_DIR"/.. && ./configure $CONFIGURE_ARGS &&
   cd src && make clean && make $MAKE_TARGET &&
   cd "$WORKING_DIR" && mkdir -p target &&
-  (cp ../src/protoc $TARGET_FILE || cp ../src/protoc.exe $TARGET_FILE) ||
+  cp ../src/$MAKE_TARGET $TARGET_FILE ||
   exit 1
 
 if [[ "$OS" == osx ]]; then
diff --git a/protoc-artifacts/build-zip.sh b/protoc-artifacts/build-zip.sh
new file mode 100755
index 0000000..3c5e887
--- /dev/null
+++ b/protoc-artifacts/build-zip.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+if [ $# -ne 2 ]; then
+  cat <<EOF
+Usage: $0 <TARGET> <VERSION_NUMBER>
+
+TARGET: protoc | protoc-gen-javalite
+
+Example:
+  $ $0 protoc 3.0.0
+  $ $0 protoc-gen-javalite 3.0.0
+
+This script will download pre-built protoc or protoc plugin binaries from maven
+repository and create .zip packages suitable to be included in the github
+release page. If the target is protoc, well-known type .proto files will also be
+included. Each invocation will create 5 zip packages:
+  dist/<TARGET>-<VERSION_NUMBER>-win32.zip
+  dist/<TARGET>-<VERSION_NUMBER>-osx-x86_32.zip
+  dist/<TARGET>-<VERSION_NUMBER>-osx-x86_64.zip
+  dist/<TARGET>-<VERSION_NUMBER>-linux-x86_32.zip
+  dist/<TARGET>-<VERSION_NUMBER>-linux-x86_64.zip
+EOF
+  exit 1
+fi
+
+TARGET=$1
+VERSION_NUMBER=$2
+
+# <zip file name> <binary file name> pairs.
+declare -a FILE_NAMES=( \
+  win32.zip windows-x86_32.exe \
+  osx-x86_32.zip osx-x86_32.exe \
+  osx-x86_64.zip osx-x86_64.exe \
+  linux-x86_32.zip linux-x86_32.exe \
+  linux-x86_64.zip linux-x86_64.exe \
+)
+
+# List of all well-known types to be included.
+declare -a WELL_KNOWN_TYPES=(           \
+  google/protobuf/descriptor.proto      \
+  google/protobuf/any.proto             \
+  google/protobuf/api.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        \
+  google/protobuf/compiler/plugin.proto \
+)
+
+set -e
+
+# A temporary working directory to put all files.
+DIR=$(mktemp -d)
+
+# Copy over well-known types.
+mkdir -p ${DIR}/include/google/protobuf/compiler
+for PROTO in ${WELL_KNOWN_TYPES[@]}; do
+  cp -f ../src/${PROTO} ${DIR}/include/${PROTO}
+done
+
+# Create a readme file.
+cat <<EOF > ${DIR}/readme.txt
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+https://developers.google.com/protocol-buffers/
+
+This package contains a precompiled binary version of the protocol buffer
+compiler (protoc). This binary is intended for users who want to use Protocol
+Buffers in languages other than C++ but do not want to compile protoc
+themselves. To install, simply place this binary somewhere in your PATH.
+
+Please refer to our official github site for more installation instructions:
+  https://github.com/google/protobuf
+EOF
+
+mkdir -p dist
+mkdir -p ${DIR}/bin
+# Create a zip file for each binary.
+for((i=0;i<${#FILE_NAMES[@]};i+=2));do
+  ZIP_NAME=${FILE_NAMES[$i]}
+  if [ ${ZIP_NAME:0:3} = "win" ]; then
+    BINARY="$TARGET.exe"
+  else
+    BINARY="$TARGET"
+  fi
+  BINARY_NAME=${FILE_NAMES[$(($i+1))]}
+  BINARY_URL=http://repo1.maven.org/maven2/com/google/protobuf/$TARGET/${VERSION_NUMBER}/$TARGET-${VERSION_NUMBER}-${BINARY_NAME}
+  if ! wget ${BINARY_URL} -O ${DIR}/bin/$BINARY &> /dev/null; then
+    echo "[ERROR] Failed to download ${BINARY_URL}" >&2
+    echo "[ERROR] Skipped $TARGET-${VERSION_NAME}-${ZIP_NAME}" >&2
+    continue
+  fi
+  TARGET_ZIP_FILE=`pwd`/dist/$TARGET-${VERSION_NUMBER}-${ZIP_NAME}
+  pushd $DIR &> /dev/null
+  chmod +x bin/$BINARY
+  if [ "$TARGET" = "protoc" ]; then
+    zip -r ${TARGET_ZIP_FILE} include bin readme.txt &> /dev/null
+  else
+    zip -r ${TARGET_ZIP_FILE} bin &> /dev/null
+  fi
+  rm  bin/$BINARY
+  popd &> /dev/null
+  echo "[INFO] Successfully created ${TARGET_ZIP_FILE}"
+done
diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml
index 5086604..840bc60 100644
--- a/protoc-artifacts/pom.xml
+++ b/protoc-artifacts/pom.xml
@@ -10,7 +10,7 @@
   </parent>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protoc</artifactId>
-  <version>3.0.0-beta-3</version>
+  <version>3.0.0</version>
   <packaging>pom</packaging>
   <name>Protobuf Compiler</name>
   <description>
@@ -59,6 +59,7 @@
             <argument>build-protoc.sh</argument>
             <argument>${os.detected.name}</argument>
             <argument>${os.detected.arch}</argument>
+            <argument>protoc</argument>
           </arguments>
         </configuration>
       </plugin>
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index 2a3c677..6210a40 100755
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -30,7 +30,7 @@
 
 # Copyright 2007 Google Inc. All Rights Reserved.
 
-__version__ = '3.0.0b3'
+__version__ = '3.0.0'
 
 if __name__ != '__main__':
   try:
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 6df12be..a5ee8ac 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -252,10 +252,7 @@
     message = json_format_proto3_pb2.TestMessage()
     json_format.Parse('{"stringValue": "\\uD83D\\uDE01"}', message)
     self.assertEqual(message.string_value,
-                     b'\xF0\x9F\x98\x81'.decode("utf-8", "strict"))
-
-    # TODO: add test that UTF-8 encoded surrogate code points are rejected.
-    # UTF-8 does not allow them.
+                     b'\xF0\x9F\x98\x81'.decode('utf-8', 'strict'))
 
     # Error case: unpaired high surrogate.
     self.CheckError(
@@ -267,7 +264,6 @@
         '{"stringValue": "\\uDE01"}',
         r'Invalid \\uXXXX escape|Unpaired.*surrogate')
 
-
   def testTimestampMessage(self):
     message = json_format_proto3_pb2.TestTimestamp()
     message.value.seconds = 0
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index f8f73dd..c0d0ad4 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -76,7 +76,6 @@
 from google.protobuf.internal import wire_format
 from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message as message_mod
-from google.protobuf import symbol_database
 from google.protobuf import text_format
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
@@ -98,16 +97,12 @@
   classes at runtime, as in this example:
 
   mydescriptor = Descriptor(.....)
-  class MyProtoClass(Message):
-    __metaclass__ = GeneratedProtocolMessageType
-    DESCRIPTOR = mydescriptor
+  factory = symbol_database.Default()
+  factory.pool.AddDescriptor(mydescriptor)
+  MyProtoClass = factory.GetPrototype(mydescriptor)
   myproto_instance = MyProtoClass()
   myproto.foo_field = 23
   ...
-
-  The above example will not work for nested types. If you wish to include them,
-  use reflection.MakeClass() instead of manually instantiating the class in
-  order to create the appropriate class structure.
   """
 
   # Must be consistent with the protocol-compiler code in
@@ -926,26 +921,33 @@
   Returns:
     The unpacked message.
   """
+  # TODO(amauryfa): Don't use the factory of generated messages.
+  # To make Any work with custom factories, use the message factory of the
+  # parent message.
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf import symbol_database
+  factory = symbol_database.Default()
+
   type_url = msg.type_url
-  db = symbol_database.Default()
 
   if not type_url:
     return None
 
   # TODO(haberman): For now we just strip the hostname.  Better logic will be
   # required.
-  type_name = type_url.split("/")[-1]
-  descriptor = db.pool.FindMessageTypeByName(type_name)
+  type_name = type_url.split('/')[-1]
+  descriptor = factory.pool.FindMessageTypeByName(type_name)
 
   if descriptor is None:
     return None
 
-  message_class = db.GetPrototype(descriptor)
+  message_class = factory.GetPrototype(descriptor)
   message = message_class()
 
   message.ParseFromString(msg.value)
   return message
 
+
 def _AddEqualsMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
   def __eq__(self, other):
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index 6dc2fff..6f3b818 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -636,7 +636,7 @@
     if struct.calcsize('L') == 4:
       # Python only has signed ints, so 32-bit python can't fit an uint32
       # in an int.
-      TestGetAndDeserialize('optional_uint32', 1 << 31, long)
+      TestGetAndDeserialize('optional_uint32', 1 << 31, integer_64)
     else:
       # 64-bit python can fit uint32 inside an int
       TestGetAndDeserialize('optional_uint32', 1 << 31, int)
@@ -972,6 +972,7 @@
     proto.repeated_nested_message.add(bb=23)
     self.assertEqual(1, len(proto.repeated_nested_message))
     self.assertEqual(23, proto.repeated_nested_message[0].bb)
+    self.assertRaises(TypeError, proto.repeated_nested_message.add, 23)
 
   def testRepeatedCompositeRemove(self):
     proto = unittest_pb2.TestAllTypes()
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
index c99b426..4f5173b 100644
--- a/python/google/protobuf/internal/symbol_database_test.py
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -39,26 +39,28 @@
 
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor
+from google.protobuf import descriptor_pool
 from google.protobuf import symbol_database
 
+
 class SymbolDatabaseTest(unittest.TestCase):
 
   def _Database(self):
-    # TODO(b/17734095): Remove this difference when the C++ implementation
-    # supports multiple databases.
     if descriptor._USE_C_DESCRIPTORS:
-      return symbol_database.Default()
+      # The C++ implementation does not allow mixing descriptors from
+      # different pools.
+      db = symbol_database.SymbolDatabase(pool=descriptor_pool.Default())
     else:
       db = symbol_database.SymbolDatabase()
-      # Register representative types from unittest_pb2.
-      db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
-      db.RegisterMessage(unittest_pb2.TestAllTypes)
-      db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
-      db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
-      db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
-      db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
-      db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
-      return db
+    # Register representative types from unittest_pb2.
+    db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
+    db.RegisterMessage(unittest_pb2.TestAllTypes)
+    db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
+    db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
+    db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
+    db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+    db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+    return db
 
   def testGetPrototype(self):
     instance = self._Database().GetPrototype(
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index bb6a199..edc0cb5 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -310,7 +310,7 @@
 
   Args:
     text: Message JSON representation.
-    message: A protocol beffer message to merge into.
+    message: A protocol buffer message to merge into.
     ignore_unknown_fields: If True, do not raise errors for unknown fields.
 
   Returns:
diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py
index b215211..fc8eb32 100644
--- a/python/google/protobuf/pyext/cpp_message.py
+++ b/python/google/protobuf/pyext/cpp_message.py
@@ -48,9 +48,9 @@
   classes at runtime, as in this example:
 
   mydescriptor = Descriptor(.....)
-  class MyProtoClass(Message):
-    __metaclass__ = GeneratedProtocolMessageType
-    DESCRIPTOR = mydescriptor
+  factory = symbol_database.Default()
+  factory.pool.AddDescriptor(mydescriptor)
+  MyProtoClass = factory.GetPrototype(mydescriptor)
   myproto_instance = MyProtoClass()
   myproto.foo_field = 23
   ...
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 90438df..0987b89 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -348,9 +348,10 @@
 }
 
 // Initializes the underlying Message object of "to" so it becomes a new parent
-// repeated scalar, and copies all the values from "from" to it. A child scalar
+// map container, and copies all the values from "from" to it. A child map
 // container can be released by passing it as both from and to (e.g. making it
 // the recipient of the new parent message and copying the values from itself).
+// In fact, this is the only supported use at the moment.
 static int InitializeAndCopyToParentContainer(MapContainer* from,
                                               MapContainer* to) {
   // For now we require from == to, re-evaluate if we want to support deep copy
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index a9261f2..5535338 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -1041,7 +1041,12 @@
 }
 
 // Initializes fields of a message. Used in constructors.
-int InitAttributes(CMessage* self, PyObject* kwargs) {
+int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
+  if (args != NULL && PyTuple_Size(args) != 0) {
+    PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
+    return -1;
+  }
+
   if (kwargs == NULL) {
     return 0;
   }
@@ -1167,7 +1172,7 @@
       }
       CMessage* cmessage = reinterpret_cast<CMessage*>(message.get());
       if (PyDict_Check(value)) {
-        if (InitAttributes(cmessage, value) < 0) {
+        if (InitAttributes(cmessage, NULL, value) < 0) {
           return -1;
         }
       } else {
@@ -1245,12 +1250,7 @@
 // The __init__ method of Message classes.
 // It initializes fields from keywords passed to the constructor.
 static int Init(CMessage* self, PyObject* args, PyObject* kwargs) {
-  if (PyTuple_Size(args) != 0) {
-    PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
-    return -1;
-  }
-
-  return InitAttributes(self, kwargs);
+  return InitAttributes(self, args, kwargs);
 }
 
 // ---------------------------------------------------------------------
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 8b399e0..c44a2ae 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -237,7 +237,9 @@
 PyObject* HasField(CMessage* self, PyObject* arg);
 
 // Initializes values of fields on a newly constructed message.
-int InitAttributes(CMessage* self, PyObject* kwargs);
+// Note that positional arguments are disallowed: 'args' must be NULL or the
+// empty tuple.
+int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs);
 
 PyObject* MergeFrom(CMessage* self, PyObject* arg);
 
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index 4f339e7..bb2f6db 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -146,7 +146,7 @@
   cmsg->owner = self->owner;
   cmsg->message = sub_message;
   cmsg->parent = self->parent;
-  if (cmessage::InitAttributes(cmsg, kwargs) < 0) {
+  if (cmessage::InitAttributes(cmsg, args, kwargs) < 0) {
     Py_DECREF(cmsg);
     return NULL;
   }
@@ -166,7 +166,7 @@
 
   // Create a new Message detached from the rest.
   PyObject* py_cmsg = PyEval_CallObjectWithKeywords(
-      self->child_message_class->AsPyObject(), NULL, kwargs);
+      self->child_message_class->AsPyObject(), args, kwargs);
   if (py_cmsg == NULL)
     return NULL;
 
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
index 0c75726..51c8332 100755
--- a/python/google/protobuf/reflection.py
+++ b/python/google/protobuf/reflection.py
@@ -58,13 +58,7 @@
   from google.protobuf.internal import python_message as message_impl
 
 # The type of all Message classes.
-# Part of the public interface.
-#
-# Used by generated files, but clients can also use it at runtime:
-#   mydescriptor = pool.FindDescriptor(.....)
-#   class MyProtoClass(Message):
-#     __metaclass__ = GeneratedProtocolMessageType
-#     DESCRIPTOR = mydescriptor
+# Part of the public interface, but normally only used by message factories.
 GeneratedProtocolMessageType = message_impl.GeneratedProtocolMessageType
 
 
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
index 87760f2..aa466ab 100644
--- a/python/google/protobuf/symbol_database.py
+++ b/python/google/protobuf/symbol_database.py
@@ -30,11 +30,9 @@
 
 """A database of Python protocol buffer generated symbols.
 
-SymbolDatabase makes it easy to create new instances of a registered type, given
-only the type's protocol buffer symbol name. Once all symbols are registered,
-they can be accessed using either the MessageFactory interface which
-SymbolDatabase exposes, or the DescriptorPool interface of the underlying
-pool.
+SymbolDatabase is the MessageFactory for messages generated at compile time,
+and makes it easy to create new instances of a registered type, given only the
+type's protocol buffer symbol name.
 
 Example usage:
 
@@ -61,27 +59,17 @@
 
 
 from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
 
 
-class SymbolDatabase(object):
-  """A database of Python generated symbols.
-
-  SymbolDatabase also models message_factory.MessageFactory.
-
-  The symbol database can be used to keep a global registry of all protocol
-  buffer types used within a program.
-  """
-
-  def __init__(self, pool=None):
-    """Constructor."""
-
-    self._symbols = {}
-    self._symbols_by_file = {}
-    self.pool = pool or descriptor_pool.Default()
+class SymbolDatabase(message_factory.MessageFactory):
+  """A database of Python generated symbols."""
 
   def RegisterMessage(self, message):
     """Registers the given message type in the local database.
 
+    Calls to GetSymbol() and GetMessages() will return messages registered here.
+
     Args:
       message: a message.Message, to be registered.
 
@@ -90,10 +78,7 @@
     """
 
     desc = message.DESCRIPTOR
-    self._symbols[desc.full_name] = message
-    if desc.file.name not in self._symbols_by_file:
-      self._symbols_by_file[desc.file.name] = {}
-    self._symbols_by_file[desc.file.name][desc.full_name] = message
+    self._classes[desc.full_name] = message
     self.pool.AddDescriptor(desc)
     return message
 
@@ -136,47 +121,46 @@
       KeyError: if the symbol could not be found.
     """
 
-    return self._symbols[symbol]
-
-  def GetPrototype(self, descriptor):
-    """Builds a proto2 message class based on the passed in descriptor.
-
-    Passing a descriptor with a fully qualified name matching a previous
-    invocation will cause the same class to be returned.
-
-    Args:
-      descriptor: The descriptor to build from.
-
-    Returns:
-      A class describing the passed in descriptor.
-    """
-
-    return self.GetSymbol(descriptor.full_name)
+    return self._classes[symbol]
 
   def GetMessages(self, files):
-    """Gets all the messages from a specified file.
+    # TODO(amauryfa): Fix the differences with MessageFactory.
+    """Gets all registered messages from a specified file.
 
-    This will find and resolve dependencies, failing if they are not registered
-    in the symbol database.
-
+    Only messages already created and registered will be returned; (this is the
+    case for imported _pb2 modules)
+    But unlike MessageFactory, this version also returns nested messages.
 
     Args:
       files: The file names to extract messages from.
 
     Returns:
-      A dictionary mapping proto names to the message classes. This will include
-      any dependent messages as well as any messages defined in the same file as
-      a specified message.
+      A dictionary mapping proto names to the message classes.
 
     Raises:
       KeyError: if a file could not be found.
     """
 
+    def _GetAllMessageNames(desc):
+      """Walk a message Descriptor and recursively yields all message names."""
+      yield desc.full_name
+      for msg_desc in desc.nested_types:
+        for full_name in _GetAllMessageNames(msg_desc):
+          yield full_name
+
     result = {}
-    for f in files:
-      result.update(self._symbols_by_file[f])
+    for file_name in files:
+      file_desc = self.pool.FindFileByName(file_name)
+      for msg_desc in file_desc.message_types_by_name.values():
+        for full_name in _GetAllMessageNames(msg_desc):
+          try:
+            result[full_name] = self._classes[full_name]
+          except KeyError:
+            # This descriptor has no registered class, skip it.
+            pass
     return result
 
+
 _DEFAULT = SymbolDatabase(pool=descriptor_pool.Default())
 
 
diff --git a/python/setup.cfg b/python/setup.cfg
new file mode 100644
index 0000000..2a9acf1
--- /dev/null
+++ b/python/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1
diff --git a/ruby/Rakefile b/ruby/Rakefile
index fa29c31..ba1cf4c 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -31,7 +31,7 @@
 unless ENV['IN_DOCKER'] == 'true'
   well_known_protos.each do |proto_file|
     input_file = "../src/" + proto_file
-    output_file = "lib/" + proto_file.sub(/\.proto$/, ".rb")
+    output_file = "lib/" + proto_file.sub(/\.proto$/, "_pb.rb")
     genproto_output << output_file
     file output_file => input_file do |file_task|
       sh "../src/protoc -I../src --ruby_out=lib #{input_file}"
@@ -80,10 +80,15 @@
 
 # Proto for tests.
 genproto_output << "tests/generated_code.rb"
+genproto_output << "tests/test_import.rb"
 file "tests/generated_code.rb" => "tests/generated_code.proto" do |file_task|
   sh "../src/protoc --ruby_out=. tests/generated_code.proto"
 end
 
+file "tests/test_import.rb" => "tests/test_import.proto" do |file_task|
+  sh "../src/protoc --ruby_out=. tests/test_import.proto"
+end
+
 task :genproto => genproto_output
 
 task :clean do
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index f6bea50..08c72bc 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -54,7 +54,7 @@
 static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) {
   size_t* hd_ofs = ALLOC(size_t);
   *hd_ofs = ofs;
-  upb_handlers_addcleanup(h, hd_ofs, free);
+  upb_handlers_addcleanup(h, hd_ofs, xfree);
   return hd_ofs;
 }
 
@@ -69,7 +69,7 @@
   submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
   hd->ofs = ofs;
   hd->md = upb_fielddef_msgsubdef(f);
-  upb_handlers_addcleanup(h, hd, free);
+  upb_handlers_addcleanup(h, hd, xfree);
   return hd;
 }
 
@@ -99,7 +99,7 @@
   } else {
     hd->md = NULL;
   }
-  upb_handlers_addcleanup(h, hd, free);
+  upb_handlers_addcleanup(h, hd, xfree);
   return hd;
 }
 
@@ -135,7 +135,7 @@
   VALUE ary = (VALUE)closure;
   VALUE str = rb_str_new2("");
   rb_enc_associate(str, kRubyStringUtf8Encoding);
-  RepeatedField_push(ary, str);
+  RepeatedField_push_native(ary, &str);
   return (void*)str;
 }
 
@@ -146,7 +146,7 @@
   VALUE ary = (VALUE)closure;
   VALUE str = rb_str_new2("");
   rb_enc_associate(str, kRubyString8bitEncoding);
-  RepeatedField_push(ary, str);
+  RepeatedField_push_native(ary, &str);
   return (void*)str;
 }
 
@@ -182,6 +182,23 @@
   return len;
 }
 
+static bool stringdata_end_handler(void* closure, const void* hd) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  VALUE rb_str = DEREF(msg, *ofs, VALUE);
+  rb_obj_freeze(rb_str);
+  return true;
+}
+
+static bool appendstring_end_handler(void* closure, const void* hd) {
+  VALUE ary = (VALUE)closure;
+  int size = RepeatedField_size(ary);
+  VALUE* last = RepeatedField_index_native(ary, size - 1);
+  VALUE rb_str = *last;
+  rb_obj_freeze(rb_str);
+  return true;
+}
+
 // Appends a submessage to a repeated field (a regular Ruby array for now).
 static void *appendsubmsg_handler(void *closure, const void *hd) {
   VALUE ary = (VALUE)closure;
@@ -238,10 +255,54 @@
 // value into the map.
 typedef struct {
   VALUE map;
+  const map_handlerdata_t* handlerdata;
   char key_storage[NATIVE_SLOT_MAX_SIZE];
   char value_storage[NATIVE_SLOT_MAX_SIZE];
 } map_parse_frame_t;
 
+static void MapParseFrame_mark(void* _self) {
+  map_parse_frame_t* frame = _self;
+
+  // This shouldn't strictly be necessary since this should be rooted by the
+  // message itself, but it can't hurt.
+  rb_gc_mark(frame->map);
+
+  native_slot_mark(frame->handlerdata->key_field_type, &frame->key_storage);
+  native_slot_mark(frame->handlerdata->value_field_type, &frame->value_storage);
+}
+
+void MapParseFrame_free(void* self) {
+  xfree(self);
+}
+
+rb_data_type_t MapParseFrame_type = {
+  "MapParseFrame",
+  { MapParseFrame_mark, MapParseFrame_free, NULL },
+};
+
+// Array of Ruby objects wrapping map_parse_frame_t.
+// We don't allow multiple concurrent decodes, so we assume that this global
+// variable is specific to the "current" decode.
+VALUE map_parse_frames;
+
+static map_parse_frame_t* map_push_frame(VALUE map,
+                                         const map_handlerdata_t* handlerdata) {
+  map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
+  frame->handlerdata = handlerdata;
+  frame->map = map;
+  native_slot_init(handlerdata->key_field_type, &frame->key_storage);
+  native_slot_init(handlerdata->value_field_type, &frame->value_storage);
+
+  rb_ary_push(map_parse_frames,
+              TypedData_Wrap_Struct(rb_cObject, &MapParseFrame_type, frame));
+
+  return frame;
+}
+
+static void map_pop_frame() {
+  rb_ary_pop(map_parse_frames);
+}
+
 // Handler to begin a map entry: allocates a temporary frame. This is the
 // 'startsubmsg' handler on the msgdef that contains the map field.
 static void *startmapentry_handler(void *closure, const void *hd) {
@@ -249,13 +310,7 @@
   const map_handlerdata_t* mapdata = hd;
   VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE);
 
-  map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
-  frame->map = map_rb;
-
-  native_slot_init(mapdata->key_field_type, &frame->key_storage);
-  native_slot_init(mapdata->value_field_type, &frame->value_storage);
-
-  return frame;
+  return map_push_frame(map_rb, mapdata);
 }
 
 // Handler to end a map entry: inserts the value defined during the message into
@@ -281,7 +336,7 @@
       &frame->value_storage);
 
   Map_index_set(frame->map, key, value);
-  free(frame);
+  map_pop_frame();
 
   return true;
 }
@@ -360,6 +415,13 @@
   return (void*)str;
 }
 
+static bool oneofstring_end_handler(void* closure, const void* hd) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+  rb_obj_freeze(DEREF(msg, oneofdata->ofs, VALUE));
+  return true;
+}
+
 // Handler for a submessage field in a oneof.
 static void *oneofsubmsg_handler(void *closure,
                                  const void *hd) {
@@ -426,6 +488,7 @@
                                appendbytes_handler : appendstr_handler,
                                NULL);
       upb_handlers_setstring(h, f, stringdata_handler, NULL);
+      upb_handlers_setendstr(h, f, appendstring_end_handler, NULL);
       break;
     }
     case UPB_TYPE_MESSAGE: {
@@ -462,6 +525,7 @@
                                is_bytes ? bytes_handler : str_handler,
                                &attr);
       upb_handlers_setstring(h, f, stringdata_handler, &attr);
+      upb_handlers_setendstr(h, f, stringdata_end_handler, &attr);
       upb_handlerattr_uninit(&attr);
       break;
     }
@@ -484,7 +548,7 @@
   map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
   upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
 
-  upb_handlers_addcleanup(h, hd, free);
+  upb_handlers_addcleanup(h, hd, xfree);
   upb_handlerattr_sethandlerdata(&attr, hd);
   upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
   upb_handlerattr_uninit(&attr);
@@ -499,7 +563,7 @@
   map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
   upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
 
-  upb_handlers_addcleanup(h, hd, free);
+  upb_handlers_addcleanup(h, hd, xfree);
   upb_handlerattr_sethandlerdata(&attr, hd);
   upb_handlers_setendmsg(h, endmap_handler, &attr);
 
@@ -546,6 +610,7 @@
                                oneofbytes_handler : oneofstr_handler,
                                &attr);
       upb_handlers_setstring(h, f, stringdata_handler, NULL);
+      upb_handlers_setendstr(h, f, oneofstring_end_handler, &attr);
       break;
     }
     case UPB_TYPE_MESSAGE: {
@@ -710,6 +775,10 @@
   msg_rb = rb_class_new_instance(0, NULL, msgklass);
   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
 
+  // We generally expect this to be clear already, but clear it in case parsing
+  // previously got interrupted somehow.
+  rb_ary_clear(map_parse_frames);
+
   {
     const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
     const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
@@ -754,6 +823,10 @@
   msg_rb = rb_class_new_instance(0, NULL, msgklass);
   TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
 
+  // We generally expect this to be clear already, but clear it in case parsing
+  // previously got interrupted somehow.
+  rb_ary_clear(map_parse_frames);
+
   {
     const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
     stackenv se;
@@ -863,9 +936,13 @@
 
   assert(BUILTIN_TYPE(str) == RUBY_T_STRING);
 
-  // Ensure that the string has the correct encoding. We also check at field-set
-  // time, but the user may have mutated the string object since then.
-  native_slot_validate_string_encoding(upb_fielddef_type(f), str);
+  // We should be guaranteed that the string has the correct encoding because
+  // we ensured this at assignment time and then froze the string.
+  if (upb_fielddef_type(f) == UPB_TYPE_STRING) {
+    assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyStringUtf8Encoding);
+  } else {
+    assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyString8bitEncoding);
+  }
 
   upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
                     &subsink);
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
index 92fc728..12f1f9d 100644
--- a/ruby/ext/google/protobuf_c/map.c
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -63,16 +63,16 @@
 // construct a key byte sequence if needed. |out_key| and |out_length| provide
 // the resulting key data/length.
 #define TABLE_KEY_BUF_LENGTH 8  // sizeof(uint64_t)
-static void table_key(Map* self, VALUE key,
-                      char* buf,
-                      const char** out_key,
-                      size_t* out_length) {
+static VALUE table_key(Map* self, VALUE key,
+                       char* buf,
+                       const char** out_key,
+                       size_t* out_length) {
   switch (self->key_type) {
     case UPB_TYPE_BYTES:
     case UPB_TYPE_STRING:
       // Strings: use string content directly.
       Check_Type(key, T_STRING);
-      native_slot_validate_string_encoding(self->key_type, key);
+      key = native_slot_encode_and_freeze_string(self->key_type, key);
       *out_key = RSTRING_PTR(key);
       *out_length = RSTRING_LEN(key);
       break;
@@ -93,6 +93,8 @@
       assert(false);
       break;
   }
+
+  return key;
 }
 
 static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) {
@@ -357,7 +359,7 @@
   const char* keyval = NULL;
   size_t length = 0;
   upb_value v;
-  table_key(self, key, keybuf, &keyval, &length);
+  key = table_key(self, key, keybuf, &keyval, &length);
 
   if (upb_strtable_lookup2(&self->table, keyval, length, &v)) {
     void* mem = value_memory(&v);
@@ -383,7 +385,7 @@
   size_t length = 0;
   upb_value v;
   void* mem;
-  table_key(self, key, keybuf, &keyval, &length);
+  key = table_key(self, key, keybuf, &keyval, &length);
 
   mem = value_memory(&v);
   native_slot_set(self->value_type, self->value_type_class, mem, value);
@@ -411,7 +413,7 @@
   char keybuf[TABLE_KEY_BUF_LENGTH];
   const char* keyval = NULL;
   size_t length = 0;
-  table_key(self, key, keybuf, &keyval, &length);
+  key = table_key(self, key, keybuf, &keyval, &length);
 
   if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) {
     return Qtrue;
@@ -434,7 +436,7 @@
   const char* keyval = NULL;
   size_t length = 0;
   upb_value v;
-  table_key(self, key, keybuf, &keyval, &length);
+  key = table_key(self, key, keybuf, &keyval, &length);
 
   if (upb_strtable_remove2(&self->table, keyval, length, &v)) {
     void* mem = value_memory(&v);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index 7cde4ae..9896366 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -112,4 +112,6 @@
 
   upb_def_to_ruby_obj_map = rb_hash_new();
   rb_gc_register_address(&upb_def_to_ruby_obj_map);
+  map_parse_frames = rb_ary_new();
+  rb_gc_register_address(&map_parse_frames);
 }
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index 2834c89..d5ced56 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -166,6 +166,8 @@
 extern VALUE cError;
 extern VALUE cParseError;
 
+extern VALUE map_parse_frames;
+
 // We forward-declare all of the Ruby method implementations here because we
 // sometimes call the methods directly across .c files, rather than going
 // through Ruby's method dispatching (e.g. during message parse). It's cleaner
@@ -313,7 +315,7 @@
 void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from);
 bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
 
-void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value);
+VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value);
 void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value);
 
 extern rb_encoding* kRubyStringUtf8Encoding;
@@ -366,6 +368,7 @@
 VALUE RepeatedField_each(VALUE _self);
 VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self);
 void* RepeatedField_index_native(VALUE _self, int index);
+int RepeatedField_size(VALUE _self);
 VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val);
 void RepeatedField_reserve(RepeatedField* self, int new_size);
 VALUE RepeatedField_push(VALUE _self, VALUE val);
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
index 83afbc9..47c207a 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -244,6 +244,11 @@
   return RepeatedField_memoryat(self, index, element_size);
 }
 
+int RepeatedField_size(VALUE _self) {
+  RepeatedField* self = ruby_to_RepeatedField(_self);
+  return self->size;
+}
+
 /*
  * Private ruby method, used by RepeatedField.pop
  */
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c
index 1c83978..3ff2bda 100644
--- a/ruby/ext/google/protobuf_c/storage.c
+++ b/ruby/ext/google/protobuf_c/storage.c
@@ -117,25 +117,24 @@
   }
 }
 
-void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) {
-  bool bad_encoding = false;
-  rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value));
-  if (type == UPB_TYPE_STRING) {
-    bad_encoding =
-        string_encoding != kRubyStringUtf8Encoding &&
-        string_encoding != kRubyStringASCIIEncoding;
-  } else {
-    bad_encoding =
-        string_encoding != kRubyString8bitEncoding;
+VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) {
+  rb_encoding* desired_encoding = (type == UPB_TYPE_STRING) ?
+      kRubyStringUtf8Encoding : kRubyString8bitEncoding;
+  VALUE desired_encoding_value = rb_enc_from_encoding(desired_encoding);
+
+  // Note: this will not duplicate underlying string data unless necessary.
+  value = rb_str_encode(value, desired_encoding_value, 0, Qnil);
+
+  if (type == UPB_TYPE_STRING &&
+      rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) {
+    rb_raise(rb_eEncodingError, "String is invalid UTF-8");
   }
-  // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT
-  // (for bytes fields).
-  if (bad_encoding) {
-    rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)",
-             (type == UPB_TYPE_STRING) ? "string" : "bytes",
-             (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT",
-             rb_enc_name(string_encoding));
-  }
+
+  // Ensure the data remains valid.  Since we called #encode a moment ago,
+  // this does not freeze the string the user assigned.
+  rb_obj_freeze(value);
+
+  return value;
 }
 
 void native_slot_set(upb_fieldtype_t type, VALUE type_class,
@@ -181,8 +180,8 @@
       if (CLASS_OF(value) != rb_cString) {
         rb_raise(rb_eTypeError, "Invalid argument for string field.");
       }
-      native_slot_validate_string_encoding(type, value);
-      DEREF(memory, VALUE) = value;
+
+      DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value);
       break;
     }
     case UPB_TYPE_MESSAGE: {
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
index 74a2a1d..544ebc0 100644
--- a/ruby/ext/google/protobuf_c/upb.c
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -11076,8 +11076,8 @@
 
     case UPB_TYPE_STRING: {
       upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
-      upb_sink_endstr(&p->top->sink, sel);
       p->top--;
+      upb_sink_endstr(&p->top->sink, sel);
       break;
     }
 
@@ -11175,7 +11175,7 @@
       sel = getsel_for_handlertype(p, UPB_HANDLER_STRING);
       upb_sink_putstring(&subsink, sel, buf, len, NULL);
       sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
-      upb_sink_endstr(&subsink, sel);
+      upb_sink_endstr(&p->top->sink, sel);
       multipart_end(p);
       break;
     }
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index c542abf..286d8fe 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -1,6 +1,6 @@
 Gem::Specification.new do |s|
   s.name        = "google-protobuf"
-  s.version     = "3.0.0.alpha.6.0.0"
+  s.version     = "3.0.0"
   s.licenses    = ["BSD"]
   s.summary     = "Protocol Buffers"
   s.description = "Protocol Buffers are Google's data interchange format."
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
index 62bdd1b..9b8d823 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -45,7 +45,7 @@
   require 'google/protobuf_java'
 else
   begin
-    require "google/#{RUBY_VERSION.sub(/\.\d$/, '')}/protobuf_c"
+    require "google/#{RUBY_VERSION.sub(/\.\d+$/, '')}/protobuf_c"
   rescue LoadError
     require 'google/protobuf_c'
   end
diff --git a/ruby/lib/google/protobuf/well_known_types.rb b/ruby/lib/google/protobuf/well_known_types.rb
new file mode 100644
index 0000000..547de87
--- /dev/null
+++ b/ruby/lib/google/protobuf/well_known_types.rb
@@ -0,0 +1,212 @@
+#!/usr/bin/ruby
+# 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.
+
+require 'google/protobuf/any_pb'
+require 'google/protobuf/duration_pb'
+require 'google/protobuf/field_mask_pb'
+require 'google/protobuf/struct_pb'
+require 'google/protobuf/timestamp_pb'
+
+module Google
+  module Protobuf
+
+    Any.class_eval do
+      def pack(msg, type_url_prefix='type.googleapis.com/')
+        if type_url_prefix.empty? or type_url_prefix[-1] != '/' then
+          self.type_url = "#{type_url_prefix}/#{msg.class.descriptor.name}"
+        else
+          self.type_url = "#{type_url_prefix}#{msg.class.descriptor.name}"
+        end
+        self.value = msg.to_proto
+      end
+
+      def unpack(klass)
+        if self.is(klass) then
+          klass.decode(self.value)
+        else
+          nil
+        end
+      end
+
+      def type_name
+        return self.type_url.split("/")[-1]
+      end
+
+      def is(klass)
+        return self.type_name == klass.descriptor.name
+      end
+    end
+
+    Timestamp.class_eval do
+      def to_time
+        Time.at(self.to_f)
+      end
+
+      def from_time(time)
+        self.seconds = time.to_i
+        self.nanos = time.nsec
+      end
+
+      def to_i
+        self.seconds
+      end
+
+      def to_f
+        self.seconds + (self.nanos.to_f / 1_000_000_000)
+      end
+    end
+
+    Duration.class_eval do
+      def to_f
+        self.seconds + (self.nanos.to_f / 1_000_000_000)
+      end
+    end
+
+    class UnexpectedStructType < Google::Protobuf::Error; end
+
+    Value.class_eval do
+      def to_ruby(recursive = false)
+        case self.kind
+        when :struct_value
+          if recursive
+            self.struct_value.to_h
+          else
+            self.struct_value
+          end
+        when :list_value
+          if recursive
+            self.list_value.to_a
+          else
+            self.list_value
+          end
+        when :null_value
+          nil
+        when :number_value
+          self.number_value
+        when :string_value
+          self.string_value
+        when :bool_value
+          self.bool_value
+        else
+          raise UnexpectedStructType
+        end
+      end
+
+      def from_ruby(value)
+        case value
+        when NilClass
+          self.null_value = 0
+        when Numeric
+          self.number_value = value
+        when String
+          self.string_value = value
+        when TrueClass
+          self.bool_value = true
+        when FalseClass
+          self.bool_value = false
+        when Struct
+          self.struct_value = value
+        when Hash
+          self.struct_value = Struct.from_hash(value)
+        when ListValue
+          self.list_value = value
+        when Array
+          self.list_value = ListValue.from_a(value)
+        else
+          raise UnexpectedStructType
+        end
+      end
+    end
+
+    Struct.class_eval do
+      def [](key)
+        self.fields[key].to_ruby
+      end
+
+      def []=(key, value)
+        unless key.is_a?(String)
+          raise UnexpectedStructType, "Struct keys must be strings."
+        end
+        self.fields[key] ||= Google::Protobuf::Value.new
+        self.fields[key].from_ruby(value)
+      end
+
+      def to_h
+        ret = {}
+        self.fields.each { |key, val| ret[key] = val.to_ruby(true) }
+        ret
+      end
+
+      def self.from_hash(hash)
+        ret = Struct.new
+        hash.each { |key, val| ret[key] = val }
+        ret
+      end
+    end
+
+    ListValue.class_eval do
+      include Enumerable
+
+      def length
+        self.values.length
+      end
+
+      def [](index)
+        self.values[index].to_ruby
+      end
+
+      def []=(index, value)
+        self.values[index].from_ruby(value)
+      end
+
+      def <<(value)
+        wrapper = Google::Protobuf::Value.new
+        wrapper.from_ruby(value)
+        self.values << wrapper
+      end
+
+      def each
+        self.values.each { |x| yield(x.to_ruby) }
+      end
+
+      def to_a
+        self.values.map { |x| x.to_ruby(true) }
+      end
+
+      def self.from_a(arr)
+        ret = ListValue.new
+        arr.each { |val| ret << val }
+        ret
+      end
+    end
+
+  end
+end
diff --git a/ruby/pom.xml b/ruby/pom.xml
index 4cbd6d3..99e8449 100644
--- a/ruby/pom.xml
+++ b/ruby/pom.xml
@@ -86,7 +86,7 @@
         <dependency>
             <groupId>com.google.protobuf</groupId>
             <artifactId>protobuf-java</artifactId>
-            <version>3.0.0-alpha-3</version>
+            <version>3.0.0-beta-4</version>
         </dependency>
     </dependencies>
 </project>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
index 2d4c03b..3adaa2a 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
@@ -148,8 +148,8 @@
      */
     @JRubyMethod(name = "[]=")
     public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) {
-        Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass);
-        Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass);
+        key = Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass);
+        value = Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass);
         IRubyObject symbol;
         if (valueType == Descriptors.FieldDescriptor.Type.ENUM &&
                 Utils.isRubyNum(value) &&
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
index 12893f7..462f8a6 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -504,7 +504,7 @@
                 break;
             case BYTES:
             case STRING:
-                Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value);
+                Utils.validateStringEncoding(context, fieldDescriptor.getType(), value);
                 RubyString str = (RubyString) value;
                 switch (fieldDescriptor.getType()) {
                     case BYTES:
@@ -695,7 +695,7 @@
                     }
                 }
                 if (addValue) {
-                    Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+                    value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
                     this.fields.put(fieldDescriptor, value);
                 } else {
                     this.fields.remove(fieldDescriptor);
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
index 946f9e7..ae2907a 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java
@@ -110,7 +110,7 @@
     @JRubyMethod(name = "[]=")
     public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) {
         int arrIndex = normalizeArrayIndex(index);
-        Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+        value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
         IRubyObject defaultValue = defaultValue(context);
         for (int i = this.storage.size(); i < arrIndex; i++) {
             this.storage.set(i, defaultValue);
@@ -166,7 +166,7 @@
     public IRubyObject push(ThreadContext context, IRubyObject value) {
         if (!(fieldType == Descriptors.FieldDescriptor.Type.MESSAGE &&
             value == context.runtime.getNil())) {
-            Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
+            value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass);
         }
         this.storage.add(value);
         return this.storage;
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
index 596a097..f199feb 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java
@@ -64,8 +64,8 @@
         return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase());
     }
 
-    public static void checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType,
-                            IRubyObject value, RubyModule typeClass) {
+    public static IRubyObject checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType,
+                                        IRubyObject value, RubyModule typeClass) {
         Ruby runtime = context.runtime;
         Object val;
         switch(fieldType) {
@@ -106,7 +106,7 @@
                 break;
             case BYTES:
             case STRING:
-                validateStringEncoding(context.runtime, fieldType, value);
+                value = validateStringEncoding(context, fieldType, value);
                 break;
             case MESSAGE:
                 if (value.getMetaClass() != typeClass) {
@@ -127,6 +127,7 @@
             default:
                 break;
         }
+        return value;
     }
 
     public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) {
@@ -148,10 +149,16 @@
                 return runtime.newFloat((Double) value);
             case BOOL:
                 return (Boolean) value ? runtime.getTrue() : runtime.getFalse();
-            case BYTES:
-                return runtime.newString(((ByteString) value).toStringUtf8());
-            case STRING:
-                return runtime.newString(value.toString());
+            case BYTES: {
+                IRubyObject wrapped = runtime.newString(((ByteString) value).toStringUtf8());
+                wrapped.setFrozen(true);
+                return wrapped;
+            }
+            case STRING: {
+                IRubyObject wrapped = runtime.newString(value.toString());
+                wrapped.setFrozen(true);
+                return wrapped;
+            }
             default:
                 return runtime.getNil();
         }
@@ -180,25 +187,21 @@
         }
     }
 
-    public static void validateStringEncoding(Ruby runtime, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
+    public static IRubyObject validateStringEncoding(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) {
         if (!(value instanceof RubyString))
-            throw runtime.newTypeError("Invalid argument for string field.");
-        Encoding encoding = ((RubyString) value).getEncoding();
+            throw context.runtime.newTypeError("Invalid argument for string field.");
         switch(type) {
             case BYTES:
-                if (encoding != ASCIIEncoding.INSTANCE)
-                    throw runtime.newTypeError("Encoding for bytes fields" +
-                            " must be \"ASCII-8BIT\", but was " + encoding);
+                value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::ASCII_8BIT"));
                 break;
             case STRING:
-                if (encoding != UTF8Encoding.INSTANCE
-                        && encoding != USASCIIEncoding.INSTANCE)
-                    throw runtime.newTypeError("Encoding for string fields" +
-                            " must be \"UTF-8\" or \"ASCII\", but was " + encoding);
+                value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::UTF_8"));
                 break;
             default:
                 break;
         }
+        value.setFrozen(true);
+        return value;
     }
 
     public static void checkNameAvailability(ThreadContext context, String name) {
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index fee07e3..8b6d329 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -255,14 +255,17 @@
       m = TestMessage.new
 
       # Assigning a normal (ASCII or UTF8) string to a bytes field, or
-      # ASCII-8BIT to a string field, raises an error.
-      assert_raise TypeError do
-        m.optional_bytes = "Test string ASCII".encode!('ASCII')
-      end
-      assert_raise TypeError do
+      # ASCII-8BIT to a string field will convert to the proper encoding.
+      m.optional_bytes = "Test string ASCII".encode!('ASCII')
+      assert m.optional_bytes.frozen?
+      assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding
+      assert_equal "Test string ASCII", m.optional_bytes
+
+      assert_raise Encoding::UndefinedConversionError do
         m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8')
       end
-      assert_raise TypeError do
+
+      assert_raise Encoding::UndefinedConversionError do
         m.optional_string = ["FFFF"].pack('H*')
       end
 
@@ -270,11 +273,10 @@
       m.optional_bytes = ["FFFF"].pack('H*')
       m.optional_string = "\u0100"
 
-      # strings are mutable so we can do this, but serialize should catch it.
+      # strings are immutable so we can't do this, but serialize should catch it.
       m.optional_string = "asdf".encode!('UTF-8')
-      m.optional_string.encode!('ASCII-8BIT')
-      assert_raise TypeError do
-        data = TestMessage.encode(m)
+      assert_raise RuntimeError do
+        m.optional_string.encode!('ASCII-8BIT')
       end
     end
 
@@ -466,9 +468,9 @@
       assert m.length == 2
 
       m2 = m.dup
-      assert m == m2
+      assert_equal m, m2
       assert m.hash != 0
-      assert m.hash == m2.hash
+      assert_equal m.hash, m2.hash
 
       collected = {}
       m.each { |k,v| collected[v] = k }
@@ -558,7 +560,7 @@
       assert_raise TypeError do
         m[1] = 1
       end
-      assert_raise TypeError do
+      assert_raise Encoding::UndefinedConversionError do
         bytestring = ["FFFF"].pack("H*")
         m[bytestring] = 1
       end
@@ -566,9 +568,8 @@
       m = Google::Protobuf::Map.new(:bytes, :int32)
       bytestring = ["FFFF"].pack("H*")
       m[bytestring] = 1
-      assert_raise TypeError do
-        m["asdf"] = 1
-      end
+      # Allowed -- we will automatically convert to ASCII-8BIT.
+      m["asdf"] = 1
       assert_raise TypeError do
         m[1] = 1
       end
@@ -853,15 +854,22 @@
 
     def test_encode_decode_helpers
       m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2'])
+      assert_equal 'foo', m.optional_string
+      assert_equal ['bar1', 'bar2'], m.repeated_string
+
       json = m.to_json
       m2 = TestMessage.decode_json(json)
-      assert m2.optional_string == 'foo'
-      assert m2.repeated_string == ['bar1', 'bar2']
+      assert_equal 'foo', m2.optional_string
+      assert_equal ['bar1', 'bar2'], m2.repeated_string
+      if RUBY_PLATFORM != "java"
+        assert m2.optional_string.frozen?
+        assert m2.repeated_string[0].frozen?
+      end
 
       proto = m.to_proto
       m2 = TestMessage.decode(proto)
-      assert m2.optional_string == 'foo'
-      assert m2.repeated_string == ['bar1', 'bar2']
+      assert_equal 'foo', m2.optional_string
+      assert_equal ['bar1', 'bar2'], m2.repeated_string
     end
 
     def test_protobuf_encode_decode_helpers
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
index 42d82a6..62fd83e 100644
--- a/ruby/tests/generated_code.proto
+++ b/ruby/tests/generated_code.proto
@@ -1,6 +1,6 @@
 syntax = "proto3";
 
-package A.B.C;
+package a.b.c;
 
 message TestMessage {
   int32 optional_int32 = 1;
diff --git a/ruby/tests/generated_code_test.rb b/ruby/tests/generated_code_test.rb
index daef357..b92b046 100644
--- a/ruby/tests/generated_code_test.rb
+++ b/ruby/tests/generated_code_test.rb
@@ -3,7 +3,8 @@
 # generated_code.rb is in the same directory as this test.
 $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
 
-require 'generated_code'
+require 'generated_code_pb'
+require 'test_import_pb'
 require 'test/unit'
 
 class GeneratedCodeTest < Test::Unit::TestCase
@@ -13,5 +14,6 @@
     # successfully creates message definitions and classes, not to test every
     # aspect of the extension (basic.rb is for that).
     m = A::B::C::TestMessage.new()
+    m2 = FooBar::TestImportedMessage.new()
   end
 end
diff --git a/ruby/tests/test_import.proto b/ruby/tests/test_import.proto
new file mode 100644
index 0000000..230484e
--- /dev/null
+++ b/ruby/tests/test_import.proto
@@ -0,0 +1,5 @@
+syntax = "proto3";
+
+package foo_bar;
+
+message TestImportedMessage {}
diff --git a/ruby/tests/well_known_types_test.rb b/ruby/tests/well_known_types_test.rb
new file mode 100644
index 0000000..9b46632
--- /dev/null
+++ b/ruby/tests/well_known_types_test.rb
@@ -0,0 +1,122 @@
+#!/usr/bin/ruby
+
+require 'test/unit'
+require 'google/protobuf/well_known_types'
+
+class TestWellKnownTypes < Test::Unit::TestCase
+  def test_timestamp
+    ts = Google::Protobuf::Timestamp.new
+
+    assert_equal Time.at(0), ts.to_time
+
+    ts.seconds = 12345
+    assert_equal Time.at(12345), ts.to_time
+    assert_equal 12345, ts.to_i
+
+    ts.from_time(Time.at(123456, 654321))
+    assert_equal 123456, ts.seconds
+    assert_equal 654321000, ts.nanos
+    assert_equal Time.at(123456.654321), ts.to_time
+  end
+
+  def test_duration
+    duration = Google::Protobuf::Duration.new(seconds: 123, nanos: 456)
+    assert_equal 123.000000456, duration.to_f
+  end
+
+  def test_struct
+    struct = Google::Protobuf::Struct.new
+
+    substruct = {
+      "subkey" => 999,
+      "subkey2" => false
+    }
+
+    sublist = ["abc", 123, {"deepkey" => "deepval"}]
+
+    struct["number"] = 12345
+    struct["boolean-true"] = true
+    struct["boolean-false"] = false
+    struct["null"] = nil
+    struct["string"] = "abcdef"
+    struct["substruct"] = substruct
+    struct["sublist"] = sublist
+
+    assert_equal 12345, struct["number"]
+    assert_equal true, struct["boolean-true"]
+    assert_equal false, struct["boolean-false"]
+    assert_equal nil, struct["null"]
+    assert_equal "abcdef", struct["string"]
+    assert_equal(Google::Protobuf::Struct.from_hash(substruct),
+                 struct["substruct"])
+    assert_equal(Google::Protobuf::ListValue.from_a(sublist),
+                 struct["sublist"])
+
+    should_equal = {
+      "number" => 12345,
+      "boolean-true" => true,
+      "boolean-false" => false,
+      "null" => nil,
+      "string" => "abcdef",
+      "substruct" => {
+        "subkey" => 999,
+        "subkey2" => false
+      },
+      "sublist" => ["abc", 123, {"deepkey" => "deepval"}]
+    }
+
+    list = struct["sublist"]
+    list.is_a?(Google::Protobuf::ListValue)
+    assert_equal "abc", list[0]
+    assert_equal 123, list[1]
+    assert_equal({"deepkey" => "deepval"}, list[2].to_h)
+
+    # to_h returns a fully-flattened Ruby structure (Hash and Array).
+    assert_equal(should_equal, struct.to_h)
+
+    # Test that we can assign Struct and ListValue directly.
+    struct["substruct"] = Google::Protobuf::Struct.from_hash(substruct)
+    struct["sublist"] = Google::Protobuf::ListValue.from_a(sublist)
+
+    assert_equal(should_equal, struct.to_h)
+
+    struct["sublist"] << nil
+    should_equal["sublist"] << nil
+
+    assert_equal(should_equal, struct.to_h)
+    assert_equal(should_equal["sublist"].length, struct["sublist"].length)
+
+    assert_raise Google::Protobuf::UnexpectedStructType do
+      struct[123] = 5
+    end
+
+    assert_raise Google::Protobuf::UnexpectedStructType do
+      struct[5] = Time.new
+    end
+
+    assert_raise Google::Protobuf::UnexpectedStructType do
+      struct[5] = [Time.new]
+    end
+
+    assert_raise Google::Protobuf::UnexpectedStructType do
+      struct[5] = {123 => 456}
+    end
+
+    assert_raise Google::Protobuf::UnexpectedStructType do
+      struct = Google::Protobuf::Struct.new
+      struct.fields["foo"] = Google::Protobuf::Value.new
+      # Tries to return a Ruby value for a Value class whose type
+      # hasn't been filled in.
+      struct["foo"]
+    end
+  end
+
+  def test_any
+    any = Google::Protobuf::Any.new
+    ts = Google::Protobuf::Timestamp.new(seconds: 12345, nanos: 6789)
+    any.pack(ts)
+
+    assert any.is(Google::Protobuf::Timestamp)
+    assert_equal ts, any.unpack(Google::Protobuf::Timestamp)
+  end
+end
diff --git a/ruby/travis-test.sh b/ruby/travis-test.sh
index 75db7d9..59e970a 100755
--- a/ruby/travis-test.sh
+++ b/ruby/travis-test.sh
@@ -5,7 +5,7 @@
 
 test_version() {
   version=$1
-  if [ "$version" == "jruby" ] ; then
+  if [ "$version" == "jruby-1.7" ] ; then
     # No conformance tests yet -- JRuby is too broken to run them.
     bash --login -c \
       "rvm install $version && rvm use $version && \
diff --git a/src/Makefile.am b/src/Makefile.am
index b75b6f7..f70e955 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,8 +19,9 @@
 endif
 
 if GCC
-# These are good warnings to turn on by default
-NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
+# Turn on all warnings except for sign comparison (we ignore sign comparison
+# in Google so our code base have tons of such warnings).
+NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wno-sign-compare
 else
 NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF)
 endif
@@ -32,6 +33,10 @@
 # If I say "dist_include_DATA", automake complains that $(includedir) is not
 # a "legitimate" directory for DATA.  Screw you, automake.
 protodir = $(includedir)
+
+# If you are adding new files here, also remember to change the build files for
+# all other languages, //protoc-artifacts/build-zip.sh and run
+# //update_file_list.sh for bazel.
 nobase_dist_proto_DATA = google/protobuf/descriptor.proto     \
                          google/protobuf/any.proto            \
                          google/protobuf/api.proto            \
@@ -50,7 +55,8 @@
 	rm -f *.loT
 
 CLEANFILES = $(protoc_outputs) unittest_proto_middleman \
-             testzip.jar testzip.list testzip.proto testzip.zip
+             testzip.jar testzip.list testzip.proto testzip.zip \
+             no_warning_test.cc
 
 MAINTAINERCLEANFILES =   \
   Makefile.in
@@ -59,6 +65,7 @@
   google/protobuf/stubs/atomic_sequence_num.h                   \
   google/protobuf/stubs/atomicops.h                             \
   google/protobuf/stubs/atomicops_internals_power.h             \
+  google/protobuf/stubs/atomicops_internals_ppc_gcc.h           \
   google/protobuf/stubs/atomicops_internals_arm64_gcc.h         \
   google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
   google/protobuf/stubs/atomicops_internals_arm_qnx.h           \
@@ -121,7 +128,6 @@
   google/protobuf/reflection.h                                  \
   google/protobuf/reflection_ops.h                              \
   google/protobuf/repeated_field.h                              \
-  google/protobuf/repeated_field_reflection.h                   \
   google/protobuf/service.h                                     \
   google/protobuf/source_context.pb.h                           \
   google/protobuf/struct.pb.h                                   \
@@ -530,6 +536,7 @@
   google/protobuf/io/gzip_stream.h                             \
   google/protobuf/io/gzip_stream_unittest.sh                   \
   google/protobuf/testdata/golden_message                      \
+  google/protobuf/testdata/golden_message_maps                 \
   google/protobuf/testdata/golden_message_oneof_implemented    \
   google/protobuf/testdata/golden_message_proto3               \
   google/protobuf/testdata/golden_packed_fields_message        \
@@ -544,9 +551,10 @@
   google/protobuf/package_info.h                               \
   google/protobuf/io/package_info.h                            \
   google/protobuf/compiler/ruby/ruby_generated_code.proto      \
-  google/protobuf/compiler/ruby/ruby_generated_code.rb         \
+  google/protobuf/compiler/ruby/ruby_generated_code_pb.rb      \
   google/protobuf/compiler/package_info.h                      \
-  google/protobuf/compiler/zip_output_unittest.sh
+  google/protobuf/compiler/zip_output_unittest.sh              \
+  README.md
 
 protoc_lite_outputs =                                          \
   google/protobuf/map_lite_unittest.pb.cc                      \
@@ -677,7 +685,7 @@
 
 check_PROGRAMS = protoc protobuf-test protobuf-lazy-descriptor-test \
                  protobuf-lite-test test_plugin protobuf-lite-arena-test \
-                 $(GZCHECKPROGRAMS)
+                 no-warning-test $(GZCHECKPROGRAMS)
 protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
                       ../gmock/gtest/lib/libgtest.la              \
                       ../gmock/lib/libgmock.la                    \
@@ -830,6 +838,27 @@
 zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
 endif
 
+# This test target is to ensure all our public header files and generated
+# code is free from warnings. We have to be more pedantic about these
+# files because they are compiled by users with different compiler flags.
+no_warning_test.cc:
+	echo "// Generated from Makefile.am" > no_warning_test.cc
+	for FILE in $(nobase_include_HEADERS); do \
+	  if ! echo $${FILE} | grep "atomicops"; then \
+	    echo "#include <$${FILE}>" >> no_warning_test.cc; \
+	  fi \
+	done
+	echo "#include <gtest/gtest.h>" >> no_warning_test.cc
+	echo "TEST(NoWarningTest, Empty) {}" >> no_warning_test.cc
+
+no_warning_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la      \
+                        ../gmock/gtest/lib/libgtest.la      \
+                        ../gmock/gtest/lib/libgtest_main.la
+no_warning_test_CPPFLAGS = -I$(srcdir)/../gmock/gtest/include
+no_warning_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) \
+                           -Wall -Werror
+nodist_no_warning_test_SOURCES = no_warning_test.cc $(protoc_outputs)
+
 TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test \
         google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS)     \
-        protobuf-lite-arena-test
+        protobuf-lite-arena-test no-warning-test
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index c91faa0..ccccc9c 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -61,6 +62,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -74,6 +76,7 @@
   delete Any_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -101,16 +104,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fany_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 void Any::PackFrom(const ::google::protobuf::Message& message) {
@@ -334,7 +327,9 @@
 
 void Any::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Any* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Any>(
           &from);
@@ -349,7 +344,9 @@
 
 void Any::MergeFrom(const Any& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.type_url().size() > 0) {
 
     type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index d5dd892..e8c2a17 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -35,6 +35,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -109,6 +110,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -130,6 +132,7 @@
   delete Mixin_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -175,16 +178,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fapi_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -601,7 +594,9 @@
 
 void Api::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Api)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Api* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Api>(
           &from);
@@ -616,7 +611,9 @@
 
 void Api::MergeFrom(const Api& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   methods_.MergeFrom(from.methods_);
   options_.MergeFrom(from.options_);
   mixins_.MergeFrom(from.mixins_);
@@ -1008,7 +1005,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -1345,7 +1342,9 @@
 
 void Method::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Method)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Method* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Method>(
           &from);
@@ -1360,7 +1359,9 @@
 
 void Method::MergeFrom(const Method& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   options_.MergeFrom(from.options_);
   if (from.name().size() > 0) {
 
@@ -1858,7 +1859,9 @@
 
 void Mixin::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Mixin)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Mixin* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Mixin>(
           &from);
@@ -1873,7 +1876,9 @@
 
 void Mixin::MergeFrom(const Mixin& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.name().size() > 0) {
 
     name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 0ebf9b6..dee438c 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -719,6 +719,11 @@
   ExpectGenerated("test_generator", "", "foo.proto", "Foo");
 }
 
+TEST_F(CommandLineInterfaceTest, Win32ErrorMessage) {
+  EXPECT_EQ("The system cannot find the file specified.\r\n",
+    Subprocess::Win32ErrorMessage(ERROR_FILE_NOT_FOUND));
+}
+
 #endif  // defined(_WIN32) || defined(__CYGWIN__)
 
 TEST_F(CommandLineInterfaceTest, PathLookup) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 385b973..b3eca66 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -336,19 +336,6 @@
 
   // Generate classes.
   for (int i = 0; i < file_->message_type_count(); i++) {
-    if (i == 0 && HasGeneratedMethods(file_, options_)) {
-      printer->Print(
-          "\n"
-          "namespace {\n"
-          "\n"
-          "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;\n"
-          "static void MergeFromFail(int line) {\n"
-          "  GOOGLE_CHECK(false) << __FILE__ << \":\" << line;\n"
-          "}\n"
-          "\n"
-          "}  // namespace\n"
-          "\n");
-    }
     printer->Print("\n");
     printer->Print(kThickSeparator);
     printer->Print("\n");
@@ -464,9 +451,10 @@
   // and we only use AddDescriptors() to allocate default instances.
   if (HasDescriptorMethods(file_, options_)) {
     printer->Print(
-      "\n"
-      "void $assigndescriptorsname$() {\n",
-      "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+        "\n"
+        "void $assigndescriptorsname$() GOOGLE_ATTRIBUTE_COLD;\n"
+        "void $assigndescriptorsname$() {\n",
+        "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
     printer->Indent();
 
     // Make sure the file has found its way into the pool.  If a descriptor
@@ -525,8 +513,9 @@
     // protobuf_RegisterTypes():  Calls
     // MessageFactory::InternalRegisterGeneratedType() for each message type.
     printer->Print(
-      "void protobuf_RegisterTypes(const ::std::string&) {\n"
-      "  protobuf_AssignDescriptorsOnce();\n");
+        "void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;\n"
+        "void protobuf_RegisterTypes(const ::std::string&) {\n"
+        "  protobuf_AssignDescriptorsOnce();\n");
     printer->Indent();
 
     for (int i = 0; i < file_->message_type_count(); i++) {
@@ -566,6 +555,7 @@
       // Note that we don't need any special synchronization in the following
       // code
       // because it is called at static init time before any threads exist.
+      "void $adddescriptorsname$() GOOGLE_ATTRIBUTE_COLD;\n"
       "void $adddescriptorsname$() {\n"
       "  static bool already_here = false;\n"
       "  if (already_here) return;\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index dd9f188..0588e34 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -251,117 +251,148 @@
   }
 }
 
+static void GenerateSerializationLoop(io::Printer* printer,
+                                      const map<string, string>& variables,
+                                      bool supports_arenas,
+                                      const string& utf8_check,
+                                      const string& loop_header,
+                                      const string& ptr,
+                                      bool loop_via_iterators) {
+  printer->Print(variables,
+      StrCat("::google::protobuf::scoped_ptr<$map_classname$> entry;\n",
+             loop_header, " {\n").c_str());
+  printer->Indent();
+
+  printer->Print(variables, StrCat(
+      "entry.reset($name$_.New$wrapper$(\n"
+      "    ", ptr, "->first, ", ptr, "->second));\n"
+      "$write_entry$;\n").c_str());
+
+  // If entry is allocated by arena, its desctructor should be avoided.
+  if (supports_arenas) {
+    printer->Print(
+        "if (entry->GetArena() != NULL) {\n"
+        "  entry.release();\n"
+        "}\n");
+  }
+
+  if (!utf8_check.empty()) {
+    // If loop_via_iterators is true then ptr is actually an iterator, and we
+    // create a pointer by prefixing it with "&*".
+    printer->Print(
+        StrCat(utf8_check, "(", (loop_via_iterators ? "&*" : ""), ptr, ");\n")
+            .c_str());
+  }
+
+  printer->Outdent();
+  printer->Print(
+      "}\n");
+}
+
 void MapFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  printer->Print(variables_,
-      "{\n"
-      "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
-      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = this->$name$().begin();\n"
-      "      it != this->$name$().end(); ++it) {\n");
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
-        "      entry.release();\n"
-        "    }\n");
-  }
-
-  printer->Print(variables_,
-      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
-      "    ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
-      "        $number$, *entry, output);\n");
-
-  printer->Indent();
-  printer->Indent();
-
-  const FieldDescriptor* key_field =
-      descriptor_->message_type()->FindFieldByName("key");
-  const FieldDescriptor* value_field =
-      descriptor_->message_type()->FindFieldByName("value");
-  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(key_field, options_, false, variables_,
-                                   "it->first.data(), it->first.length(),\n",
-                                   printer);
-  }
-  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(value_field, options_, false, variables_,
-                                   "it->second.data(), it->second.length(),\n",
-                                   printer);
-  }
-
-  printer->Outdent();
-  printer->Outdent();
-
-  printer->Print(
-      "  }\n");
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
-        "    entry.release();\n"
-        "  }\n");
-  }
-
-  printer->Print("}\n");
+  map<string, string> variables(variables_);
+  variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" +
+                             variables["stream_writer"] + "(\n            " +
+                             variables["number"] + ", *entry, output)";
+  variables["deterministic"] = "output->IsSerializationDeterminstic()";
+  GenerateSerializeWithCachedSizes(printer, variables);
 }
 
 void MapFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  printer->Print(variables_,
-      "{\n"
-      "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
-      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = this->$name$().begin();\n"
-      "      it != this->$name$().end(); ++it) {\n");
+  map<string, string> variables(variables_);
+  variables["write_entry"] =
+      "target = ::google::protobuf::internal::WireFormatLite::\n"
+      "                   InternalWrite" + variables["declared_type"] +
+      "NoVirtualToArray(\n                       " + variables["number"] +
+      ", *entry, deterministic, target);\n";
+  variables["deterministic"] = "deterministic";
+  GenerateSerializeWithCachedSizes(printer, variables);
+}
 
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-        "    if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
-        "      entry.release();\n"
-        "    }\n");
-  }
-
-  printer->Print(variables_,
-      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
-      "    target = ::google::protobuf::internal::WireFormatLite::\n"
-      "        InternalWrite$declared_type$NoVirtualToArray(\n"
-      "            $number$, *entry, false, target);\n");
-
+void MapFieldGenerator::GenerateSerializeWithCachedSizes(
+    io::Printer* printer, const map<string, string>& variables) const {
+  printer->Print(variables,
+      "if (!this->$name$().empty()) {\n");
   printer->Indent();
-  printer->Indent();
-
   const FieldDescriptor* key_field =
       descriptor_->message_type()->FindFieldByName("key");
   const FieldDescriptor* value_field =
       descriptor_->message_type()->FindFieldByName("value");
-  if (key_field->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(key_field, options_, false, variables_,
-                                   "it->first.data(), it->first.length(),\n",
-                                   printer);
+  const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
+  const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
+
+  printer->Print(variables,
+      "typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
+      "    ConstPtr;\n");
+  if (string_key) {
+    printer->Print(variables,
+        "typedef ConstPtr SortItem;\n"
+        "typedef ::google::protobuf::internal::"
+        "CompareByDerefFirst<SortItem> Less;\n");
+  } else {
+    printer->Print(variables,
+        "typedef ::google::protobuf::internal::SortItem< $key_cpp$, ConstPtr > "
+        "SortItem;\n"
+        "typedef ::google::protobuf::internal::CompareByFirstField<SortItem> Less;\n");
   }
-  if (value_field->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(value_field, options_, false, variables_,
-                                   "it->second.data(), it->second.length(),\n",
-                                   printer);
+  string utf8_check;
+  if (string_key || string_value) {
+    printer->Print(
+        "struct Utf8Check {\n"
+        "  static void Check(ConstPtr p) {\n");
+    printer->Indent();
+    printer->Indent();
+    if (string_key) {
+      GenerateUtf8CheckCodeForString(key_field, options_, false, variables,
+                                     "p->first.data(), p->first.length(),\n",
+                                     printer);
+    }
+    if (string_value) {
+      GenerateUtf8CheckCodeForString(value_field, options_, false, variables,
+                                     "p->second.data(), p->second.length(),\n",
+                                     printer);
+    }
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "};\n");
+    utf8_check = "Utf8Check::Check";
   }
 
-  printer->Outdent();
+  printer->Print(variables,
+      "\n"
+      "if ($deterministic$ &&\n"
+      "    this->$name$().size() > 1) {\n"
+      "  ::google::protobuf::scoped_array<SortItem> items(\n"
+      "      new SortItem[this->$name$().size()]);\n"
+      "  typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n"
+      "  size_type n = 0;\n"
+      "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it, ++n) {\n"
+      "    items[n] = SortItem(&*it);\n"
+      "  }\n"
+      "  ::std::sort(&items[0], &items[n], Less());\n");
+  printer->Indent();
+  GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_),
+                            utf8_check, "for (size_type i = 0; i < n; i++)",
+                            string_key ? "items[i]" : "items[i].second", false);
   printer->Outdent();
   printer->Print(
-      "  }\n");
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables_,
-        "  if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
-        "    entry.release();\n"
-        "  }\n");
-  }
-
+      "} else {\n");
+  printer->Indent();
+  GenerateSerializationLoop(
+      printer, variables, SupportsArenas(descriptor_), utf8_check,
+      "for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "    it = this->$name$().begin();\n"
+      "    it != this->$name$().end(); ++it)",
+      "it", true);
+  printer->Outdent();
+  printer->Print("}\n");
+  printer->Outdent();
   printer->Print("}\n");
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index 087dcde..2930fe5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -61,6 +61,10 @@
   void GenerateByteSize(io::Printer* printer) const;
 
  private:
+  // A helper for GenerateSerializeWithCachedSizes{,ToArray}.
+  void GenerateSerializeWithCachedSizes(
+      io::Printer* printer, const map<string, string>& variables) const;
+
   const FieldDescriptor* descriptor_;
   const bool dependent_field_;
   map<string, string> variables_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 32f6315..69cd5f3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -2419,7 +2419,7 @@
       "  &reinterpret_cast<$classname$*>(16)->f)\n"
       "#endif\n\n"
       "#define ZR_(first, last) do {\\\n"
-      "  ::memset(&first, 0,\\\n"
+      "  ::memset(&(first), 0,\\\n"
       "           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n"
       "} while (0)\n\n";
   for (int i = 0; i < runs_of_fields_.size(); i++) {
@@ -2715,7 +2715,9 @@
         "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
         "// @@protoc_insertion_point(generalized_merge_from_start:"
         "$full_name$)\n"
-        "  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
+        "  if (GOOGLE_PREDICT_FALSE(&from == this)) {\n"
+        "    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);\n"
+        "  }\n",
         "classname", classname_, "full_name", descriptor_->full_name());
     printer->Indent();
 
@@ -2756,7 +2758,9 @@
       "void $classname$::MergeFrom(const $classname$& from) {\n"
       "// @@protoc_insertion_point(class_specific_merge_from_start:"
       "$full_name$)\n"
-      "  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
+      "  if (GOOGLE_PREDICT_FALSE(&from == this)) {\n"
+      "    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);\n"
+      "  }\n",
       "classname", classname_, "full_name", descriptor_->full_name());
   printer->Indent();
 
@@ -2952,7 +2956,7 @@
     // on the CodedOutputStream.
     printer->Print(
       "  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
-      "      ::google::protobuf::internal::NewPermanentCallback(\n"
+      "      ::google::protobuf::NewPermanentCallback(\n"
       "          &MutableUnknownFieldsFor$classname$, this));\n"
       "  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
       "      &unknown_fields_string, false);\n",
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 5d82946..b7b6039 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -1252,7 +1252,7 @@
       foo_(descriptor_->FindMethodByName("Foo")),
       bar_(descriptor_->FindMethodByName("Bar")),
       stub_(&mock_channel_),
-      done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {}
+      done_(NewPermanentCallback(&DoNothing)) {}
 
   virtual void SetUp() {
     ASSERT_TRUE(foo_ != NULL);
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc
index 64381d0..9e4da1e 100644
--- a/src/google/protobuf/compiler/csharp/csharp_enum.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -68,9 +68,7 @@
   for (int i = 0; i < descriptor_->value_count(); i++) {
       WriteEnumValueDocComment(printer, descriptor_->value(i));
       string original_name = descriptor_->value(i)->name();
-      string name = options()->legacy_enum_values
-          ? descriptor_->value(i)->name()
-          : GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
+      string name = GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
       // Make sure we don't get any duplicate names due to prefix removal.
       while (!used_names.insert(name).second) {
         // It's possible we'll end up giving this warning multiple times, but that's better than not at all.
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc
index d74e8c8..c13ed65 100644
--- a/src/google/protobuf/compiler/csharp/csharp_generator.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -83,9 +83,6 @@
       cli_options.base_namespace_specified = true;
     } else if (options[i].first == "internal_access") {
       cli_options.internal_access = true;
-    } else if (options[i].first == "legacy_enum_values") {
-      // TODO: Remove this before final release
-      cli_options.legacy_enum_values = true;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h
index 4079bf7..426fb3b 100644
--- a/src/google/protobuf/compiler/csharp/csharp_options.h
+++ b/src/google/protobuf/compiler/csharp/csharp_options.h
@@ -45,8 +45,7 @@
       file_extension(".cs"),
       base_namespace(""),
       base_namespace_specified(false),
-      internal_access(false),
-      legacy_enum_values(false) {
+      internal_access(false) {
   }
   // Extension of the generated file. Defaults to ".cs"
   string file_extension;
@@ -69,12 +68,6 @@
   // Whether the generated classes should have accessibility level of "internal".
   // Defaults to false that generates "public" classes.
   bool internal_access;
-  // By default, C# codegen now uses PascalCased enum values names, after
-  // removing the enum type name as a prefix (if it *is* a prefix of the value).
-  // Setting this option reverts to the previous behavior of just copying the
-  // value name specified in the .proto file, allowing gradual migration.
-  // This option will be removed before final release.
-  bool legacy_enum_values;
 };
 
 }  // namespace csharp
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index a06c5f6..5e38728 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -266,9 +266,7 @@
 
   printer->Print(
     "public static void registerAllExtensions(\n"
-    "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
-    "lite",
-    HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite");
+    "    com.google.protobuf.ExtensionRegistryLite registry) {\n");
 
   printer->Indent();
 
@@ -283,6 +281,20 @@
   printer->Outdent();
   printer->Print(
     "}\n");
+  if (HasDescriptorMethods(file_, context_->EnforceLite())) {
+    // Overload registerAllExtensions for the non-lite usage to
+    // redundantly maintain the original signature (this is
+    // redundant because ExtensionRegistryLite now invokes
+    // ExtensionRegistry in the non-lite usage). Intent is
+    // to remove this in the future.
+    printer->Print(
+      "\n"
+      "public static void registerAllExtensions(\n"
+      "    com.google.protobuf.ExtensionRegistry registry) {\n"
+      "  registerAllExtensions(\n"
+      "      (com.google.protobuf.ExtensionRegistryLite) registry);\n"
+      "}\n");
+  }
 
   // -----------------------------------------------------------------
 
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index 3c545e1..b1ab404 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -79,8 +79,6 @@
       file_options.generate_mutable_code = true;
     } else if (options[i].first == "shared") {
       file_options.generate_shared_code = true;
-    } else if (options[i].first == "lite") {
-      file_options.enforce_lite = true;
     } else if (options[i].first == "annotate_code") {
       file_options.annotate_code = true;
     } else if (options[i].first == "annotation_list_file") {
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index d55a984..6c80d07 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -205,9 +205,10 @@
   } else {
     vars["final"] = "";
   }
+  vars["ver"] = GeneratedCodeVersionSuffix();
   printer->Print(vars,
     "$private$static $final$\n"
-    "  com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "  com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n"
     "    internal_$identifier$_fieldAccessorTable;\n");
 
   // 6 bytes per field and oneof
@@ -220,11 +221,11 @@
   int bytecode_estimate = 10;
   printer->Print(
     "internal_$identifier$_fieldAccessorTable = new\n"
-    "  com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
+    "  com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable(\n"
     "    internal_$identifier$_descriptor,\n"
     "    new java.lang.String[] { ",
-    "identifier",
-    UniqueFileScopeIdentifier(descriptor_));
+    "identifier", UniqueFileScopeIdentifier(descriptor_),
+    "ver", GeneratedCodeVersionSuffix());
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
     const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
@@ -254,11 +255,11 @@
     printer->Print(
         "public interface $classname$OrBuilder$idend$ extends\n"
         "    $extra_interfaces$\n"
-        "    com.google.protobuf.GeneratedMessage.\n"
+        "    com.google.protobuf.GeneratedMessage$ver$.\n"
         "        ExtendableMessageOrBuilder<$classname$> {\n",
         "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
         "classname", descriptor_->name(),
-        "idend", "");
+        "idend", "", "ver", GeneratedCodeVersionSuffix());
   } else {
     printer->Print(
         "public interface $classname$OrBuilder$idend$ extends\n"
@@ -302,6 +303,7 @@
   variables["static"] = is_own_file ? " " : " static ";
   variables["classname"] = descriptor_->name();
   variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+  variables["ver"] = GeneratedCodeVersionSuffix();
 
   WriteMessageDocComment(printer, descriptor_);
   MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
@@ -315,22 +317,25 @@
     printer->Annotate("classname", descriptor_);
     printer->Print(
         variables,
-        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+        "    com.google.protobuf.GeneratedMessage$ver$.ExtendableMessage<\n"
         "      $classname$> implements\n"
         "    $extra_interfaces$\n"
         "    $classname$OrBuilder {\n");
     builder_type = strings::Substitute(
-             "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
-             name_resolver_->GetImmutableClassName(descriptor_));
+        "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>",
+        name_resolver_->GetImmutableClassName(descriptor_),
+        GeneratedCodeVersionSuffix());
   } else {
     printer->Print(variables,
                    "public $static$final class $classname$ extends\n");
     printer->Annotate("classname", descriptor_);
     printer->Print(variables,
-      "    com.google.protobuf.GeneratedMessage implements\n"
+      "    com.google.protobuf.GeneratedMessage$ver$ implements\n"
       "    $extra_interfaces$\n"
       "    $classname$OrBuilder {\n");
-    builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>";
+    builder_type = strings::Substitute(
+        "com.google.protobuf.GeneratedMessage$0.Builder<?>",
+        GeneratedCodeVersionSuffix());
   }
   printer->Indent();
   // Using builder_type, instead of Builder, prevents the Builder class from
@@ -581,16 +586,18 @@
   if (descriptor_->extension_range_count() > 0) {
     if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
-        "com.google.protobuf.GeneratedMessage\n"
+        "com.google.protobuf.GeneratedMessage$ver$\n"
         "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
         "    extensionWriter = newMessageSetExtensionWriter();\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "ver", GeneratedCodeVersionSuffix());
     } else {
       printer->Print(
-        "com.google.protobuf.GeneratedMessage\n"
+        "com.google.protobuf.GeneratedMessage$ver$\n"
         "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
         "    extensionWriter = newExtensionWriter();\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+        "classname", name_resolver_->GetImmutableClassName(descriptor_),
+        "ver", GeneratedCodeVersionSuffix());
     }
   }
 
@@ -694,43 +701,44 @@
     "}\n"
     "public static $classname$ parseFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseDelimitedWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage\n"
+    "  return com.google.protobuf.GeneratedMessage$ver$\n"
     "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "ver", GeneratedCodeVersionSuffix());
 }
 
 void ImmutableMessageGenerator::GenerateSerializeOneField(
@@ -769,10 +777,11 @@
   printer->Print(
     "@java.lang.Override\n"
     "protected Builder newBuilderForType(\n"
-    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "    com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n"
     "  Builder builder = new Builder(parent);\n"
     "  return builder;\n"
-    "}\n");
+    "}\n",
+    "ver", GeneratedCodeVersionSuffix());
 
   MessageBuilderGenerator builderGenerator(descriptor_, context_);
   builderGenerator.Generate(printer);
@@ -826,7 +835,7 @@
         "}\n");
   }
   printer->Print(
-    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "protected com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n"
     "    internalGetFieldAccessorTable() {\n"
     "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
     "      .ensureFieldAccessorsInitialized(\n"
@@ -835,7 +844,8 @@
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_),
     "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-    "identifier", UniqueFileScopeIdentifier(descriptor_));
+    "identifier", UniqueFileScopeIdentifier(descriptor_),
+    "ver", GeneratedCodeVersionSuffix());
 }
 
 // ===================================================================
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index b3e9e98..4215469 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -94,20 +94,22 @@
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
       "public static final class Builder extends\n"
-      "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+      "    com.google.protobuf.GeneratedMessage$ver$.ExtendableBuilder<\n"
       "      $classname$, Builder> implements\n"
       "    $extra_interfaces$\n"
       "    $classname$OrBuilder {\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_),
-      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_),
+      "ver", GeneratedCodeVersionSuffix());
   } else {
     printer->Print(
       "public static final class Builder extends\n"
-      "    com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
+      "    com.google.protobuf.GeneratedMessage$ver$.Builder<Builder> implements\n"
       "    $extra_interfaces$\n"
       "    $classname$OrBuilder {\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_),
-      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_),
+      "ver", GeneratedCodeVersionSuffix());
   }
   printer->Indent();
 
@@ -181,6 +183,18 @@
       "  return this;\n"
       "}\n"
       "\n");
+  } else {
+    printer->Print(
+      "public final Builder setUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return super.setUnknownFields(unknownFields);\n"
+      "}\n"
+      "\n"
+      "public final Builder mergeUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return super.mergeUnknownFields(unknownFields);\n"
+      "}\n"
+      "\n");
   }
 
   printer->Print(
@@ -268,7 +282,7 @@
         "}\n");
   }
   printer->Print(
-    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "protected com.google.protobuf.GeneratedMessage$ver$.FieldAccessorTable\n"
     "    internalGetFieldAccessorTable() {\n"
     "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
     "      .ensureFieldAccessorsInitialized(\n"
@@ -277,7 +291,8 @@
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_),
     "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-    "identifier", UniqueFileScopeIdentifier(descriptor_));
+    "identifier", UniqueFileScopeIdentifier(descriptor_),
+    "ver", GeneratedCodeVersionSuffix());
 }
 
 // ===================================================================
@@ -294,15 +309,18 @@
 
   printer->Print(
     "private Builder(\n"
-    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "    com.google.protobuf.GeneratedMessage$ver$.BuilderParent parent) {\n"
     "  super(parent);\n"
     "  maybeForceBuilderInitialization();\n"
     "}\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "ver", GeneratedCodeVersionSuffix());
 
   printer->Print(
     "private void maybeForceBuilderInitialization() {\n"
-    "  if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
+    "  if (com.google.protobuf.GeneratedMessage$ver$\n"
+    "          .alwaysUseFieldBuilders) {\n",
+    "ver", GeneratedCodeVersionSuffix());
 
   printer->Indent();
   printer->Indent();
@@ -438,6 +456,62 @@
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
+  printer->Print(
+    "public Builder clone() {\n"
+    "  return (Builder) super.clone();\n"
+    "}\n"
+    "public Builder setField(\n"
+    "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+    "    Object value) {\n"
+    "  return (Builder) super.setField(field, value);\n"
+    "}\n"
+    "public Builder clearField(\n"
+    "    com.google.protobuf.Descriptors.FieldDescriptor field) {\n"
+    "  return (Builder) super.clearField(field);\n"
+    "}\n"
+    "public Builder clearOneof(\n"
+    "    com.google.protobuf.Descriptors.OneofDescriptor oneof) {\n"
+    "  return (Builder) super.clearOneof(oneof);\n"
+    "}\n"
+    "public Builder setRepeatedField(\n"
+    "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+    "    int index, Object value) {\n"
+    "  return (Builder) super.setRepeatedField(field, index, value);\n"
+    "}\n"
+    "public Builder addRepeatedField(\n"
+    "    com.google.protobuf.Descriptors.FieldDescriptor field,\n"
+    "    Object value) {\n"
+    "  return (Builder) super.addRepeatedField(field, value);\n"
+    "}\n");
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "public <Type> Builder setExtension(\n"
+      "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "        $classname$, Type> extension,\n"
+      "    Type value) {\n"
+      "  return (Builder) super.setExtension(extension, value);\n"
+      "}\n"
+      "public <Type> Builder setExtension(\n"
+      "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "        $classname$, java.util.List<Type>> extension,\n"
+      "    int index, Type value) {\n"
+      "  return (Builder) super.setExtension(extension, index, value);\n"
+      "}\n"
+      "public <Type> Builder addExtension(\n"
+      "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "        $classname$, java.util.List<Type>> extension,\n"
+      "    Type value) {\n"
+      "  return (Builder) super.addExtension(extension, value);\n"
+      "}\n"
+      "public <Type> Builder clearExtension(\n"
+      "    com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+      "        $classname$, ?> extension) {\n"
+      "  return (Builder) super.clearExtension(extension);\n"
+      "}\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  }
+
   // -----------------------------------------------------------------
 
   if (context_->HasGeneratedMethods(descriptor_)) {
@@ -522,6 +596,7 @@
       "  return this;\n"
       "}\n"
       "\n");
+
   }
 }
 
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index cc627b5..c9865dd 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -1203,7 +1203,7 @@
     "    $name$_ = other.$name$_;\n"
     "    $clear_mutable_bit_builder$;\n"
     "    $name$Builder_ = \n"
-    "      com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n"
+    "      com.google.protobuf.GeneratedMessage$ver$.alwaysUseFieldBuilders ?\n"
     "         get$capitalized_name$FieldBuilder() : null;\n"
     "  } else {\n"
     "    $name$Builder_.addAllMessages(other.$name$_);\n"
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index e1e5496..ff1865b 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -79,9 +79,11 @@
       "    throw new NullPointerException();\n"
       "  }\n";
   (*variables)["writeString"] =
-      "com.google.protobuf.GeneratedMessage.writeString";
+      "com.google.protobuf.GeneratedMessage" + GeneratedCodeVersionSuffix() +
+      ".writeString";
   (*variables)["computeStringSize"] =
-      "com.google.protobuf.GeneratedMessage.computeStringSize";
+      "com.google.protobuf.GeneratedMessage" + GeneratedCodeVersionSuffix() +
+      ".computeStringSize";
 
   // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
   // by the proto compiler
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 8a2633d..58c77d0 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -768,7 +768,6 @@
 }
 
 string JSFieldDefault(const FieldDescriptor* field) {
-  assert(field->has_default_value());
   switch (field->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32:
       return MaybeNumberString(
@@ -943,7 +942,7 @@
   }
 
   if (field->is_optional() && is_primitive &&
-      (!field->has_default_value() || force_optional) && !force_present) {
+      force_optional && !force_present) {
     jstype += "?";
   } else if (field->is_required() && !is_primitive && !force_optional) {
     jstype = "!" + jstype;
@@ -1258,6 +1257,10 @@
 // Returns true for fields that represent "null" as distinct from the default
 // value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
 bool HasFieldPresence(const FieldDescriptor* field) {
+  if (field->is_repeated()) {
+    return false;
+  }
+
   return
       (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
       (field->containing_oneof() != NULL) ||
@@ -2031,9 +2034,8 @@
                      "getter", JSGetterName(options, field, BYTES_B64));
     } else {
       if (field->has_default_value()) {
-        printer->Print("jspb.Message.getField(msg, $index$) == null ? "
-                       "$defaultValue$ : ",
-                       "index", JSFieldIndex(field),
+        printer->Print("!msg.has$name$() ? $defaultValue$ : ",
+                       "name", JSGetterName(options, field),
                        "defaultValue", JSFieldDefault(field));
       }
       if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
@@ -2253,25 +2255,6 @@
           "      null");
     }
 
-    if (options.binary) {
-      printer->Print(",\n"
-          "      $keyWriterFn$,\n"
-          "      $keyReaderFn$,\n"
-          "      $valueWriterFn$,\n"
-          "      $valueReaderFn$",
-          "keyWriterFn", JSBinaryWriterMethodName(options, key_field),
-          "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
-          "valueWriterFn", JSBinaryWriterMethodName(options, value_field),
-          "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
-
-      if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
-        printer->Print(",\n"
-            "      $messageType$.serializeBinaryToWriter,\n"
-            "      $messageType$.deserializeBinaryFromReader",
-            "messageType", GetPath(options, value_field->message_type()));
-      }
-    }
-
     printer->Print(
         "));\n");
 
@@ -2407,10 +2390,9 @@
                      "index", JSFieldIndex(field),
                      "default", Proto3PrimitiveFieldDefault(field));
     } else {
-      if (field->has_default_value()) {
-        printer->Print("jspb.Message.getField(this, $index$) == null ? "
-                       "$defaultValue$ : ",
-                       "index", JSFieldIndex(field),
+      if (!field->is_repeated()) {
+        printer->Print("!this.has$name$() ? $defaultValue$ : ",
+                       "name", JSGetterName(options, field),
                        "defaultValue", JSFieldDefault(field));
       }
       if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
@@ -2419,10 +2401,6 @@
           printer->Print("jspb.Message.getRepeatedFloatingPointField("
                          "this, $index$)",
                          "index", JSFieldIndex(field));
-        } else if (field->is_optional() && !field->has_default_value()) {
-          printer->Print("jspb.Message.getOptionalFloatingPointField("
-                         "this, $index$)",
-                         "index", JSFieldIndex(field));
         } else {
           // Convert "NaN" to NaN.
           printer->Print("+jspb.Message.getField(this, $index$)",
@@ -2498,7 +2476,7 @@
           "returndoc", JSReturnDoc(options, field));
     }
 
-    if (HasFieldPresence(field)) {
+    if (HasFieldPresence(field) || field->is_repeated()) {
       printer->Print(
           "$class$.prototype.clear$name$ = function() {\n"
           "  jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
@@ -2517,6 +2495,22 @@
           "returnvalue", JSReturnClause(field));
     }
   }
+
+  if (HasFieldPresence(field)) {
+    printer->Print(
+        "/**\n"
+        " * Returns whether this field is set.\n"
+        " * @return{!boolean}\n"
+        " */\n"
+        "$class$.prototype.has$name$ = function() {\n"
+        "  return jspb.Message.getField(this, $index$) != null;\n"
+        "};\n"
+        "\n"
+        "\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(options, field),
+        "index", JSFieldIndex(field));
+  }
 }
 
 void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
@@ -2543,6 +2537,29 @@
         "$class$.extensions = {};\n"
         "\n",
         "class", GetPath(options, desc));
+
+    if (options.binary) {
+      printer->Print(
+          "\n"
+          "/**\n"
+          " * The extensions registered with this message class. This is a "
+          "map of\n"
+          " * extension field number to fieldInfo object.\n"
+          " *\n"
+          " * For example:\n"
+          " *     { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
+          "ctor: proto.example.MyMessage} }\n"
+          " *\n"
+          " * fieldName contains the JsCompiler renamed field name property "
+          "so that it\n"
+          " * works in OPTIMIZED mode.\n"
+          " *\n"
+          " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n"
+          " */\n"
+          "$class$.extensionsBinary = {};\n"
+          "\n",
+          "class", GetPath(options, desc));
+    }
   }
 }
 
@@ -2590,7 +2607,7 @@
       "    default:\n");
   if (IsExtendable(desc)) {
     printer->Print(
-        "      jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
+        "      jspb.Message.readBinaryExtension(msg, reader, $extobj$Binary,\n"
         "        $class$.prototype.getExtension,\n"
         "        $class$.prototype.setExtension);\n"
         "      break;\n",
@@ -2620,10 +2637,25 @@
                  "num", SimpleItoa(field->number()));
 
   if (field->is_map()) {
+    const FieldDescriptor* key_field = MapFieldKey(field);
+    const FieldDescriptor* value_field = MapFieldValue(field);
     printer->Print(
         "      var value = msg.get$name$();\n"
-        "      reader.readMessage(value, jspb.Map.deserializeBinary);\n",
+        "      reader.readMessage(value, function(message, reader) {\n",
         "name", JSGetterName(options, field));
+
+    printer->Print("        jspb.Map.deserializeBinary(message, reader, "
+                   "$keyReaderFn$, $valueReaderFn$",
+          "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
+          "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
+
+    if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      printer->Print(", $messageType$.deserializeBinaryFromReader",
+          "messageType", GetPath(options, value_field->message_type()));
+    }
+
+    printer->Print(");\n");
+    printer->Print("         });\n");
   } else {
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       printer->Print(
@@ -2709,8 +2741,8 @@
 
   if (IsExtendable(desc)) {
     printer->Print(
-        "  jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
-        "    $class$.prototype.getExtension);\n",
+        "  jspb.Message.serializeBinaryExtensions(this, writer,\n"
+        "    $extobj$Binary, $class$.prototype.getExtension);\n",
         "extobj", JSExtensionsObjectName(options, desc->file(), desc),
         "class", GetPath(options, desc));
   }
@@ -2725,11 +2757,18 @@
     const GeneratorOptions& options,
     io::Printer* printer,
     const FieldDescriptor* field) const {
-  printer->Print(
-      "  f = this.get$name$($nolazy$);\n",
-      "name", JSGetterName(options, field, BYTES_U8),
-      // No lazy creation for maps containers -- fastpath the empty case.
-      "nolazy", (field->is_map()) ? "true" : "");
+  if (HasFieldPresence(field) &&
+      field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "  f = jspb.Message.getField(this, $index$);\n",
+        "index", JSFieldIndex(field));
+  } else {
+    printer->Print(
+        "  f = this.get$name$($nolazy$);\n",
+        "name", JSGetterName(options, field, BYTES_U8),
+        // No lazy creation for maps containers -- fastpath the empty case.
+        "nolazy", (field->is_map()) ? "true" : "");
+  }
 
 
   // Print an `if (condition)` statement that evaluates to true if the field
@@ -2782,9 +2821,21 @@
 
   // Write the field on the wire.
   if (field->is_map()) {
+    const FieldDescriptor* key_field = MapFieldKey(field);
+    const FieldDescriptor* value_field = MapFieldValue(field);
     printer->Print(
-        "    f.serializeBinary($index$, writer);\n",
-        "index", SimpleItoa(field->number()));
+        "    f.serializeBinary($index$, writer, "
+                              "$keyWriterFn$, $valueWriterFn$",
+        "index", SimpleItoa(field->number()),
+        "keyWriterFn", JSBinaryWriterMethodName(options, key_field),
+        "valueWriterFn", JSBinaryWriterMethodName(options, value_field));
+
+    if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      printer->Print(", $messageType$.serializeBinaryToWriter",
+          "messageType", GetPath(options, value_field->message_type()));
+    }
+
+    printer->Print(");\n");
   } else {
     printer->Print(
         "    writer.write$method$(\n"
@@ -2866,7 +2917,7 @@
       "     /** @type {?function((boolean|undefined),!jspb.Message=): "
       "!Object} */ (\n"
       "         $toObject$),\n"
-      "    $repeated$",
+      "    $repeated$);\n",
       "index", SimpleItoa(field->number()),
       "name", JSObjectFieldName(options, field),
       "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
@@ -2878,12 +2929,18 @@
 
   if (options.binary) {
     printer->Print(
-        ",\n"
+        "\n"
+        "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n"
+        "    $class$.$name$,\n"
         "    $binaryReaderFn$,\n"
         "    $binaryWriterFn$,\n"
         "    $binaryMessageSerializeFn$,\n"
-        "    $binaryMessageDeserializeFn$,\n"
-        "    $isPacked$);\n",
+        "    $binaryMessageDeserializeFn$,\n",
+        "extendName", JSExtensionsObjectName(options, field->file(),
+                                             field->containing_type()),
+        "index", SimpleItoa(field->number()),
+        "class", extension_scope,
+        "name", JSObjectFieldName(options, field),
         "binaryReaderFn", JSBinaryReaderMethodName(options, field),
         "binaryWriterFn", JSBinaryWriterMethodName(options, field),
         "binaryMessageSerializeFn",
@@ -2893,10 +2950,11 @@
         "binaryMessageDeserializeFn",
         (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
         (SubmessageTypeRef(options, field) +
-         ".deserializeBinaryFromReader") : "null",
+         ".deserializeBinaryFromReader") : "null");
+
+    printer->Print(
+        "    $isPacked$);\n",
         "isPacked", (field->is_packed() ? "true" : "false"));
-  } else {
-    printer->Print(");\n");
   }
 
   printer->Print(
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
index e76f8e9..34e1782 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
@@ -62,7 +62,7 @@
   string enum_comments;
   SourceLocation location;
   if (descriptor_->GetSourceLocation(&location)) {
-    enum_comments = BuildCommentsString(location);
+    enum_comments = BuildCommentsString(location, true);
   } else {
     enum_comments = "";
   }
@@ -81,16 +81,18 @@
   if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
     // Include the unknown value.
     printer->Print(
-      "/// Value used if any message's field encounters a value that is not defined\n"
-      "/// by this enum. The message will also have C functions to get/set the rawValue\n"
-      "/// of the field.\n"
+      "/**\n"
+      " * Value used if any message's field encounters a value that is not defined\n"
+      " * by this enum. The message will also have C functions to get/set the rawValue\n"
+      " * of the field.\n"
+      " **/\n"
       "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n",
       "name", name_);
   }
   for (int i = 0; i < all_values_.size(); i++) {
     SourceLocation location;
     if (all_values_[i]->GetSourceLocation(&location)) {
-      string comments = BuildCommentsString(location).c_str();
+      string comments = BuildCommentsString(location, true).c_str();
       if (comments.length() > 0) {
         if (i > 0) {
           printer->Print("\n");
@@ -111,8 +113,10 @@
       "\n"
       "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
       "\n"
-      "/// Checks to see if the given value is defined by the enum or was not known at\n"
-      "/// the time this source was generated.\n"
+      "/**\n"
+      " * Checks to see if the given value is defined by the enum or was not known at\n"
+      " * the time this source was generated.\n"
+      " **/\n"
       "BOOL $name$_IsValidValue(int32_t value);\n"
       "\n",
       "name", name_);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
index b63bc0d..7a774a0 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -83,12 +83,16 @@
 
   printer->Print(
       variables_,
-      "/// Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n"
-      "/// if the value was not defined by the enum at the time the code was generated.\n"
+      "/**\n"
+      " * Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even\n"
+      " * if the value was not defined by the enum at the time the code was generated.\n"
+      " **/\n"
       "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);\n"
-      "/// Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n"
-      "/// it to be set to a value that was not defined by the enum at the time the code\n"
-      "/// was generated.\n"
+      "/**\n"
+      " * Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing\n"
+      " * it to be set to a value that was not defined by the enum at the time the code\n"
+      " * was generated.\n"
+      " **/\n"
       "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n"
       "\n");
 }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
index 3f7ab9d..d0de1ec 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -63,7 +63,7 @@
   vars["method_name"] = method_name_;
   SourceLocation location;
   if (descriptor_->GetSourceLocation(&location)) {
-    vars["comments"] = BuildCommentsString(location);
+    vars["comments"] = BuildCommentsString(location, true);
   } else {
     vars["comments"] = "";
   }
@@ -85,7 +85,7 @@
   if (descriptor_->containing_type()->options().message_set_wire_format())
     options.push_back("GPBExtensionSetWireFormat");
 
-  vars["options"] = BuildFlagsString(options);
+  vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options);
 
   ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
   string singular_type;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
index 812b4a1..527b7c0 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -64,7 +64,7 @@
 
   SourceLocation location;
   if (descriptor->GetSourceLocation(&location)) {
-    (*variables)["comments"] = BuildCommentsString(location);
+    (*variables)["comments"] = BuildCommentsString(location, true);
   } else {
     (*variables)["comments"] = "\n";
   }
@@ -93,7 +93,7 @@
     field_flags.push_back("GPBFieldHasEnumDescriptor");
   }
 
-  (*variables)["fieldflags"] = BuildFlagsString(field_flags);
+  (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
 
   (*variables)["default"] = DefaultValue(descriptor);
   (*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
@@ -335,7 +335,7 @@
   if (WantsHasProperty()) {
     printer->Print(
         variables_,
-        "/// Test to see if @c $name$ has been set.\n"
+        "/** Test to see if @c $name$ has been set. */\n"
         "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
   }
   if (IsInitName(variables_.find("name")->second)) {
@@ -387,7 +387,7 @@
       "$comments$"
       "$array_comment$"
       "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
-      "/// The number of items in @c $name$ without causing the array to be created.\n"
+      "/** The number of items in @c $name$ without causing the array to be created. */\n"
       "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
   if (IsInitName(variables_.find("name")->second)) {
     // If property name starts with init we need to annotate it to get past ARC.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index cf8c34e..878a374 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <algorithm> // std::find()
 #include <iostream>
 #include <sstream>
 
@@ -45,218 +46,122 @@
 
 namespace google {
 namespace protobuf {
-
-// This is also found in GPBBootstrap.h, and needs to be kept in sync.  It
-// is the version check done to ensure generated code works with the current
-// runtime being used.
-const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
-
 namespace compiler {
 namespace objectivec {
 
 namespace {
 
-class ImportWriter {
- public:
-  ImportWriter(const Options& options)
-      : options_(options),
-        need_to_parse_mapping_file_(true) {}
+// This is also found in GPBBootstrap.h, and needs to be kept in sync.  It
+// is the version check done to ensure generated code works with the current
+// runtime being used.
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30002;
 
-  void AddFile(const FileGenerator* file);
-  void Print(io::Printer *printer) const;
+const char* kHeaderExtension = ".pbobjc.h";
 
- private:
-  class ProtoFrameworkCollector : public LineConsumer {
-   public:
-    ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
-        : map_(inout_proto_file_to_framework_name) {}
-
-    virtual bool ConsumeLine(const StringPiece& line, string* out_error);
-
-   private:
-    map<string, string>* map_;
-  };
-
-  void ParseFrameworkMappings();
-
-  const Options options_;
-  map<string, string> proto_file_to_framework_name_;
-  bool need_to_parse_mapping_file_;
-
-  vector<string> protobuf_framework_imports_;
-  vector<string> protobuf_non_framework_imports_;
-  vector<string> other_framework_imports_;
-  vector<string> other_imports_;
-};
-
-void ImportWriter::AddFile(const FileGenerator* file) {
-  const FileDescriptor* file_descriptor = file->Descriptor();
-  const string extension(".pbobjc.h");
-
-  if (IsProtobufLibraryBundledProtoFile(file_descriptor)) {
-    protobuf_framework_imports_.push_back(
-        FilePathBasename(file_descriptor) + extension);
-    protobuf_non_framework_imports_.push_back(file->Path() + extension);
-    return;
+// Checks if a message contains any extension definitions (on the message or
+// a nested message under it).
+bool MessageContainsExtensions(const Descriptor* message) {
+  if (message->extension_count() > 0) {
+    return true;
   }
-
-  // Lazy parse any mappings.
-  if (need_to_parse_mapping_file_) {
-    ParseFrameworkMappings();
+  for (int i = 0; i < message->nested_type_count(); i++) {
+    if (MessageContainsExtensions(message->nested_type(i))) {
+      return true;
+    }
   }
-
-  map<string, string>::iterator proto_lookup =
-      proto_file_to_framework_name_.find(file_descriptor->name());
-  if (proto_lookup != proto_file_to_framework_name_.end()) {
-    other_framework_imports_.push_back(
-        proto_lookup->second + "/" +
-        FilePathBasename(file_descriptor) + extension);
-    return;
-  }
-
-  if (!options_.generate_for_named_framework.empty()) {
-    other_framework_imports_.push_back(
-        options_.generate_for_named_framework + "/" +
-        FilePathBasename(file_descriptor) + extension);
-    return;
-  }
-
-  other_imports_.push_back(file->Path() + extension);
+  return false;
 }
 
-void ImportWriter::Print(io::Printer* printer) const {
-  assert(protobuf_non_framework_imports_.size() ==
-         protobuf_framework_imports_.size());
-
-  bool add_blank_line = false;
-
-  if (protobuf_framework_imports_.size() > 0) {
-    const string framework_name(ProtobufLibraryFrameworkName);
-    const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
-
-    printer->Print(
-        "#if $cpp_symbol$\n",
-        "cpp_symbol", cpp_symbol);
-    for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
-         iter != protobuf_framework_imports_.end(); ++iter) {
-      printer->Print(
-          " #import <$framework_name$/$header$>\n",
-          "framework_name", framework_name,
-          "header", *iter);
-    }
-    printer->Print(
-        "#else\n");
-    for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
-         iter != protobuf_non_framework_imports_.end(); ++iter) {
-      printer->Print(
-          " #import \"$header$\"\n",
-          "header", *iter);
-    }
-    printer->Print(
-        "#endif\n");
-
-    add_blank_line = true;
+// Checks if the file contains any extensions definitions (at the root or
+// nested under a message).
+bool FileContainsExtensions(const FileDescriptor* file) {
+  if (file->extension_count() > 0) {
+    return true;
   }
-
-  if (other_framework_imports_.size() > 0) {
-    if (add_blank_line) {
-      printer->Print("\n");
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (MessageContainsExtensions(file->message_type(i))) {
+      return true;
     }
-
-    for (vector<string>::const_iterator iter = other_framework_imports_.begin();
-         iter != other_framework_imports_.end(); ++iter) {
-      printer->Print(
-          " #import <$header$>\n",
-          "header", *iter);
-    }
-
-    add_blank_line = true;
   }
+  return false;
+}
 
-  if (other_imports_.size() > 0) {
-    if (add_blank_line) {
-      printer->Print("\n");
+// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all
+// deps as visited and prunes them from the needed files list.
+void PruneFileAndDepsMarkingAsVisited(
+    const FileDescriptor* file,
+    vector<const FileDescriptor*>* files,
+    set<const FileDescriptor*>* files_visited) {
+  vector<const FileDescriptor*>::iterator iter =
+      std::find(files->begin(), files->end(), file);
+  if (iter != files->end()) {
+    files->erase(iter);
+  }
+  files_visited->insert(file);
+  for (int i = 0; i < file->dependency_count(); i++) {
+    PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);
+  }
+}
+
+// Helper for CollectMinimalFileDepsContainingExtensions.
+void CollectMinimalFileDepsContainingExtensionsWorker(
+    const FileDescriptor* file,
+    vector<const FileDescriptor*>* files,
+    set<const FileDescriptor*>* files_visited) {
+  if (files_visited->find(file) != files_visited->end()) {
+    return;
+  }
+  files_visited->insert(file);
+
+  if (FileContainsExtensions(file)) {
+    files->push_back(file);
+    for (int i = 0; i < file->dependency_count(); i++) {
+      const FileDescriptor* dep = file->dependency(i);
+      PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
     }
-
-    for (vector<string>::const_iterator iter = other_imports_.begin();
-         iter != other_imports_.end(); ++iter) {
-      printer->Print(
-          " #import \"$header$\"\n",
-          "header", *iter);
+  } else {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      const FileDescriptor* dep = file->dependency(i);
+      CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
+                                                       files_visited);
     }
   }
 }
 
-void ImportWriter::ParseFrameworkMappings() {
-  need_to_parse_mapping_file_ = false;
-  if (options_.named_framework_to_proto_path_mappings_path.empty()) {
-    return;  // Nothing to do.
-  }
-
-  ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
-  string parse_error;
-  if (!ParseSimpleFile(options_.named_framework_to_proto_path_mappings_path,
-                       &collector, &parse_error)) {
-    cerr << "error parsing " << options_.named_framework_to_proto_path_mappings_path
-         << " : " << parse_error << endl;
-    cerr.flush();
+// Collect the deps of the given file that contain extensions. This can be used to
+// create the chain of roots that need to be wired together.
+//
+// NOTE: If any changes are made to this and the supporting functions, you will
+// need to manually validate what the generated code is for the test files:
+//   objectivec/Tests/unittest_extension_chain_*.proto
+// There are comments about what the expected code should be line and limited
+// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
+// specifically).
+void CollectMinimalFileDepsContainingExtensions(
+    const FileDescriptor* file,
+    vector<const FileDescriptor*>* files) {
+  set<const FileDescriptor*> files_visited;
+  for (int i = 0; i < file->dependency_count(); i++) {
+    const FileDescriptor* dep = file->dependency(i);
+    CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
+                                                     &files_visited);
   }
 }
 
-bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
-    const StringPiece& line, string* out_error) {
-  int offset = line.find(':');
-  if (offset == StringPiece::npos) {
-    *out_error =
-        string("Framework/proto file mapping line without colon sign: '") +
-        line.ToString() + "'.";
-    return false;
-  }
-  StringPiece framework_name(line, 0, offset);
-  StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
-  StringPieceTrimWhitespace(&framework_name);
-
-  int start = 0;
-  while (start < proto_file_list.length()) {
-    offset = proto_file_list.find(',', start);
-    if (offset == StringPiece::npos) {
-      offset = proto_file_list.length();
+bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
+  for (int i = 0; i < file->dependency_count(); i++) {
+    if (dep == file->dependency(i)) {
+      return true;
     }
-
-    StringPiece proto_file(proto_file_list, start, offset);
-    StringPieceTrimWhitespace(&proto_file);
-    if (proto_file.size() != 0) {
-      map<string, string>::iterator existing_entry =
-          map_->find(proto_file.ToString());
-      if (existing_entry != map_->end()) {
-        cerr << "warning: duplicate proto file reference, replacing framework entry for '"
-             << proto_file.ToString() << "' with '" << framework_name.ToString()
-             << "' (was '" << existing_entry->second << "')." << endl;
-        cerr.flush();
-      }
-
-      if (proto_file.find(' ') != StringPiece::npos) {
-        cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
-             << proto_file.ToString() << "'" << endl;
-        cerr.flush();
-      }
-
-      (*map_)[proto_file.ToString()] = framework_name.ToString();
-    }
-
-    start = offset + 1;
   }
-
-  return true;
+  return false;
 }
 
 }  // namespace
 
-
 FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
     : file_(file),
       root_class_name_(FileClassName(file)),
-      is_public_dep_(false),
       options_(options) {
   for (int i = 0; i < file_->enum_type_count(); i++) {
     EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
@@ -275,8 +180,6 @@
 }
 
 FileGenerator::~FileGenerator() {
-  STLDeleteContainerPointers(dependency_generators_.begin(),
-                             dependency_generators_.end());
   STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
   STLDeleteContainerPointers(message_generators_.begin(),
                              message_generators_.end());
@@ -299,14 +202,12 @@
 
   // #import any headers for "public imports" in the proto file.
   {
-    ImportWriter import_writer(options_);
-    const vector<FileGenerator *> &dependency_generators = DependencyGenerators();
-    for (vector<FileGenerator *>::const_iterator iter =
-             dependency_generators.begin();
-         iter != dependency_generators.end(); ++iter) {
-      if ((*iter)->IsPublicDependency()) {
-        import_writer.AddFile(*iter);
-      }
+    ImportWriter import_writer(
+        options_.generate_for_named_framework,
+        options_.named_framework_to_proto_path_mappings_path);
+    const string header_extension(kHeaderExtension);
+    for (int i = 0; i < file_->public_dependency_count(); i++) {
+      import_writer.AddFile(file_->public_dependency(i), header_extension);
     }
     import_writer.Print(printer);
   }
@@ -357,14 +258,16 @@
   printer->Print(
       "#pragma mark - $root_class_name$\n"
       "\n"
-      "/// Exposes the extension registry for this file.\n"
-      "///\n"
-      "/// The base class provides:\n"
-      "/// @code\n"
-      "///   + (GPBExtensionRegistry *)extensionRegistry;\n"
-      "/// @endcode\n"
-      "/// which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
-      "/// this file and all files that it depends on.\n"
+      "/**\n"
+      " * Exposes the extension registry for this file.\n"
+      " *\n"
+      " * The base class provides:\n"
+      " * @code\n"
+      " *   + (GPBExtensionRegistry *)extensionRegistry;\n"
+      " * @endcode\n"
+      " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
+      " * this file and all files that it depends on.\n"
+      " **/\n"
       "@interface $root_class_name$ : GPBRootObject\n"
       "@end\n"
       "\n",
@@ -404,21 +307,41 @@
   // #import the runtime support.
   PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h");
 
+  vector<const FileDescriptor*> deps_with_extensions;
+  CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);
+
   {
-    ImportWriter import_writer(options_);
+    ImportWriter import_writer(
+        options_.generate_for_named_framework,
+        options_.named_framework_to_proto_path_mappings_path);
+    const string header_extension(kHeaderExtension);
 
     // #import the header for this proto file.
-    import_writer.AddFile(this);
+    import_writer.AddFile(file_, header_extension);
 
     // #import the headers for anything that a plain dependency of this proto
     // file (that means they were just an include, not a "public" include).
-    const vector<FileGenerator *> &dependency_generators =
-        DependencyGenerators();
-    for (vector<FileGenerator *>::const_iterator iter =
-             dependency_generators.begin();
-         iter != dependency_generators.end(); ++iter) {
-      if (!(*iter)->IsPublicDependency()) {
-        import_writer.AddFile(*iter);
+    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++) {
+      const FileDescriptor *dep = file_->dependency(i);
+      bool public_import = (public_import_names.count(dep->name()) != 0);
+      if (!public_import) {
+        import_writer.AddFile(dep, header_extension);
+      }
+    }
+
+    // If any indirect dependency provided extensions, it needs to be directly
+    // imported so it can get merged into the root's extensions registry.
+    // See the Note by CollectMinimalFileDepsContainingExtensions before
+    // changing this.
+    for (vector<const FileDescriptor *>::iterator iter =
+             deps_with_extensions.begin();
+         iter != deps_with_extensions.end(); ++iter) {
+      if (!IsDirectDependency(*iter, file_)) {
+        import_writer.AddFile(*iter, header_extension);
       }
     }
 
@@ -458,29 +381,11 @@
       "@implementation $root_class_name$\n\n",
       "root_class_name", root_class_name_);
 
-  // Generate the extension initialization structures for the top level and
-  // any nested messages.
-  ostringstream extensions_stringstream;
-  if (file_->extension_count() + file_->message_type_count() > 0) {
-    io::OstreamOutputStream extensions_outputstream(&extensions_stringstream);
-    io::Printer extensions_printer(&extensions_outputstream, '$');
-    for (vector<ExtensionGenerator *>::iterator iter =
-             extension_generators_.begin();
-         iter != extension_generators_.end(); ++iter) {
-      (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
-    }
-    for (vector<MessageGenerator *>::iterator iter =
-             message_generators_.begin();
-         iter != message_generators_.end(); ++iter) {
-      (*iter)->GenerateStaticVariablesInitialization(&extensions_printer);
-    }
-    extensions_stringstream.flush();
-  }
+  const bool file_contains_extensions = FileContainsExtensions(file_);
 
   // If there were any extensions or this file has any dependencies, output
   // a registry to override to create the file specific registry.
-  const string& extensions_str = extensions_stringstream.str();
-  if (extensions_str.length() > 0 || file_->dependency_count() > 0) {
+  if (file_contains_extensions || !deps_with_extensions.empty()) {
     printer->Print(
         "+ (GPBExtensionRegistry*)extensionRegistry {\n"
         "  // This is called by +initialize so there is no need to worry\n"
@@ -493,11 +398,20 @@
     printer->Indent();
     printer->Indent();
 
-    if (extensions_str.length() > 0) {
+    if (file_contains_extensions) {
       printer->Print(
           "static GPBExtensionDescription descriptions[] = {\n");
       printer->Indent();
-      printer->Print(extensions_str.c_str());
+      for (vector<ExtensionGenerator *>::iterator iter =
+               extension_generators_.begin();
+           iter != extension_generators_.end(); ++iter) {
+        (*iter)->GenerateStaticVariablesInitialization(printer);
+      }
+      for (vector<MessageGenerator *>::iterator iter =
+               message_generators_.begin();
+           iter != message_generators_.end(); ++iter) {
+        (*iter)->GenerateStaticVariablesInitialization(printer);
+      }
       printer->Outdent();
       printer->Print(
           "};\n"
@@ -510,14 +424,21 @@
           "}\n");
     }
 
-    const vector<FileGenerator *> &dependency_generators =
-        DependencyGenerators();
-    for (vector<FileGenerator *>::const_iterator iter =
-             dependency_generators.begin();
-         iter != dependency_generators.end(); ++iter) {
+    if (deps_with_extensions.empty()) {
       printer->Print(
-          "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
-          "dependency", (*iter)->RootClassName());
+          "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
+          "// them to this registry.\n");
+    } else {
+      printer->Print(
+          "// Merge in the imports (direct or indirect) that defined extensions.\n");
+      for (vector<const FileDescriptor *>::iterator iter =
+               deps_with_extensions.begin();
+           iter != deps_with_extensions.end(); ++iter) {
+        const string root_class_name(FileClassName((*iter)));
+        printer->Print(
+            "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
+            "dependency", root_class_name);
+      }
     }
 
     printer->Outdent();
@@ -526,27 +447,39 @@
     printer->Print(
         "  }\n"
         "  return registry;\n"
-        "}\n"
-        "\n");
+        "}\n");
+  } else {
+    if (file_->dependency_count() > 0) {
+      printer->Print(
+          "// No extensions in the file and none of the imports (direct or indirect)\n"
+          "// defined extensions, so no need to generate +extensionRegistry.\n");
+    } else {
+      printer->Print(
+          "// No extensions in the file and no imports, so no need to generate\n"
+          "// +extensionRegistry.\n");
+    }
   }
 
-  printer->Print("@end\n\n");
+  printer->Print("\n@end\n\n");
 
   // File descriptor only needed if there are messages to use it.
   if (message_generators_.size() > 0) {
-    string syntax;
+    map<string, string> vars;
+    vars["root_class_name"] = root_class_name_;
+    vars["package"] = file_->package();
+    vars["objc_prefix"] = FileClassPrefix(file_);
     switch (file_->syntax()) {
       case FileDescriptor::SYNTAX_UNKNOWN:
-        syntax = "GPBFileSyntaxUnknown";
+        vars["syntax"] = "GPBFileSyntaxUnknown";
         break;
       case FileDescriptor::SYNTAX_PROTO2:
-        syntax = "GPBFileSyntaxProto2";
+        vars["syntax"] = "GPBFileSyntaxProto2";
         break;
       case FileDescriptor::SYNTAX_PROTO3:
-        syntax = "GPBFileSyntaxProto3";
+        vars["syntax"] = "GPBFileSyntaxProto3";
         break;
     }
-    printer->Print(
+    printer->Print(vars,
         "#pragma mark - $root_class_name$_FileDescriptor\n"
         "\n"
         "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
@@ -554,16 +487,24 @@
         "  // about thread safety of the singleton.\n"
         "  static GPBFileDescriptor *descriptor = NULL;\n"
         "  if (!descriptor) {\n"
-        "    GPBDebugCheckRuntimeVersion();\n"
-        "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
-        "                                                     syntax:$syntax$];\n"
+        "    GPBDebugCheckRuntimeVersion();\n");
+    if (vars["objc_prefix"].size() > 0) {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                 objcPrefix:@\"$objc_prefix$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    } else {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    }
+    printer->Print(
         "  }\n"
         "  return descriptor;\n"
         "}\n"
-        "\n",
-        "root_class_name", root_class_name_,
-        "package", file_->package(),
-        "syntax", syntax);
+        "\n");
   }
 
   for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
@@ -582,24 +523,6 @@
     "// @@protoc_insertion_point(global_scope)\n");
 }
 
-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), options_);
-      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_;
-}
-
 // Helper to print the import of the runtime support at the top of generated
 // files. This currently only supports the runtime coming from a framework
 // as defined by the official CocoaPod.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
index 8e4388d..a60a688 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -62,32 +62,17 @@
   void GenerateHeader(io::Printer* printer);
 
   const string& RootClassName() const { return root_class_name_; }
-  const string Path() const { return FilePath(file_); }
-  const FileDescriptor* Descriptor() const { return file_; }
-
-  bool IsPublicDependency() const { return is_public_dep_; }
-
- protected:
-  void SetIsPublicDependency(bool is_public_dep) {
-    is_public_dep_ = is_public_dep;
-  }
 
  private:
   const FileDescriptor* file_;
   string root_class_name_;
 
-  // Access this field through the DependencyGenerators accessor call below.
-  // Do not reference it directly.
-  vector<FileGenerator*> dependency_generators_;
-
   vector<EnumGenerator*> enum_generators_;
   vector<MessageGenerator*> message_generators_;
   vector<ExtensionGenerator*> extension_generators_;
-  bool is_public_dep_;
 
   const Options options_;
 
-  const vector<FileGenerator*>& DependencyGenerators();
   void PrintFileRuntimePreamble(
       io::Printer* printer, const string& header_to_import) const;
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index 29a8765..3640746 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -45,12 +45,29 @@
 
 ObjectiveCGenerator::~ObjectiveCGenerator() {}
 
+bool ObjectiveCGenerator::HasGenerateAll() const {
+  return true;
+}
+
 bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
                                    const string& parameter,
-                                   OutputDirectory* output_directory,
+                                   GeneratorContext* context,
                                    string* error) const {
+  *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+  return false;
+}
+
+bool ObjectiveCGenerator::GenerateAll(const vector<const FileDescriptor*>& files,
+                                      const string& parameter,
+                                      GeneratorContext* context,
+                                      string* error) const {
   // -----------------------------------------------------------------
-  // Parse generator options.
+  // Parse generator options. These options are passed to the compiler using the
+  // --objc_opt flag. The options are passed as a comma separated list of
+  // options along with their values. If the option appears multiple times, only
+  // the last value will be considered.
+  //
+  // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework
 
   Options generation_options;
 
@@ -70,7 +87,7 @@
       //     (i.e. - "package=prefix # comment")
       //
       // There is no validation that the prefixes are good prefixes, it is
-      // assume they are when you create the file.
+      // assumed that they are when you create the file.
       generation_options.expected_prefixes_path = options[i].second;
     } else if (options[i].first == "generate_for_named_framework") {
       // The name of the framework that protos are being generated for. This
@@ -79,11 +96,12 @@
       //
       // NOTE: If this option is used with
       // named_framework_to_proto_path_mappings_path, then this is effectively
-      // the "default" to use for everything that wasn't mapped by the other.
-      generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
+      // the "default" framework name used for everything that wasn't mapped by
+      // the mapping file.
+      generation_options.generate_for_named_framework = options[i].second;
     } else if (options[i].first == "named_framework_to_proto_path_mappings_path") {
-      // Path to find a file containing the listing of framework names and
-      // proto files. The generator uses this to decide if another proto file
+      // Path to find a file containing the list of framework names and proto
+      // files. The generator uses this to decide if a proto file
       // referenced should use a framework style import vs. a user level import
       // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h").
       //
@@ -97,8 +115,11 @@
       // with commas.
       //
       // There can be multiple lines listing the same frameworkName incase it
-      // has a lot of proto files included in it; and having multiple lines
-      // makes things easier to read.
+      // has a lot of proto files included in it; having multiple lines makes
+      // things easier to read. If a proto file is not configured in the
+      // mappings file, it will use the default framework name if one was passed
+      // with generate_for_named_framework, or the relative path to it's include
+      // path otherwise.
       generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
     } else {
       *error = "error: Unknown generator option: " + options[i].first;
@@ -108,29 +129,32 @@
 
   // -----------------------------------------------------------------
 
-  // Validate the objc prefix/package pairing.
-  if (!ValidateObjCClassPrefix(file, generation_options, error)) {
+  // Validate the objc prefix/package pairings.
+  if (!ValidateObjCClassPrefixes(files, generation_options, error)) {
     // *error will have been filled in.
     return false;
   }
 
-  FileGenerator file_generator(file, generation_options);
-  string filepath = FilePath(file);
+  for (int i = 0; i < files.size(); i++) {
+    const FileDescriptor* file = files[i];
+    FileGenerator file_generator(file, generation_options);
+    string filepath = FilePath(file);
 
-  // Generate header.
-  {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
-        output_directory->Open(filepath + ".pbobjc.h"));
-    io::Printer printer(output.get(), '$');
-    file_generator.GenerateHeader(&printer);
-  }
+    // Generate header.
+    {
+      scoped_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filepath + ".pbobjc.h"));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateHeader(&printer);
+    }
 
-  // Generate m file.
-  {
-    scoped_ptr<io::ZeroCopyOutputStream> output(
-        output_directory->Open(filepath + ".pbobjc.m"));
-    io::Printer printer(output.get(), '$');
-    file_generator.GenerateSource(&printer);
+    // Generate m file.
+    {
+      scoped_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filepath + ".pbobjc.m"));
+      io::Printer printer(output.get(), '$');
+      file_generator.GenerateSource(&printer);
+    }
   }
 
   return true;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.h b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
index 09266b0..9d801d5 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.h
@@ -47,8 +47,15 @@
   ~ObjectiveCGenerator();
 
   // implements CodeGenerator ----------------------------------------
-  bool Generate(const FileDescriptor* file, const string& parameter,
-                OutputDirectory* output_directory, string* error) const;
+  bool HasGenerateAll() const;
+  bool Generate(const FileDescriptor* file,
+                const string& parameter,
+                GeneratorContext* context,
+                string* error) const;
+  bool GenerateAll(const vector<const FileDescriptor*>& files,
+                   const string& parameter,
+                   GeneratorContext* context,
+                   string* error) const;
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 311bf35..c7fd96a 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -44,9 +44,10 @@
 
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 
@@ -209,10 +210,14 @@
 hash_set<string> kReservedWords =
     MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
 
-string SanitizeNameForObjC(const string& input, const string& extension) {
+string SanitizeNameForObjC(const string& input,
+                           const string& extension,
+                           string* out_suffix_added) {
   if (kReservedWords.count(input) > 0) {
+    if (out_suffix_added) *out_suffix_added = extension;
     return input + extension;
   }
+  if (out_suffix_added) out_suffix_added->clear();
   return input;
 }
 
@@ -261,6 +266,34 @@
   return false;
 }
 
+string GetZeroEnumNameForFlagType(const FlagType flag_type) {
+  switch(flag_type) {
+    case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+      return "GPBDescriptorInitializationFlag_None";
+    case FLAGTYPE_EXTENSION:
+      return "GPBExtensionNone";
+    case FLAGTYPE_FIELD:
+      return "GPBFieldNone";
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      return "0";
+  }
+}
+
+string GetEnumNameForFlagType(const FlagType flag_type) {
+  switch(flag_type) {
+    case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
+      return "GPBDescriptorInitializationFlags";
+    case FLAGTYPE_EXTENSION:
+      return "GPBExtensionOptions";
+    case FLAGTYPE_FIELD:
+      return "GPBFieldFlags";
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      return string();
+  }
+}
+
 }  // namespace
 
 // Escape C++ trigraphs by escaping question marks to \?
@@ -307,6 +340,12 @@
   return basename;
 }
 
+string FileClassPrefix(const FileDescriptor* file) {
+  // Default is empty string, no need to check has_objc_class_prefix.
+  string result = file->options().objc_class_prefix();
+  return result;
+}
+
 string FilePath(const FileDescriptor* file) {
   string output;
   string basename;
@@ -337,19 +376,13 @@
   return output;
 }
 
-string FileClassPrefix(const FileDescriptor* file) {
-  // Default is empty string, no need to check has_objc_class_prefix.
-  string result = file->options().objc_class_prefix();
-  return result;
-}
-
 string FileClassName(const FileDescriptor* file) {
   string name = FileClassPrefix(file);
   name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
   name += "Root";
   // There aren't really any reserved words that end in "Root", but playing
   // it safe and checking.
-  return SanitizeNameForObjC(name, "_RootClass");
+  return SanitizeNameForObjC(name, "_RootClass", NULL);
 }
 
 string ClassNameWorker(const Descriptor* descriptor) {
@@ -371,11 +404,15 @@
 }
 
 string ClassName(const Descriptor* descriptor) {
+  return ClassName(descriptor, NULL);
+}
+
+string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
   // 1. Message names are used as is (style calls for CamelCase, trust it).
   // 2. Check for reserved word at the very end and then suffix things.
   string prefix = FileClassPrefix(descriptor->file());
   string name = ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(prefix + name, "_Class");
+  return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added);
 }
 
 string EnumName(const EnumDescriptor* descriptor) {
@@ -389,7 +426,7 @@
   //    yields Fixed_Class, Fixed_Size.
   string name = FileClassPrefix(descriptor->file());
   name += ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(name, "_Enum");
+  return SanitizeNameForObjC(name, "_Enum", NULL);
 }
 
 string EnumValueName(const EnumValueDescriptor* descriptor) {
@@ -404,7 +441,7 @@
   const string& name = class_name + "_" + value_str;
   // There aren't really any reserved words with an underscore and a leading
   // capital letter, but playing it safe and checking.
-  return SanitizeNameForObjC(name, "_Value");
+  return SanitizeNameForObjC(name, "_Value", NULL);
 }
 
 string EnumValueShortName(const EnumValueDescriptor* descriptor) {
@@ -441,7 +478,7 @@
 string ExtensionMethodName(const FieldDescriptor* descriptor) {
   const string& name = NameFromFieldDescriptor(descriptor);
   const string& result = UnderscoresToCamelCase(name, false);
-  return SanitizeNameForObjC(result, "_Extension");
+  return SanitizeNameForObjC(result, "_Extension", NULL);
 }
 
 string FieldName(const FieldDescriptor* field) {
@@ -456,7 +493,7 @@
       result += "_p";
     }
   }
-  return SanitizeNameForObjC(result, "_p");
+  return SanitizeNameForObjC(result, "_p", NULL);
 }
 
 string FieldNameCapitalized(const FieldDescriptor* field) {
@@ -816,21 +853,26 @@
   return false;
 }
 
-string BuildFlagsString(const vector<string>& strings) {
+string BuildFlagsString(const FlagType flag_type,
+                        const vector<string>& strings) {
   if (strings.size() == 0) {
-    return "0";
+    return GetZeroEnumNameForFlagType(flag_type);
+  } else if (strings.size() == 1) {
+    return strings[0];
   }
-  string string;
+  string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
   for (size_t i = 0; i != strings.size(); ++i) {
     if (i > 0) {
       string.append(" | ");
     }
     string.append(strings[i]);
   }
+  string.append(")");
   return string;
 }
 
-string BuildCommentsString(const SourceLocation& location) {
+string BuildCommentsString(const SourceLocation& location,
+                           bool prefer_single_line) {
   const string& comments = location.leading_comments.empty()
                                ? location.trailing_comments
                                : location.leading_comments;
@@ -839,15 +881,45 @@
   while (!lines.empty() && lines.back().empty()) {
     lines.pop_back();
   }
-  string prefix("///");
-  string suffix("\n");
-  string final_comments;
-  for (int i = 0; i < lines.size(); i++) {
-    // HeaderDoc uses '\' and '@' for markers; escape them.
-    const string line = StringReplace(lines[i], "\\", "\\\\", true);
-    final_comments +=
-        prefix + StringReplace(line, "@", "\\@", true) + suffix;
+  // If there are no comments, just return an empty string.
+  if (lines.size() == 0) {
+    return "";
   }
+
+  string prefix;
+  string suffix;
+  string final_comments;
+  string epilogue;
+
+  bool add_leading_space = false;
+
+  if (prefer_single_line && lines.size() == 1) {
+    prefix = "/** ";
+    suffix = " */\n";
+  } else {
+    prefix = "* ";
+    suffix = "\n";
+    final_comments += "/**\n";
+    epilogue = " **/\n";
+    add_leading_space = true;
+  }
+
+  for (int i = 0; i < lines.size(); i++) {
+    string line = StripPrefixString(lines[i], " ");
+    // HeaderDoc and appledoc use '\' and '@' for markers; escape them.
+    line = StringReplace(line, "\\", "\\\\", true);
+    line = StringReplace(line, "@", "\\@", true);
+    // Decouple / from * to not have inline comments inside comments.
+    line = StringReplace(line, "/*", "/\\*", true);
+    line = StringReplace(line, "*/", "*\\/", true);
+    line = prefix + line;
+    StripWhitespace(&line);
+    // If not a one line, need to add the first space before *, as
+    // StripWhitespace would have removed it.
+    line = (add_leading_space ? " " : "") + line;
+    final_comments += line + suffix;
+  }
+  final_comments += epilogue;
   return final_comments;
 }
 
@@ -948,28 +1020,20 @@
       generation_options.expected_prefixes_path, &collector, out_error);
 }
 
-}  // namespace
-
-bool ValidateObjCClassPrefix(const FileDescriptor* file,
-                             const Options& generation_options,
-                             string* out_error) {
+bool ValidateObjCClassPrefix(
+    const FileDescriptor* file,
+    const string& expected_prefixes_path,
+    const map<string, string>& expected_package_prefixes,
+    string* out_error) {
   const string prefix = file->options().objc_class_prefix();
   const string package = file->package();
 
   // 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 warnings.
 
-  // Load any expected package prefixes to validate against those.
-  map<string, string> expected_package_prefixes;
-  if (!LoadExpectedPackagePrefixes(generation_options,
-                                   &expected_package_prefixes,
-                                   out_error)) {
-    return false;
-  }
-
   // Check: Error - See if there was an expected prefix for the package and
   // report if it doesn't match (wrong or missing).
-  map<string, string>::iterator package_match =
+  map<string, string>::const_iterator package_match =
       expected_package_prefixes.find(package);
   if (package_match != expected_package_prefixes.end()) {
     // There was an entry, and...
@@ -990,27 +1054,11 @@
   }
 
   // If there was no prefix option, we're done at this point.
-  if (prefix.length() == 0) {
+  if (prefix.empty()) {
     // No prefix, nothing left to check.
     return true;
   }
 
-  // Check: Error - Make sure the prefix wasn't expected for a different
-  // package (overlap is allowed, but it has to be listed as an expected
-  // overlap).
-  for (map<string, string>::iterator i = expected_package_prefixes.begin();
-       i != expected_package_prefixes.end(); ++i) {
-    if (i->second == prefix) {
-      *out_error =
-          "error: Found 'option objc_class_prefix = \"" + prefix +
-          "\";' in '" + file->name() +
-          "'; that prefix is already used for 'package " + i->first +
-          ";'. It can only be reused by listing it in the expected file (" +
-          generation_options.expected_prefixes_path + ").";
-      return false;  // Only report first usage of the prefix.
-    }
-  }
-
   // Check: Warning - Make sure the prefix is is a reasonable value according
   // to Apple's rules (the checks above implicitly whitelist anything that
   // doesn't meet these rules).
@@ -1032,6 +1080,56 @@
     cerr.flush();
   }
 
+  // Look for any other package that uses the same prefix.
+  string other_package_for_prefix;
+  for (map<string, string>::const_iterator i = expected_package_prefixes.begin();
+       i != expected_package_prefixes.end(); ++i) {
+    if (i->second == prefix) {
+      other_package_for_prefix = i->first;
+      break;
+    }
+  }
+
+  // Check: Warning - If the file does not have a package, check whether
+  // the prefix declared is being used by another package or not.
+  if (package.empty()) {
+    // The file does not have a package and ...
+    if (other_package_for_prefix.empty()) {
+      // ... no other package has declared that prefix.
+      cerr << endl
+           << "protoc:0: warning: File '" << file->name() << "' has no "
+           << "package. Consider adding a new package to the proto and adding '"
+           << "new.package = " << prefix << "' to the expected prefixes file ("
+           << expected_prefixes_path << ")." << endl;
+      cerr.flush();
+    } else {
+      // ... another package has declared the same prefix.
+      cerr << endl
+           << "protoc:0: warning: File '" << file->name() << "' has no package "
+           << "and package '" << other_package_for_prefix << "' already uses '"
+           << prefix << "' as its prefix. Consider either adding a new package "
+           << "to the proto, or reusing one of the packages already using this "
+           << "prefix in the expected prefixes file ("
+           << expected_prefixes_path << ")." << endl;
+      cerr.flush();
+    }
+    return true;
+  }
+
+  // Check: Error - Make sure the prefix wasn't expected for a different
+  // package (overlap is allowed, but it has to be listed as an expected
+  // overlap).
+  if (!other_package_for_prefix.empty()) {
+    *out_error =
+        "error: Found 'option objc_class_prefix = \"" + prefix +
+        "\";' in '" + file->name() +
+        "'; that prefix is already used for 'package " +
+        other_package_for_prefix + ";'. It can only be reused by listing " +
+        "it in the expected file (" +
+        expected_prefixes_path + ").";
+    return false;  // Only report first usage of the prefix.
+  }
+
   // Check: Warning - If the given package/prefix pair wasn't expected, issue a
   // warning issue a warning suggesting it gets added to the file.
   if (!expected_package_prefixes.empty()) {
@@ -1039,13 +1137,39 @@
          << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
          << prefix << "\";' in '" << file->name() << "';"
          << " consider adding it to the expected prefixes file ("
-         << generation_options.expected_prefixes_path << ")." << endl;
+         << expected_prefixes_path << ")." << endl;
     cerr.flush();
   }
 
   return true;
 }
 
+}  // namespace
+
+bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files,
+                               const Options& generation_options,
+                               string* out_error) {
+  // Load the expected package prefixes, if available, to validate against.
+  map<string, string> expected_package_prefixes;
+  if (!LoadExpectedPackagePrefixes(generation_options,
+                                   &expected_package_prefixes,
+                                   out_error)) {
+    return false;
+  }
+
+  for (int i = 0; i < files.size(); i++) {
+    bool is_valid =
+        ValidateObjCClassPrefix(files[i],
+                                generation_options.expected_prefixes_path,
+                                expected_package_prefixes,
+                                out_error);
+    if (!is_valid) {
+      return false;
+    }
+  }
+  return true;
+}
+
 TextFormatDecodeData::TextFormatDecodeData() { }
 
 TextFormatDecodeData::~TextFormatDecodeData() { }
@@ -1306,7 +1430,8 @@
     return true;
   }
   // Force a newline onto the end to finish parsing.
-  p_ = StringPiece(leftover_ + "\n");
+  leftover_ += "\n";
+  p_ = StringPiece(leftover_);
   if (!ParseLoop()) {
     return false;
   }
@@ -1367,6 +1492,178 @@
   return parser.Finish();
 }
 
+ImportWriter::ImportWriter(
+  const string& generate_for_named_framework,
+  const string& named_framework_to_proto_path_mappings_path)
+    : generate_for_named_framework_(generate_for_named_framework),
+      named_framework_to_proto_path_mappings_path_(
+          named_framework_to_proto_path_mappings_path),
+      need_to_parse_mapping_file_(true) {
+}
+
+ImportWriter::~ImportWriter() {}
+
+void ImportWriter::AddFile(const FileDescriptor* file,
+                           const string& header_extension) {
+  const string file_path(FilePath(file));
+
+  if (IsProtobufLibraryBundledProtoFile(file)) {
+    protobuf_framework_imports_.push_back(
+        FilePathBasename(file) + header_extension);
+    protobuf_non_framework_imports_.push_back(file_path + header_extension);
+    return;
+  }
+
+  // Lazy parse any mappings.
+  if (need_to_parse_mapping_file_) {
+    ParseFrameworkMappings();
+  }
+
+  map<string, string>::iterator proto_lookup =
+      proto_file_to_framework_name_.find(file->name());
+  if (proto_lookup != proto_file_to_framework_name_.end()) {
+    other_framework_imports_.push_back(
+        proto_lookup->second + "/" +
+        FilePathBasename(file) + header_extension);
+    return;
+  }
+
+  if (!generate_for_named_framework_.empty()) {
+    other_framework_imports_.push_back(
+        generate_for_named_framework_ + "/" +
+        FilePathBasename(file) + header_extension);
+    return;
+  }
+
+  other_imports_.push_back(file_path + header_extension);
+}
+
+void ImportWriter::Print(io::Printer* printer) const {
+  assert(protobuf_non_framework_imports_.size() ==
+         protobuf_framework_imports_.size());
+
+  bool add_blank_line = false;
+
+  if (protobuf_framework_imports_.size() > 0) {
+    const string framework_name(ProtobufLibraryFrameworkName);
+    const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
+
+    printer->Print(
+        "#if $cpp_symbol$\n",
+        "cpp_symbol", cpp_symbol);
+    for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin();
+         iter != protobuf_framework_imports_.end(); ++iter) {
+      printer->Print(
+          " #import <$framework_name$/$header$>\n",
+          "framework_name", framework_name,
+          "header", *iter);
+    }
+    printer->Print(
+        "#else\n");
+    for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin();
+         iter != protobuf_non_framework_imports_.end(); ++iter) {
+      printer->Print(
+          " #import \"$header$\"\n",
+          "header", *iter);
+    }
+    printer->Print(
+        "#endif\n");
+
+    add_blank_line = true;
+  }
+
+  if (other_framework_imports_.size() > 0) {
+    if (add_blank_line) {
+      printer->Print("\n");
+    }
+
+    for (vector<string>::const_iterator iter = other_framework_imports_.begin();
+         iter != other_framework_imports_.end(); ++iter) {
+      printer->Print(
+          " #import <$header$>\n",
+          "header", *iter);
+    }
+
+    add_blank_line = true;
+  }
+
+  if (other_imports_.size() > 0) {
+    if (add_blank_line) {
+      printer->Print("\n");
+    }
+
+    for (vector<string>::const_iterator iter = other_imports_.begin();
+         iter != other_imports_.end(); ++iter) {
+      printer->Print(
+          " #import \"$header$\"\n",
+          "header", *iter);
+    }
+  }
+}
+
+void ImportWriter::ParseFrameworkMappings() {
+  need_to_parse_mapping_file_ = false;
+  if (named_framework_to_proto_path_mappings_path_.empty()) {
+    return;  // Nothing to do.
+  }
+
+  ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
+  string parse_error;
+  if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
+                       &collector, &parse_error)) {
+    cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
+         << " : " << parse_error << endl;
+    cerr.flush();
+  }
+}
+
+bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
+    const StringPiece& line, string* out_error) {
+  int offset = line.find(':');
+  if (offset == StringPiece::npos) {
+    *out_error =
+        string("Framework/proto file mapping line without colon sign: '") +
+        line.ToString() + "'.";
+    return false;
+  }
+  StringPiece framework_name(line, 0, offset);
+  StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
+  StringPieceTrimWhitespace(&framework_name);
+
+  int start = 0;
+  while (start < proto_file_list.length()) {
+    offset = proto_file_list.find(',', start);
+    if (offset == StringPiece::npos) {
+      offset = proto_file_list.length();
+    }
+
+    StringPiece proto_file(proto_file_list, start, offset - start);
+    StringPieceTrimWhitespace(&proto_file);
+    if (proto_file.size() != 0) {
+      map<string, string>::iterator existing_entry =
+          map_->find(proto_file.ToString());
+      if (existing_entry != map_->end()) {
+        cerr << "warning: duplicate proto file reference, replacing framework entry for '"
+             << proto_file.ToString() << "' with '" << framework_name.ToString()
+             << "' (was '" << existing_entry->second << "')." << endl;
+        cerr.flush();
+      }
+
+      if (proto_file.find(' ') != StringPiece::npos) {
+        cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
+             << proto_file.ToString() << "'" << endl;
+        cerr.flush();
+      }
+
+      (*map_)[proto_file.ToString()] = framework_name.ToString();
+    }
+
+    start = offset + 1;
+  }
+
+  return true;
+}
+
 
 }  // namespace objectivec
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index be20bee..d17d44a 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -67,6 +67,9 @@
 // handling under ARC.
 bool IsInitName(const string& name);
 
+// Gets the objc_class_prefix.
+string FileClassPrefix(const FileDescriptor* file);
+
 // Gets the path of the file we're going to generate (sans the .pb.h
 // extension).  The path will be dependent on the objectivec package
 // declared in the proto package.
@@ -83,6 +86,7 @@
 // These return the fully-qualified class name corresponding to the given
 // descriptor.
 string ClassName(const Descriptor* descriptor);
+string ClassName(const Descriptor* descriptor, string* out_suffix_added);
 string EnumName(const EnumDescriptor* descriptor);
 
 // Returns the fully-qualified name of the enum value corresponding to the
@@ -137,6 +141,12 @@
   OBJECTIVECTYPE_MESSAGE
 };
 
+enum FlagType {
+  FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+  FLAGTYPE_EXTENSION,
+  FLAGTYPE_FIELD
+};
+
 template<class TDescriptor>
 string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) {
   if (descriptor->options().deprecated()) {
@@ -168,10 +178,12 @@
 string DefaultValue(const FieldDescriptor* field);
 bool HasNonZeroDefaultValue(const FieldDescriptor* field);
 
-string BuildFlagsString(const vector<string>& strings);
+string BuildFlagsString(const FlagType type, const vector<string>& strings);
 
-// Builds a HeaderDoc style comment out of the comments in the .proto file.
-string BuildCommentsString(const SourceLocation& location);
+// Builds HeaderDoc/appledoc style comments out of the comments in the .proto
+// file.
+string BuildCommentsString(const SourceLocation& location,
+                           bool prefer_single_line);
 
 // The name the commonly used by the library when built as a framework.
 // This lines up to the name used in the CocoaPod.
@@ -183,12 +195,12 @@
 // Checks if the file is one of the proto's bundled with the library.
 bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file);
 
-// Checks the prefix for a given file and outputs any warnings needed, if
-// there are flat out errors, then out_error is filled in and the result is
-// false.
-bool ValidateObjCClassPrefix(const FileDescriptor* file,
-                             const Options& generation_options,
-                             string* out_error);
+// Checks the prefix for the given files and outputs any warnings as needed. If
+// there are flat out errors, then out_error is filled in with the first error
+// and the result is false.
+bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files,
+                               const Options& generation_options,
+                               string* out_error);
 
 // Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
 // the input into the expected output.
@@ -223,6 +235,43 @@
 bool ParseSimpleFile(
     const string& path, LineConsumer* line_consumer, string* out_error);
 
+
+// Helper class for parsing framework import mappings and generating
+// import statements.
+class LIBPROTOC_EXPORT ImportWriter {
+ public:
+  ImportWriter(const string& generate_for_named_framework,
+               const string& named_framework_to_proto_path_mappings_path);
+  ~ImportWriter();
+
+  void AddFile(const FileDescriptor* file, const string& header_extension);
+  void Print(io::Printer *printer) const;
+
+ private:
+  class ProtoFrameworkCollector : public LineConsumer {
+   public:
+    ProtoFrameworkCollector(map<string, string>* inout_proto_file_to_framework_name)
+        : map_(inout_proto_file_to_framework_name) {}
+
+    virtual bool ConsumeLine(const StringPiece& line, string* out_error);
+
+   private:
+    map<string, string>* map_;
+  };
+
+  void ParseFrameworkMappings();
+
+  const string generate_for_named_framework_;
+  const string named_framework_to_proto_path_mappings_path_;
+  map<string, string> proto_file_to_framework_name_;
+  bool need_to_parse_mapping_file_;
+
+  vector<string> protobuf_framework_imports_;
+  vector<string> protobuf_non_framework_imports_;
+  vector<string> other_framework_imports_;
+  vector<string> other_imports_;
+};
+
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
index ac5d8ae..0bc9dc1 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -115,7 +115,7 @@
   if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) {
     field_flags.push_back("GPBFieldHasEnumDescriptor");
   }
-  variables_["fieldflags"] = BuildFlagsString(field_flags);
+  variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
 
   ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
   const bool value_is_object_type =
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index e1a7861..4c6e1b5 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -331,7 +331,7 @@
   string message_comments;
   SourceLocation location;
   if (descriptor_->GetSourceLocation(&location)) {
-    message_comments = BuildCommentsString(location);
+    message_comments = BuildCommentsString(location, false);
   } else {
     message_comments = "";
   }
@@ -521,7 +521,8 @@
     if (descriptor_->options().message_set_wire_format()) {
       init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
     }
-    vars["init_flags"] = BuildFlagsString(init_flags);
+    vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
+                                          init_flags);
 
     printer->Print(
         vars,
@@ -579,6 +580,19 @@
           "    [localDescriptor setupExtensionRanges:ranges\n"
           "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
     }
+    if (descriptor_->containing_type() != NULL) {
+      string parent_class_name = ClassName(descriptor_->containing_type());
+      printer->Print(
+          "    [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
+          "parent_name", parent_class_name);
+    }
+    string suffix_added;
+    ClassName(descriptor_, &suffix_added);
+    if (suffix_added.size() > 0) {
+      printer->Print(
+          "    [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
+          "suffix", suffix_added);
+    }
     printer->Print(
         "    NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
         "    descriptor = localDescriptor;\n"
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
index 44bafd7..5531ae2 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
@@ -53,7 +53,7 @@
   string comments;
   SourceLocation location;
   if (descriptor_->GetSourceLocation(&location)) {
-    comments = BuildCommentsString(location);
+    comments = BuildCommentsString(location, true);
   } else {
     comments = "";
   }
@@ -104,7 +104,9 @@
 void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) {
   printer->Print(
       variables_,
-      "/// Clears whatever value was set for the oneof '$name$'.\n"
+      "/**\n"
+      " * Clears whatever value was set for the oneof '$name$'.\n"
+      " **/\n"
       "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n");
 }
 
@@ -119,7 +121,7 @@
       variables_,
       "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n"
       "  GPBDescriptor *descriptor = [message descriptor];\n"
-      "  GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n"
+      "  GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:$raw_index$];\n"
       "  GPBMaybeClearOneof(message, oneof, $index$, 0);\n"
       "}\n");
 }
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 214d7c9..519ed8f 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -525,7 +525,6 @@
   SourceCodeInfo source_code_info;
   source_code_info_ = &source_code_info;
 
-  vector<string> top_doc_comments;
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
     // Advance to first token.
     input_->NextWithComments(NULL, &upcoming_detached_comments_,
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index c4d48fc..9064c38 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -36,6 +36,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -102,6 +103,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -123,6 +125,7 @@
   delete CodeGeneratorResponse_File_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -161,16 +164,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -451,7 +444,9 @@
 
 void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const CodeGeneratorRequest* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>(
           &from);
@@ -466,7 +461,9 @@
 
 void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   file_to_generate_.MergeFrom(from.file_to_generate_);
   proto_file_.MergeFrom(from.proto_file_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
@@ -962,7 +959,9 @@
 
 void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const CodeGeneratorResponse_File* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>(
           &from);
@@ -977,7 +976,9 @@
 
 void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -1269,7 +1270,9 @@
 
 void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const CodeGeneratorResponse* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>(
           &from);
@@ -1284,7 +1287,9 @@
 
 void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   file_.MergeFrom(from.file_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_error()) {
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index cc54a8a..d5468a0 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -44,6 +44,7 @@
 // performance-minded Python code leverage the fast C++ implementation
 // directly.
 
+#include <algorithm>
 #include <google/protobuf/stubs/hash.h>
 #include <limits>
 #include <map>
@@ -107,20 +108,25 @@
   return module_name;
 }
 
+// Keywords reserved by the Python language.
+const char* const kKeywords[] = {
+    "False",   "None",     "True",     "and",    "as",    "assert", "break",
+    "class",   "continue", "def",      "del",    "elif",  "else",   "except",
+    "finally", "for",      "from",     "global", "if",    "import", "in",
+    "is",      "lambda",   "nonlocal", "not",    "or",    "pass",   "raise",
+    "return",  "try",      "while",    "with",   "yield",
+};
+const char* const* kKeywordsEnd =
+    kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
 
-// Returns an import statement of form "from X.Y.Z import T" for the given
-// .proto filename.
-string ModuleImportStatement(const string& filename) {
-  string module_name = ModuleName(filename);
-  int last_dot_pos = module_name.rfind('.');
-  if (last_dot_pos == string::npos) {
-    // NOTE(petya): this is not tested as it would require a protocol buffer
-    // outside of any package, and I don't think that is easily achievable.
-    return "import " + module_name;
-  } else {
-    return "from " + module_name.substr(0, last_dot_pos) + " import " +
-        module_name.substr(last_dot_pos + 1);
+bool ContainsPythonKeyword(const string& module_name) {
+  vector<string> tokens = Split(module_name, ".");
+  for (int i = 0; i < tokens.size(); ++i) {
+    if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
+      return true;
+    }
   }
+  return false;
 }
 
 
@@ -359,10 +365,32 @@
 void Generator::PrintImports() const {
   for (int i = 0; i < file_->dependency_count(); ++i) {
     const string& filename = file_->dependency(i)->name();
-    string import_statement = ModuleImportStatement(filename);
+
+    string module_name = ModuleName(filename);
     string module_alias = ModuleAlias(filename);
-    printer_->Print("$statement$ as $alias$\n", "statement",
-                    import_statement, "alias", module_alias);
+    if (ContainsPythonKeyword(module_name)) {
+      // If the module path contains a Python keyword, we have to quote the
+      // module name and import it using importlib. Otherwise the usual kind of
+      // import statement would result in a syntax error from the presence of
+      // the keyword.
+      printer_->Print("import importlib\n");
+      printer_->Print("$alias$ = importlib.import_module('$name$')\n", "alias",
+                      module_alias, "name", module_name);
+    } else {
+      int last_dot_pos = module_name.rfind('.');
+      string import_statement;
+      if (last_dot_pos == string::npos) {
+        // NOTE(petya): this is not tested as it would require a protocol buffer
+        // outside of any package, and I don't think that is easily achievable.
+        import_statement = "import " + module_name;
+      } else {
+        import_statement = "from " + module_name.substr(0, last_dot_pos) +
+                           " import " + module_name.substr(last_dot_pos + 1);
+      }
+      printer_->Print("$statement$ as $alias$\n", "statement", import_statement,
+                      "alias", module_alias);
+    }
+
     CopyPublicDependenciesAliases(module_alias, file_->dependency(i));
   }
   printer_->Print("\n");
diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
index 23f2449..34f857f 100644
--- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -46,6 +46,7 @@
 
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -115,6 +116,53 @@
   EXPECT_EQ(0, cli.Run(5, argv));
 }
 
+// This test verifies that the generated Python output uses regular imports (as
+// opposed to importlib) in the usual case where the .proto file paths do not
+// not contain any Python keywords.
+TEST(PythonPluginTest, ImportTest) {
+  // Create files test1.proto and test2.proto with the former importing the
+  // latter.
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test1.proto",
+                             "syntax = \"proto3\";\n"
+                             "package foo;\n"
+                             "import \"test2.proto\";"
+                             "message Message1 {\n"
+                             "  Message2 message_2 = 1;\n"
+                             "}\n",
+                             true));
+  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test2.proto",
+                             "syntax = \"proto3\";\n"
+                             "package foo;\n"
+                             "message Message2 {}\n",
+                             true));
+
+  google::protobuf::compiler::CommandLineInterface cli;
+  cli.SetInputsAreProtoPathRelative(true);
+  python::Generator python_generator;
+  cli.RegisterGenerator("--python_out", &python_generator, "");
+  string proto_path = "-I" + TestTempDir();
+  string python_out = "--python_out=" + TestTempDir();
+  const char* argv[] = {"protoc", proto_path.c_str(), "-I.", python_out.c_str(),
+                        "test1.proto"};
+  ASSERT_EQ(0, cli.Run(5, argv));
+
+  // Loop over the lines of the generated code and verify that we find an
+  // ordinary Python import but do not find the string "importlib".
+  string output;
+  GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/test1_pb2.py", &output,
+                             true));
+  std::vector<string> lines = Split(output, "\n");
+  string expected_import = "import test2_pb2";
+  bool found_expected_import = false;
+  for (int i = 0; i < lines.size(); ++i) {
+    if (lines[i].find(expected_import) != string::npos) {
+      found_expected_import = true;
+    }
+    EXPECT_EQ(string::npos, lines[i].find("importlib"));
+  }
+  EXPECT_TRUE(found_expected_import);
+}
+
 }  // namespace
 }  // namespace python
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
similarity index 100%
rename from src/google/protobuf/compiler/ruby/ruby_generated_code.rb
rename to src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
index 92c76fb..fbe3b4c 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -48,7 +48,7 @@
 
 // Forward decls.
 std::string IntToString(int32 value);
-std::string StripDotProto(const std::string& proto_file);
+std::string GetRequireName(const std::string& proto_file);
 std::string LabelForField(google::protobuf::FieldDescriptor* field);
 std::string TypeName(google::protobuf::FieldDescriptor* field);
 void GenerateMessage(const google::protobuf::Descriptor* message,
@@ -70,13 +70,13 @@
   return os.str();
 }
 
-std::string StripDotProto(const std::string& proto_file) {
+std::string GetRequireName(const std::string& proto_file) {
   int lastindex = proto_file.find_last_of(".");
-  return proto_file.substr(0, lastindex);
+  return proto_file.substr(0, lastindex) + "_pb";
 }
 
 std::string GetOutputFilename(const std::string& proto_file) {
-  return StripDotProto(proto_file) + ".rb";
+  return GetRequireName(proto_file) + ".rb";
 }
 
 std::string LabelForField(const google::protobuf::FieldDescriptor* field) {
@@ -237,15 +237,52 @@
     "end\n");
 }
 
-// Module names, class names, and enum value names need to be Ruby constants,
-// which must start with a capital letter.
+// Locale-agnostic utility functions.
+bool IsLower(char ch) { return ch >= 'a' && ch <= 'z'; }
+
+bool IsUpper(char ch) { return ch >= 'A' && ch <= 'Z'; }
+
+bool IsAlpha(char ch) { return IsLower(ch) || IsUpper(ch); }
+
+char ToUpper(char ch) { return IsLower(ch) ? (ch - 'a' + 'A') : ch; }
+
+
+// Package names in protobuf are snake_case by convention, but Ruby module
+// names must be PascalCased.
+//
+//   foo_bar_baz -> FooBarBaz
+std::string PackageToModule(const std::string& name) {
+  bool next_upper = true;
+  std::string result;
+  result.reserve(name.size());
+
+  for (int i = 0; i < name.size(); i++) {
+    if (name[i] == '_') {
+      next_upper = true;
+    } else {
+      if (next_upper) {
+        result.push_back(ToUpper(name[i]));
+      } else {
+        result.push_back(name[i]);
+      }
+      next_upper = false;
+    }
+  }
+
+  return result;
+}
+
+// Class and enum names in protobuf should be PascalCased by convention, but
+// since there is nothing enforcing this we need to ensure that they are valid
+// Ruby constants.  That mainly means making sure that the first character is
+// an upper-case letter.
 std::string RubifyConstant(const std::string& name) {
   std::string ret = name;
   if (!ret.empty()) {
-    if (ret[0] >= 'a' && ret[0] <= 'z') {
+    if (IsLower(ret[0])) {
       // If it starts with a lowercase letter, capitalize it.
-      ret[0] = ret[0] - 'a' + 'A';
-    } else if (ret[0] < 'A' || ret[0] > 'Z') {
+      ret[0] = ToUpper(ret[0]);
+    } else if (!IsAlpha(ret[0])) {
       // Otherwise (e.g. if it begins with an underscore), we need to come up
       // with some prefix that starts with a capital letter. We could be smarter
       // here, e.g. try to strip leading underscores, but this may cause other
@@ -254,6 +291,7 @@
       ret = "PB_" + ret;
     }
   }
+
   return ret;
 }
 
@@ -314,7 +352,7 @@
       component = package_name.substr(0, dot_index);
       package_name = package_name.substr(dot_index + 1);
     }
-    component = RubifyConstant(component);
+    component = PackageToModule(component);
     printer->Print(
       "module $name$\n",
       "name", component);
@@ -391,7 +429,7 @@
     return true;
   } else {
     printer->Print(
-      "require '$name$'\n", "name", StripDotProto(import->name()));
+      "require '$name$'\n", "name", GetRequireName(import->name()));
     return true;
   }
 }
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index c0acb40..1aabe8a 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -91,12 +91,12 @@
   // Load the generated output and compare to the expected result.
   string output;
   GOOGLE_CHECK_OK(File::GetContents(
-      TestTempDir() + "/ruby_generated_code.rb",
+      TestTempDir() + "/ruby_generated_code_pb.rb",
       &output,
       true));
   string expected_output;
   GOOGLE_CHECK_OK(File::GetContents(
-      ruby_tests + "/ruby_generated_code.rb",
+      ruby_tests + "/ruby_generated_code_pb.rb",
       &expected_output,
       true));
   EXPECT_EQ(expected_output, output);
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 6e25866..e929e4f 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -261,12 +261,12 @@
   char* message;
 
   // WTF?
-  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                FORMAT_MESSAGE_FROM_SYSTEM |
-                FORMAT_MESSAGE_IGNORE_INSERTS,
-                NULL, error_code, 0,
-                (LPTSTR)&message,  // NOT A BUG!
-                0, NULL);
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                 FORMAT_MESSAGE_FROM_SYSTEM |
+                 FORMAT_MESSAGE_IGNORE_INSERTS,
+                 NULL, error_code, 0,
+                 (LPSTR)&message,  // NOT A BUG!
+                 0, NULL);
 
   string result = message;
   LocalFree(message);
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 4e2c9dc..92c70c0 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -106,6 +106,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -588,6 +589,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -697,6 +699,7 @@
   delete GeneratedCodeInfo_Annotation_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -834,9 +837,9 @@
     ".protobuf.GeneratedCodeInfo.Annotation\032O"
     "\n\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source"
     "_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B"
-    "X\n\023com.google.protobufB\020DescriptorProtos"
-    "H\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf.R"
-    "eflection", 5289);
+    "[\n\023com.google.protobufB\020DescriptorProtos"
+    "H\001Z\ndescriptor\240\001\001\242\002\003GPB\252\002\032Google.Protobu"
+    "f.Reflection", 5292);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -899,16 +902,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -1088,7 +1081,9 @@
 
 void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorSet)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FileDescriptorSet* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorSet>(
           &from);
@@ -1103,7 +1098,9 @@
 
 void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   file_.MergeFrom(from.file_);
   if (from._internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->MergeFrom(from.unknown_fields());
@@ -1856,7 +1853,9 @@
 
 void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FileDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorProto>(
           &from);
@@ -1871,7 +1870,9 @@
 
 void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   dependency_.MergeFrom(from.dependency_);
   public_dependency_.MergeFrom(from.public_dependency_);
   weak_dependency_.MergeFrom(from.weak_dependency_);
@@ -2532,7 +2533,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -2682,7 +2683,9 @@
 
 void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const DescriptorProto_ExtensionRange* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ExtensionRange>(
           &from);
@@ -2697,7 +2700,9 @@
 
 void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_start()) {
       set_start(from.start());
@@ -2831,7 +2836,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -2981,7 +2986,9 @@
 
 void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const DescriptorProto_ReservedRange* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ReservedRange>(
           &from);
@@ -2996,7 +3003,9 @@
 
 void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_start()) {
       set_start(from.start());
@@ -3608,7 +3617,9 @@
 
 void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const DescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto>(
           &from);
@@ -3623,7 +3634,9 @@
 
 void DescriptorProto::MergeFrom(const DescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   field_.MergeFrom(from.field_);
   extension_.MergeFrom(from.extension_);
   nested_type_.MergeFrom(from.nested_type_);
@@ -4844,7 +4857,9 @@
 
 void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FieldDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FieldDescriptorProto>(
           &from);
@@ -4859,7 +4874,9 @@
 
 void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -5606,7 +5623,9 @@
 
 void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const OneofDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const OneofDescriptorProto>(
           &from);
@@ -5621,7 +5640,9 @@
 
 void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -6056,7 +6077,9 @@
 
 void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const EnumDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const EnumDescriptorProto>(
           &from);
@@ -6071,7 +6094,9 @@
 
 void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   value_.MergeFrom(from.value_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
@@ -6534,7 +6559,9 @@
 
 void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const EnumValueDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueDescriptorProto>(
           &from);
@@ -6549,7 +6576,9 @@
 
 void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -7012,7 +7041,9 @@
 
 void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const ServiceDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const ServiceDescriptorProto>(
           &from);
@@ -7027,7 +7058,9 @@
 
 void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   method_.MergeFrom(from.method_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
@@ -7314,7 +7347,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -7642,7 +7675,9 @@
 
 void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const MethodDescriptorProto* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const MethodDescriptorProto>(
           &from);
@@ -7657,7 +7692,9 @@
 
 void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -8126,7 +8163,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -8792,7 +8829,9 @@
 
 void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FileOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FileOptions>(
           &from);
@@ -8807,7 +8846,9 @@
 
 void FileOptions::MergeFrom(const FileOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_java_package()) {
@@ -9529,7 +9570,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -9789,7 +9830,9 @@
 
 void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MessageOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const MessageOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const MessageOptions>(
           &from);
@@ -9804,7 +9847,9 @@
 
 void MessageOptions::MergeFrom(const MessageOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_message_set_wire_format()) {
@@ -10138,7 +10183,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -10477,7 +10522,9 @@
 
 void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FieldOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FieldOptions>(
           &from);
@@ -10492,7 +10539,9 @@
 
 void FieldOptions::MergeFrom(const FieldOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_ctype()) {
@@ -10943,7 +10992,9 @@
 
 void OneofOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const OneofOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const OneofOptions>(
           &from);
@@ -10958,7 +11009,9 @@
 
 void OneofOptions::MergeFrom(const OneofOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   _extensions_.MergeFrom(from._extensions_);
   if (from._internal_metadata_.have_unknown_fields()) {
@@ -11124,7 +11177,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -11324,7 +11377,9 @@
 
 void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const EnumOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const EnumOptions>(
           &from);
@@ -11339,7 +11394,9 @@
 
 void EnumOptions::MergeFrom(const EnumOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_allow_alias()) {
@@ -11709,7 +11766,9 @@
 
 void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const EnumValueOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueOptions>(
           &from);
@@ -11724,7 +11783,9 @@
 
 void EnumValueOptions::MergeFrom(const EnumValueOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -12066,7 +12127,9 @@
 
 void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const ServiceOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const ServiceOptions>(
           &from);
@@ -12081,7 +12144,9 @@
 
 void ServiceOptions::MergeFrom(const ServiceOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -12423,7 +12488,9 @@
 
 void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const MethodOptions* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const MethodOptions>(
           &from);
@@ -12438,7 +12505,9 @@
 
 void MethodOptions::MergeFrom(const MethodOptions& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_deprecated()) {
@@ -12796,7 +12865,9 @@
 
 void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const UninterpretedOption_NamePart* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption_NamePart>(
           &from);
@@ -12811,7 +12882,9 @@
 
 void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name_part()) {
       set_has_name_part();
@@ -12960,7 +13033,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -13313,7 +13386,9 @@
 
 void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const UninterpretedOption* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption>(
           &from);
@@ -13328,7 +13403,9 @@
 
 void UninterpretedOption::MergeFrom(const UninterpretedOption& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   name_.MergeFrom(from.name_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
     if (from.has_identifier_value()) {
@@ -14170,7 +14247,9 @@
 
 void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo.Location)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const SourceCodeInfo_Location* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo_Location>(
           &from);
@@ -14185,7 +14264,9 @@
 
 void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   path_.MergeFrom(from.path_);
   span_.MergeFrom(from.span_);
   leading_detached_comments_.MergeFrom(from.leading_detached_comments_);
@@ -14426,7 +14507,9 @@
 
 void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const SourceCodeInfo* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo>(
           &from);
@@ -14441,7 +14524,9 @@
 
 void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   location_.MergeFrom(from.location_);
   if (from._internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->MergeFrom(from.unknown_fields());
@@ -14833,7 +14918,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -15093,7 +15178,9 @@
 
 void GeneratedCodeInfo_Annotation::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const GeneratedCodeInfo_Annotation* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>(
           &from);
@@ -15108,7 +15195,9 @@
 
 void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   path_.MergeFrom(from.path_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
     if (from.has_source_file()) {
@@ -15348,7 +15437,9 @@
 
 void GeneratedCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const GeneratedCodeInfo* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>(
           &from);
@@ -15363,7 +15454,9 @@
 
 void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   annotation_.MergeFrom(from.annotation_);
   if (from._internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->MergeFrom(from.unknown_fields());
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index da853db..28410d4 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -45,6 +45,7 @@
 option java_outer_classname = "DescriptorProtos";
 option csharp_namespace = "Google.Protobuf.Reflection";
 option objc_class_prefix = "GPB";
+option java_generate_equals_and_hash = true;
 
 // descriptor.proto must be optimized for speed because reflection-based
 // algorithms don't work during bootstrapping.
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index b0c641b..ed5cca4 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -61,6 +62,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fduration_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -74,6 +76,7 @@
   delete Duration_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -101,16 +104,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fduration_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -192,7 +185,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -322,7 +315,9 @@
 
 void Duration::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Duration)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Duration* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Duration>(
           &from);
@@ -337,7 +332,9 @@
 
 void Duration::MergeFrom(const Duration& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.seconds() != 0) {
     set_seconds(from.seconds());
   }
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 8b46120..8377575 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -59,6 +60,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fempty_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -72,6 +74,7 @@
   delete Empty_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -98,16 +101,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fempty_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -240,7 +233,9 @@
 
 void Empty::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Empty)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Empty* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Empty>(
           &from);
@@ -255,7 +250,9 @@
 
 void Empty::MergeFrom(const Empty& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
 }
 
 void Empty::CopyFrom(const ::google::protobuf::Message& from) {
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 5dd171e..b26a246 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -341,7 +341,7 @@
 
 int ExtensionSet::SpaceUsedExcludingSelf() const {
   int total_size =
-      extensions_.size() * sizeof(map<int, Extension>::value_type);
+      extensions_.size() * sizeof(ExtensionMap::value_type);
   for (ExtensionMap::const_iterator iter = extensions_.begin(),
        end = extensions_.end();
        iter != end;
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index d197b40..ed05fe5 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -60,6 +61,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2ffield_5fmask_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -73,6 +75,7 @@
   delete FieldMask_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -99,16 +102,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2ffield_5fmask_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -281,7 +274,9 @@
 
 void FieldMask::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldMask)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FieldMask* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>(
           &from);
@@ -296,7 +291,9 @@
 
 void FieldMask::MergeFrom(const FieldMask& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   paths_.MergeFrom(from.paths_);
 }
 
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 7b813f8..7ad6d61 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -73,6 +73,12 @@
 
 
 
+void MergeFromFail(const char* file, int line) {
+  GOOGLE_CHECK(false) << file << ":" << line;
+  // Open-source GOOGLE_CHECK(false) is not NORETURN.
+  exit(1);
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 56f5afd..8967726 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -41,8 +41,8 @@
 #include <assert.h>
 #include <string>
 
-#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
 
 namespace google {
 
@@ -112,8 +112,13 @@
 // pointer to a copy of the string that resides in *arena.  Requires both
 // args to be non-NULL.  If something goes wrong while reading the data
 // then NULL is returned (e.g., input does not start with a valid varint).
-ArenaString* ReadArenaString(::google::protobuf::io::CodedInputStream* input,
-                             ::google::protobuf::Arena* arena);
+LIBPROTOBUF_EXPORT ArenaString* ReadArenaString(
+    ::google::protobuf::io::CodedInputStream* input,
+    ::google::protobuf::Arena* arena);
+
+// Helper function to crash on merge failure.
+// Moved out of generated code to reduce binary size.
+LIBPROTOBUF_EXPORT void MergeFromFail(const char* file, int line) GOOGLE_ATTRIBUTE_NORETURN;
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 148eee0..a5675e7 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -649,13 +649,16 @@
 
 // CodedOutputStream =================================================
 
+bool CodedOutputStream::default_serialization_deterministic_ = false;
+
 CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
   : output_(output),
     buffer_(NULL),
     buffer_size_(0),
     total_bytes_(0),
     had_error_(false),
-    aliasing_enabled_(false) {
+    aliasing_enabled_(false),
+    serialization_deterministic_is_overridden_(false) {
   // Eagerly Refresh() so buffer space is immediately available.
   Refresh();
   // The Refresh() may have failed. If the client doesn't write any data,
@@ -671,7 +674,8 @@
     buffer_size_(0),
     total_bytes_(0),
     had_error_(false),
-    aliasing_enabled_(false) {
+    aliasing_enabled_(false),
+    serialization_deterministic_is_overridden_(false) {
   if (do_eager_refresh) {
     // Eagerly Refresh() so buffer space is immediately available.
     Refresh();
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index eb32074..316da76 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -813,6 +813,44 @@
   // created.
   bool HadError() const { return had_error_; }
 
+  // Deterministic serialization, if requested, guarantees that for a given
+  // binary, equal messages will always be serialized to the same bytes. This
+  // implies:
+  //   . repeated serialization of a message will return the same bytes
+  //   . different processes of the same binary (which may be executing on
+  //     different machines) will serialize equal messages to the same bytes.
+  //
+  // Note the deterministic serialization is NOT canonical across languages; it
+  // is also unstable across different builds with schema changes due to unknown
+  // fields. Users who need canonical serialization, e.g., persistent storage in
+  // a canonical form, fingerprinting, etc., should define their own
+  // canonicalization specification and implement the serializer using
+  // reflection APIs rather than relying on this API.
+  //
+  // If determinisitc serialization is requested, the serializer will
+  // sort map entries by keys in lexicographical order or numerical order.
+  // (This is an implementation detail and may subject to change.)
+  //
+  // There are two ways to determine whether serialization should be
+  // deterministic for this CodedOutputStream.  If SetSerializationDeterministic
+  // has not yet been called, then the default comes from the global default,
+  // which is false, until SetDefaultSerializationDeterministic has been called.
+  // Otherwise, SetSerializationDeterministic has been called, and the last
+  // value passed to it is all that matters.
+  void SetSerializationDeterministic(bool value) {
+    serialization_deterministic_is_overridden_ = true;
+    serialization_deterministic_override_ = value;
+  }
+  // See above.  Also, note that users of this CodedOutputStream may need to
+  // call IsSerializationDeterminstic() to serialize in the intended way.  This
+  // CodedOutputStream cannot enforce a desire for deterministic serialization
+  // by itself.
+  bool IsSerializationDeterminstic() const {
+    return serialization_deterministic_is_overridden_ ?
+        serialization_deterministic_override_ :
+        default_serialization_deterministic_;
+  }
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
 
@@ -822,6 +860,10 @@
   int total_bytes_;  // Sum of sizes of all buffers seen so far.
   bool had_error_;   // Whether an error occurred during output.
   bool aliasing_enabled_;  // See EnableAliasing().
+  // See SetSerializationDeterministic() regarding these three fields.
+  bool serialization_deterministic_is_overridden_;
+  bool serialization_deterministic_override_;
+  static bool default_serialization_deterministic_;
 
   // Advance the buffer by a given number of bytes.
   void Advance(int amount);
@@ -849,6 +891,11 @@
       uint64 value, uint8* target);
 
   static int VarintSize32Fallback(uint32 value);
+
+  // See above.  Other projects may use "friend" to allow them to call this.
+  static void SetDefaultSerializationDeterministic() {
+    default_serialization_deterministic_ = true;
+  }
 };
 
 // inline methods ====================================================
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 42bcfd9..1b9aa70 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -1250,7 +1250,7 @@
     // Return whether table_[b] is a linked list that seems awfully long.
     // Requires table_[b] to point to a non-empty linked list.
     bool TableEntryIsTooLong(size_type b) {
-      const int kMaxLength = 8;
+      const size_type kMaxLength = 8;
       size_type count = 0;
       Node* node = static_cast<Node*>(table_[b]);
       do {
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 23ac7b8..4dedfd5 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -535,6 +535,32 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
 };
 
+// Helpers for deterministic serialization =============================
+
+// This struct can be used with any generic sorting algorithm.  If the Key
+// type is relatively small and easy to copy then copying Keys into an
+// array of SortItems can be beneficial.  Then all the data the sorting
+// algorithm needs to touch is in that one array.
+template <typename Key, typename PtrToKeyValuePair> struct SortItem {
+  SortItem() {}
+  explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {}
+
+  Key first;
+  PtrToKeyValuePair second;
+};
+
+template <typename T> struct CompareByFirstField {
+  bool operator()(const T& a, const T& b) const {
+    return a.first < b.first;
+  }
+};
+
+template <typename T> struct CompareByDerefFirst {
+  bool operator()(const T& a, const T& b) const {
+    return a->first < b->first;
+  }
+};
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
index 916cc54..ddc2a58 100644
--- a/src/google/protobuf/map_proto2_unittest.proto
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -64,3 +64,23 @@
 message TestImportEnumMap {
   map<int32, protobuf_unittest_import.ImportEnumForMap> import_enum_amp = 1;
 }
+
+message TestIntIntMap {
+  map<int32, int32> m = 1;
+}
+
+// Test all key types: string, plus the non-floating-point scalars.
+message TestMaps {
+  map<int32, TestIntIntMap> m_int32 = 1;
+  map<int64, TestIntIntMap> m_int64 = 2;
+  map<uint32, TestIntIntMap> m_uint32 = 3;
+  map<uint64, TestIntIntMap> m_uint64 = 4;
+  map<sint32, TestIntIntMap> m_sint32 = 5;
+  map<sint64, TestIntIntMap> m_sint64 = 6;
+  map<fixed32, TestIntIntMap> m_fixed32 = 7;
+  map<fixed64, TestIntIntMap> m_fixed64 = 8;
+  map<sfixed32, TestIntIntMap> m_sfixed32 = 9;
+  map<sfixed64, TestIntIntMap> m_sfixed64 = 10;
+  map<bool, TestIntIntMap> m_bool = 11;
+  map<string, TestIntIntMap> m_string = 12;
+}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index cdd1ccd..03954e7 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -74,6 +74,7 @@
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/util/time_util.h>
+#include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <gmock/gmock.h>
@@ -2869,6 +2870,82 @@
   }
 }
 
+// Deterministic Serialization Test ==========================================
+
+template <typename T>
+static string DeterministicSerialization(const T& t) {
+  const int size = t.ByteSize();
+  string result(size, '\0');
+  io::ArrayOutputStream array_stream(string_as_array(&result), size);
+  io::CodedOutputStream output_stream(&array_stream);
+  output_stream.SetSerializationDeterministic(true);
+  t.SerializeWithCachedSizes(&output_stream);
+  EXPECT_FALSE(output_stream.HadError());
+  EXPECT_EQ(size, output_stream.ByteCount());
+  return result;
+}
+
+// Helper to test the serialization of the first arg against a golden file.
+static void TestDeterministicSerialization(const protobuf_unittest::TestMaps& t,
+                                           const string& filename) {
+  string expected;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestSourceDir() + "/google/protobuf/testdata/" + filename,
+      &expected, true));
+  const string actual = DeterministicSerialization(t);
+  EXPECT_EQ(expected, actual);
+  protobuf_unittest::TestMaps u;
+  EXPECT_TRUE(u.ParseFromString(actual));
+  EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(u, t));
+}
+
+// Helper for MapSerializationTest.  Return a 7-bit ASCII string.
+static string ConstructKey(uint64 n) {
+  string s(n % static_cast<uint64>(9), '\0');
+  if (s.empty()) {
+    return StrCat(n);
+  } else {
+    while (n != 0) {
+      s[n % s.size()] = (n >> 10) & 0x7f;
+      n /= 888;
+    }
+    return s;
+  }
+}
+
+TEST(MapSerializationTest, Deterministic) {
+  const int kIters = 25;
+  protobuf_unittest::TestMaps t;
+  protobuf_unittest::TestIntIntMap inner;
+  (*inner.mutable_m())[0] = (*inner.mutable_m())[10] =
+      (*inner.mutable_m())[-200] = 0;
+  uint64 frog = 9;
+  const uint64 multiplier = 0xa29cd16f;
+  for (int i = 0; i < kIters; i++) {
+    const int32 i32 = static_cast<int32>(frog & 0xffffffff);
+    const uint32 u32 = static_cast<uint32>(i32) * 91919;
+    const int64 i64 = static_cast<int64>(frog);
+    const uint64 u64 = frog * static_cast<uint64>(187321);
+    const bool b = i32 > 0;
+    const string s = ConstructKey(frog);
+    (*inner.mutable_m())[i] = i32;
+    (*t.mutable_m_int32())[i32] = (*t.mutable_m_sint32())[i32] =
+        (*t.mutable_m_sfixed32())[i32] = inner;
+    (*t.mutable_m_uint32())[u32] = (*t.mutable_m_fixed32())[u32] = inner;
+    (*t.mutable_m_int64())[i64] = (*t.mutable_m_sint64())[i64] =
+        (*t.mutable_m_sfixed64())[i64] = inner;
+    (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner;
+    (*t.mutable_m_bool())[b] = inner;
+    (*t.mutable_m_string())[s] = inner;
+    (*t.mutable_m_string())[s + string(1 << (u32 % static_cast<uint32>(9)),
+                                       b)] = inner;
+    inner.mutable_m()->erase(i);
+    frog = frog * multiplier + i;
+    frog ^= (frog >> 41);
+  }
+  TestDeterministicSerialization(t, "golden_message_maps");
+}
+
 // Text Format Test =================================================
 
 TEST(TextFormatMapTest, SerializeAndParse) {
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 74e8bb5..685a770 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -166,10 +166,10 @@
                            io::CodedOutputStream* output);
   static inline uint8* InternalWriteToArray(int field,
                                             const MapEntryAccessorType& value,
-                                            bool deterministic, uint8* output);
+                                            bool deterministic, uint8* target);
   static inline uint8* WriteToArray(int field,
                                     const MapEntryAccessorType& value,
-                                    uint8* output);
+                                    uint8* target);
 
   // Functions to manipulate data on memory. ========================
   static inline const Type& GetExternalReference(const Type* value);
@@ -227,11 +227,11 @@
         int field,                                                            \
         const MapEntryAccessorType& value,                                    \
         bool deterministic,                                                   \
-        uint8* output);                                                       \
+        uint8* target);                                                       \
     static inline uint8* WriteToArray(int field,                              \
                                       const MapEntryAccessorType& value,      \
-                                      uint8* output) {                        \
-      return InternalWriteToArray(field, value, false, output);               \
+                                      uint8* target) {                        \
+      return InternalWriteToArray(field, value, false, target);               \
     }                                                                         \
     static inline const MapEntryAccessorType& GetExternalReference(           \
         const TypeOnMemory& value);                                           \
@@ -374,9 +374,9 @@
 inline uint8*
 MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::InternalWriteToArray(
     int field, const MapEntryAccessorType& value, bool deterministic,
-    uint8* output) {
+    uint8* target) {
   return WireFormatLite::InternalWriteMessageToArray(field, value,
-                                                     deterministic, output);
+                                                     deterministic, target);
 }
 
 #define WRITE_METHOD(FieldType, DeclaredType)                                  \
@@ -390,8 +390,8 @@
   inline uint8*                                                                \
   MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
                  Type>::InternalWriteToArray(                                  \
-      int field, const MapEntryAccessorType& value, bool, uint8* output) {     \
-    return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
+      int field, const MapEntryAccessorType& value, bool, uint8* target) {     \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, target); \
   }
 
 WRITE_METHOD(STRING  , String)
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index d62ca79..f18077d 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -62,8 +62,6 @@
 using internal::WireFormat;
 using internal::ReflectionOps;
 
-Message::~Message() {}
-
 void Message::MergeFrom(const Message& from) {
   const Descriptor* descriptor = GetDescriptor();
   GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index dcdffe1..9705e97 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -179,7 +179,7 @@
 class LIBPROTOBUF_EXPORT Message : public MessageLite {
  public:
   inline Message() {}
-  virtual ~Message();
+  virtual ~Message() {}
 
   // Basic Operations ------------------------------------------------
 
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 3913be1..ba56db9 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -46,8 +46,6 @@
 namespace google {
 namespace protobuf {
 
-MessageLite::~MessageLite() {}
-
 string MessageLite::InitializationErrorString() const {
   return "(cannot determine missing fields for lite message)";
 }
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index f606aee..2bdfe49 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -81,7 +81,7 @@
 class LIBPROTOBUF_EXPORT MessageLite {
  public:
   inline MessageLite() {}
-  virtual ~MessageLite();
+  virtual ~MessageLite() {}
 
   // Basic Operations ------------------------------------------------
 
diff --git a/src/google/protobuf/repeated_field_reflection.h b/src/google/protobuf/repeated_field_reflection.h
deleted file mode 100644
index 512c0f1..0000000
--- a/src/google/protobuf/repeated_field_reflection.h
+++ /dev/null
@@ -1,337 +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.
-
-// This header file is protobuf internal. Users should not include this
-// file directly.
-#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
-#define GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
-
-#include <memory>
-#ifndef _SHARED_PTR_H
-#include <google/protobuf/stubs/shared_ptr.h>
-#endif
-
-#include <google/protobuf/generated_enum_reflection.h>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-// Interfaces used to implement reflection RepeatedFieldRef API.
-// Reflection::GetRepeatedAccessor() should return a pointer to an singleton
-// object that implements the below interface.
-//
-// This interface passes/returns values using void pointers. The actual type
-// of the value depends on the field's cpp_type. Following is a mapping from
-// cpp_type to the type that should be used in this interface:
-//
-//   field->cpp_type()      T                Actual type of void*
-//   CPPTYPE_INT32        int32                   int32
-//   CPPTYPE_UINT32       uint32                  uint32
-//   CPPTYPE_INT64        int64                   int64
-//   CPPTYPE_UINT64       uint64                  uint64
-//   CPPTYPE_DOUBLE       double                  double
-//   CPPTYPE_FLOAT        float                   float
-//   CPPTYPE_BOOL         bool                    bool
-//   CPPTYPE_ENUM         generated enum type     int32
-//   CPPTYPE_STRING       string                  string
-//   CPPTYPE_MESSAGE      generated message type  google::protobuf::Message
-//                        or google::protobuf::Message
-//
-// Note that for enums we use int32 in the interface.
-//
-// You can map from T to the actual type using RefTypeTraits:
-//   typedef RefTypeTraits<T>::AccessorValueType ActualType;
-class LIBPROTOBUF_EXPORT RepeatedFieldAccessor {
- public:
-  // Typedefs for clarity.
-  typedef void Field;
-  typedef void Value;
-  typedef void Iterator;
-
-  virtual ~RepeatedFieldAccessor();
-  virtual bool IsEmpty(const Field* data) const = 0;
-  virtual int Size(const Field* data) const = 0;
-  // Depends on the underlying representation of the repeated field, this
-  // method can return a pointer to the underlying object if such an object
-  // exists, or fill the data into scratch_space and return scratch_space.
-  // Callers of this method must ensure scratch_space is a valid pointer
-  // to a mutable object of the correct type.
-  virtual const Value* Get(
-      const Field* data, int index, Value* scratch_space) const = 0;
-
-  virtual void Clear(Field* data) const = 0;
-  virtual void Set(Field* data, int index, const Value* value) const = 0;
-  virtual void Add(Field* data, const Value* value) const = 0;
-  virtual void RemoveLast(Field* data) const = 0;
-  virtual void SwapElements(Field* data, int index1, int index2) const = 0;
-  virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator,
-                    Field* other_data) const = 0;
-
-  // Create an iterator that points at the beginning of the repeated field.
-  virtual Iterator* BeginIterator(const Field* data) const = 0;
-  // Create an iterator that points at the end of the repeated field.
-  virtual Iterator* EndIterator(const Field* data) const = 0;
-  // Make a copy of an iterator and return the new copy.
-  virtual Iterator* CopyIterator(const Field* data,
-                                 const Iterator* iterator) const = 0;
-  // Move an iterator to point to the next element.
-  virtual Iterator* AdvanceIterator(const Field* data,
-                                    Iterator* iterator) const = 0;
-  // Compare whether two iterators point to the same element.
-  virtual bool EqualsIterator(const Field* data, const Iterator* a,
-                              const Iterator* b) const = 0;
-  // Delete an iterator created by BeginIterator(), EndIterator() and
-  // CopyIterator().
-  virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0;
-  // Like Get() but for iterators.
-  virtual const Value* GetIteratorValue(const Field* data,
-                                        const Iterator* iterator,
-                                        Value* scratch_space) const = 0;
-
-  // Templated methods that make using this interface easier for non-message
-  // types.
-  template<typename T>
-  T Get(const Field* data, int index) const {
-    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
-    ActualType scratch_space;
-    return static_cast<T>(
-        *reinterpret_cast<const ActualType*>(
-            Get(data, index, static_cast<Value*>(&scratch_space))));
-  }
-
-  template<typename T, typename ValueType>
-  void Set(Field* data, int index, const ValueType& value) const {
-    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
-    // In this RepeatedFieldAccessor interface we pass/return data using
-    // raw pointers. Type of the data these raw pointers point to should
-    // be ActualType. Here we have a ValueType object and want a ActualType
-    // pointer. We can't cast a ValueType pointer to an ActualType pointer
-    // directly because their type might be different (for enums ValueType
-    // may be a generated enum type while ActualType is int32). To be safe
-    // we make a copy to get a temporary ActualType object and use it.
-    ActualType tmp = static_cast<ActualType>(value);
-    Set(data, index, static_cast<const Value*>(&tmp));
-  }
-
-  template<typename T, typename ValueType>
-  void Add(Field* data, const ValueType& value) const {
-    typedef typename RefTypeTraits<T>::AccessorValueType ActualType;
-    // In this RepeatedFieldAccessor interface we pass/return data using
-    // raw pointers. Type of the data these raw pointers point to should
-    // be ActualType. Here we have a ValueType object and want a ActualType
-    // pointer. We can't cast a ValueType pointer to an ActualType pointer
-    // directly because their type might be different (for enums ValueType
-    // may be a generated enum type while ActualType is int32). To be safe
-    // we make a copy to get a temporary ActualType object and use it.
-    ActualType tmp = static_cast<ActualType>(value);
-    Add(data, static_cast<const Value*>(&tmp));
-  }
-};
-
-// Implement (Mutable)RepeatedFieldRef::iterator
-template<typename T>
-class RepeatedFieldRefIterator
-    : public std::iterator<std::forward_iterator_tag, T> {
-  typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType;
-  typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType;
-  typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType;
-
- public:
-  // Constructor for non-message fields.
-  RepeatedFieldRefIterator(const void* data,
-                           const RepeatedFieldAccessor* accessor,
-                           bool begin)
-      : data_(data), accessor_(accessor),
-        iterator_(begin ? accessor->BeginIterator(data) :
-                          accessor->EndIterator(data)),
-        scratch_space_(new AccessorValueType) {
-  }
-  // Constructor for message fields.
-  RepeatedFieldRefIterator(const void* data,
-                           const RepeatedFieldAccessor* accessor,
-                           bool begin,
-                           AccessorValueType* scratch_space)
-      : data_(data), accessor_(accessor),
-        iterator_(begin ? accessor->BeginIterator(data) :
-                          accessor->EndIterator(data)),
-        scratch_space_(scratch_space) {
-  }
-  ~RepeatedFieldRefIterator() {
-    accessor_->DeleteIterator(data_, iterator_);
-  }
-  RepeatedFieldRefIterator operator++(int) {
-    RepeatedFieldRefIterator tmp(*this);
-    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
-    return tmp;
-  }
-  RepeatedFieldRefIterator& operator++() {
-    iterator_ = accessor_->AdvanceIterator(data_, iterator_);
-    return *this;
-  }
-  IteratorValueType operator*() const {
-    return static_cast<IteratorValueType>(
-        *static_cast<const AccessorValueType*>(
-            accessor_->GetIteratorValue(
-                data_, iterator_, scratch_space_.get())));
-  }
-  IteratorPointerType operator->() const {
-    return static_cast<IteratorPointerType>(
-        accessor_->GetIteratorValue(
-            data_, iterator_, scratch_space_.get()));
-  }
-  bool operator!=(const RepeatedFieldRefIterator& other) const {
-    assert(data_ == other.data_);
-    assert(accessor_ == other.accessor_);
-    return !accessor_->EqualsIterator(data_, iterator_, other.iterator_);
-  }
-  bool operator==(const RepeatedFieldRefIterator& other) const {
-    return !this->operator!=(other);
-  }
-
-  RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other)
-      : data_(other.data_), accessor_(other.accessor_),
-        iterator_(accessor_->CopyIterator(data_, other.iterator_)) {
-  }
-  RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) {
-    if (this != &other) {
-      accessor_->DeleteIterator(data_, iterator_);
-      data_ = other.data_;
-      accessor_ = other.accessor_;
-      iterator_ = accessor_->CopyIterator(data_, other.iterator_);
-    }
-    return *this;
-  }
-
- protected:
-  const void* data_;
-  const RepeatedFieldAccessor* accessor_;
-  void* iterator_;
-  google::protobuf::scoped_ptr<AccessorValueType> scratch_space_;
-};
-
-// TypeTraits that maps the type parameter T of RepeatedFieldRef or
-// MutableRepeatedFieldRef to corresponding iterator type,
-// RepeatedFieldAccessor type, etc.
-template<typename T>
-struct PrimitiveTraits {
-  static const bool is_primitive = false;
-};
-#define DEFINE_PRIMITIVE(TYPE, type) \
-    template<> struct PrimitiveTraits<type> { \
-      static const bool is_primitive = true; \
-      static const FieldDescriptor::CppType cpp_type = \
-          FieldDescriptor::CPPTYPE_ ## TYPE; \
-    };
-DEFINE_PRIMITIVE(INT32, int32)
-DEFINE_PRIMITIVE(UINT32, uint32)
-DEFINE_PRIMITIVE(INT64, int64)
-DEFINE_PRIMITIVE(UINT64, uint64)
-DEFINE_PRIMITIVE(FLOAT, float)
-DEFINE_PRIMITIVE(DOUBLE, double)
-DEFINE_PRIMITIVE(BOOL, bool)
-#undef DEFINE_PRIMITIVE
-
-template<typename T>
-struct RefTypeTraits<
-    T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> {
-  typedef RepeatedFieldRefIterator<T> iterator;
-  typedef RepeatedFieldAccessor AccessorType;
-  typedef T AccessorValueType;
-  typedef T IteratorValueType;
-  typedef T* IteratorPointerType;
-  static const FieldDescriptor::CppType cpp_type =
-      PrimitiveTraits<T>::cpp_type;
-  static const Descriptor* GetMessageFieldDescriptor() {
-    return NULL;
-  }
-};
-
-template<typename T>
-struct RefTypeTraits<
-    T, typename internal::enable_if<is_proto_enum<T>::value>::type> {
-  typedef RepeatedFieldRefIterator<T> iterator;
-  typedef RepeatedFieldAccessor AccessorType;
-  // We use int32 for repeated enums in RepeatedFieldAccessor.
-  typedef int32 AccessorValueType;
-  typedef T IteratorValueType;
-  typedef int32* IteratorPointerType;
-  static const FieldDescriptor::CppType cpp_type =
-      FieldDescriptor::CPPTYPE_ENUM;
-  static const Descriptor* GetMessageFieldDescriptor() {
-    return NULL;
-  }
-};
-
-template<typename T>
-struct RefTypeTraits<
-    T, typename internal::enable_if<internal::is_same<string, T>::value>::type> {
-  typedef RepeatedFieldRefIterator<T> iterator;
-  typedef RepeatedFieldAccessor AccessorType;
-  typedef string AccessorValueType;
-  typedef string IteratorValueType;
-  typedef string* IteratorPointerType;
-  static const FieldDescriptor::CppType cpp_type =
-      FieldDescriptor::CPPTYPE_STRING;
-  static const Descriptor* GetMessageFieldDescriptor() {
-    return NULL;
-  }
-};
-
-template<typename T>
-struct MessageDescriptorGetter {
-  static const Descriptor* get() {
-    return T::default_instance().GetDescriptor();
-  }
-};
-template<>
-struct MessageDescriptorGetter<Message> {
-  static const Descriptor* get() {
-    return NULL;
-  }
-};
-
-template<typename T>
-struct RefTypeTraits<
-    T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> {
-  typedef RepeatedFieldRefIterator<T> iterator;
-  typedef RepeatedFieldAccessor AccessorType;
-  typedef Message AccessorValueType;
-  typedef const T& IteratorValueType;
-  typedef const T* IteratorPointerType;
-  static const FieldDescriptor::CppType cpp_type =
-      FieldDescriptor::CPPTYPE_MESSAGE;
-  static const Descriptor* GetMessageFieldDescriptor() {
-    return MessageDescriptorGetter<T>::get();
-  }
-};
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 4d8e77c..5cc77bf 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -60,6 +61,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fsource_5fcontext_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -73,6 +75,7 @@
   delete SourceContext_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -99,16 +102,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fsource_5fcontext_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -281,7 +274,9 @@
 
 void SourceContext::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceContext)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const SourceContext* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const SourceContext>(
           &from);
@@ -296,7 +291,9 @@
 
 void SourceContext::MergeFrom(const SourceContext& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.file_name().size() > 0) {
 
     file_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.file_name_);
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index dd6b78d..a551384 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -45,6 +45,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -116,6 +117,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -147,6 +149,7 @@
   delete ListValue_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -203,16 +206,6 @@
 }
 
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -348,18 +341,51 @@
     ::google::protobuf::io::CodedOutputStream* output) const {
   // @@protoc_insertion_point(serialize_start:google.protobuf.Struct)
   // map<string, .google.protobuf.Value> fields = 1;
-  {
-    ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
-    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = this->fields().begin();
-        it != this->fields().end(); ++it) {
-      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
-      ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-          1, *entry, output);
-      ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
-        it->first.data(), it->first.length(),
-        ::google::protobuf::internal::WireFormatLite::SERIALIZE,
-        "google.protobuf.Struct.FieldsEntry.key");
+  if (!this->fields().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "google.protobuf.Struct.FieldsEntry.key");
+      }
+    };
+
+    if (output->IsSerializationDeterminstic() &&
+        this->fields().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->fields().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+          it = this->fields().begin();
+          it != this->fields().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(fields_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            1, *entry, output);
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+          it = this->fields().begin();
+          it != this->fields().end(); ++it) {
+        entry.reset(fields_.NewEntryWrapper(
+            it->first, it->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            1, *entry, output);
+        Utf8Check::Check(&*it);
+      }
     }
   }
 
@@ -370,19 +396,55 @@
     bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
   // map<string, .google.protobuf.Value> fields = 1;
-  {
-    ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
-    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = this->fields().begin();
-        it != this->fields().end(); ++it) {
-      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
-      target = ::google::protobuf::internal::WireFormatLite::
-          InternalWriteMessageNoVirtualToArray(
-              1, *entry, false, target);
-      ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
-        it->first.data(), it->first.length(),
-        ::google::protobuf::internal::WireFormatLite::SERIALIZE,
-        "google.protobuf.Struct.FieldsEntry.key");
+  if (!this->fields().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "google.protobuf.Struct.FieldsEntry.key");
+      }
+    };
+
+    if (deterministic &&
+        this->fields().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->fields().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+          it = this->fields().begin();
+          it != this->fields().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(fields_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       1, *entry, deterministic, target);
+;
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+          it = this->fields().begin();
+          it != this->fields().end(); ++it) {
+        entry.reset(fields_.NewEntryWrapper(
+            it->first, it->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       1, *entry, deterministic, target);
+;
+        Utf8Check::Check(&*it);
+      }
     }
   }
 
@@ -415,7 +477,9 @@
 
 void Struct::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Struct)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Struct* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Struct>(
           &from);
@@ -430,7 +494,9 @@
 
 void Struct::MergeFrom(const Struct& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   fields_.MergeFrom(from.fields_);
 }
 
@@ -881,7 +947,9 @@
 
 void Value::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Value* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Value>(
           &from);
@@ -896,7 +964,9 @@
 
 void Value::MergeFrom(const Value& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   switch (from.kind_case()) {
     case kNullValue: {
       set_null_value(from.null_value());
@@ -1406,7 +1476,9 @@
 
 void ListValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ListValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const ListValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const ListValue>(
           &from);
@@ -1421,7 +1493,9 @@
 
 void ListValue::MergeFrom(const ListValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   values_.MergeFrom(from.values_);
 }
 
diff --git a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
index a0116a6..7314ee4 100644
--- a/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
+++ b/src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
@@ -128,6 +128,24 @@
   return old_value;
 }
 
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __atomic_store_n(ptr, value, __ATOMIC_RELAXED);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return __atomic_load_n(ptr, __ATOMIC_RELAXED);
+}
+
 #endif // defined(__LP64__)
 
 }  // namespace internal
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index 87271c5..bbd507a 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -381,6 +381,8 @@
   typename remove_reference<P5>::type p5_;
 };
 
+}  // namespace internal
+
 // See Closure.
 inline Closure* NewCallback(void (*function)()) {
   return new internal::FunctionClosure0(function, true);
@@ -533,8 +535,6 @@
                                                     p2, p3, p4, p5);
 }
 
-}  // namespace internal
-
 // A function which does nothing.  Useful for creating no-op callbacks, e.g.:
 //   Closure* nothing = NewCallback(&DoNothing);
 void LIBPROTOBUF_EXPORT DoNothing();
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index 25bae9b..f9e2cfd 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -41,8 +41,6 @@
 
 namespace google {
 namespace protobuf {
-using internal::NewCallback;
-using internal::NewPermanentCallback;
 namespace {
 
 // TODO(kenton):  More tests.
diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc
index 3a36b4b..a509080 100644
--- a/src/google/protobuf/stubs/int128.cc
+++ b/src/google/protobuf/stubs/int128.cc
@@ -145,15 +145,15 @@
   std::streamsize div_base_log;
   switch (flags & std::ios::basefield) {
     case std::ios::hex:
-      div = GOOGLE_ULONGLONG(0x1000000000000000);  // 16^15
+      div = static_cast<uint64>(GOOGLE_ULONGLONG(0x1000000000000000));  // 16^15
       div_base_log = 15;
       break;
     case std::ios::oct:
-      div = GOOGLE_ULONGLONG(01000000000000000000000);  // 8^21
+      div = static_cast<uint64>(GOOGLE_ULONGLONG(01000000000000000000000));  // 8^21
       div_base_log = 21;
       break;
     default:  // std::ios::dec
-      div = GOOGLE_ULONGLONG(10000000000000000000);  // 10^19
+      div = static_cast<uint64>(GOOGLE_ULONGLONG(10000000000000000000));  // 10^19
       div_base_log = 19;
       break;
   }
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
index 4cccbbe..887f12a 100644
--- a/src/google/protobuf/stubs/map_util.h
+++ b/src/google/protobuf/stubs/map_util.h
@@ -208,7 +208,7 @@
 FindLinkedPtrOrDie(const Collection& collection,
                    const typename Collection::value_type::first_type& key) {
   typename Collection::const_iterator it = collection.find(key);
-  CHECK(it != collection.end()) <<  "key not found: " << key;
+  GOOGLE_CHECK(it != collection.end()) <<  "key not found: " << key;
   // Since linked_ptr::operator*() is a const member returning a non const,
   // we do not need a version of this function taking a non const collection.
   return *it->second;
@@ -337,14 +337,15 @@
 template <class Collection>
 void InsertOrDie(Collection* const collection,
                  const typename Collection::value_type& value) {
-  CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value))
+      << "duplicate value: " << value;
 }
 
 // Same as above except doesn't log the value on error.
 template <class Collection>
 void InsertOrDieNoPrint(Collection* const collection,
                         const typename Collection::value_type& value) {
-  CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
+  GOOGLE_CHECK(InsertIfNotPresent(collection, value)) << "duplicate value.";
 }
 
 // Inserts the key-value pair into the collection. Dies if key was already
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index 37def58..d5f7779 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -43,7 +43,6 @@
 
 namespace google {
 namespace protobuf {
-using internal::NewCallback;
 namespace {
 
 class OnceInitTest : public testing::Test {
@@ -128,11 +127,11 @@
   };
 
   TestThread* RunInitOnceInNewThread() {
-    return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce));
+    return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
   }
   TestThread* RunInitRecursiveOnceInNewThread() {
     return new TestThread(
-        internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce));
+        NewCallback(this, &OnceInitTest::InitRecursiveOnce));
   }
 
   enum State {
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index 328258b..d7f93b4 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -109,15 +109,15 @@
 typedef unsigned __int32 uint32;
 typedef unsigned __int64 uint64;
 #else
-typedef signed char  int8;
-typedef short int16;
-typedef int int32;
-typedef long long int64;
+typedef int8_t int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
 
-typedef unsigned char  uint8;
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-typedef unsigned long long uint64;
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
 #endif
 
 // long long macros to be used because gcc and vc++ use different suffixes,
@@ -131,8 +131,10 @@
 #define GOOGLE_ULONGLONG(x) x##UI64
 #define GOOGLE_LL_FORMAT "I64"  // As in printf("%I64d", ...)
 #else
+// By long long, we actually mean int64.
 #define GOOGLE_LONGLONG(x) x##LL
 #define GOOGLE_ULONGLONG(x) x##ULL
+// Used to format real long long integers.
 #define GOOGLE_LL_FORMAT "ll"  // As in "%lld". Note that "q" is poor form also.
 #endif
 
diff --git a/src/google/protobuf/testdata/golden_message_maps b/src/google/protobuf/testdata/golden_message_maps
new file mode 100644
index 0000000..c70a4d7
--- /dev/null
+++ b/src/google/protobuf/testdata/golden_message_maps
Binary files differ
diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc
index 3d07b12..470512e 100644
--- a/src/google/protobuf/testing/file.cc
+++ b/src/google/protobuf/testing/file.cc
@@ -91,6 +91,7 @@
 
   if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
     GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno);
+    fclose(file);
     return false;
   }
 
@@ -140,12 +141,12 @@
 
 #ifdef _MSC_VER
   // This interface is so weird.
-  WIN32_FIND_DATA find_data;
-  HANDLE find_handle = FindFirstFile((name + "/*").c_str(), &find_data);
+  WIN32_FIND_DATAA find_data;
+  HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data);
   if (find_handle == INVALID_HANDLE_VALUE) {
     // Just delete it, whatever it is.
-    DeleteFile(name.c_str());
-    RemoveDirectory(name.c_str());
+    DeleteFileA(name.c_str());
+    RemoveDirectoryA(name.c_str());
     return;
   }
 
@@ -155,15 +156,15 @@
       string path = name + "/" + entry_name;
       if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
         DeleteRecursively(path, NULL, NULL);
-        RemoveDirectory(path.c_str());
+        RemoveDirectoryA(path.c_str());
       } else {
-        DeleteFile(path.c_str());
+        DeleteFileA(path.c_str());
       }
     }
-  } while(FindNextFile(find_handle, &find_data));
+  } while(FindNextFileA(find_handle, &find_data));
   FindClose(find_handle);
 
-  RemoveDirectory(name.c_str());
+  RemoveDirectoryA(name.c_str());
 #else
   // Use opendir()!  Yay!
   // lstat = Don't follow symbolic links.
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index d49d858..66b2648 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -759,6 +759,20 @@
       }
       return true;
     }
+    if (TryConsume("[")) {
+      while (true) {
+        if (!LookingAt("{") && !LookingAt("<")) {
+          DO(SkipFieldValue());
+        } else {
+          DO(SkipFieldMessage());
+        }
+        if (TryConsume("]")) {
+          break;
+        }
+        DO(Consume(","));
+      }
+      return true;
+    }
     // Possible field values other than string:
     //   12345        => TYPE_INTEGER
     //   -12345       => TYPE_SYMBOL + TYPE_INTEGER
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 2ec4bc5..487e62b 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -29,6 +29,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -61,6 +62,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2ftimestamp_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -74,6 +76,7 @@
   delete Timestamp_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -101,16 +104,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2ftimestamp_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -206,7 +199,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -336,7 +329,9 @@
 
 void Timestamp::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Timestamp)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Timestamp* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Timestamp>(
           &from);
@@ -351,7 +346,9 @@
 
 void Timestamp::MergeFrom(const Timestamp& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.seconds() != 0) {
     set_seconds(from.seconds());
   }
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index f9182a7..a2a7f28 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -44,6 +44,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -159,6 +160,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -188,6 +190,7 @@
   delete Option_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -272,16 +275,6 @@
 }
 
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -658,7 +651,9 @@
 
 void Type::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Type)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Type* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Type>(
           &from);
@@ -673,7 +668,9 @@
 
 void Type::MergeFrom(const Type& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   fields_.MergeFrom(from.fields_);
   oneofs_.MergeFrom(from.oneofs_);
   options_.MergeFrom(from.options_);
@@ -1128,7 +1125,7 @@
 #endif
 
 #define ZR_(first, last) do {\
-  ::memset(&first, 0,\
+  ::memset(&(first), 0,\
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
@@ -1581,7 +1578,9 @@
 
 void Field::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Field)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Field* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Field>(
           &from);
@@ -1596,7 +1595,9 @@
 
 void Field::MergeFrom(const Field& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   options_.MergeFrom(from.options_);
   if (from.kind() != 0) {
     set_kind(from.kind());
@@ -2285,7 +2286,9 @@
 
 void Enum::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Enum)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Enum* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Enum>(
           &from);
@@ -2300,7 +2303,9 @@
 
 void Enum::MergeFrom(const Enum& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   enumvalue_.MergeFrom(from.enumvalue_);
   options_.MergeFrom(from.options_);
   if (from.name().size() > 0) {
@@ -2764,7 +2769,9 @@
 
 void EnumValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const EnumValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const EnumValue>(
           &from);
@@ -2779,7 +2786,9 @@
 
 void EnumValue::MergeFrom(const EnumValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   options_.MergeFrom(from.options_);
   if (from.name().size() > 0) {
 
@@ -3133,7 +3142,9 @@
 
 void Option::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Option)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Option* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Option>(
           &from);
@@ -3148,7 +3159,9 @@
 
 void Option::MergeFrom(const Option& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.name().size() > 0) {
 
     name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index d4e383d..8ee99d4 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -69,28 +69,14 @@
   return default_unknown_field_set_instance_;
 }
 
-UnknownFieldSet::UnknownFieldSet()
-    : fields_(NULL) {}
-
-UnknownFieldSet::~UnknownFieldSet() {
-  Clear();
-  delete fields_;
-}
-
 void UnknownFieldSet::ClearFallback() {
-  if (fields_ != NULL) {
-    for (int i = 0; i < fields_->size(); i++) {
-      (*fields_)[i].Delete();
-    }
-    delete fields_;
-    fields_ = NULL;
-  }
-}
-
-void UnknownFieldSet::ClearAndFreeMemory() {
-  if (fields_ != NULL) {
-    Clear();
-  }
+  GOOGLE_DCHECK(fields_ != NULL && fields_->size() > 0);
+  int n = fields_->size();
+  do {
+    (*fields_)[--n].Delete();
+  } while (n > 0);
+  delete fields_;
+  fields_ = NULL;
 }
 
 void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) {
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 612a942..aa75291 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -241,8 +241,14 @@
 // ===================================================================
 // inline implementations
 
+inline UnknownFieldSet::UnknownFieldSet() : fields_(NULL) {}
+
+inline UnknownFieldSet::~UnknownFieldSet() { Clear(); }
+
+inline void UnknownFieldSet::ClearAndFreeMemory() { Clear(); }
+
 inline void UnknownFieldSet::Clear() {
-  if (fields_) {
+  if (fields_ != NULL) {
     ClearFallback();
   }
 }
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc
index 21d7a2e..fa31f76 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -64,6 +64,7 @@
       type_(type),
       current_(NULL),
       root_(NULL),
+      suppress_empty_list_(false),
       field_scrub_callback_(NULL),
       ow_(ow) {}
 
@@ -164,7 +165,10 @@
   if (current_ == NULL) {
     ow_->RenderBytes(name, value);
   } else {
-    RenderDataPiece(name, DataPiece(value, false, true));
+    // Since StringPiece is essentially a pointer, takes a copy of "value" to
+    // avoid ownership issues.
+    string_values_.push_back(new string(value.ToString()));
+    RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
   }
   return this;
 }
@@ -184,12 +188,10 @@
   field_scrub_callback_.reset(field_scrub_callback.release());
 }
 
-DefaultValueObjectWriter::Node::Node(const string& name,
-                                     const google::protobuf::Type* type,
-                                     NodeKind kind, const DataPiece& data,
-                                     bool is_placeholder,
-                                     const vector<string>& path,
-                                     FieldScrubCallBack* field_scrub_callback)
+DefaultValueObjectWriter::Node::Node(
+    const string& name, const google::protobuf::Type* type, NodeKind kind,
+    const DataPiece& data, bool is_placeholder, const vector<string>& path,
+    bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback)
     : name_(name),
       type_(type),
       kind_(kind),
@@ -197,6 +199,7 @@
       data_(data),
       is_placeholder_(is_placeholder),
       path_(path),
+      suppress_empty_list_(suppress_empty_list),
       field_scrub_callback_(field_scrub_callback) {}
 
 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
@@ -230,6 +233,9 @@
   // Write out lists. If we didn't have any list in response, write out empty
   // list.
   if (kind_ == LIST) {
+    // Suppress empty lists if requested.
+    if (suppress_empty_list_ && is_placeholder_) return;
+
     ow->StartList(name_);
     WriteChildren(ow);
     ow->EndList();
@@ -366,7 +372,7 @@
         field.json_name(), field_type, kind,
         kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo)
                           : DataPiece::NullData(),
-        true, path, field_scrub_callback_));
+        true, path, suppress_empty_list_, field_scrub_callback_));
     new_children.push_back(child.release());
   }
   // Adds all leftover nodes in children_ to the beginning of new_child.
@@ -462,7 +468,8 @@
   if (current_ == NULL) {
     vector<string> path;
     root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
-                         false, path, field_scrub_callback_.get()));
+                         false, path, suppress_empty_list_,
+                         field_scrub_callback_.get()));
     root_->PopulateChildren(typeinfo_);
     current_ = root_.get();
     return this;
@@ -478,7 +485,7 @@
                               : NULL),
         OBJECT, DataPiece::NullData(), false,
         child == NULL ? current_->path() : child->path(),
-        field_scrub_callback_.get()));
+        suppress_empty_list_, field_scrub_callback_.get()));
     child = node.get();
     current_->AddChild(node.release());
   }
@@ -509,7 +516,8 @@
   if (current_ == NULL) {
     vector<string> path;
     root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(),
-                         false, path, field_scrub_callback_.get()));
+                         false, path, suppress_empty_list_,
+                         field_scrub_callback_.get()));
     current_ = root_.get();
     return this;
   }
@@ -519,7 +527,7 @@
     google::protobuf::scoped_ptr<Node> node(
         new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false,
                  child == NULL ? current_->path() : child->path(),
-                 field_scrub_callback_.get()));
+                 suppress_empty_list_, field_scrub_callback_.get()));
     child = node.get();
     current_->AddChild(node.release());
   }
@@ -577,7 +585,7 @@
     google::protobuf::scoped_ptr<Node> node(
         new Node(name.ToString(), NULL, PRIMITIVE, data, false,
                  child == NULL ? current_->path() : child->path(),
-                 field_scrub_callback_.get()));
+                 suppress_empty_list_, field_scrub_callback_.get()));
     child = node.get();
     current_->AddChild(node.release());
   } else {
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
index 1d85bed..5f3b25f 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.h
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -122,6 +122,10 @@
   // field_scrub_callback pointer is also transferred to this class
   void RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback);
 
+  // If set to true, empty lists are suppressed from output when default values
+  // are written.
+  void set_suppress_empty_list(bool value) { suppress_empty_list_ = value; }
+
  private:
   enum NodeKind {
     PRIMITIVE = 0,
@@ -136,7 +140,7 @@
    public:
     Node(const string& name, const google::protobuf::Type* type, NodeKind kind,
          const DataPiece& data, bool is_placeholder, const vector<string>& path,
-         FieldScrubCallBack* field_scrub_callback);
+         bool suppress_empty_list, FieldScrubCallBack* field_scrub_callback);
     virtual ~Node() {
       for (int i = 0; i < children_.size(); ++i) {
         delete children_[i];
@@ -212,6 +216,9 @@
     // Path of the field of this node
     std::vector<string> path_;
 
+    // Whether to suppress empty list output.
+    bool suppress_empty_list_;
+
     // Pointer to function for determining whether a field needs to be scrubbed
     // or not. This callback is owned by the creator of this node.
     FieldScrubCallBack* field_scrub_callback_;
@@ -257,6 +264,9 @@
   // The stack to hold the path of Nodes from current_ to root_;
   std::stack<Node*> stack_;
 
+  // Whether to suppress output of empty lists.
+  bool suppress_empty_list_;
+
   // Unique Pointer to function for determining whether a field needs to be
   // scrubbed or not.
   FieldScrubCallBackPtr field_scrub_callback_;
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
index 8254c0f..e1dd697 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -149,6 +149,39 @@
 }
 
 
+class DefaultValueObjectWriterSuppressListTest
+    : public BaseDefaultValueObjectWriterTest {
+ protected:
+  DefaultValueObjectWriterSuppressListTest()
+      : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {
+    testing_->set_suppress_empty_list(true);
+  }
+  ~DefaultValueObjectWriterSuppressListTest() {}
+};
+
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        DefaultValueObjectWriterSuppressListTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(DefaultValueObjectWriterSuppressListTest, Empty) {
+  // Set expectation. Emtpy lists should be suppressed.
+  expects_.StartObject("")
+      ->RenderDouble("doubleValue", 0.0)
+      ->RenderFloat("floatValue", 0.0)
+      ->RenderInt64("int64Value", 0)
+      ->RenderUint64("uint64Value", 0)
+      ->RenderInt32("int32Value", 0)
+      ->RenderUint32("uint32Value", 0)
+      ->RenderBool("boolValue", false)
+      ->RenderString("stringValue", "")
+      ->RenderBytes("bytesValue", "")
+      ->RenderString("enumValue", "ENUM_FIRST")
+      ->EndObject();
+
+  // Actual testing
+  testing_->StartObject("")->EndObject();
+}
 }  // namespace testing
 }  // namespace converter
 }  // namespace util
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 7a1a6cb..0c38aeb 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -298,7 +298,9 @@
       proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
       type_(type),
       size_index_(-1),
-      array_index_(-1) {
+      array_index_(-1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type.oneofs_size() + 1) {
   if (!proto3_) {
     required_fields_ = GetRequiredFields(type_);
   }
@@ -312,13 +314,15 @@
       ow_(this->parent()->ow_),
       parent_field_(field),
       typeinfo_(this->parent()->typeinfo_),
-      proto3_(this->parent()->proto3_),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
       type_(type),
       size_index_(
           !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
               ? ow_->size_insert_.size()
               : -1),
-      array_index_(is_list ? 0 : -1) {
+      array_index_(is_list ? 0 : -1),
+      // oneof_indices_ values are 1-indexed (0 means not present).
+      oneof_indices_(type_.oneofs_size() + 1) {
   if (!is_list) {
     if (ow_->IsRepeated(*field)) {
       // Update array_index_ if it is an explicit list.
@@ -411,11 +415,11 @@
 }
 
 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
-  return ContainsKey(oneof_indices_, index);
+  return oneof_indices_[index];
 }
 
 void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
-  InsertIfNotPresent(&oneof_indices_, index);
+  oneof_indices_[index] = true;
 }
 
 void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
@@ -573,10 +577,19 @@
 
   // Pushing a ProtoElement and then pop it off at the end for 2 purposes:
   // error location reporting and required field accounting.
-  element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  //
+  // For proto3, since there is no required field tracking, we only need to push
+  // ProtoElement for error cases.
+  if (!element_->proto3()) {
+    element_.reset(new ProtoElement(element_.release(), &field, type, false));
+  }
 
   if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
       field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+    // Push a ProtoElement for location reporting purposes.
+    if (element_->proto3()) {
+      element_.reset(new ProtoElement(element_.release(), &field, type, false));
+    }
     InvalidValue(field.type_url().empty()
                      ? google::protobuf::Field_Kind_Name(field.kind())
                      : field.type_url(),
@@ -657,11 +670,18 @@
   }
 
   if (!status.ok()) {
+    // Push a ProtoElement for location reporting purposes.
+    if (element_->proto3()) {
+      element_.reset(new ProtoElement(element_.release(), &field, type, false));
+    }
     InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
                  status.error_message());
+    element_.reset(element()->pop());
+    return this;
   }
 
-  element_.reset(element()->pop());
+  if (!element_->proto3()) element_.reset(element()->pop());
+
   return this;
 }
 
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
index 8b7c6c3..7f1108a 100644
--- a/src/google/protobuf/util/internal/proto_writer.h
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -32,8 +32,8 @@
 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
 
 #include <deque>
-#include <google/protobuf/stubs/hash.h>
 #include <string>
+#include <vector>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
@@ -45,6 +45,7 @@
 #include <google/protobuf/util/internal/structured_objectwriter.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/stubs/hash.h>
 
 namespace google {
 namespace protobuf {
@@ -191,6 +192,8 @@
     // generate an error.
     void TakeOneofIndex(int32 index);
 
+    bool proto3() { return proto3_; }
+
    private:
     // Used for access to variables of the enclosing instance of
     // ProtoWriter.
@@ -203,7 +206,7 @@
     // TypeInfo to lookup types.
     const TypeInfo* typeinfo_;
 
-    // Whether the root type is a proto3 or not.
+    // Whether the type_ is proto3 or not.
     bool proto3_;
 
     // Additional variables if this element is a message:
@@ -221,7 +224,7 @@
 
     // Set of oneof indices already seen for the type_. Used to validate
     // incoming messages so no more than one oneof is set.
-    hash_set<int32> oneof_indices_;
+    std::vector<bool> oneof_indices_;
 
     GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
   };
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 1825f55..73e05cf 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -907,7 +907,7 @@
 // conversions as much as possible. Because ToSnakeCase sometimes returns the
 // wrong value.
   google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
-      ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
+      NewPermanentCallback(&RenderOneFieldPath, ow));
   return DecodeCompactFieldMaskPaths(data.str(), callback.get());
 }
 
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 6d45a4f..d7ac2db 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -177,6 +177,66 @@
       resolver, type_url, &input_stream, &output_stream, options);
 }
 
+namespace {
+const char* kTypeUrlPrefix = "type.googleapis.com";
+TypeResolver* generated_type_resolver_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(generated_type_resolver_init_);
+
+string GetTypeUrl(const Message& message) {
+  return string(kTypeUrlPrefix) + "/" + message.GetDescriptor()->full_name();
+}
+
+void DeleteGeneratedTypeResolver() { delete generated_type_resolver_; }
+
+void InitGeneratedTypeResolver() {
+  generated_type_resolver_ = NewTypeResolverForDescriptorPool(
+      kTypeUrlPrefix, DescriptorPool::generated_pool());
+  ::google::protobuf::internal::OnShutdown(&DeleteGeneratedTypeResolver);
+}
+
+TypeResolver* GetGeneratedTypeResolver() {
+  ::google::protobuf::GoogleOnceInit(&generated_type_resolver_init_, &InitGeneratedTypeResolver);
+  return generated_type_resolver_;
+}
+}  // namespace
+
+util::Status MessageToJsonString(const Message& message, string* output,
+                                   const JsonOptions& options) {
+  const DescriptorPool* pool = message.GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  util::Status result =
+      BinaryToJsonString(resolver, GetTypeUrl(message),
+                         message.SerializeAsString(), output, options);
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
+util::Status JsonStringToMessage(const string& input, Message* message,
+                                   const JsonParseOptions& options) {
+  const DescriptorPool* pool = message->GetDescriptor()->file()->pool();
+  TypeResolver* resolver =
+      pool == DescriptorPool::generated_pool()
+          ? GetGeneratedTypeResolver()
+          : NewTypeResolverForDescriptorPool(kTypeUrlPrefix, pool);
+  string binary;
+  util::Status result = JsonToBinaryString(
+      resolver, GetTypeUrl(*message), input, &binary, options);
+  if (result.ok() && !message->ParseFromString(binary)) {
+    result =
+        util::Status(util::error::INVALID_ARGUMENT,
+                       "JSON transcoder produced invalid protobuf output.");
+  }
+  if (pool != DescriptorPool::generated_pool()) {
+    delete resolver;
+  }
+  return result;
+}
+
 }  // namespace util
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index b4c2579..6d3cee52 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -33,6 +33,7 @@
 #ifndef GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
 #define GOOGLE_PROTOBUF_UTIL_JSON_UTIL_H__
 
+#include <google/protobuf/message.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/bytestream.h>
 
@@ -69,13 +70,37 @@
 // DEPRECATED. Use JsonPrintOptions instead.
 typedef JsonPrintOptions JsonOptions;
 
+// Converts from protobuf message to JSON. This is a simple wrapper of
+// BinaryToJsonString(). It will use the DescriptorPool of the passed-in
+// message to resolve Any types.
+LIBPROTOBUF_EXPORT util::Status MessageToJsonString(const Message& message,
+                                   string* output,
+                                   const JsonOptions& options);
+
+inline util::Status MessageToJsonString(const Message& message,
+                                          string* output) {
+  return MessageToJsonString(message, output, JsonOptions());
+}
+
+// Converts from JSON to protobuf message. This is a simple wrapper of
+// JsonStringToBinary(). It will use the DescriptorPool of the passed-in
+// message to resolve Any types.
+LIBPROTOBUF_EXPORT util::Status JsonStringToMessage(const string& input,
+                                   Message* message,
+                                   const JsonParseOptions& options);
+
+inline util::Status JsonStringToMessage(const string& input,
+                                          Message* message) {
+  return JsonStringToMessage(input, message, JsonParseOptions());
+}
+
 // Converts protobuf binary data to JSON.
 // The conversion will fail if:
 //   1. TypeResolver fails to resolve a type.
 //   2. input is not valid protobuf wire format, or conflicts with the type
 //      information returned by TypeResolver.
 // Note that unknown fields will be discarded silently.
-util::Status BinaryToJsonStream(
+LIBPROTOBUF_EXPORT util::Status BinaryToJsonStream(
     TypeResolver* resolver,
     const string& type_url,
     io::ZeroCopyInputStream* binary_input,
@@ -110,7 +135,7 @@
 //   1. TypeResolver fails to resolve a type.
 //   2. input is not valid JSON format, or conflicts with the type
 //      information returned by TypeResolver.
-util::Status JsonToBinaryStream(
+LIBPROTOBUF_EXPORT util::Status JsonToBinaryStream(
     TypeResolver* resolver,
     const string& type_url,
     io::ZeroCopyInputStream* json_input,
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index c7d5c59..24ff5fd 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -34,6 +34,8 @@
 #include <string>
 
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor_database.h>
+#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/util/json_format_proto3.pb.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/util/type_resolver_util.h>
@@ -63,28 +65,21 @@
 class JsonUtilTest : public testing::Test {
  protected:
   JsonUtilTest() {
-    resolver_.reset(NewTypeResolverForDescriptorPool(
-        kTypeUrlPrefix, DescriptorPool::generated_pool()));
   }
 
   string ToJson(const Message& message, const JsonPrintOptions& options) {
     string result;
-    GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(),
-                                GetTypeUrl(message.GetDescriptor()),
-                                message.SerializeAsString(), &result, options));
+    GOOGLE_CHECK_OK(MessageToJsonString(message, &result, options));
     return result;
   }
 
   bool FromJson(const string& json, Message* message,
                 const JsonParseOptions& options) {
-    string binary;
-    if (!JsonToBinaryString(resolver_.get(),
-                            GetTypeUrl(message->GetDescriptor()), json, &binary,
-                            options)
-             .ok()) {
-      return false;
-    }
-    return message->ParseFromString(binary);
+    return JsonStringToMessage(json, message, options).ok();
+  }
+
+  bool FromJson(const string& json, Message* message) {
+    return FromJson(json, message, JsonParseOptions());
   }
 
   google::protobuf::scoped_ptr<TypeResolver> resolver_;
@@ -133,6 +128,34 @@
       "\"repeatedMessageValue\":[]"
       "}",
       ToJson(m, options));
+
+  options.always_print_primitive_fields = true;
+  m.set_string_value("i am a test string value");
+  m.set_bytes_value("i am a test bytes value");
+  EXPECT_EQ(
+      "{\"boolValue\":false,"
+      "\"int32Value\":0,"
+      "\"int64Value\":\"0\","
+      "\"uint32Value\":0,"
+      "\"uint64Value\":\"0\","
+      "\"floatValue\":0,"
+      "\"doubleValue\":0,"
+      "\"stringValue\":\"i am a test string value\","
+      "\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
+      "\"enumValue\":\"FOO\","
+      "\"repeatedBoolValue\":[],"
+      "\"repeatedInt32Value\":[],"
+      "\"repeatedInt64Value\":[],"
+      "\"repeatedUint32Value\":[],"
+      "\"repeatedUint64Value\":[],"
+      "\"repeatedFloatValue\":[],"
+      "\"repeatedDoubleValue\":[],"
+      "\"repeatedStringValue\":[],"
+      "\"repeatedBytesValue\":[],"
+      "\"repeatedEnumValue\":[],"
+      "\"repeatedMessageValue\":[]"
+      "}",
+      ToJson(m, options));
 }
 
 TEST_F(JsonUtilTest, ParseMessage) {
@@ -189,6 +212,45 @@
   EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m, options));
 }
 
+TEST_F(JsonUtilTest, TestDynamicMessage) {
+  // Some random message but good enough to test the wrapper functions.
+  string input =
+      "{\n"
+      "  \"int32Value\": 1024,\n"
+      "  \"repeatedInt32Value\": [1, 2],\n"
+      "  \"messageValue\": {\n"
+      "    \"value\": 2048\n"
+      "  },\n"
+      "  \"repeatedMessageValue\": [\n"
+      "    {\"value\": 40}, {\"value\": 96}\n"
+      "  ]\n"
+      "}\n";
+
+  // Create a new DescriptorPool with the same protos as the generated one.
+  DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
+  DescriptorPool pool(&database);
+  // A dynamic version of the test proto.
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<Message> message(factory.GetPrototype(
+      pool.FindMessageTypeByName("proto3.TestMessage"))->New());
+  EXPECT_TRUE(FromJson(input, message.get()));
+
+  // Convert to generated message for easy inspection.
+  TestMessage generated;
+  EXPECT_TRUE(generated.ParseFromString(message->SerializeAsString()));
+  EXPECT_EQ(1024, generated.int32_value());
+  ASSERT_EQ(2, generated.repeated_int32_value_size());
+  EXPECT_EQ(1, generated.repeated_int32_value(0));
+  EXPECT_EQ(2, generated.repeated_int32_value(1));
+  EXPECT_EQ(2048, generated.message_value().value());
+  ASSERT_EQ(2, generated.repeated_message_value_size());
+  EXPECT_EQ(40, generated.repeated_message_value(0).value());
+  EXPECT_EQ(96, generated.repeated_message_value(1).value());
+
+  JsonOptions options;
+  EXPECT_EQ(ToJson(generated, options), ToJson(*message, options));
+}
+
 typedef pair<char*, int> Segment;
 // A ZeroCopyOutputStream that writes to multiple buffers.
 class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index a6d0cb0..03a334b 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -1389,8 +1389,7 @@
       // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
       // algorithm will fail to find a maximum matching.
       // Here we use the argumenting path algorithm.
-      MaximumMatcher::NodeMatchCallback* callback =
-          ::google::protobuf::internal::NewPermanentCallback(
+      MaximumMatcher::NodeMatchCallback* callback = NewPermanentCallback(
               this, &MessageDifferencer::IsMatch,
               repeated_field, key_comparator,
               &message1, &message2, parent_fields);
diff --git a/src/google/protobuf/util/time_util.cc b/src/google/protobuf/util/time_util.cc
index c782d69..031d019 100644
--- a/src/google/protobuf/util/time_util.cc
+++ b/src/google/protobuf/util/time_util.cc
@@ -142,6 +142,13 @@
 }
 }  // namespace
 
+// Actually define these static const integers. Required by C++ standard (but
+// omitting them may still work with some compilers).
+const int64 TimeUtil::kTimestampMinSeconds;
+const int64 TimeUtil::kTimestampMaxSeconds;
+const int64 TimeUtil::kDurationMaxSeconds;
+const int64 TimeUtil::kDurationMinSeconds;
+
 string TimeUtil::ToString(const Timestamp& timestamp) {
   return FormatTime(timestamp.seconds(), timestamp.nanos());
 }
@@ -174,7 +181,7 @@
     seconds = -seconds;
     nanos = -nanos;
   }
-  result += StringPrintf("%" GOOGLE_LL_FORMAT "d", seconds);
+  result += SimpleItoa(seconds);
   if (nanos != 0) {
     result += "." + FormatNanos(nanos);
   }
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index f251707..05cc085 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -466,7 +466,8 @@
   const int size = value.GetCachedSize();
   uint8* target = output->GetDirectBufferForNBytesAndAdvance(size);
   if (target != NULL) {
-    uint8* end = value.SerializeWithCachedSizesToArray(target);
+    uint8* end = value.InternalSerializeWithCachedSizesToArray(
+        output->IsSerializationDeterminstic(), target);
     GOOGLE_DCHECK_EQ(end - target, size);
   } else {
     value.SerializeWithCachedSizes(output);
@@ -482,7 +483,8 @@
   output->WriteVarint32(size);
   uint8* target = output->GetDirectBufferForNBytesAndAdvance(size);
   if (target != NULL) {
-    uint8* end = value.SerializeWithCachedSizesToArray(target);
+    uint8* end = value.InternalSerializeWithCachedSizesToArray(
+        output->IsSerializationDeterminstic(), target);
     GOOGLE_DCHECK_EQ(end - target, size);
   } else {
     value.SerializeWithCachedSizes(output);
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index ebd858f..93d7c82 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -346,9 +346,9 @@
     io::CodedInputStream* input, RepeatedField<CType>* values) {
   int length;
   if (!input->ReadVarintSizeAsInt(&length)) return false;
-  const uint32 old_entries = values->size();
-  const uint32 new_entries = length / sizeof(CType);
-  const uint32 new_bytes = new_entries * sizeof(CType);
+  const int old_entries = values->size();
+  const int new_entries = length / sizeof(CType);
+  const int new_bytes = new_entries * sizeof(CType);
   if (new_bytes != length) return false;
   // We would *like* to pre-allocate the buffer to write into (for
   // speed), but *must* avoid performing a very large allocation due
@@ -382,7 +382,7 @@
 #else
     values->Reserve(old_entries + new_entries);
     CType value;
-    for (uint32 i = 0; i < new_entries; ++i) {
+    for (int i = 0; i < new_entries; ++i) {
       if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
       values->AddAlreadyReserved(value);
     }
@@ -392,7 +392,7 @@
     // safely allocate.  We read as much as we can into *values
     // without pre-allocating "length" bytes.
     CType value;
-    for (uint32 i = 0; i < new_entries; ++i) {
+    for (int i = 0; i < new_entries; ++i) {
       if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false;
       values->Add(value);
     }
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 08490f3..33a69d3 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -53,6 +53,7 @@
 }  // namespace
 
 
+void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto() {
   protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto();
   const ::google::protobuf::FileDescriptor* file =
@@ -204,6 +205,7 @@
                  &protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto);
 }
 
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
 void protobuf_RegisterTypes(const ::std::string&) {
   protobuf_AssignDescriptorsOnce();
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
@@ -249,6 +251,7 @@
   delete BytesValue_reflection_;
 }
 
+void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() GOOGLE_ATTRIBUTE_COLD;
 void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() {
   static bool already_here = false;
   if (already_here) return;
@@ -298,16 +301,6 @@
   }
 } static_descriptor_initializer_google_2fprotobuf_2fwrappers_2eproto_;
 
-namespace {
-
-static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
-static void MergeFromFail(int line) {
-  GOOGLE_CHECK(false) << __FILE__ << ":" << line;
-}
-
-}  // namespace
-
-
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
@@ -477,7 +470,9 @@
 
 void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DoubleValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const DoubleValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const DoubleValue>(
           &from);
@@ -492,7 +487,9 @@
 
 void DoubleValue::MergeFrom(const DoubleValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -735,7 +732,9 @@
 
 void FloatValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FloatValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const FloatValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const FloatValue>(
           &from);
@@ -750,7 +749,9 @@
 
 void FloatValue::MergeFrom(const FloatValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -995,7 +996,9 @@
 
 void Int64Value::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int64Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Int64Value* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Int64Value>(
           &from);
@@ -1010,7 +1013,9 @@
 
 void Int64Value::MergeFrom(const Int64Value& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -1255,7 +1260,9 @@
 
 void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt64Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const UInt64Value* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const UInt64Value>(
           &from);
@@ -1270,7 +1277,9 @@
 
 void UInt64Value::MergeFrom(const UInt64Value& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -1515,7 +1524,9 @@
 
 void Int32Value::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int32Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const Int32Value* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const Int32Value>(
           &from);
@@ -1530,7 +1541,9 @@
 
 void Int32Value::MergeFrom(const Int32Value& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -1775,7 +1788,9 @@
 
 void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt32Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const UInt32Value* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const UInt32Value>(
           &from);
@@ -1790,7 +1805,9 @@
 
 void UInt32Value::MergeFrom(const UInt32Value& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -2033,7 +2050,9 @@
 
 void BoolValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BoolValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const BoolValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const BoolValue>(
           &from);
@@ -2048,7 +2067,9 @@
 
 void BoolValue::MergeFrom(const BoolValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value() != 0) {
     set_value(from.value());
   }
@@ -2308,7 +2329,9 @@
 
 void StringValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.StringValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const StringValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const StringValue>(
           &from);
@@ -2323,7 +2346,9 @@
 
 void StringValue::MergeFrom(const StringValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value().size() > 0) {
     set_value(from.value());
   }
@@ -2623,7 +2648,9 @@
 
 void BytesValue::MergeFrom(const ::google::protobuf::Message& from) {
 // @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BytesValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   const BytesValue* source = 
       ::google::protobuf::internal::DynamicCastToGenerated<const BytesValue>(
           &from);
@@ -2638,7 +2665,9 @@
 
 void BytesValue::MergeFrom(const BytesValue& from) {
 // @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue)
-  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (GOOGLE_PREDICT_FALSE(&from == this)) {
+    ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__);
+  }
   if (from.value().size() > 0) {
     set_value(from.value());
   }
diff --git a/tests.sh b/tests.sh
index 72465a7..9e95f2b 100755
--- a/tests.sh
+++ b/tests.sh
@@ -44,6 +44,30 @@
 build_cpp_distcheck() {
   ./autogen.sh
   ./configure
+  make dist
+
+  # List all files that should be included in the distribution package.
+  git ls-files | grep "^\(java\|python\|objectivec\|csharp\|js\|ruby\|cmake\|examples\)" |\
+      grep -v ".gitignore" | grep -v "java/compatibility_tests" > dist.lst
+  # Unzip the dist tar file.
+  DIST=`ls *.tar.gz`
+  tar -xf $DIST
+  cd ${DIST//.tar.gz}
+  # Check if every file exists in the dist tar file.
+  FILES_MISSING=""
+  for FILE in $(<../dist.lst); do
+    if ! file $FILE &>/dev/null; then
+      echo "$FILE is not found!"
+      FILES_MISSING="$FILE $FILES_MISSING"
+    fi
+  done
+  cd ..
+  if [ ! -z "$FILES_MISSING" ]; then
+    echo "Missing files in EXTRA_DIST: $FILES_MISSING"
+    exit 1
+  fi
+
+  # Do the regular dist-check for C++.
   make distcheck -j2
 }
 
@@ -57,15 +81,27 @@
   if [ "$TRAVIS" == "true" ]; then
     # Install latest version of Mono
     sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1397BC53640DB551
     echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
-    echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
     sudo apt-get update -qq
     sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit
-    wget www.nuget.org/NuGet.exe -O nuget.exe
-    NUGET=../../nuget.exe
+    
+    # Then install the dotnet SDK as per Ubuntu 14.04 instructions on dot.net.
+    sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
+    sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
+    sudo apt-get update -qq
+    sudo apt-get install -qq dotnet-dev-1.0.0-preview2-003121
   fi
 
-  (cd csharp/src; mono $NUGET restore)
+  # Perform "dotnet new" once to get the setup preprocessing out of the
+  # way. That spews a lot of output (including backspaces) into logs
+  # otherwise, and can cause problems. It doesn't matter if this step
+  # is performed multiple times; it's cheap after the first time anyway.
+  mkdir dotnettmp
+  (cd dotnettmp; dotnet new > /dev/null)
+  rm -rf dotnettmp
+
+  (cd csharp/src; dotnet restore)
   csharp/buildall.sh
   cd conformance && make test_csharp && cd ..
 }
@@ -77,10 +113,12 @@
   export PATH="`pwd`/src:$PATH"
 
   # Install Go and the Go protobuf compiler plugin.
-  sudo apt-get update -qq
-  sudo apt-get install -qq golang
+  on_travis sudo apt-get update -qq
+  on_travis sudo apt-get install -qq golang
+
   export GOPATH="$HOME/gocode"
   mkdir -p "$GOPATH/src/github.com/google"
+  rm -f "$GOPATH/src/github.com/google/protobuf"
   ln -s "`pwd`" "$GOPATH/src/github.com/google/protobuf"
   export PATH="$GOPATH/bin:$PATH"
   go get github.com/golang/protobuf/protoc-gen-go
@@ -91,13 +129,10 @@
 use_java() {
   version=$1
   case "$version" in
-    jdk6)
-      on_travis sudo apt-get install openjdk-6-jdk
-      export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH
-      ;;
     jdk7)
       on_travis sudo apt-get install openjdk-7-jdk
       export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
+      export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
       ;;
     oracle7)
       if [ "$TRAVIS" == "true" ]; then
@@ -108,6 +143,7 @@
         yes | sudo apt-get install oracle-java7-installer
       fi;
       export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH
+      export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
       ;;
   esac
 
@@ -118,6 +154,7 @@
 
   which java
   java -version
+  $MVN -version
 }
 
 # --batch-mode supresses download progress output that spams the logs.
@@ -150,10 +187,6 @@
   cd javanano && $MVN test && cd ..
 }
 
-build_java_jdk6() {
-  use_java jdk6
-  build_java jdk6
-}
 build_java_jdk7() {
   use_java jdk7
   build_java_with_conformance_tests
@@ -162,11 +195,15 @@
   use_java oracle7
   build_java oracle7
 }
-
-build_javanano_jdk6() {
-  use_java jdk6
-  build_javanano
+build_java_compatibility() {
+  use_java jdk7
+  internal_build_cpp
+  # Use the unit-tests extraced from 2.5.0 to test the compatibilty between
+  # 3.0.0-beta-4 and the current version.
+  cd java/compatibility_tests/v2.5.0
+  ./test.sh 3.0.0-beta-4
 }
+
 build_javanano_jdk7() {
   use_java jdk7
   build_javanano
@@ -226,6 +263,10 @@
 build_objectivec_cocoapods_integration() {
   # First, load the RVM environment in bash, needed to update ruby.
   source ~/.rvm/scripts/rvm
+  # Update rvm to the latest version. This is needed to solve
+  # https://github.com/google/protobuf/issues/1786 and may not be needed in the
+  # future when Travis updates the default version of rvm.
+  rvm get head
   # Update ruby to 2.2.3 as the default one crashes with segmentation faults
   # when using pod.
   rvm use 2.2.3 --install --binary --fuzzy
@@ -265,14 +306,6 @@
   cd ..
 }
 
-build_ruby19() {
-  internal_build_cpp  # For conformance tests.
-  cd ruby && bash travis-test.sh ruby-1.9 && cd ..
-}
-build_ruby20() {
-  internal_build_cpp  # For conformance tests.
-  cd ruby && bash travis-test.sh ruby-2.0 && cd ..
-}
 build_ruby21() {
   internal_build_cpp  # For conformance tests.
   cd ruby && bash travis-test.sh ruby-2.1 && cd ..
@@ -283,7 +316,14 @@
 }
 build_jruby() {
   internal_build_cpp  # For conformance tests.
-  cd ruby && bash travis-test.sh jruby && cd ..
+  # TODO(xiaofeng): Upgrade to jruby-9.x. There are some broken jests to be
+  # fixed.
+  cd ruby && bash travis-test.sh jruby-1.7 && cd ..
+}
+build_ruby_all() {
+  build_ruby21
+  build_ruby22
+  build_jruby
 }
 
 build_javascript() {
@@ -304,11 +344,11 @@
 if [ "$#" -ne 1 ]; then
   echo "
 Usage: $0 { cpp |
+            cpp_distcheck |
             csharp |
-            java_jdk6 |
             java_jdk7 |
             java_oracle7 |
-            javanano_jdk6 |
+            java_compatibility |
             javanano_jdk7 |
             javanano_oracle7 |
             objectivec_ios |
@@ -318,11 +358,10 @@
             objectivec_cocoapods_integration |
             python |
             python_cpp |
-            ruby19 |
-            ruby20 |
             ruby21 |
             ruby22 |
-            jruby }
+            jruby |
+            ruby_all)
 "
   exit 1
 fi