Merge pull request #804 from bsilver8192/master

Add atomics support for 32-bit PPC.
diff --git a/.gitignore b/.gitignore
index a2cb75f..a2d6ca9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@
 python/.tox
 python/build/
 python/google/protobuf/compiler/
+python/google/protobuf/util/
 
 src/protoc
 src/unittest_proto_middleman
@@ -81,6 +82,7 @@
 
 # Windows native output.
 cmake/build
+build_msvc
 
 # NuGet packages: we want the repository configuration, but not the
 # packages themselves.
@@ -100,7 +102,14 @@
 conformance/.libs/
 conformance/com/
 conformance/conformance-cpp
+conformance/conformance-csharp
+conformance/conformance-java
+conformance/conformance-objc
 conformance/conformance-test-runner
 conformance/conformance.pb.cc
 conformance/conformance.pb.h
+conformance/Conformance.pbobjc.h
+conformance/Conformance.pbobjc.m
+conformance/conformance.rb
+conformance/javac_middleman
 conformance/protoc_middleman
diff --git a/.travis.yml b/.travis.yml
index 4edf3b3..9bc4d88 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,18 +7,22 @@
 os:
   - linux
   - osx
+# The Objective C build needs Xcode 7.0 or later.
+osx_image: xcode7.2
 script:
   - ./travis.sh $CONFIG
 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
   - CONFIG=python
   - CONFIG=python_cpp
   - CONFIG=ruby19
@@ -46,11 +50,26 @@
     # 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
+  # Add into the matrix OS X tests of Objective C (needs Xcode, so it won't
+  # work on other platforms). These are split so it doesn't take as long to run.
+  include:
+    - os: osx
+      env: CONFIG=objectivec_ios
+    - os: osx
+      env: CONFIG=objectivec_osx
   allow_failures:
     # These currently do not work on OS X but are being worked on by @haberman.
     - os: osx
       env: CONFIG=ruby22
     - os: osx
       env: CONFIG=jruby
+    # https://github.com/google/protobuf/issues/1253 - Started failing when
+    # we moved to an OS X image that is 10.11.
+    - os: osx
+      env: CONFIG=python_cpp
 notifications:
   email: false
diff --git a/BUILD b/BUILD
index 571f48b..c4de1c4 100644
--- a/BUILD
+++ b/BUILD
@@ -18,6 +18,14 @@
 # Bazel should provide portable link_opts for pthread.
 LINK_OPTS = ["-lpthread"]
 
+load(
+    "protobuf",
+    "cc_proto_library",
+    "py_proto_library",
+    "internal_copied_filegroup",
+    "internal_protobuf_py_tests",
+)
+
 cc_library(
     name = "protobuf_lite",
     srcs = [
@@ -46,6 +54,7 @@
         "src/google/protobuf/stubs/time.cc",
         "src/google/protobuf/wire_format_lite.cc",
     ],
+    hdrs = glob(["src/google/protobuf/**/*.h"]),
     copts = COPTS,
     includes = ["src/"],
     linkopts = LINK_OPTS,
@@ -97,6 +106,7 @@
         "src/google/protobuf/util/internal/json_objectwriter.cc",
         "src/google/protobuf/util/internal/json_stream_parser.cc",
         "src/google/protobuf/util/internal/object_writer.cc",
+        "src/google/protobuf/util/internal/proto_writer.cc",
         "src/google/protobuf/util/internal/protostream_objectsource.cc",
         "src/google/protobuf/util/internal/protostream_objectwriter.cc",
         "src/google/protobuf/util/internal/type_info.cc",
@@ -109,6 +119,7 @@
         "src/google/protobuf/wire_format.cc",
         "src/google/protobuf/wrappers.pb.cc",
     ],
+    hdrs = glob(["src/**/*.h"]),
     copts = COPTS,
     includes = ["src/"],
     linkopts = LINK_OPTS,
@@ -124,7 +135,7 @@
     visibility = ["//visibility:public"],
 )
 
-WELL_KNOWN_PROTOS = [
+RELATIVE_WELL_KNOWN_PROTOS = [
     # AUTOGEN(well_known_protos)
     "google/protobuf/any.proto",
     "google/protobuf/api.proto",
@@ -140,6 +151,18 @@
     "google/protobuf/wrappers.proto",
 ]
 
+WELL_KNOWN_PROTOS = ["src/" + s for s in RELATIVE_WELL_KNOWN_PROTOS]
+
+cc_proto_library(
+    name = "cc_wkt_protos",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    internal_bootstrap_hack = 1,
+    protoc = ":protoc",
+    visibility = ["//visibility:public"],
+)
+
 ################################################################################
 # Protocol Buffers Compiler
 ################################################################################
@@ -163,6 +186,7 @@
         "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc",
         "src/google/protobuf/compiler/cpp/cpp_service.cc",
         "src/google/protobuf/compiler/cpp/cpp_string_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc",
         "src/google/protobuf/compiler/csharp/csharp_enum.cc",
         "src/google/protobuf/compiler/csharp/csharp_enum_field.cc",
         "src/google/protobuf/compiler/csharp/csharp_field_base.cc",
@@ -172,11 +196,11 @@
         "src/google/protobuf/compiler/csharp/csharp_message.cc",
         "src/google/protobuf/compiler/csharp/csharp_message_field.cc",
         "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc",
+        "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc",
         "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc",
         "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc",
         "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc",
         "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc",
-        "src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc",
         "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc",
         "src/google/protobuf/compiler/java/java_context.cc",
         "src/google/protobuf/compiler/java/java_doc_comment.cc",
@@ -218,6 +242,7 @@
         "src/google/protobuf/compiler/javanano/javanano_message.cc",
         "src/google/protobuf/compiler/javanano/javanano_message_field.cc",
         "src/google/protobuf/compiler/javanano/javanano_primitive_field.cc",
+        "src/google/protobuf/compiler/js/js_generator.cc",
         "src/google/protobuf/compiler/objectivec/objectivec_enum.cc",
         "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc",
         "src/google/protobuf/compiler/objectivec/objectivec_extension.cc",
@@ -256,7 +281,7 @@
 # Tests
 ################################################################################
 
-LITE_TEST_PROTOS = [
+RELATIVE_LITE_TEST_PROTOS = [
     # AUTOGEN(lite_test_protos)
     "google/protobuf/map_lite_unittest.proto",
     "google/protobuf/unittest_import_lite.proto",
@@ -265,7 +290,9 @@
     "google/protobuf/unittest_no_arena_lite.proto",
 ]
 
-TEST_PROTOS = [
+LITE_TEST_PROTOS = ["src/" + s for s in RELATIVE_LITE_TEST_PROTOS]
+
+RELATIVE_TEST_PROTOS = [
     # AUTOGEN(test_protos)
     "google/protobuf/any_test.proto",
     "google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto",
@@ -303,24 +330,18 @@
     "google/protobuf/util/internal/testdata/struct.proto",
     "google/protobuf/util/internal/testdata/timestamp_duration.proto",
     "google/protobuf/util/json_format_proto3.proto",
+    "google/protobuf/util/message_differencer_unittest.proto",
 ]
 
-PROTOS = LITE_TEST_PROTOS + TEST_PROTOS
+TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
 
-INPUTS = PROTOS + WELL_KNOWN_PROTOS
-
-OUTPUTS = ["src/" + x[:-5] + "pb.h" for x in PROTOS] + \
-          ["src/" + x[:-5] + "pb.cc" for x in PROTOS]
-
-genrule(
-    name = "gen_test_protos",
-    srcs = ["src/" + x for x in INPUTS],
-    outs = OUTPUTS,
-    cmd =
-        "$(location :protoc) --cpp_out=$(@D)/src" +
-        "".join([" -I" + x + "=$(location src/" + x + ")" for x in INPUTS]) +
-        "".join([" $(location src/" + x + ")" for x in PROTOS]),
-    tools = [":protoc"],
+cc_proto_library(
+    name = "cc_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = ":protobuf",
+    protoc = ":protoc",
+    deps = [":cc_wkt_protos"],
 )
 
 COMMON_TEST_SRCS = [
@@ -349,7 +370,7 @@
 
 cc_test(
     name = "protobuf_test",
-    srcs = OUTPUTS + COMMON_TEST_SRCS + [
+    srcs = COMMON_TEST_SRCS + [
         # AUTOGEN(test_srcs)
         "src/google/protobuf/any_test.cc",
         "src/google/protobuf/arena_unittest.cc",
@@ -410,6 +431,7 @@
         "src/google/protobuf/util/internal/protostream_objectwriter_test.cc",
         "src/google/protobuf/util/internal/type_info_test_helper.cc",
         "src/google/protobuf/util/json_util_test.cc",
+        "src/google/protobuf/util/message_differencer_unittest.cc",
         "src/google/protobuf/util/time_util_test.cc",
         "src/google/protobuf/util/type_resolver_util_test.cc",
         "src/google/protobuf/well_known_types_unittest.cc",
@@ -418,15 +440,220 @@
     copts = COPTS,
     data = [
         ":test_plugin",
-    ],
+    ] + glob([
+        "src/google/protobuf/**/*",
+    ]),
     includes = [
         "src/",
     ],
     linkopts = LINK_OPTS,
     deps = [
+        ":cc_test_protos",
         ":protobuf",
         ":protoc_lib",
         "//external:gtest_main",
     ],
 )
 
+################################################################################
+# Java support
+################################################################################
+genrule(
+    name = "gen_well_known_protos_java",
+    srcs = WELL_KNOWN_PROTOS,
+    outs = [
+        "wellknown.srcjar",
+    ],
+    cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" +
+          " -Isrc $(SRCS) " +
+          " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar",
+    tools = [":protoc"],
+)
+
+java_library(
+    name = "protobuf_java",
+    srcs = glob([
+        "java/core/src/main/java/com/google/protobuf/*.java",
+    ]) + [
+        ":gen_well_known_protos_java",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+################################################################################
+# Python support
+################################################################################
+
+# Hack:
+# protoc generated files contain imports like:
+#   "from google.protobuf.xxx import yyy"
+# However, the sources files of the python runtime are not directly under
+# "google/protobuf" (they are under python/google/protobuf).  We workaround
+# this by copying runtime source files into the desired location to workaround
+# the import issue. Ideally py_library should support something similiar to the
+# "include" attribute in cc_library to inject the PYTHON_PATH for all libraries
+# that depend on the target.
+#
+# If you use python protobuf as a third_party library in your bazel managed
+# project:
+# 1) Please import the whole package to //google/protobuf in your
+# project. Otherwise, bazel disallows generated files out of the current
+# package, thus we won't be able to copy protobuf runtime files into
+# //google/protobuf/.
+# 2) The runtime also requires "six" for Python2/3 compatibility, please see the
+# WORKSPACE file and bind "six" to your workspace as well.
+internal_copied_filegroup(
+    name = "python_srcs",
+    srcs = glob(
+        [
+            "python/google/protobuf/*.py",
+            "python/google/protobuf/**/*.py",
+        ],
+        exclude = [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    include = "python",
+)
+
+cc_binary(
+    name = "internal/_api_implementation.so",
+    srcs = ["python/google/protobuf/internal/api_implementation.cc"],
+    copts = COPTS + [
+        "-DPYTHON_PROTO2_CPP_IMPL_V2",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//util/python:python_headers"],
+    }),
+)
+
+cc_binary(
+    name = "pyext/_message.so",
+    srcs = glob([
+        "python/google/protobuf/pyext/*.cc",
+        "python/google/protobuf/pyext/*.h",
+    ]),
+    copts = COPTS + [
+        "-DGOOGLE_PROTOBUF_HAS_ONEOF=1",
+    ] + select({
+        "//conditions:default": [],
+        ":allow_oversize_protos": ["-DPROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS=1"],
+    }),
+    includes = [
+        "python/",
+        "src/",
+    ],
+    linkshared = 1,
+    linkstatic = 1,
+    deps = [
+        ":protobuf",
+    ] + select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": ["//util/python:python_headers"],
+    }),
+)
+
+config_setting(
+    name = "use_fast_cpp_protos",
+    values = {
+        "define": "use_fast_cpp_protos=true",
+    },
+)
+
+config_setting(
+    name = "allow_oversize_protos",
+    values = {
+        "define": "allow_oversize_protos=true",
+    },
+)
+
+py_proto_library(
+    name = "protobuf_python",
+    srcs = WELL_KNOWN_PROTOS,
+    include = "src",
+    data = select({
+        "//conditions:default": [],
+        ":use_fast_cpp_protos": [
+            ":internal/_api_implementation.so",
+            ":pyext/_message.so",
+        ],
+    }),
+    default_runtime = "",
+    protoc = ":protoc",
+    py_extra_srcs = [":python_srcs"],
+    py_libs = ["//external:six"],
+    srcs_version = "PY2AND3",
+    visibility = ["//visibility:public"],
+)
+
+internal_copied_filegroup(
+    name = "python_test_srcs",
+    srcs = glob(
+        [
+            "python/google/protobuf/internal/*_test.py",
+            "python/google/protobuf/internal/test_util.py",
+        ],
+    ),
+    include = "python",
+)
+
+py_proto_library(
+    name = "python_common_test_protos",
+    srcs = LITE_TEST_PROTOS + TEST_PROTOS,
+    include = "src",
+    default_runtime = "",
+    protoc = ":protoc",
+    deps = [":protobuf_python"],
+)
+
+py_proto_library(
+    name = "python_specific_test_protos",
+    srcs = glob([
+        "python/google/protobuf/internal/*.proto",
+        "python/google/protobuf/internal/import_test_package/*.proto",
+    ]),
+    include = "python",
+    default_runtime = ":protobuf_python",
+    protoc = ":protoc",
+    deps = [":python_common_test_protos"],
+)
+
+py_library(
+    name = "python_tests",
+    srcs = [":python_test_srcs"],
+    srcs_version = "PY2AND3",
+    deps = [
+        ":protobuf_python",
+        ":python_common_test_protos",
+        ":python_specific_test_protos",
+    ],
+)
+
+internal_protobuf_py_tests(
+    name = "python_tests_batch",
+    data = glob([
+        "src/google/protobuf/**/*",
+    ]),
+    modules = [
+        "descriptor_database_test",
+        "descriptor_pool_test",
+        "descriptor_test",
+        "generator_test",
+        "json_format_test",
+        "message_factory_test",
+        "message_test",
+        "proto_builder_test",
+        "reflection_test",
+        "service_reflection_test",
+        "symbol_database_test",
+        "text_encoding_test",
+        "text_format_test",
+        "unknown_fields_test",
+        "wire_format_test",
+    ],
+    deps = [":python_tests"],
+)
diff --git a/CHANGES.txt b/CHANGES.txt
index ca3078c..c3503fc 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,68 @@
+2015-12-30 version 3.0.0-beta-2 (C++/Java/Python/Ruby/Nano/Objective-C/C#/JavaScript)
+  General
+  * Introduced a new language implementation: JavaScript.
+  * Added a new field option "json_name". By default proto field names are
+    converted to "lowerCamelCase" in proto3 JSON format. This option can be
+    used to override this behavior and specify a different JSON name for the
+    field.
+  * Added conformance tests to ensure implementations are following proto3 JSON
+    specification.
+
+  C++ (Beta)
+  * Various bug fixes and improvements to the JSON support utility:
+      - Duplicate map keys in JSON are now rejected (i.e., translation will
+        fail).
+      - Fixed wire-format for google.protobuf.Value/ListValue.
+      - Fixed precision loss when converting google.protobuf.Timestamp.
+      - Fixed a bug when parsing invalid UTF-8 code points.
+      - Fixed a memory leak.
+      - Reduced call stack usage.
+
+  Java (Beta)
+  * Cleaned up some unused methods on CodedOutputStream.
+  * Presized lists for packed fields during parsing in the lite runtime to
+    reduce allocations and improve performance.
+  * Improved the performance of unknown fields in the lite runtime.
+  * Introduced UnsafeByteStrings to support zero-copy ByteString creation.
+  * Various bug fixes and improvements to the JSON support utility:
+      - Fixed a thread-safety bug.
+      - Added a new option “preservingProtoFieldNames” to JsonFormat.
+      - Added a new option “includingDefaultValueFields” to JsonFormat.
+      - Updated the JSON utility to comply with proto3 JSON specification.
+
+  Python (Beta)
+  * Added proto3 JSON format utility. It includes support for all field types
+    and a few well-known types except for Any and Struct.
+  * Added runtime support for Any, Timestamp, Duration and FieldMask.
+  * [ ] is now accepted for repeated scalar fields in text format parser.
+  * Map fields now have proper O(1) performance for lookup/insert/delete
+    when using the Python/C++ implementation. They were previously using O(n)
+    search-based algorithms because the C++ reflection interface didn't
+    support true map operations.
+
+  Objective-C (Beta)
+  * Various bug-fixes and code tweaks to pass more strict compiler warnings.
+  * Now has conformance test coverage and is passing all tests.
+
+  C# (Beta)
+  * Various bug-fixes.
+  * Code generation: Files generated in directories based on namespace.
+  * Code generation: Include comments from .proto files in XML doc
+    comments (naively)
+  * Code generation: Change organization/naming of "reflection class" (access
+    to file descriptor)
+  * Code generation and library: Add Parser property to MessageDescriptor,
+    and introduce a non-generic parser type.
+  * Library: Added TypeRegistry to support JSON parsing/formatting of Any.
+  * Library: Added Any.Pack/Unpack support.
+  * Library: Implemented JSON parsing.
+
+  Javascript (Alpha)
+  * Added proto3 support for JavaScript. The runtime is written in pure
+    JavaScript and works in browsers and in Node.js. To generate JavaScript
+    code for your proto, invoke protoc with "--js_out". See js/README.md
+    for more build instructions.
+
 2015-08-26 version 3.0.0-beta-1 (C++/Java/Python/Ruby/Nano/Objective-C/C#)
   About Beta
   * This is the first beta release of protobuf v3.0.0. Not all languages
@@ -115,7 +180,7 @@
     still disable packed serialization by setting packed to false for now.
   * Added well-known type protos (any.proto, empty.proto, timestamp.proto,
     duration.proto, etc.). Users can import and use these protos just like
-    regular proto files. Addtional runtime support will be added for them in
+    regular proto files. Additional runtime support will be added for them in
     future releases (in the form of utility helper functions, or having them
     replaced by language specific types in generated code).
   * Added a "reserved" keyword in both proto2 and proto3 syntax. User can use
@@ -157,7 +222,7 @@
       https://github.com/jskeet/protobuf-csharp-port. The original project was
       frozen and all the new development will happen here.
     * Codegen plugin for C# was completely rewritten to C++ and is now an
-      intergral part of protoc.
+      integral part of protoc.
     * Some refactorings and cleanup has been applied to the C# runtime library.
     * Only proto2 is supported in C# at the moment, proto3 support is in
       progress and will likely bring significant breaking changes to the API.
@@ -321,7 +386,7 @@
 
     This release (v3.0.0-alpha-1) includes partial proto3 support for C++ and
     Java. Items 6 (well-known types) and 7 (JSON format) in the above feature
-    list are not impelmented.
+    list are not implemented.
 
     A new notion "syntax" is introduced to specify whether a .proto file
     uses proto2 or proto3:
@@ -422,7 +487,7 @@
       }
   * Files, services, enums, messages, methods and enum values can be marked
     as deprecated now.
-  * Added Support for list values, including lists of mesaages, when
+  * Added Support for list values, including lists of messages, when
     parsing text-formatted protos in C++ and Java.
       For example:  foo: [1, 2, 3]
 
@@ -502,7 +567,7 @@
 
   Python
   * Added support for dynamic message creation. DescriptorDatabase,
-    DescriptorPool, and MessageFactory work like their C++ couterparts to
+    DescriptorPool, and MessageFactory work like their C++ counterparts to
     simplify Descriptor construction from *DescriptorProtos, and MessageFactory
     provides a message instance from a Descriptor.
   * Added pickle support for protobuf messages.
@@ -516,7 +581,7 @@
 2011-05-01 version 2.4.1:
 
   C++
-  * Fixed the frendship problem for old compilers to make the library now gcc 3
+  * Fixed the friendship problem for old compilers to make the library now gcc 3
     compatible again.
   * Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.
 
@@ -783,7 +848,7 @@
   * Fixed tendency for TextFormat's parsing to overflow the stack when
     parsing large string values.  The underlying problem is with Java's
     regex implementation (which unfortunately uses recursive backtracking
-    rather than building an NFA).  Worked around by making use of possesive
+    rather than building an NFA).  Worked around by making use of possessive
     quantifiers.
   * Generated service classes now also generate pure interfaces.  For a service
     Foo, Foo.Interface is a pure interface containing all of the service's
@@ -797,7 +862,7 @@
     RPC implementations will have to implement the new interfaces in order to
     support blocking mode.
   * New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and
-    writeDelimitedTo() read and write "delemited" messages from/to a stream,
+    writeDelimitedTo() read and write "delimited" messages from/to a stream,
     meaning that the message size precedes the data.  This way, you can write
     multiple messages to a stream without having to worry about delimiting
     them yourself.
diff --git a/INSTALL.txt b/INSTALL.txt
deleted file mode 100644
index ce3b094..0000000
--- a/INSTALL.txt
+++ /dev/null
@@ -1,237 +0,0 @@
-This file contains detailed but generic information on building and
-installing the C++ part of this project.  For shorter instructions,
-as well as instructions for compiling and installing the Java or
-Python parts, see README.
-
-======================================================================
-
-Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
-
-   This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-
-Basic Installation
-==================
-
-   These are generic installation instructions.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.  If you're
-     using `csh' on an old version of System V, you might need to type
-     `sh ./configure' instead to prevent `csh' from trying to execute
-     `configure' itself.
-
-     Running `configure' takes awhile.  While running, it prints some
-     messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-Compilers and Options
-=====================
-
-   Some systems require unusual options for compilation or linking that
-the `configure' script does not know about.  Run `./configure --help'
-for details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-   You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory.  After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
-   By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc.  You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
-   Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
-   There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on.  Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
-   If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
-   Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
-   `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
-     Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
-     Print the version of Autoconf used to generate the `configure'
-     script, and exit.
-
-`--cache-file=FILE'
-     Enable the cache: use and save the results of the tests in FILE,
-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
-     disable caching.
-
-`--config-cache'
-`-C'
-     Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
-     Do not print messages saying which checks are being made.  To
-     suppress all normal output, redirect it to `/dev/null' (any error
-     messages will still be shown).
-
-`--srcdir=DIR'
-     Look for the package's source code in directory DIR.  Usually
-     `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options.  Run
-`configure --help' for more details.
-
diff --git a/LICENSE b/LICENSE
index a15d52c..f028c82 100644
--- a/LICENSE
+++ b/LICENSE
@@ -5,7 +5,7 @@
     This file is copyrighted by Red Hat Inc.
 
   - Atomicops support for AIX/POWER, located in
-    src/google/protobuf/stubs/atomicops_internals_aix.h.
+    src/google/protobuf/stubs/atomicops_internals_power.h.
     This file is copyrighted by Bloomberg Finance LP.
 
 Copyright 2014, Google Inc.  All rights reserved.
diff --git a/Makefile.am b/Makefile.am
index 8b36178..fbd27fc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,10 @@
 	if test -e conformance/Makefile; then \
 	  echo "Making clean in conformance"; \
 	  cd conformance && $(MAKE) $(AM_MAKEFLAGS) clean; \
+	fi; \
+	if test -e objectivec/DevTools; then \
+	  echo "Cleaning any ObjC pyc files"; \
+	  rm -f objectivec/DevTools/*.pyc; \
 	fi
 
 pkgconfigdir = $(libdir)/pkgconfig
@@ -82,10 +86,13 @@
   csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj                \
   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                         \
@@ -117,16 +124,20 @@
   csharp/src/Google.Protobuf/Google.Protobuf.nuspec                          \
   csharp/src/Google.Protobuf/IDeepCloneable.cs                               \
   csharp/src/Google.Protobuf/IMessage.cs                                     \
+  csharp/src/Google.Protobuf/InvalidJsonException.cs                         \
   csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs               \
   csharp/src/Google.Protobuf/JsonFormatter.cs                                \
+  csharp/src/Google.Protobuf/JsonParser.cs                                   \
+  csharp/src/Google.Protobuf/JsonToken.cs                                    \
+  csharp/src/Google.Protobuf/JsonTokenizer.cs                                \
   csharp/src/Google.Protobuf/LimitedInputStream.cs                           \
   csharp/src/Google.Protobuf/MessageExtensions.cs                            \
   csharp/src/Google.Protobuf/MessageParser.cs                                \
-  csharp/src/Google.Protobuf/Preconditions.cs                                \
+  csharp/src/Google.Protobuf/ProtoPreconditions.cs                           \
   csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs                      \
+  csharp/src/Google.Protobuf/Reflection/Descriptor.cs                        \
   csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs                    \
   csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs                    \
-  csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs               \
   csharp/src/Google.Protobuf/Reflection/DescriptorUtil.cs                    \
   csharp/src/Google.Protobuf/Reflection/DescriptorValidationException.cs     \
   csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs                    \
@@ -135,7 +146,7 @@
   csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs                   \
   csharp/src/Google.Protobuf/Reflection/FieldType.cs                         \
   csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs                    \
-  csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs                 \
+  csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs              \
   csharp/src/Google.Protobuf/Reflection/IDescriptor.cs                       \
   csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs                    \
   csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs                  \
@@ -149,6 +160,7 @@
   csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs             \
   csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs                 \
   csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs               \
+  csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs                      \
   csharp/src/Google.Protobuf/WellKnownTypes/Any.cs                           \
   csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs                    \
   csharp/src/Google.Protobuf/WellKnownTypes/Api.cs                           \
@@ -162,157 +174,167 @@
   csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs                     \
   csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs              \
   csharp/src/Google.Protobuf/WellKnownTypes/Type.cs                          \
+  csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs                  \
   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/packages/repositories.config
 
-java_EXTRA_DIST=                                                             \
-  java/src/main/java/com/google/protobuf/AbstractMessage.java                \
-  java/src/main/java/com/google/protobuf/AbstractMessageLite.java            \
-  java/src/main/java/com/google/protobuf/AbstractParser.java                 \
-  java/src/main/java/com/google/protobuf/AbstractProtobufList.java           \
-  java/src/main/java/com/google/protobuf/BlockingRpcChannel.java             \
-  java/src/main/java/com/google/protobuf/BlockingService.java                \
-  java/src/main/java/com/google/protobuf/BooleanArrayList.java               \
-  java/src/main/java/com/google/protobuf/BoundedByteString.java              \
-  java/src/main/java/com/google/protobuf/ByteString.java                     \
-  java/src/main/java/com/google/protobuf/CodedInputStream.java               \
-  java/src/main/java/com/google/protobuf/CodedOutputStream.java              \
-  java/src/main/java/com/google/protobuf/Descriptors.java                    \
-  java/src/main/java/com/google/protobuf/DoubleArrayList.java                \
-  java/src/main/java/com/google/protobuf/DynamicMessage.java                 \
-  java/src/main/java/com/google/protobuf/Extension.java                      \
-  java/src/main/java/com/google/protobuf/ExtensionLite.java                  \
-  java/src/main/java/com/google/protobuf/ExtensionRegistry.java              \
-  java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java          \
-  java/src/main/java/com/google/protobuf/FieldSet.java                       \
-  java/src/main/java/com/google/protobuf/FloatArrayList.java                 \
-  java/src/main/java/com/google/protobuf/GeneratedMessage.java               \
-  java/src/main/java/com/google/protobuf/GeneratedMessageLite.java           \
-  java/src/main/java/com/google/protobuf/IntArrayList.java                   \
-  java/src/main/java/com/google/protobuf/Internal.java                       \
-  java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
-  java/src/main/java/com/google/protobuf/LazyField.java                      \
-  java/src/main/java/com/google/protobuf/LazyFieldLite.java                  \
-  java/src/main/java/com/google/protobuf/LazyStringArrayList.java            \
-  java/src/main/java/com/google/protobuf/LazyStringList.java                 \
-  java/src/main/java/com/google/protobuf/LiteralByteString.java              \
-  java/src/main/java/com/google/protobuf/LongArrayList.java                  \
-  java/src/main/java/com/google/protobuf/MapEntry.java                       \
-  java/src/main/java/com/google/protobuf/MapEntryLite.java                   \
-  java/src/main/java/com/google/protobuf/MapField.java                       \
-  java/src/main/java/com/google/protobuf/MapFieldLite.java                   \
-  java/src/main/java/com/google/protobuf/Message.java                        \
-  java/src/main/java/com/google/protobuf/MessageLite.java                    \
-  java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java           \
-  java/src/main/java/com/google/protobuf/MessageOrBuilder.java               \
-  java/src/main/java/com/google/protobuf/MessageReflection.java              \
-  java/src/main/java/com/google/protobuf/MutabilityOracle.java               \
-  java/src/main/java/com/google/protobuf/Parser.java                         \
-  java/src/main/java/com/google/protobuf/ProtobufArrayList.java              \
-  java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java            \
-  java/src/main/java/com/google/protobuf/ProtocolStringList.java             \
-  java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java           \
-  java/src/main/java/com/google/protobuf/RopeByteString.java                 \
-  java/src/main/java/com/google/protobuf/RpcCallback.java                    \
-  java/src/main/java/com/google/protobuf/RpcChannel.java                     \
-  java/src/main/java/com/google/protobuf/RpcController.java                  \
-  java/src/main/java/com/google/protobuf/RpcUtil.java                        \
-  java/src/main/java/com/google/protobuf/Service.java                        \
-  java/src/main/java/com/google/protobuf/ServiceException.java               \
-  java/src/main/java/com/google/protobuf/SingleFieldBuilder.java             \
-  java/src/main/java/com/google/protobuf/SmallSortedMap.java                 \
-  java/src/main/java/com/google/protobuf/TextFormat.java                     \
-  java/src/main/java/com/google/protobuf/UninitializedMessageException.java  \
-  java/src/main/java/com/google/protobuf/UnknownFieldSet.java                \
-  java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java            \
-  java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java     \
-  java/src/main/java/com/google/protobuf/Utf8.java                           \
-  java/src/main/java/com/google/protobuf/WireFormat.java                     \
-  java/src/test/java/com/google/protobuf/AbstractMessageTest.java            \
-  java/src/test/java/com/google/protobuf/AnyTest.java                        \
-  java/src/test/java/com/google/protobuf/BooleanArrayListTest.java           \
-  java/src/test/java/com/google/protobuf/BoundedByteStringTest.java          \
-  java/src/test/java/com/google/protobuf/ByteStringTest.java                 \
-  java/src/test/java/com/google/protobuf/CheckUtf8Test.java                  \
-  java/src/test/java/com/google/protobuf/CodedInputStreamTest.java           \
-  java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java          \
-  java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java            \
-  java/src/test/java/com/google/protobuf/DescriptorsTest.java                \
-  java/src/test/java/com/google/protobuf/DoubleArrayListTest.java            \
-  java/src/test/java/com/google/protobuf/DynamicMessageTest.java             \
-  java/src/test/java/com/google/protobuf/FieldPresenceTest.java              \
-  java/src/test/java/com/google/protobuf/FloatArrayListTest.java             \
-  java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java       \
-  java/src/test/java/com/google/protobuf/GeneratedMessageTest.java           \
-  java/src/test/java/com/google/protobuf/IntArrayListTest.java               \
-  java/src/test/java/com/google/protobuf/IsValidUtf8Test.java                \
-  java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java            \
-  java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java              \
-  java/src/test/java/com/google/protobuf/LazyFieldTest.java                  \
-  java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java            \
-  java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java        \
-  java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java         \
-  java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java          \
-  java/src/test/java/com/google/protobuf/LiteTest.java                       \
-  java/src/test/java/com/google/protobuf/LiteralByteStringTest.java          \
-  java/src/test/java/com/google/protobuf/LongArrayListTest.java              \
-  java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java           \
-  java/src/test/java/com/google/protobuf/MapForProto2Test.java               \
-  java/src/test/java/com/google/protobuf/MapTest.java                        \
-  java/src/test/java/com/google/protobuf/MessageTest.java                    \
-  java/src/test/java/com/google/protobuf/NestedBuildersTest.java             \
-  java/src/test/java/com/google/protobuf/ParserTest.java                     \
-  java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java          \
-  java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java       \
-  java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java    \
-  java/src/test/java/com/google/protobuf/RopeByteStringTest.java             \
-  java/src/test/java/com/google/protobuf/ServiceTest.java                    \
-  java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java         \
-  java/src/test/java/com/google/protobuf/SmallSortedMapTest.java             \
-  java/src/test/java/com/google/protobuf/TestBadIdentifiers.java             \
-  java/src/test/java/com/google/protobuf/TestUtil.java                       \
-  java/src/test/java/com/google/protobuf/TextFormatTest.java                 \
-  java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java           \
-  java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java        \
-  java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java            \
-  java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java \
-  java/src/test/java/com/google/protobuf/WellKnownTypesTest.java             \
-  java/src/test/java/com/google/protobuf/WireFormatTest.java                 \
-  java/src/test/java/com/google/protobuf/any_test.proto                      \
-  java/src/test/java/com/google/protobuf/field_presence_test.proto           \
-  java/src/test/java/com/google/protobuf/lazy_fields_lite.proto              \
-  java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto          \
-  java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto      \
-  java/src/test/java/com/google/protobuf/map_for_proto2_test.proto           \
-  java/src/test/java/com/google/protobuf/map_initialization_order_test.proto \
-  java/src/test/java/com/google/protobuf/map_test.proto                      \
-  java/src/test/java/com/google/protobuf/multiple_files_test.proto           \
-  java/src/test/java/com/google/protobuf/nested_builders_test.proto          \
-  java/src/test/java/com/google/protobuf/nested_extension.proto              \
-  java/src/test/java/com/google/protobuf/nested_extension_lite.proto         \
-  java/src/test/java/com/google/protobuf/non_nested_extension.proto          \
-  java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto     \
-  java/src/test/java/com/google/protobuf/outer_class_name_test.proto         \
-  java/src/test/java/com/google/protobuf/outer_class_name_test2.proto        \
-  java/src/test/java/com/google/protobuf/outer_class_name_test3.proto        \
-  java/src/test/java/com/google/protobuf/test_bad_identifiers.proto          \
-  java/src/test/java/com/google/protobuf/test_check_utf8.proto               \
-  java/src/test/java/com/google/protobuf/test_check_utf8_size.proto          \
-  java/src/test/java/com/google/protobuf/test_custom_options.proto           \
-  java/src/test/java/com/google/protobuf/test_extra_interfaces.proto         \
-  java/util/pom.xml                                                          \
-  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/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       \
-  java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java         \
-  java/util/src/test/java/com/google/protobuf/util/json_test.proto           \
-  java/pom.xml                                                               \
-  java/README.md
+java_EXTRA_DIST=                                                                   \
+  java/README.md                                                                   \
+  java/core/generate-sources-build.xml                                             \
+  java/core/generate-test-sources-build.xml                                        \
+  java/core/pom.xml                                                                \
+  java/core/src/main/java/com/google/protobuf/AbstractMessage.java                 \
+  java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java             \
+  java/core/src/main/java/com/google/protobuf/AbstractParser.java                  \
+  java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java            \
+  java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java              \
+  java/core/src/main/java/com/google/protobuf/BlockingService.java                 \
+  java/core/src/main/java/com/google/protobuf/BooleanArrayList.java                \
+  java/core/src/main/java/com/google/protobuf/ByteString.java                      \
+  java/core/src/main/java/com/google/protobuf/CodedInputStream.java                \
+  java/core/src/main/java/com/google/protobuf/CodedOutputStream.java               \
+  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/Extension.java                       \
+  java/core/src/main/java/com/google/protobuf/ExtensionLite.java                   \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java               \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java           \
+  java/core/src/main/java/com/google/protobuf/FieldSet.java                        \
+  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/IntArrayList.java                    \
+  java/core/src/main/java/com/google/protobuf/Internal.java                        \
+  java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java  \
+  java/core/src/main/java/com/google/protobuf/LazyField.java                       \
+  java/core/src/main/java/com/google/protobuf/LazyFieldLite.java                   \
+  java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java             \
+  java/core/src/main/java/com/google/protobuf/LazyStringList.java                  \
+  java/core/src/main/java/com/google/protobuf/LongArrayList.java                   \
+  java/core/src/main/java/com/google/protobuf/MapEntry.java                        \
+  java/core/src/main/java/com/google/protobuf/MapEntryLite.java                    \
+  java/core/src/main/java/com/google/protobuf/MapField.java                        \
+  java/core/src/main/java/com/google/protobuf/MapFieldLite.java                    \
+  java/core/src/main/java/com/google/protobuf/Message.java                         \
+  java/core/src/main/java/com/google/protobuf/MessageLite.java                     \
+  java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java            \
+  java/core/src/main/java/com/google/protobuf/MessageLiteToString.java             \
+  java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java                \
+  java/core/src/main/java/com/google/protobuf/MessageReflection.java               \
+  java/core/src/main/java/com/google/protobuf/MutabilityOracle.java                \
+  java/core/src/main/java/com/google/protobuf/NioByteString.java                   \
+  java/core/src/main/java/com/google/protobuf/Parser.java                          \
+  java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java               \
+  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/RopeByteString.java                  \
+  java/core/src/main/java/com/google/protobuf/RpcCallback.java                     \
+  java/core/src/main/java/com/google/protobuf/RpcChannel.java                      \
+  java/core/src/main/java/com/google/protobuf/RpcController.java                   \
+  java/core/src/main/java/com/google/protobuf/RpcUtil.java                         \
+  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/SmallSortedMap.java                  \
+  java/core/src/main/java/com/google/protobuf/TextFormat.java                      \
+  java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java               \
+  java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java   \
+  java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java                 \
+  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/Utf8.java                            \
+  java/core/src/main/java/com/google/protobuf/WireFormat.java                      \
+  java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java             \
+  java/core/src/test/java/com/google/protobuf/AnyTest.java                         \
+  java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java            \
+  java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/ByteStringTest.java                  \
+  java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java                   \
+  java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java            \
+  java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java           \
+  java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java             \
+  java/core/src/test/java/com/google/protobuf/DescriptorsTest.java                 \
+  java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java             \
+  java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java              \
+  java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java               \
+  java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java              \
+  java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java        \
+  java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java            \
+  java/core/src/test/java/com/google/protobuf/IntArrayListTest.java                \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java                 \
+  java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java             \
+  java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java               \
+  java/core/src/test/java/com/google/protobuf/LazyFieldTest.java                   \
+  java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java             \
+  java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java         \
+  java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java          \
+  java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java           \
+  java/core/src/test/java/com/google/protobuf/LiteTest.java                        \
+  java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java           \
+  java/core/src/test/java/com/google/protobuf/LongArrayListTest.java               \
+  java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java            \
+  java/core/src/test/java/com/google/protobuf/MapForProto2Test.java                \
+  java/core/src/test/java/com/google/protobuf/MapTest.java                         \
+  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/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/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/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/TextFormatTest.java                  \
+  java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java            \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java         \
+  java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java             \
+  java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java  \
+  java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java              \
+  java/core/src/test/java/com/google/protobuf/WireFormatTest.java                  \
+  java/core/src/test/proto/com/google/protobuf/any_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/field_presence_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto              \
+  java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto          \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto      \
+  java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto \
+  java/core/src/test/proto/com/google/protobuf/map_test.proto                      \
+  java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto           \
+  java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto          \
+  java/core/src/test/proto/com/google/protobuf/nested_extension.proto              \
+  java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto         \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto          \
+  java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto     \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto         \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto        \
+  java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto        \
+  java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto          \
+  java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto               \
+  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/pom.xml                                                                \
+  java/pom.xml                                                                     \
+  java/util/pom.xml                                                                \
+  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/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             \
+  java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java               \
+  java/util/src/test/proto/com/google/protobuf/util/json_test.proto
 
 javanano_EXTRA_DIST=                                                                      \
   javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java          \
@@ -456,8 +478,8 @@
   objectivec/Tests/GPBMessageTests+Runtime.m                                 \
   objectivec/Tests/GPBMessageTests+Serialization.m                           \
   objectivec/Tests/GPBMessageTests.m                                         \
+  objectivec/Tests/GPBObjectiveCPlusPlusTest.mm                              \
   objectivec/Tests/GPBPerfTests.m                                            \
-  objectivec/Tests/GPBStringTests.m                                          \
   objectivec/Tests/GPBSwiftTests.swift                                       \
   objectivec/Tests/GPBTestUtilities.h                                        \
   objectivec/Tests/GPBTestUtilities.m                                        \
@@ -493,6 +515,15 @@
 
 python_EXTRA_DIST=                                                           \
   python/MANIFEST.in                                                         \
+  python/google/__init__.py                                                  \
+  python/google/protobuf/__init__.py                                         \
+  python/google/protobuf/descriptor.py                                       \
+  python/google/protobuf/descriptor_database.py                              \
+  python/google/protobuf/descriptor_pool.py                                  \
+  python/google/protobuf/internal/__init__.py                                \
+  python/google/protobuf/internal/_parameterized.py                          \
+  python/google/protobuf/internal/any_test.proto                             \
+  python/google/protobuf/internal/any_test.proto                             \
   python/google/protobuf/internal/api_implementation.cc                      \
   python/google/protobuf/internal/api_implementation.py                      \
   python/google/protobuf/internal/containers.py                              \
@@ -507,16 +538,19 @@
   python/google/protobuf/internal/factory_test1.proto                        \
   python/google/protobuf/internal/factory_test2.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            \
+  python/google/protobuf/internal/import_test_package/outer.proto            \
+  python/google/protobuf/internal/json_format_test.py                        \
   python/google/protobuf/internal/message_factory_test.py                    \
   python/google/protobuf/internal/message_listener.py                        \
   python/google/protobuf/internal/message_set_extensions.proto               \
   python/google/protobuf/internal/message_test.py                            \
   python/google/protobuf/internal/missing_enum_values.proto                  \
-  python/google/protobuf/internal/more_extensions_dynamic.proto              \
   python/google/protobuf/internal/more_extensions.proto                      \
+  python/google/protobuf/internal/more_extensions_dynamic.proto              \
   python/google/protobuf/internal/more_messages.proto                        \
   python/google/protobuf/internal/packed_field_test.proto                    \
-  python/google/protobuf/internal/_parameterized.py                          \
   python/google/protobuf/internal/proto_builder_test.py                      \
   python/google/protobuf/internal/python_message.py                          \
   python/google/protobuf/internal/reflection_test.py                         \
@@ -528,51 +562,47 @@
   python/google/protobuf/internal/text_format_test.py                        \
   python/google/protobuf/internal/type_checkers.py                           \
   python/google/protobuf/internal/unknown_fields_test.py                     \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types.py                        \
+  python/google/protobuf/internal/well_known_types_test.py                   \
+  python/google/protobuf/internal/well_known_types_test.py                   \
   python/google/protobuf/internal/wire_format.py                             \
   python/google/protobuf/internal/wire_format_test.py                        \
-  python/google/protobuf/internal/__init__.py                                \
-  python/google/protobuf/internal/import_test_package/__init__.py            \
-  python/google/protobuf/internal/import_test_package/inner.proto            \
-  python/google/protobuf/internal/import_test_package/outer.proto            \
-  python/google/protobuf/pyext/README                                        \
-  python/google/protobuf/pyext/cpp_message.py                                \
-  python/google/protobuf/pyext/descriptor.h                                  \
-  python/google/protobuf/pyext/descriptor.cc                                 \
-  python/google/protobuf/pyext/descriptor_pool.h                             \
-  python/google/protobuf/pyext/descriptor_pool.cc                            \
-  python/google/protobuf/pyext/descriptor_containers.h                       \
-  python/google/protobuf/pyext/descriptor_containers.cc                      \
-  python/google/protobuf/pyext/extension_dict.h                              \
-  python/google/protobuf/pyext/extension_dict.cc                             \
-  python/google/protobuf/pyext/message.h                                     \
-  python/google/protobuf/pyext/message.cc                                    \
-  python/google/protobuf/pyext/message_map_container.cc                      \
-  python/google/protobuf/pyext/message_map_container.h                       \
-  python/google/protobuf/pyext/proto2_api_test.proto                         \
-  python/google/protobuf/pyext/python.proto                                  \
-  python/google/protobuf/pyext/python_protobuf.h                             \
-  python/google/protobuf/pyext/repeated_composite_container.h                \
-  python/google/protobuf/pyext/repeated_composite_container.cc               \
-  python/google/protobuf/pyext/repeated_scalar_container.h                   \
-  python/google/protobuf/pyext/repeated_scalar_container.cc                  \
-  python/google/protobuf/pyext/scalar_map_container.cc                       \
-  python/google/protobuf/pyext/scalar_map_container.h                        \
-  python/google/protobuf/pyext/scoped_pyobject_ptr.h                         \
-  python/google/protobuf/pyext/__init__.py                                   \
-  python/google/protobuf/descriptor.py                                       \
-  python/google/protobuf/descriptor_database.py                              \
-  python/google/protobuf/descriptor_pool.py                                  \
+  python/google/protobuf/json_format.py                                      \
   python/google/protobuf/message.py                                          \
   python/google/protobuf/message_factory.py                                  \
   python/google/protobuf/proto_builder.py                                    \
+  python/google/protobuf/pyext/README                                        \
+  python/google/protobuf/pyext/__init__.py                                   \
+  python/google/protobuf/pyext/cpp_message.py                                \
+  python/google/protobuf/pyext/descriptor.cc                                 \
+  python/google/protobuf/pyext/descriptor.h                                  \
+  python/google/protobuf/pyext/descriptor_containers.cc                      \
+  python/google/protobuf/pyext/descriptor_containers.h                       \
+  python/google/protobuf/pyext/descriptor_database.cc                        \
+  python/google/protobuf/pyext/descriptor_database.h                         \
+  python/google/protobuf/pyext/descriptor_pool.cc                            \
+  python/google/protobuf/pyext/descriptor_pool.h                             \
+  python/google/protobuf/pyext/extension_dict.cc                             \
+  python/google/protobuf/pyext/extension_dict.h                              \
+  python/google/protobuf/pyext/map_container.cc                              \
+  python/google/protobuf/pyext/map_container.h                               \
+  python/google/protobuf/pyext/message.cc                                    \
+  python/google/protobuf/pyext/message.h                                     \
+  python/google/protobuf/pyext/proto2_api_test.proto                         \
+  python/google/protobuf/pyext/python.proto                                  \
+  python/google/protobuf/pyext/python_protobuf.h                             \
+  python/google/protobuf/pyext/repeated_composite_container.cc               \
+  python/google/protobuf/pyext/repeated_composite_container.h                \
+  python/google/protobuf/pyext/repeated_scalar_container.cc                  \
+  python/google/protobuf/pyext/repeated_scalar_container.h                   \
+  python/google/protobuf/pyext/scoped_pyobject_ptr.h                         \
   python/google/protobuf/reflection.py                                       \
   python/google/protobuf/service.py                                          \
   python/google/protobuf/service_reflection.py                               \
   python/google/protobuf/symbol_database.py                                  \
   python/google/protobuf/text_encoding.py                                    \
   python/google/protobuf/text_format.py                                      \
-  python/google/protobuf/__init__.py                                         \
-  python/google/__init__.py                                                  \
   python/mox.py                                                              \
   python/setup.py                                                            \
   python/stubout.py                                                          \
@@ -627,13 +657,46 @@
   ruby/tests/generated_code_test.rb                                          \
   ruby/travis-test.sh
 
-all_EXTRA_DIST=$(csharp_EXTRA_DIST) $(java_EXTRA_DIST) $(javanano_EXTRA_DIST) $(objectivec_EXTRA_DIST) $(python_EXTRA_DIST) $(ruby_EXTRA_DIST)
+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/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/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)
 
 EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)   \
   autogen.sh                             \
   generate_descriptor_proto.sh           \
   README.md                              \
-  INSTALL.txt                            \
   LICENSE                                \
   CONTRIBUTORS.txt                       \
   CHANGES.txt                            \
@@ -660,15 +723,23 @@
   examples/Makefile                      \
   examples/addressbook.proto             \
   examples/add_person.cc                 \
+  examples/add_person.go                 \
+  examples/add_person_test.go            \
   examples/list_people.cc                \
+  examples/list_people.go                \
   examples/AddPerson.java                \
   examples/ListPeople.java               \
   examples/add_person.py                 \
-  examples/list_people.py
+  examples/list_people.py                \
+  examples/list_people_test.go           \
+  protobuf.bzl                           \
+  six.BUILD                              \
+  util/python/BUILD
 
 # Deletes all the files generated by autogen.sh.
 MAINTAINERCLEANFILES =   \
   aclocal.m4             \
+  ar-lib                 \
   config.guess           \
   config.sub             \
   configure              \
diff --git a/Protobuf.podspec b/Protobuf.podspec
index 698583b..02c8372 100644
--- a/Protobuf.podspec
+++ b/Protobuf.podspec
@@ -5,12 +5,15 @@
 # dependent projects use the :git notation to refer to the library.
 Pod::Spec.new do |s|
   s.name     = 'Protobuf'
-  s.version  = '3.0.0-alpha-4'
+  s.version  = '3.0.0-beta-2'
   s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
   s.homepage = 'https://github.com/google/protobuf'
   s.license  = 'New BSD'
   s.authors  = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
 
+  s.source = { :git => 'https://github.com/google/protobuf.git',
+               :tag => "v#{s.version}" }
+
   s.source_files = 'objectivec/*.{h,m}',
                    'objectivec/google/protobuf/Any.pbobjc.{h,m}',
                    'objectivec/google/protobuf/Api.pbobjc.{h,m}',
diff --git a/README.md b/README.md
index a974d30..ba9c589 100644
--- a/README.md
+++ b/README.md
@@ -7,182 +7,66 @@
 
 https://developers.google.com/protocol-buffers/
 
-C++ Installation - Unix
------------------------
+Overview
+--------
 
-If you get the source from github, you need to generate the configure script
-first:
+Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
+platform-neutral, extensible mechanism for serializing structured data. You
+can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
 
-    $ ./autogen.sh
+This README file contains protobuf installation instructions. To install
+protobuf, you need to install the protocol compiler (used to compile .proto
+files) and the protobuf runtime for your chosen programming language.
 
-This will download gmock source (which is used for C++ Protocol Buffer
-unit-tests) to the current directory and run automake, autoconf, etc.
-to generate the configure script and various template makefiles.
+Protocol Compiler Installation
+------------------------------
 
-You can skip this step if you are using a release package (which already
-contains gmock and the configure script).
+The protocol compiler is written in C++. If you are using C++, please follow
+the [C++ Installation Instructions](src/README.md) to install protoc along
+with the C++ runtime.
 
-To build and install the C++ Protocol Buffer runtime and the Protocol
-Buffer compiler (protoc) execute the following:
+For non-C++ users, the simplest way to install the protocol compiler is to
+download a pre-built binary from our release page:
 
-    $ ./configure
-    $ make
-    $ make check
-    $ make install
+  [https://github.com/google/protobuf/releases](https://github.com/google/protobuf/releases)
 
-If "make check" fails, you can still install, but it is likely that
-some features of this library will not work correctly on your system.
-Proceed at your own risk.
+In the downloads section of each release, you can find pre-built binaries in
+zip packages: protoc-$VERSION-$PLATFORM.zip. It contains the protoc binary
+as well as a set of standard .proto files distributed along with protobuf.
 
-"make install" may require superuser privileges.
+If you are looking for an old version that is not available in the release
+page, check out the maven repo here:
 
-For advanced usage information on configure and make, see INSTALL.txt.
+  [http://repo1.maven.org/maven2/com/google/protobuf/protoc/](http://repo1.maven.org/maven2/com/google/protobuf/protoc/)
 
-**Hint on install location**
+These pre-built binaries are only provided for released versions. If you want
+to use the github master version at HEAD, or you need to modify protobuf code,
+or you are using C++, it's recommended to build your own protoc binary from
+source.
 
-  By default, the package will be installed to /usr/local.  However,
-  on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
-  You can add it, but it may be easier to just install to /usr
-  instead.  To do this, invoke configure as follows:
+If you would like to build protoc binary from source, see the [C++ Installation
+Instructions](src/README.md).
 
-    ./configure --prefix=/usr
+Protobuf Runtime Installation
+-----------------------------
 
-  If you already built the package with a different prefix, make sure
-  to run "make clean" before building again.
+Protobuf supports several different programming languages. For each programming
+language, you can find instructions in the corresponding source directory about
+how to install protobuf runtime for that specific language:
 
-**Compiling dependent packages**
+| Language                             | Source                                                |
+|--------------------------------------|-------------------------------------------------------|
+| C++ (include C++ runtime and protoc) | [src](src)                                            |
+| Java                                 | [java](java)                                          |
+| Python                               | [python](python)                                      |
+| Objective-C                          | [objectivec](objectivec)                              |
+| C#                                   | [csharp](csharp)                                      |
+| JavaNano                             | [javanano](javanano)                                  |
+| JavaScript                           | [js](js)                                              |
+| Ruby                                 | [ruby](ruby)                                          |
+| Go                                   | [golang/protobuf](https://github.com/golang/protobuf) |
+| PHP                                  | TBD                                                   |
 
-  To compile a package that uses Protocol Buffers, you need to pass
-  various flags to your compiler and linker.  As of version 2.2.0,
-  Protocol Buffers integrates with pkg-config to manage this.  If you
-  have pkg-config installed, then you can invoke it to get a list of
-  flags like so:
-
-    pkg-config --cflags protobuf         # print compiler flags
-    pkg-config --libs protobuf           # print linker flags
-    pkg-config --cflags --libs protobuf  # print both
-
-  For example:
-
-    c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
-
-  Note that packages written prior to the 2.2.0 release of Protocol
-  Buffers may not yet integrate with pkg-config to get flags, and may
-  not pass the correct set of flags to correctly link against
-  libprotobuf.  If the package in question uses autoconf, you can
-  often fix the problem by invoking its configure script like:
-
-    configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
-              LIBS="$(pkg-config --libs protobuf)"
-
-  This will force it to use the correct flags.
-
-  If you are writing an autoconf-based package that uses Protocol
-  Buffers, you should probably use the PKG_CHECK_MODULES macro in your
-  configure script like:
-
-    PKG_CHECK_MODULES([protobuf], [protobuf])
-
-  See the pkg-config man page for more info.
-
-  If you only want protobuf-lite, substitute "protobuf-lite" in place
-  of "protobuf" in these examples.
-
-**Note for Mac users**
-
-  For a Mac system, Unix tools are not available by default. You will first need
-  to install Xcode from the Mac AppStore and then run the following command from
-  a terminal:
-
-    $ sudo xcode-select --install
-
-  To install Unix tools, you can install "port" following the instructions at
-  https://www.macports.org . This will reside in /opt/local/bin/port for most
-  Mac installations.
-
-    $ sudo /opt/local/bin/port install autoconf automake libtool
-
-  Then follow the Unix instructions above.
-
-**Note for cross-compiling**
-
-  The makefiles normally invoke the protoc executable that they just
-  built in order to build tests.  When cross-compiling, the protoc
-  executable may not be executable on the host machine.  In this case,
-  you must build a copy of protoc for the host machine first, then use
-  the --with-protoc option to tell configure to use it instead.  For
-  example:
-
-    ./configure --with-protoc=protoc
-
-  This will use the installed protoc (found in your $PATH) instead of
-  trying to execute the one built during the build process.  You can
-  also use an executable that hasn't been installed.  For example, if
-  you built the protobuf package for your host machine in ../host,
-  you might do:
-
-    ./configure --with-protoc=../host/src/protoc
-
-  Either way, you must make sure that the protoc executable you use
-  has the same version as the protobuf source code you are trying to
-  use it with.
-
-**Note for Solaris users**
-
-  Solaris 10 x86 has a bug that will make linking fail, complaining
-  about libstdc++.la being invalid.  We have included a work-around
-  in this package.  To use the work-around, run configure as follows:
-
-    ./configure LDFLAGS=-L$PWD/src/solaris
-
-  See src/solaris/libstdc++.la for more info on this bug.
-
-**Note for HP C++ Tru64 users**
-
-  To compile invoke configure as follows:
-
-    ./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
-
-  Also, you will need to use gmake instead of make.
-
-**Note for AIX users**
-
-  Compile using the IBM xlC C++ compiler as follows:
-
-    ./configure CXX=xlC
-
-  Also, you will need to use GNU `make` (`gmake`) instead of AIX `make`.
-
-C++ Installation - Windows
---------------------------
-
-If you are using Microsoft Visual C++, see cmake/README.md.
-
-If you are using Cygwin or MinGW, follow the Unix installation
-instructions, above.
-
-Binary Compatibility Warning
-----------------------------
-
-Due to the nature of C++, it is unlikely that any two versions of the
-Protocol Buffers C++ runtime libraries will have compatible ABIs.
-That is, if you linked an executable against an older version of
-libprotobuf, it is unlikely to work with a newer version without
-re-compiling.  This problem, when it occurs, will normally be detected
-immediately on startup of your app.  Still, you may want to consider
-using static linkage.  You can configure this package to install
-static libraries only using:
-
-    ./configure --disable-shared
-
-Java and Python Installation
-----------------------------
-
-The Java and Python runtime libraries for Protocol Buffers are located
-in the java and python directories.  See the README file in each
-directory for more information on how to compile and install them.
-Note that both of them require you to first install the Protocol
-Buffer compiler (protoc), which is part of the C++ package.
 
 Usage
 -----
diff --git a/WORKSPACE b/WORKSPACE
index f72f239..c3f18cc 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -5,6 +5,13 @@
   build_file = "gmock.BUILD",
 )
 
+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",
+)
+
 bind(
   name = "gtest",
   actual = "@gmock_archive//:gtest",
@@ -14,3 +21,8 @@
   name = "gtest_main",
   actual = "@gmock_archive//:gtest_main",
 )
+
+bind(
+  name = "six",
+  actual = "@six_archive//:six",
+)
diff --git a/appveyor.bat b/appveyor.bat
index 356a13f..9a46b92 100644
--- a/appveyor.bat
+++ b/appveyor.bat
@@ -10,7 +10,7 @@
 echo Building C++
 mkdir build_msvc
 cd build_msvc
-cmake -G "%generator%" -DBUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
+cmake -G "%generator%" -Dprotobuf_BUILD_SHARED_LIBS=%BUILD_DLL% ../cmake
 msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" || goto error
 cd %configuration%
 tests.exe || goto error
@@ -26,4 +26,4 @@
 
 :error
 echo Failed!
-EXIT /b %ERRORLEVEL%
\ No newline at end of file
+EXIT /b %ERRORLEVEL%
diff --git a/appveyor.yml b/appveyor.yml
index 3447602..c84ecae 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,32 +1,32 @@
-# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can

-# test more combinations but AppVeyor just takes too long to finish (each

-# combination takes ~15mins).

-platform:

-  - Win64

-

-configuration:

-  - Debug

-

-environment:

-  matrix:

-    - language: cpp

-      BUILD_DLL: ON

-

-    - language: csharp

-

-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

-

-before_build:

-  - if %platform%==Win32 set generator=Visual Studio 12

-  - if %platform%==Win64 set generator=Visual Studio 12 Win64

-  - if %platform%==Win32 set vcplatform=Win32

-  - if %platform%==Win64 set vcplatform=x64

-

-build_script:

-  - CALL appveyor.bat

-

-skip_commits:

-  message: /.*\[skip appveyor\].*/

+# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can
+# test more combinations but AppVeyor just takes too long to finish (each
+# combination takes ~15mins).
+platform:
+  - Win64
+
+configuration:
+  - Debug
+
+environment:
+  matrix:
+    - language: cpp
+      BUILD_DLL: ON
+
+    - language: csharp
+
+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
+
+before_build:
+  - if %platform%==Win32 set generator=Visual Studio 12
+  - if %platform%==Win64 set generator=Visual Studio 12 Win64
+  - if %platform%==Win32 set vcplatform=Win32
+  - if %platform%==Win64 set vcplatform=x64
+
+build_script:
+  - CALL appveyor.bat
+
+skip_commits:
+  message: /.*\[skip appveyor\].*/
diff --git a/autogen.sh b/autogen.sh
index 8160313..5b4c29f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -6,6 +6,18 @@
 
 set -e
 
+if [ ! -z "$@" ]; then
+  for argument in "$@"; do
+    case $argument in
+	  # make curl silent
+      "-s")
+        curlopts="-s"
+        ;;
+    esac
+  done
+fi
+
+
 # Check that we're being run from the right directory.
 if test ! -f src/google/protobuf/stubs/common.h; then
   cat >&2 << __EOF__
@@ -19,7 +31,7 @@
 # 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 -O https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+  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
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 33e069f..15ae457 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -4,39 +4,65 @@
 # Project
 project(protobuf C CXX)
 
+# CMake policies
+cmake_policy(SET CMP0022 NEW)
+
 # Options
-option(BUILD_TESTING "Build tests" ON)
-option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF)
+option(protobuf_VERBOSE "Enable for verbose output" OFF)
+option(protobuf_BUILD_TESTS "Build tests" ON)
+if (BUILD_SHARED_LIBS)
+  set(protobuf_BUILD_SHARED_LIBS_DEFAULT ON)
+else (BUILD_SHARED_LIBS)
+  set(protobuf_BUILD_SHARED_LIBS_DEFAULT OFF)
+endif (BUILD_SHARED_LIBS)
+option(protobuf_BUILD_SHARED_LIBS "Build Shared Libraries" ${protobuf_BUILD_SHARED_LIBS_DEFAULT})
+option(protobuf_MSVC_STATIC_RUNTIME "Link static runtime libraries" ON)
 if (MSVC)
-  option(ZLIB "Build with zlib support" OFF)
+  set(protobuf_WITH_ZLIB_DEFAULT OFF)
+else (MSVC)
+  set(protobuf_WITH_ZLIB_DEFAULT ON)
 endif (MSVC)
+option(protobuf_WITH_ZLIB "Build with zlib support" ${protobuf_WITH_ZLIB_DEFAULT})
+set(protobuf_DEBUG_POSTFIX "d"
+  CACHE STRING "Default debug postfix")
 
 # Path to main configure script
 set(protobuf_CONFIGURE_SCRIPT "../configure.ac")
 
-# Parse version from configure script
-file(STRINGS "${protobuf_CONFIGURE_SCRIPT}" protobuf_VERSION_LINE
-  LIMIT_COUNT 1
-  REGEX "^AC_INIT")
-# Replace special characters
-string(REPLACE "(" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE})
-string(REPLACE ")" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE})
-string(REPLACE "[" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE})
-string(REPLACE "]" "_" protobuf_VERSION_LINE ${protobuf_VERSION_LINE})
-# Parse version string
-string(REGEX REPLACE "^AC_INIT__Protocol Buffers_,_([^_]+).*$" "\\1"
-    protobuf_VERSION_STRING "${protobuf_VERSION_LINE}")
+# Parse configure script
+set(protobuf_AC_INIT_REGEX
+  "^AC_INIT\\(\\[([^]]+)\\],\\[([^]]+)\\],\\[([^]]+)\\],\\[([^]]+)\\]\\)$")
+file(STRINGS "${protobuf_CONFIGURE_SCRIPT}" protobuf_AC_INIT_LINE
+  LIMIT_COUNT 1 REGEX "^AC_INIT")
+# Description
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\1"
+    protobuf_DESCRIPTION    "${protobuf_AC_INIT_LINE}")
+# Version
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\2"
+    protobuf_VERSION_STRING "${protobuf_AC_INIT_LINE}")
+# Contact
+string(REGEX REPLACE        "${protobuf_AC_INIT_REGEX}" "\\3"
+    protobuf_CONTACT        "${protobuf_AC_INIT_LINE}")
 # Parse version tweaks
-string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\1"
+set(protobuf_VERSION_REGEX "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$")
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\1"
   protobuf_VERSION_MAJOR "${protobuf_VERSION_STRING}")
-string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\2"
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\2"
   protobuf_VERSION_MINOR "${protobuf_VERSION_STRING}")
-string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$" "\\3"
+string(REGEX REPLACE     "${protobuf_VERSION_REGEX}" "\\3"
   protobuf_VERSION_PATCH "${protobuf_VERSION_STRING}")
 # Package version
 set(protobuf_VERSION
   "${protobuf_VERSION_MAJOR}.${protobuf_VERSION_MINOR}.${protobuf_VERSION_PATCH}")
 
+if(protobuf_VERBOSE)
+  message(STATUS "Configuration script parsing status [")
+  message(STATUS "  Description : ${protobuf_DESCRIPTION}")
+  message(STATUS "  Version     : ${protobuf_VERSION} (${protobuf_VERSION_STRING})")
+  message(STATUS "  Contact     : ${protobuf_CONTACT}")
+  message(STATUS "]")
+endif()
+
 add_definitions(-DGOOGLE_PROTOBUF_CMAKE_BUILD)
 
 find_package(Threads REQUIRED)
@@ -44,18 +70,17 @@
   add_definitions(-DHAVE_PTHREAD)
 endif (CMAKE_USE_PTHREADS_INIT)
 
-if (MSVC)
-  if (ZLIB)
-    set(HAVE_ZLIB 1)
-    find_path(ZLIB_INCLUDE_DIRECTORIES zlib.h ${protobuf_SOURCE_DIR})
-    find_library(ZLIB_LIBRARIES zdll ${protobuf_SOURCE_DIR})
-  else (ZLIB)
-    set(HAVE_ZLIB 0)
-  endif (ZLIB)
-else (MSVC)
+if (protobuf_WITH_ZLIB)
   find_package(ZLIB)
   if (ZLIB_FOUND)
     set(HAVE_ZLIB 1)
+    # FindZLIB module define ZLIB_INCLUDE_DIRS variable
+    # Set ZLIB_INCLUDE_DIRECTORIES for compatible
+    set(ZLIB_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIRECTORIES} ${ZLIB_INCLUDE_DIRS})
+    # Using imported target if exists
+    if (TARGET ZLIB::ZLIB)
+      set(ZLIB_LIBRARIES ZLIB::ZLIB)
+    endif (TARGET ZLIB::ZLIB)
   else (ZLIB_FOUND)
     set(HAVE_ZLIB 0)
     # Explicitly set these to empty (override NOT_FOUND) so cmake doesn't
@@ -63,21 +88,22 @@
     set(ZLIB_INCLUDE_DIRECTORIES)
     set(ZLIB_LIBRARIES)
   endif (ZLIB_FOUND)
-endif (MSVC)
+endif (protobuf_WITH_ZLIB)
 
 if (HAVE_ZLIB)
   add_definitions(-DHAVE_ZLIB)
 endif (HAVE_ZLIB)
 
-if (MSVC)
-  if (BUILD_SHARED_LIBS)
-    add_definitions(-DPROTOBUF_USE_DLLS)
-  else (BUILD_SHARED_LIBS)
-    # In case we are building static libraries, link also the runtime library statically
-	# so that MSVCR*.DLL is not required at runtime.
-    # https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
-    # This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
-    # http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
+if (protobuf_BUILD_SHARED_LIBS)
+  set(protobuf_SHARED_OR_STATIC "SHARED")
+else (protobuf_BUILD_SHARED_LIBS)
+  set(protobuf_SHARED_OR_STATIC "STATIC")
+  # In case we are building static libraries, link also the runtime library statically
+  # so that MSVCR*.DLL is not required at runtime.
+  # https://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
+  # This is achieved by replacing msvc option /MD with /MT and /MDd with /MTd
+  # 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)
@@ -85,11 +111,13 @@
         string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
       endif(${flag_var} MATCHES "/MD")
     endforeach(flag_var)
-  endif (BUILD_SHARED_LIBS)
-  add_definitions(/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305)
-endif (MSVC)
+  endif (MSVC AND protobuf_MSVC_STATIC_RUNTIME)
+endif (protobuf_BUILD_SHARED_LIBS)
 
 if (MSVC)
+  # Build with multiple processes
+  add_definitions(/MP)
+  add_definitions(/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305)
   string(REPLACE "/" "\\" PROTOBUF_SOURCE_WIN32_PATH ${protobuf_SOURCE_DIR})
   string(REPLACE "/" "\\" PROTOBUF_BINARY_WIN32_PATH ${protobuf_BINARY_DIR})
   configure_file(extract_includes.bat.in extract_includes.bat)
@@ -116,8 +144,8 @@
 include(libprotoc.cmake)
 include(protoc.cmake)
 
-if (BUILD_TESTING)
+if (protobuf_BUILD_TESTS)
   include(tests.cmake)
-endif (BUILD_TESTING)
+endif (protobuf_BUILD_TESTS)
 
 include(install.cmake)
diff --git a/cmake/README.md b/cmake/README.md
index c68defd..1e7410d 100644
--- a/cmake/README.md
+++ b/cmake/README.md
@@ -1,60 +1,236 @@
-This directory contains cmake files that can be used to generate MSVC project
-files in order to build protobuf on windows. You need to have cmake installed
-on your computer before proceeding.
+This directory contains *CMake* files that can be used to build protobuf
+with *MSVC* on *Windows*. You can build the project from *Command Prompt*
+and using an *Visual Studio* IDE.
 
-Compiling and Installing
-========================
+You need to have [CMake](http://www.cmake.org), [Visual Studio](https://www.visualstudio.com)
+and optionally [Git](http://git-scm.com) installed on your computer before proceeding.
 
-1. Check whether a gmock directory exists in the upper level directory. If you
-   checkout the code from github via "git clone", this gmock directory won't
-   exist and you won't be able to build protobuf unit-tests. Consider using one
-   of the release tar balls instead:
+Most of the instructions will be given to the *Сommand Prompt*, but the same
+actions can be performed using appropriate GUI tools.
 
-        https://github.com/google/protobuf/releases
+Environment Setup
+=================
 
-   These release tar balls are more stable versions of protobuf and already
-   have the gmock directory included.
+Open the appropriate *Command Prompt* from the *Start* menu.
 
-   You can also download gmock by yourself and put it in the right place.
+For example *VS2013 x64 Native Tools Command Prompt*:
 
-   If you absolutely don't want to build and run protobuf unit-tests, skip
-   this step and use protobuf at your own risk.
+    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64>
 
-2. Use cmake to generate MSVC project files. Running the following commands
-   in a command shell will generate project files for Visual Studio 2008 in
-   a sub-directory named "build".
+Change to your working directory:
 
-        $ cd path/to/protobuf/cmake
-        $ mkdir build
-        $ cd build
-        $ cmake -G "Visual Studio 9 2008" ..
+    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64>cd C:\Path\to
+    C:\Path\to>
 
-   If you don't have gmock, skip the build of tests by turning off the
-   BUILD_TESTING option:
+Where *C:\Path\to* is path to your real working directory.
 
-        $ cmake -G "Visual Studio 9 2008" -DBUILD_TESTING=OFF ..
+Create a folder where protobuf headers/libraries/binaries will be installed after built:
 
-3. Open the generated protobuf.sln file in Microsoft Visual Studio.
-4. Choose "Debug" or "Release" configuration as desired.
-5. From the Build menu, choose "Build Solution".  Wait for compiling to finish.
-6. If you have built tests, run tests.exe and lite-test.exe from a command
-   shell and check that all tests pass. Make sure you have changed the working
-   directory to the output directory because tests.exe will try to find and run
-   test_plugin.exe in the working directory.
-7. Run extract_includes.bat to copy all the public headers into a separate
-   "include" directory. This batch script can be found along with the generated
-   protobuf.sln file in the same directory.
-8. Copy the contents of the include directory to wherever you want to put
-   headers.
-9. Copy protoc.exe wherever you put build tools (probably somewhere in your
-   PATH).
-10. Copy libprotobuf.lib, libprotobuf-lite.lib, and libprotoc.lib wherever you
-    put libraries.
+    C:\Path\to>mkdir install
 
-  To avoid conflicts between the MSVC debug and release runtime libraries, when
-  compiling a debug build of your application, you may need to link against a
-  debug build of libprotobuf.lib.  Similarly, release builds should link against
-  release libs.
+If *cmake* command is not available from *Command Prompt*, add it to system *PATH* variable:
+
+    C:\Path\to>set PATH=%PATH%;C:\Program Files (x86)\CMake\bin
+
+If *git* command is not available from *Command Prompt*, add it to system *PATH* variable:
+
+    C:\Path\to>set PATH=%PATH%;C:\Program Files\Git\cmd
+
+Good. Now you are ready to continue.
+
+Getting Sources
+===============
+
+You can get the latest stable source packages from the
+[releases](https://github.com/google/protobuf/releases) page.
+Or you can type:
+
+     C:\Path\to> git clone -b [release_tag] https://github.com/google/protobuf.git
+
+Where *[release_tag]* is a git tag like *v3.0.0-beta-1* or a branch name like *master*
+if you want to get the latest code.
+
+Go to the project folder:
+
+     C:\Path\to>cd protobuf
+     C:\Path\to\protobuf>
+
+Protobuf unit-tests require gmock to build. If you download protobuf source code
+from the *releases* page, the *gmock* directory should already be there. If you checkout
+the code via `git clone`, this *gmock* directory won't exist and you will have to
+download it manually or skip building protobuf unit-tests.
+
+You can download gmock as follows:
+
+     C:\Path\to\protobuf>git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock
+
+Then go to *gmock* folder and download gtest:
+
+     C:\Path\to\protobuf>cd gmock
+     C:\Path\to\protobuf\gmock>git clone -b release-1.7.0 https://github.com/google/googletest.git gtest
+
+If you absolutely don't want to build and run protobuf unit-tests, skip
+this steps and use protobuf at your own risk.
+
+Now go to *cmake* folder in protobuf sources:
+
+     C:\Path\to\protobuf\gmock>cd ..\cmake
+     C:\Path\to\protobuf\cmake>
+
+Good. Now you are ready to *CMake* configuration.
+
+CMake Configuration
+===================
+
+*CMake* supports a lot of different
+[generators](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html)
+for various native build systems.
+We are only interested in
+[Makefile](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html#makefile-generators)
+and
+[Visual Studio](http://www.cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators)
+generators.
+
+We will use shadow building to separate the temporary files from the protobuf source code.
+
+Create a temporary *build* folder and change your working directory to it:
+
+     C:\Path\to\protobuf\cmake>mkdir build & cd build
+     C:\Path\to\protobuf\cmake\build>
+
+The *Makefile* generator can build the project in only one configuration, so you need to build
+a separate folder for each configuration.
+
+To start using a *Release* configuration:
+
+     C:\Path\to\protobuf\cmake\build>mkdir release & cd release
+     C:\Path\to\protobuf\cmake\build\release>cmake -G "NMake Makefiles" ^
+     -DCMAKE_BUILD_TYPE=Release ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *nmake* *Makefile* in current directory.
+
+To use *Debug* configuration:
+
+     C:\Path\to\protobuf\cmake\build>mkdir debug & cd debug
+     C:\Path\to\protobuf\cmake\build\debug>cmake -G "NMake Makefiles" ^
+     -DCMAKE_BUILD_TYPE=Debug ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *nmake* *Makefile* in current directory.
+
+To create *Visual Studio* solution file:
+
+     C:\Path\to\protobuf\cmake\build>mkdir solution & cd solution
+     C:\Path\to\protobuf\cmake\build\solution>cmake -G "Visual Studio 12 2013 Win64" ^
+     -DCMAKE_INSTALL_PREFIX=../../../../install ^
+     ../..
+
+It will generate *Visual Studio* solution file *protobuf.sln* in current directory.
+
+If the *gmock* directory does not exist, and you do not want to build protobuf unit tests,
+you need to add *cmake* command argument `-Dprotobuf_BUILD_TESTS=OFF` to disable testing.
+
+Compiling
+=========
+
+To compile protobuf:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake
+
+And wait for the compilation to finish.
+
+If you prefer to use the IDE:
+
+  * Open the generated protobuf.sln file in Microsoft Visual Studio.
+  * Choose "Debug" or "Release" configuration as desired.
+  * From the Build menu, choose "Build Solution".
+
+And wait for the compilation to finish.
+
+Testing
+=======
+
+To run unit-tests, first you must compile protobuf as described above.
+Then run:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake check
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake check
+
+You can also build project *check* from Visual Studio solution.
+Yes, it may sound strange, but it works.
+
+You should see output similar to:
+
+     Running main() from gmock_main.cc
+     [==========] Running 1546 tests from 165 test cases.
+     
+     ...
+     
+     [==========] 1546 tests from 165 test cases ran. (2529 ms total)
+     [  PASSED  ] 1546 tests.
+
+To run specific tests:
+
+     C:\Path\to\protobuf>cmake\build\release\tests.exe --gtest_filter=AnyTest*
+     Running main() from gmock_main.cc
+     Note: Google Test filter = AnyTest*
+     [==========] Running 3 tests from 1 test case.
+     [----------] Global test environment set-up.
+     [----------] 3 tests from AnyTest
+     [ RUN      ] AnyTest.TestPackAndUnpack
+     [       OK ] AnyTest.TestPackAndUnpack (0 ms)
+     [ RUN      ] AnyTest.TestPackAndUnpackAny
+     [       OK ] AnyTest.TestPackAndUnpackAny (0 ms)
+     [ RUN      ] AnyTest.TestIs
+     [       OK ] AnyTest.TestIs (0 ms)
+     [----------] 3 tests from AnyTest (1 ms total)
+     
+     [----------] Global test environment tear-down
+     [==========] 3 tests from 1 test case ran. (2 ms total)
+     [  PASSED  ] 3 tests.
+
+Note that the tests must be run from the source folder.
+
+If all tests are passed, safely continue.
+
+Installing
+==========
+
+To install protobuf to the specified *install* folder:
+
+     C:\Path\to\protobuf\cmake\build\release>nmake install
+
+or
+
+     C:\Path\to\protobuf\cmake\build\debug>nmake install
+
+You can also build project *INSTALL* from Visual Studio solution.
+It sounds not so strange and it works.
+
+This will create the following folders under the *install* location:
+  * bin - that contains protobuf *protoc.exe* compiler;
+  * include - that contains C++ headers and protobuf *.proto files;
+  * lib - that contains linking libraries and *CMake* configuration files for *protobuf* package.
+
+Now you can if needed:
+  * Copy the contents of the include directory to wherever you want to put headers.
+  * Copy protoc.exe wherever you put build tools (probably somewhere in your PATH).
+  * Copy linking libraries libprotobuf[d].lib, libprotobuf-lite[d].lib, and libprotoc[d].lib wherever you put libraries.
+
+To avoid conflicts between the MSVC debug and release runtime libraries, when
+compiling a debug build of your application, you may need to link against a
+debug build of libprotobufd.lib with "d" postfix.  Similarly, release builds should link against
+release libprotobuf.lib library.
 
 DLLs vs. static linking
 =======================
@@ -66,12 +242,9 @@
 build libprotobuf and libprotoc as DLLs if you really want.  To do this,
 do the following:
 
-  1. Add an additional flag "-DBUILD_SHARED_LIBS=ON" when invoking cmake:
-
-        $ cmake -G "Visual Studio 9 2008" -DBUILD_SHARED_LIBS=ON ..
-
-  2. Follow the same steps as described in the above section.
-  3. When compiling your project, make sure to #define PROTOBUF_USE_DLLS.
+  * Add an additional flag `-Dprotobuf_BUILD_SHARED_LIBS=ON` when invoking cmake
+  * Follow the same steps as described in the above section.
+  * When compiling your project, make sure to `#define PROTOBUF_USE_DLLS`.
 
 When distributing your software to end users, we strongly recommend that you
 do NOT install libprotobuf.dll or libprotoc.dll to any shared location.
@@ -90,21 +263,46 @@
 
 If you want to include GzipInputStream and GzipOutputStream
 (google/protobuf/io/gzip_stream.h) in libprotobuf, you will need to do a few
-additional steps:
+additional steps.
 
-1. Obtain a copy of the zlib library.  The pre-compiled DLL at zlib.net works.
-2. Make sure zlib's two headers are in your include path and that the .lib file
-   is in your library path.  You could place all three files directly into this
-   cmake directory to compile libprotobuf, but they need to be visible to
-   your own project as well, so you should probably just put them into the
-   VC shared icnlude and library directories.
-3. Add flag "-DZLIB=ON" when invoking cmake:
+Obtain a copy of the zlib library.  The pre-compiled DLL at zlib.net works.
+You need prepare it:
 
-        $ cmake -G "Visual Studio 9 2008" -DZLIB=ON ..
+  * Make sure zlib's two headers are in your `C:\Path\to\install\include` path
+  * Make sure zlib's linking libraries (*.lib file) is in your
+    `C:\Path\to\install\lib` library path.
 
-   If it reports NOTFOUND for zlib_include or zlib_lib, you might haven't put
-   the headers or the .lib file in the right directory.
-4) Open the generated protobuf.sln file and build as usual.
+You can also compile it from source by yourself.
+
+Getting sources:
+
+     C:\Path\to>git clone -b v1.2.8 https://github.com/madler/zlib.git
+     C:\Path\to>cd zlib
+
+Compiling and Installing:
+
+     C:\Path\to\zlib>mkdir build & cd build
+     C:\Path\to\zlib\build>mkdir release & cd release
+     C:\Path\to\zlib\build\release>cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ^
+     -DCMAKE_INSTALL_PREFIX=../../../install ../..
+     C:\Path\to\zlib\build\release>nmake & nmake install
+
+You can make *debug* version or use *Visual Studio* generator also as before for the
+protobuf project.
+
+Now add *bin* folder from *install* to system *PATH*:
+
+     C:\Path\to>set PATH=%PATH%;C:\Path\to\install\bin
+
+You need reconfigure protobuf with flag `-Dprotobuf_WITH_ZLIB=ON` when invoking cmake.
+
+Note that if you have compiled ZLIB yourself, as stated above,
+further disable the option `-Dprotobuf_MSVC_STATIC_RUNTIME=OFF`.
+
+If it reports NOTFOUND for zlib_include or zlib_lib, you might haven't put
+the headers or the .lib file in the right directory.
+
+Build and testing protobuf as usual.
 
 Notes on Compiler Warnings
 ==========================
@@ -136,4 +334,3 @@
 nevertheless.  So, we disable it.  Unfortunately, this warning will also be
 produced when compiling code which merely uses protocol buffers, meaning you
 may have to disable it in your code too.
-
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index eaf9758..b593e0c 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -6,6 +6,7 @@
 mkdir include\google\protobuf\compiler\csharp
 mkdir include\google\protobuf\compiler\java
 mkdir include\google\protobuf\compiler\javanano
+mkdir include\google\protobuf\compiler\js
 mkdir include\google\protobuf\compiler\objectivec
 mkdir include\google\protobuf\compiler\python
 mkdir include\google\protobuf\compiler\ruby
@@ -26,6 +27,7 @@
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_names.h include\google\protobuf\compiler\java\java_names.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\javanano\javanano_generator.h include\google\protobuf\compiler\javanano\javanano_generator.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\js\js_generator.h include\google\protobuf\compiler\js\js_generator.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_generator.h include\google\protobuf\compiler\objectivec\objectivec_generator.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\objectivec\objectivec_helpers.h include\google\protobuf\compiler\objectivec\objectivec_helpers.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h include\google\protobuf\compiler\parser.h
@@ -72,7 +74,6 @@
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h include\google\protobuf\struct.pb.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomic_sequence_num.h include\google\protobuf\stubs\atomic_sequence_num.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops.h include\google\protobuf\stubs\atomicops.h
-copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_aix.h include\google\protobuf\stubs\atomicops_internals_aix.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm64_gcc.h include\google\protobuf\stubs\atomicops_internals_arm64_gcc.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
@@ -81,6 +82,7 @@
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_macosx.h include\google\protobuf\stubs\atomicops_internals_macosx.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_pnacl.h include\google\protobuf\stubs\atomicops_internals_pnacl.h
+copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_power.h include\google\protobuf\stubs\atomicops_internals_power.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_solaris.h include\google\protobuf\stubs\atomicops_internals_solaris.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_tsan.h include\google\protobuf\stubs\atomicops_internals_tsan.h
 copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.h include\google\protobuf\stubs\atomicops_internals_x86_gcc.h
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
index 9fafc31..036b051 100644
--- a/cmake/libprotobuf-lite.cmake
+++ b/cmake/libprotobuf-lite.cmake
@@ -24,9 +24,15 @@
   ${protobuf_source_dir}/src/google/protobuf/wire_format_lite.cc
 )
 
-add_library(libprotobuf-lite ${libprotobuf_lite_files})
+add_library(libprotobuf-lite ${protobuf_SHARED_OR_STATIC}
+  ${libprotobuf_lite_files})
 target_link_libraries(libprotobuf-lite ${CMAKE_THREAD_LIBS_INIT})
 target_include_directories(libprotobuf-lite PUBLIC ${protobuf_source_dir}/src)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotobuf-lite
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOBUF_EXPORTS)
+endif()
 set_target_properties(libprotobuf-lite PROPERTIES
-    COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS
-    OUTPUT_NAME ${LIB_PREFIX}protobuf-lite)
+    OUTPUT_NAME ${LIB_PREFIX}protobuf-lite
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake
index 64a9cae..8930c1c 100644
--- a/cmake/libprotobuf.cmake
+++ b/cmake/libprotobuf.cmake
@@ -40,6 +40,7 @@
   ${protobuf_source_dir}/src/google/protobuf/util/internal/json_objectwriter.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/json_stream_parser.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/object_writer.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/internal/proto_writer.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectsource.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectwriter.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info.cc
@@ -53,9 +54,15 @@
   ${protobuf_source_dir}/src/google/protobuf/wrappers.pb.cc
 )
 
-add_library(libprotobuf ${libprotobuf_lite_files} ${libprotobuf_files})
+add_library(libprotobuf ${protobuf_SHARED_OR_STATIC}
+  ${libprotobuf_lite_files} ${libprotobuf_files})
 target_link_libraries(libprotobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES})
 target_include_directories(libprotobuf PUBLIC ${protobuf_source_dir}/src)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotobuf
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOBUF_EXPORTS)
+endif()
 set_target_properties(libprotobuf PROPERTIES
-    COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS
-    OUTPUT_NAME ${LIB_PREFIX}protobuf)
+    OUTPUT_NAME ${LIB_PREFIX}protobuf
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index 7aa92ee..8df8986 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -14,6 +14,7 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_service.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -23,11 +24,11 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
-  ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_context.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment.cc
@@ -36,6 +37,7 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_extension_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_file.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator.cc
@@ -69,6 +71,7 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_message.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_message_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/js/js_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
@@ -89,8 +92,15 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
 )
 
-add_library(libprotoc ${libprotoc_files})
+add_library(libprotoc ${protobuf_SHARED_OR_STATIC}
+  ${libprotoc_files})
 target_link_libraries(libprotoc libprotobuf)
+if(MSVC AND protobuf_BUILD_SHARED_LIBS)
+  target_compile_definitions(libprotoc
+    PUBLIC  PROTOBUF_USE_DLLS
+    PRIVATE LIBPROTOC_EXPORTS)
+endif()
 set_target_properties(libprotoc PROPERTIES
     COMPILE_DEFINITIONS LIBPROTOC_EXPORTS
-    OUTPUT_NAME ${LIB_PREFIX}protoc)
+    OUTPUT_NAME ${LIB_PREFIX}protoc
+    DEBUG_POSTFIX "${protobuf_DEBUG_POSTFIX}")
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 65feca2..941f33d 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -2,6 +2,9 @@
   message(FATAL_ERROR "Cannot find gmock directory.")
 endif()
 
+option(protobuf_ABSOLUTE_TEST_PLUGIN_PATH
+  "Using absolute test_plugin path in tests" ON)
+
 include_directories(
   ${protobuf_source_dir}/gmock
   ${protobuf_source_dir}/gmock/gtest
@@ -60,6 +63,7 @@
   google/protobuf/util/internal/testdata/struct.proto
   google/protobuf/util/internal/testdata/timestamp_duration.proto
   google/protobuf/util/json_format_proto3.proto
+  google/protobuf/util/message_differencer_unittest.proto
 )
 
 macro(compile_proto_file filename)
@@ -164,12 +168,17 @@
   ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
   ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info_test_helper.cc
   ${protobuf_source_dir}/src/google/protobuf/util/json_util_test.cc
+  ${protobuf_source_dir}/src/google/protobuf/util/message_differencer_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/util/time_util_test.cc
   ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util_test.cc
   ${protobuf_source_dir}/src/google/protobuf/well_known_types_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.cc
 )
 
+if(protobuf_ABSOLUTE_TEST_PLUGIN_PATH)
+  add_compile_options(-DGOOGLE_PROTOBUF_TEST_PLUGIN_PATH="$<TARGET_FILE:test_plugin>")
+endif()
+
 add_executable(tests ${tests_files} ${common_test_files} ${tests_proto_files} ${lite_test_proto_files})
 target_link_libraries(tests libprotoc libprotobuf gmock_main)
 
@@ -194,3 +203,7 @@
 )
 add_executable(lite-arena-test ${lite_arena_test_files} ${common_lite_test_files} ${lite_test_proto_files})
 target_link_libraries(lite-arena-test libprotobuf-lite gmock_main)
+
+add_custom_target(check
+  COMMAND tests
+  WORKING_DIRECTORY ${protobuf_source_dir})
diff --git a/configure.ac b/configure.ac
index 0e58789..33a6c64 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,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-1],[protobuf@googlegroups.com],[protobuf])
+AC_INIT([Protocol Buffers],[3.0.0-beta-2],[protobuf@googlegroups.com],[protobuf])
 
 AM_MAINTAINER_MODE([enable])
 
@@ -26,7 +26,7 @@
 AC_ARG_VAR(DIST_LANG, [language to include in the distribution package (i.e., make dist)])
 case "$DIST_LANG" in
   "") DIST_LANG=all ;;
-  all | cpp | csharp | java | python | javanano | objectivec | ruby) ;;
+  all | cpp | csharp | java | python | javanano | objectivec | ruby | js) ;;
   *) AC_MSG_FAILURE([unknown language: $DIST_LANG]) ;;
 esac
 AC_SUBST(DIST_LANG)
@@ -59,6 +59,7 @@
 ACX_USE_SYSTEM_EXTENSIONS
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc
+AC_PROG_OBJC
 
 # test_util.cc takes forever to compile with GCC and optimization turned on.
 AC_MSG_CHECKING([C++ compiler flags...])
@@ -163,6 +164,15 @@
     ;;
 esac
 
+# Enable ObjC support for conformance directory on OS X.
+OBJC_CONFORMANCE_TEST=0
+case "$target_os" in
+  darwin*)
+    OBJC_CONFORMANCE_TEST=1
+    ;;
+esac
+AM_CONDITIONAL([OBJC_CONFORMANCE_TEST], [test $OBJC_CONFORMANCE_TEST = 1])
+
 # HACK:  Make gmock's configure script pick up our copy of CFLAGS and CXXFLAGS,
 #   since the flags added by ACX_CHECK_SUNCC must be used when compiling gmock
 #   too.
diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java
index 25646b8..a983ba3 100644
--- a/conformance/ConformanceJava.java
+++ b/conformance/ConformanceJava.java
@@ -1,9 +1,12 @@
 
 import com.google.protobuf.conformance.Conformance;
+import com.google.protobuf.util.JsonFormat;
+import com.google.protobuf.util.JsonFormat.TypeRegistry;
 import com.google.protobuf.InvalidProtocolBufferException;
 
 class ConformanceJava {
   private int testCount = 0;
+  private TypeRegistry typeRegistry;
 
   private boolean readFromStdin(byte[] buf, int len) throws Exception {
     int ofs = 0;
@@ -29,7 +32,10 @@
     if (!readFromStdin(buf, 4)) {
       return -1;
     }
-    return buf[0] | (buf[1] << 1) | (buf[2] << 2) | (buf[3] << 3);
+    return (buf[0] & 0xff)
+        | ((buf[1] & 0xff) << 8)
+        | ((buf[2] & 0xff) << 16)
+        | ((buf[3] & 0xff) << 24);
   }
 
   private void writeLittleEndianIntToStdout(int val) throws Exception {
@@ -54,7 +60,15 @@
         break;
       }
       case JSON_PAYLOAD: {
-        return Conformance.ConformanceResponse.newBuilder().setSkipped("JSON not yet supported.").build();
+        try {
+          Conformance.TestAllTypes.Builder builder = Conformance.TestAllTypes.newBuilder();
+          JsonFormat.parser().usingTypeRegistry(typeRegistry)
+              .merge(request.getJsonPayload(), builder);
+          testMessage = builder.build();
+        } catch (InvalidProtocolBufferException e) {
+          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        }
+        break;
       }
       case PAYLOAD_NOT_SET: {
         throw new RuntimeException("Request didn't have payload.");
@@ -73,7 +87,13 @@
         return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build();
 
       case JSON:
-        return Conformance.ConformanceResponse.newBuilder().setSkipped("JSON not yet supported.").build();
+        try {
+          return Conformance.ConformanceResponse.newBuilder().setJsonPayload(
+              JsonFormat.printer().usingTypeRegistry(typeRegistry).print(testMessage)).build();
+        } catch (InvalidProtocolBufferException | IllegalArgumentException e) {
+          return Conformance.ConformanceResponse.newBuilder().setSerializeError(
+              e.getMessage()).build();
+        }
 
       default: {
         throw new RuntimeException("Unexpected request output.");
@@ -106,6 +126,8 @@
   }
 
   public void run() throws Exception {
+    typeRegistry = TypeRegistry.newBuilder().add(
+        Conformance.TestAllTypes.getDescriptor()).build();
     while (doTestIo()) {
       // Empty.
     }
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index c74eb1c..2a43113 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -1,28 +1,93 @@
 ## Process this file with automake to produce Makefile.in
 
-protoc_inputs =                                                \
+conformance_protoc_inputs =                                    \
   conformance.proto
 
+well_known_type_protoc_inputs =                                \
+  $(top_srcdir)/src/google/protobuf/any.proto                  \
+  $(top_srcdir)/src/google/protobuf/duration.proto             \
+  $(top_srcdir)/src/google/protobuf/field_mask.proto           \
+  $(top_srcdir)/src/google/protobuf/struct.proto               \
+  $(top_srcdir)/src/google/protobuf/timestamp.proto            \
+  $(top_srcdir)/src/google/protobuf/wrappers.proto
+
+
 protoc_outputs =                                               \
   conformance.pb.cc                                            \
   conformance.pb.h
 
+other_language_protoc_outputs =                                \
+  conformance.rb                                               \
+  com/google/protobuf/conformance/Conformance.java             \
+  conformance_pb2.py                                           \
+  Conformance.pbobjc.h                                         \
+  Conformance.pbobjc.m
+
 bin_PROGRAMS = conformance-test-runner conformance-cpp
 
+# All source files excepet C++/Objective-C ones should be explicitly listed
+# here because the autoconf tools don't include files of other languages
+# automatically.
+EXTRA_DIST =                  \
+  ConformanceJava.java        \
+  README.md                   \
+  conformance.proto           \
+  conformance_python.py       \
+  conformance_ruby.rb         \
+  failure_list_cpp.txt        \
+  failure_list_csharp.txt     \
+  failure_list_java.txt       \
+  failure_list_objc.txt       \
+  failure_list_python.txt     \
+  failure_list_python_cpp.txt \
+  failure_list_python-post26.txt \
+  failure_list_ruby.txt
+
 conformance_test_runner_LDADD = $(top_srcdir)/src/libprotobuf.la
-conformance_test_runner_SOURCES = conformance_test.cc conformance_test_runner.cc
+conformance_test_runner_SOURCES = conformance_test.h conformance_test.cc \
+                                  conformance_test_runner.cc             \
+                                  third_party/jsoncpp/json.h             \
+                                  third_party/jsoncpp/jsoncpp.cpp
 nodist_conformance_test_runner_SOURCES = conformance.pb.cc
-conformance_test_runner_CPPFLAGS = -I$(top_srcdir)/src
+conformance_test_runner_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir)
+conformance_test_runner_CXXFLAGS = -std=c++11
+# Explicit deps beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_cpp" could fail if parallel enough.
+conformance_test_runner-conformance_test.$(OBJEXT): conformance.pb.h
+conformance_test_runner-conformance_test_runner.$(OBJEXT): conformance.pb.h
 
 conformance_cpp_LDADD = $(top_srcdir)/src/libprotobuf.la
 conformance_cpp_SOURCES = conformance_cpp.cc
 nodist_conformance_cpp_SOURCES = conformance.pb.cc
 conformance_cpp_CPPFLAGS = -I$(top_srcdir)/src
+# Explicit dep beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_cpp" could fail if parallel enough.
+conformance_cpp-conformance_cpp.$(OBJEXT): conformance.pb.h
+
+if OBJC_CONFORMANCE_TEST
+
+bin_PROGRAMS += conformance-objc
+
+conformance_objc_SOURCES = conformance_objc.m ../objectivec/GPBProtocolBuffers.m
+nodist_conformance_objc_SOURCES = Conformance.pbobjc.m
+# On travis, the build fails without the isysroot because whatever system
+# headers are being found don't include generics support for
+# NSArray/NSDictionary, the only guess is their image at one time had an odd
+# setup for Xcode and old frameworks are being found.
+conformance_objc_CPPFLAGS = -I$(top_srcdir)/objectivec -isysroot `xcrun --sdk macosx --show-sdk-path`
+conformance_objc_LDFLAGS = -framework Foundation
+# Explicit dep beacuse BUILT_SOURCES are only done before a "make all/check"
+# so a direct "make test_objc" could fail if parallel enough.
+conformance_objc-conformance_objc.$(OBJEXT): Conformance.pbobjc.h
+
+endif
 
 if USE_EXTERNAL_PROTOC
 
-protoc_middleman: $(protoc_inputs)
-	$(PROTOC) -I$(srcdir) --cpp_out=. --java_out=. --ruby_out=. $^
+# Some implementations include pre-generated versions of well-known types.
+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)
 	touch protoc_middleman
 
 else
@@ -30,35 +95,38 @@
 # We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
 # relative to srcdir, which may not be the same as the current directory when
 # building out-of-tree.
-protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(protoc_inputs)
-	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd $(protoc_inputs) )
+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) )
 	touch protoc_middleman
 
 endif
 
 $(protoc_outputs): protoc_middleman
 
-BUILT_SOURCES = $(protoc_outputs)
+$(other_language_protoc_outputs): protoc_middleman
 
-CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java conformance-csharp
+BUILT_SOURCES = $(protoc_outputs) $(other_language_protoc_outputs)
+
+CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java conformance-csharp $(other_language_protoc_outputs)
 
 MAINTAINERCLEANFILES =   \
   Makefile.in
 
-javac_middleman: ConformanceJava.java protoc_middleman
-	javac -classpath ../java/target/classes ConformanceJava.java com/google/protobuf/conformance/Conformance.java
+javac_middleman: ConformanceJava.java protoc_middleman $(other_language_protoc_outputs)
+	jar=`ls ../java/util/target/*jar-with-dependencies.jar` && javac -classpath ../java/target/classes:$$jar ConformanceJava.java com/google/protobuf/conformance/Conformance.java
 	@touch javac_middleman
 
 conformance-java: javac_middleman
 	@echo "Writing shortcut script conformance-java..."
 	@echo '#! /bin/sh' > conformance-java
-	@echo 'java -classpath .:../java/target/classes ConformanceJava "$$@"' >> conformance-java
+	@jar=`ls ../java/util/target/*jar-with-dependencies.jar` && echo java -classpath .:../java/target/classes:$$jar ConformanceJava '$$@' >> conformance-java
 	@chmod +x conformance-java
 
 # Currently the conformance code is alongside the rest of the C#
 # source, as it's easier to maintain there. We assume we've already
 # built that, so we just need a script to run it.
-conformance-csharp:
+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
@@ -69,10 +137,25 @@
 	./conformance-test-runner --failure_list failure_list_cpp.txt ./conformance-cpp
 
 test_java: protoc_middleman conformance-test-runner conformance-java
-	./conformance-test-runner ./conformance-java
+	./conformance-test-runner --failure_list failure_list_java.txt ./conformance-java
 
 test_csharp: protoc_middleman conformance-test-runner conformance-csharp
 	./conformance-test-runner --failure_list failure_list_csharp.txt ./conformance-csharp
 
-test_ruby: protoc_middleman conformance-test-runner
+test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
 	RUBYLIB=../ruby/lib:. ./conformance-test-runner --failure_list failure_list_ruby.txt ./conformance_ruby.rb
+
+# These depend on library paths being properly set up.  The easiest way to
+# run them is to just use "tox" from the python dir.
+test_python: protoc_middleman conformance-test-runner
+	./conformance-test-runner --failure_list failure_list_python.txt $(CONFORMANCE_PYTHON_EXTRA_FAILURES) ./conformance_python.py
+
+test_python_cpp: protoc_middleman conformance-test-runner
+	./conformance-test-runner --failure_list failure_list_python_cpp.txt $(CONFORMANCE_PYTHON_EXTRA_FAILURES) ./conformance_python.py
+
+if OBJC_CONFORMANCE_TEST
+
+test_objc: protoc_middleman conformance-test-runner conformance-objc
+	./conformance-test-runner --failure_list failure_list_objc.txt ./conformance-objc
+
+endif
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
index 714cbe7..fc96074 100644
--- a/conformance/conformance.proto
+++ b/conformance/conformance.proto
@@ -32,6 +32,13 @@
 package conformance;
 option java_package = "com.google.protobuf.conformance";
 
+import "google/protobuf/any.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+
 // This defines the conformance testing protocol.  This protocol exists between
 // the conformance test suite itself and the code being tested.  For each test,
 // the suite will send a ConformanceRequest message and expect a
@@ -84,6 +91,11 @@
     // test.  Some of the test cases are intentionally invalid input.
     string parse_error = 1;
 
+    // If the input was successfully parsed but errors occurred when
+    // serializing it to the requested output format, set the error message in
+    // this field.
+    string serialize_error = 6;
+
     // This should be set if some other error occurred.  This will always
     // indicate that the test failed.  The string can provide more information
     // about the failure.
@@ -199,6 +211,55 @@
     string oneof_string = 113;
     bytes oneof_bytes = 114;
   }
+
+  // Well-known types
+  google.protobuf.BoolValue optional_bool_wrapper = 201;
+  google.protobuf.Int32Value optional_int32_wrapper = 202;
+  google.protobuf.Int64Value optional_int64_wrapper = 203;
+  google.protobuf.UInt32Value optional_uint32_wrapper = 204;
+  google.protobuf.UInt64Value optional_uint64_wrapper = 205;
+  google.protobuf.FloatValue optional_float_wrapper = 206;
+  google.protobuf.DoubleValue optional_double_wrapper = 207;
+  google.protobuf.StringValue optional_string_wrapper = 208;
+  google.protobuf.BytesValue optional_bytes_wrapper = 209;
+
+  repeated google.protobuf.BoolValue repeated_bool_wrapper = 211;
+  repeated google.protobuf.Int32Value repeated_int32_wrapper = 212;
+  repeated google.protobuf.Int64Value repeated_int64_wrapper = 213;
+  repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214;
+  repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215;
+  repeated google.protobuf.FloatValue repeated_float_wrapper = 216;
+  repeated google.protobuf.DoubleValue repeated_double_wrapper = 217;
+  repeated google.protobuf.StringValue repeated_string_wrapper = 218;
+  repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219;
+
+  google.protobuf.Duration optional_duration = 301;
+  google.protobuf.Timestamp optional_timestamp = 302;
+  google.protobuf.FieldMask optional_field_mask = 303;
+  google.protobuf.Struct optional_struct = 304;
+  google.protobuf.Any optional_any = 305;
+  google.protobuf.Value optional_value = 306;
+
+  repeated google.protobuf.Duration repeated_duration = 311;
+  repeated google.protobuf.Timestamp repeated_timestamp = 312;
+  repeated google.protobuf.FieldMask repeated_fieldmask = 313;
+  repeated google.protobuf.Struct repeated_struct = 324;
+  repeated google.protobuf.Any repeated_any = 315;
+  repeated google.protobuf.Value repeated_value = 316;
+
+  // Test field-name-to-JSON-name convention.
+  int32 fieldname1 = 401;
+  int32 field_name2 = 402;
+  int32 _field_name3 = 403;
+  int32 field__name4_ = 404;
+  int32 field0name5 = 405;
+  int32 field_0_name6 = 406;
+  int32 fieldName7 = 407;
+  int32 FieldName8 = 408;
+  int32 field_Name9 = 409;
+  int32 Field_Name10 = 410;
+  int32 FIELD_NAME11 = 411;
+  int32 FIELD_name12 = 412;
 }
 
 message ForeignMessage {
diff --git a/conformance/conformance_cpp.cc b/conformance/conformance_cpp.cc
index 863b6a5..1a26549 100644
--- a/conformance/conformance_cpp.cc
+++ b/conformance/conformance_cpp.cc
@@ -108,7 +108,11 @@
         return;
       }
 
-      GOOGLE_CHECK(test_message.ParseFromString(proto_binary));
+      if (!test_message.ParseFromString(proto_binary)) {
+        response->set_runtime_error(
+            "Parsing JSON generates invalid proto output.");
+        return;
+      }
       break;
     }
 
@@ -132,9 +136,18 @@
       GOOGLE_CHECK(test_message.SerializeToString(&proto_binary));
       Status status = BinaryToJsonString(type_resolver, *type_url, proto_binary,
                                          response->mutable_json_payload());
-      GOOGLE_CHECK(status.ok());
+      if (!status.ok()) {
+        response->set_serialize_error(
+            string("Failed to serialize JSON output: ") +
+            status.error_message().as_string());
+        return;
+      }
       break;
     }
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unknown output format: "
+                        << request.requested_output_format();
   }
 }
 
diff --git a/conformance/conformance_objc.m b/conformance/conformance_objc.m
new file mode 100644
index 0000000..1124bfe
--- /dev/null
+++ b/conformance/conformance_objc.m
@@ -0,0 +1,179 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "Conformance.pbobjc.h"
+
+static void Die(NSString *format, ...) __dead2;
+
+static BOOL verbose = NO;
+static int32_t testCount = 0;
+
+static void Die(NSString *format, ...) {
+  va_list args;
+  va_start(args, format);
+  NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
+  NSLog(@"%@", msg);
+  va_end(args);
+  [msg release];
+  exit(66);
+}
+
+static NSData *CheckedReadDataOfLength(NSFileHandle *handle, NSUInteger numBytes) {
+  NSData *data = [handle readDataOfLength:numBytes];
+  NSUInteger dataLen = data.length;
+  if (dataLen == 0) {
+    return nil;  // EOF.
+  }
+  if (dataLen != numBytes) {
+    Die(@"Failed to read the request length (%d), only got: %@",
+        numBytes, data);
+  }
+  return data;
+}
+
+static ConformanceResponse *DoTest(ConformanceRequest *request) {
+  ConformanceResponse *response = [ConformanceResponse message];
+  TestAllTypes *testMessage = nil;
+
+  switch (request.payloadOneOfCase) {
+    case ConformanceRequest_Payload_OneOfCase_GPBUnsetOneOfCase:
+      Die(@"Request didn't have a payload: %@", request);
+      break;
+
+    case ConformanceRequest_Payload_OneOfCase_ProtobufPayload: {
+      NSError *error = nil;
+      testMessage = [TestAllTypes parseFromData:request.protobufPayload
+                                          error:&error];
+      if (!testMessage) {
+        response.parseError =
+            [NSString stringWithFormat:@"Parse error: %@", error];
+      }
+      break;
+    }
+
+    case ConformanceRequest_Payload_OneOfCase_JsonPayload:
+      response.skipped = @"ObjC doesn't support parsing JSON";
+      break;
+  }
+
+  if (testMessage) {
+    switch (request.requestedOutputFormat) {
+      case WireFormat_GPBUnrecognizedEnumeratorValue:
+      case WireFormat_Unspecified:
+        Die(@"Unrecognized/unspecified output format: %@", request);
+        break;
+
+      case WireFormat_Protobuf:
+        response.protobufPayload = testMessage.data;
+        if (!response.protobufPayload) {
+          response.serializeError =
+            [NSString stringWithFormat:@"Failed to make data from: %@", testMessage];
+        }
+        break;
+
+      case WireFormat_Json:
+        response.skipped = @"ObjC doesn't support generating JSON";
+        break;
+    }
+  }
+
+  return response;
+}
+
+static uint32_t UInt32FromLittleEndianData(NSData *data) {
+  if (data.length != sizeof(uint32_t)) {
+    Die(@"Data not the right size for uint32_t: %@", data);
+  }
+  uint32_t value;
+  memcpy(&value, data.bytes, sizeof(uint32_t));
+  return CFSwapInt32LittleToHost(value);
+}
+
+static NSData *UInt32ToLittleEndianData(uint32_t num) {
+  uint32_t value = CFSwapInt32HostToLittle(num);
+  return [NSData dataWithBytes:&value length:sizeof(uint32_t)];
+}
+
+static BOOL DoTestIo(NSFileHandle *input, NSFileHandle *output) {
+  // See conformance_test_runner.cc for the wire format.
+  NSData *data = CheckedReadDataOfLength(input, sizeof(uint32_t));
+  if (!data) {
+    // EOF.
+    return NO;
+  }
+  uint32_t numBytes = UInt32FromLittleEndianData(data);
+  data = CheckedReadDataOfLength(input, numBytes);
+  if (!data) {
+    Die(@"Failed to read request");
+  }
+
+  NSError *error = nil;
+  ConformanceRequest *request = [ConformanceRequest parseFromData:data
+                                                            error:&error];
+  if (!request) {
+    Die(@"Failed to parse the message data: %@", error);
+  }
+
+  ConformanceResponse *response = DoTest(request);
+  if (!response) {
+    Die(@"Failed to make a reply from %@", request);
+  }
+
+  data = response.data;
+  [output writeData:UInt32ToLittleEndianData((int32_t)data.length)];
+  [output writeData:data];
+
+  if (verbose) {
+    NSLog(@"Request: %@", request);
+    NSLog(@"Response: %@", response);
+  }
+
+  ++testCount;
+  return YES;
+}
+
+int main(int argc, const char *argv[]) {
+  @autoreleasepool {
+    NSFileHandle *input = [[NSFileHandle fileHandleWithStandardInput] retain];
+    NSFileHandle *output = [[NSFileHandle fileHandleWithStandardOutput] retain];
+
+    BOOL notDone = YES;
+    while (notDone) {
+      @autoreleasepool {
+        notDone = DoTestIo(input, output);
+      }
+    }
+
+    NSLog(@"Received EOF from test runner after %d tests, exiting.", testCount);
+  }
+  return 0;
+}
diff --git a/conformance/conformance_python.py b/conformance/conformance_python.py
new file mode 100755
index 0000000..a490c8e
--- /dev/null
+++ b/conformance/conformance_python.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""A conformance test implementation for the Python protobuf library.
+
+See conformance.proto for more information.
+"""
+
+import struct
+import sys
+import os
+from google.protobuf import message
+from google.protobuf import json_format
+import conformance_pb2
+
+sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)
+sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
+
+test_count = 0
+verbose = False
+
+class ProtocolError(Exception):
+  pass
+
+def do_test(request):
+  test_message = conformance_pb2.TestAllTypes()
+  response = conformance_pb2.ConformanceResponse()
+  test_message = conformance_pb2.TestAllTypes()
+
+  try:
+    if request.WhichOneof('payload') == 'protobuf_payload':
+      try:
+        test_message.ParseFromString(request.protobuf_payload)
+      except message.DecodeError as e:
+        response.parse_error = str(e)
+        return response
+
+    elif request.WhichOneof('payload') == 'json_payload':
+      try:
+        json_format.Parse(request.json_payload, test_message)
+      except json_format.ParseError as e:
+        response.parse_error = str(e)
+        return response
+
+    else:
+      raise ProtocolError("Request didn't have payload.")
+
+    if request.requested_output_format == conformance_pb2.UNSPECIFIED:
+      raise ProtocolError("Unspecified output format")
+
+    elif request.requested_output_format == conformance_pb2.PROTOBUF:
+      response.protobuf_payload = test_message.SerializeToString()
+
+    elif request.requested_output_format == conformance_pb2.JSON:
+      response.json_payload = json_format.MessageToJson(test_message)
+
+  except Exception as e:
+    response.runtime_error = str(e)
+
+  return response
+
+def do_test_io():
+  length_bytes = sys.stdin.read(4)
+  if len(length_bytes) == 0:
+    return False   # EOF
+  elif len(length_bytes) != 4:
+    raise IOError("I/O error")
+
+  # "I" is "unsigned int", so this depends on running on a platform with
+  # 32-bit "unsigned int" type.  The Python struct module unfortunately
+  # has no format specifier for uint32_t.
+  length = struct.unpack("<I", length_bytes)[0]
+  serialized_request = sys.stdin.read(length)
+  if len(serialized_request) != length:
+    raise IOError("I/O error")
+
+  request = conformance_pb2.ConformanceRequest()
+  request.ParseFromString(serialized_request)
+
+  response = do_test(request)
+
+  serialized_response = response.SerializeToString()
+  sys.stdout.write(struct.pack("<I", len(serialized_response)))
+  sys.stdout.write(serialized_response)
+  sys.stdout.flush()
+
+  if verbose:
+    sys.stderr.write("conformance_python: request=%s, response=%s\n" % (
+                       request.ShortDebugString().c_str(),
+                       response.ShortDebugString().c_str()))
+
+  global test_count
+  test_count += 1
+
+  return True
+
+while True:
+  if not do_test_io():
+    sys.stderr.write("conformance_python: received EOF from test runner " +
+                     "after %s tests, exiting\n" % (test_count))
+    sys.exit(0)
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 0ee201f..fc0605b 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -37,10 +37,13 @@
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/util/json_util.h>
+#include <google/protobuf/util/field_comparator.h>
 #include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/util/type_resolver_util.h>
 #include <google/protobuf/wire_format_lite.h>
 
+#include "third_party/jsoncpp/json.h"
+
 using conformance::ConformanceRequest;
 using conformance::ConformanceResponse;
 using conformance::TestAllTypes;
@@ -49,6 +52,7 @@
 using google::protobuf::FieldDescriptor;
 using google::protobuf::internal::WireFormatLite;
 using google::protobuf::TextFormat;
+using google::protobuf::util::DefaultFieldComparator;
 using google::protobuf::util::JsonToBinaryString;
 using google::protobuf::util::MessageDifferencer;
 using google::protobuf::util::NewTypeResolverForDescriptorPool;
@@ -220,7 +224,7 @@
   string serialized_response;
   request.SerializeToString(&serialized_request);
 
-  runner_->RunTest(serialized_request, &serialized_response);
+  runner_->RunTest(test_name, serialized_request, &serialized_response);
 
   if (!response->ParseFromString(serialized_response)) {
     response->Clear();
@@ -240,7 +244,9 @@
     const string& equivalent_text_format, WireFormat requested_output) {
   TestAllTypes reference_message;
   GOOGLE_CHECK(
-      TextFormat::ParseFromString(equivalent_text_format, &reference_message));
+      TextFormat::ParseFromString(equivalent_text_format, &reference_message))
+          << "Failed to parse data for test case: " << test_name
+          << ", data: " << equivalent_text_format;
 
   ConformanceRequest request;
   ConformanceResponse response;
@@ -254,9 +260,8 @@
       request.set_json_payload(input);
       break;
 
-    case conformance::UNSPECIFIED:
+    default:
       GOOGLE_LOG(FATAL) << "Unspecified input format";
-
   }
 
   request.set_requested_output_format(requested_output);
@@ -268,8 +273,9 @@
   switch (response.result_case()) {
     case ConformanceResponse::kParseError:
     case ConformanceResponse::kRuntimeError:
+    case ConformanceResponse::kSerializeError:
       ReportFailure(test_name, request, response,
-                    "Failed to parse valid JSON input.");
+                    "Failed to parse JSON input or produce JSON output.");
       return;
 
     case ConformanceResponse::kSkipped:
@@ -293,7 +299,13 @@
         return;
       }
 
-      GOOGLE_CHECK(test_message.ParseFromString(binary_protobuf));
+      if (!test_message.ParseFromString(binary_protobuf)) {
+        ReportFailure(test_name, request, response,
+                      "INTERNAL ERROR: internal JSON->protobuf transcode "
+                      "yielded unparseable proto.");
+        return;
+      }
+
       break;
     }
 
@@ -313,13 +325,20 @@
 
       break;
     }
+
+    default:
+      GOOGLE_LOG(FATAL) << test_name << ": unknown payload type: "
+                        << response.result_case();
   }
 
   MessageDifferencer differencer;
+  DefaultFieldComparator field_comparator;
+  field_comparator.set_treat_nan_as_equal(true);
+  differencer.set_field_comparator(&field_comparator);
   string differences;
   differencer.ReportDifferencesToString(&differences);
 
-  if (differencer.Equals(reference_message, test_message)) {
+  if (differencer.Compare(reference_message, test_message)) {
     ReportSuccess(test_name);
   } else {
     ReportFailure(test_name, request, response,
@@ -343,6 +362,8 @@
   RunTest(effective_test_name, request, &response);
   if (response.result_case() == ConformanceResponse::kParseError) {
     ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
   } else {
     ReportFailure(effective_test_name, request, response,
                   "Should have failed to parse, but didn't.");
@@ -362,13 +383,112 @@
 void ConformanceTestSuite::RunValidJsonTest(
     const string& test_name, const string& input_json,
     const string& equivalent_text_format) {
-  RunValidInputTest("JsonInput." + test_name + ".JsonOutput", input_json,
+  RunValidInputTest("JsonInput." + test_name + ".ProtobufOutput", input_json,
                     conformance::JSON, equivalent_text_format,
                     conformance::PROTOBUF);
-  RunValidInputTest("JsonInput." + test_name + ".ProtobufOutput", input_json, conformance::JSON,
+  RunValidInputTest("JsonInput." + test_name + ".JsonOutput", input_json,
+                    conformance::JSON, equivalent_text_format,
+                    conformance::JSON);
+}
+
+void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
+    const string& test_name, const TestAllTypes& input,
+    const string& equivalent_text_format) {
+  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
+// method allows strict checking on a proto3 JSON serializer by inspecting
+// the JSON output directly.
+void ConformanceTestSuite::RunValidJsonTestWithValidator(
+    const string& test_name, const string& input_json,
+    const Validator& validator) {
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_json_payload(input_json);
+  request.set_requested_output_format(conformance::JSON);
+
+  string effective_test_name = "JsonInput." + test_name + ".Validator";
+
+  RunTest(effective_test_name, request, &response);
+
+  if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+    return;
+  }
+
+  if (response.result_case() != ConformanceResponse::kJsonPayload) {
+    ReportFailure(effective_test_name, request, response,
+                  "Expected JSON payload but got type %d.",
+                  response.result_case());
+    return;
+  }
+  Json::Reader reader;
+  Json::Value value;
+  if (!reader.parse(response.json_payload(), value)) {
+    ReportFailure(effective_test_name, request, response,
+                  "JSON payload cannot be parsed as valid JSON: %s",
+                  reader.getFormattedErrorMessages().c_str());
+    return;
+  }
+  if (!validator(value)) {
+    ReportFailure(effective_test_name, request, response,
+                  "JSON payload validation failed.");
+    return;
+  }
+  ReportSuccess(effective_test_name);
+}
+
+void ConformanceTestSuite::ExpectParseFailureForJson(
+    const string& test_name, const string& input_json) {
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_json_payload(input_json);
+  string effective_test_name = "JsonInput." + test_name;
+
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  request.set_requested_output_format(conformance::JSON);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+void ConformanceTestSuite::ExpectSerializeFailureForJson(
+    const string& test_name, const string& text_format) {
+  TestAllTypes payload_message;
+  GOOGLE_CHECK(
+      TextFormat::ParseFromString(text_format, &payload_message))
+          << "Failed to parse: " << text_format;
+
+  ConformanceRequest request;
+  ConformanceResponse response;
+  request.set_protobuf_payload(payload_message.SerializeAsString());
+  string effective_test_name = test_name + ".JsonOutput";
+  request.set_requested_output_format(conformance::JSON);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kSerializeError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, request, response,
+                  "Should have failed to serialize, but didn't.");
+  }
+}
+
 void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
   // Incomplete values for each wire type.
   static const string incompletes[6] = {
@@ -500,23 +620,1375 @@
   RunValidJsonTest("HelloWorld", "{\"optionalString\":\"Hello, World!\"}",
                    "optional_string: 'Hello, World!'");
 
-  bool ok =
-      CheckSetEmpty(expected_to_fail_,
-                    "These tests were listed in the failure list, but they "
-                    "don't exist.  Remove them from the failure list") &&
+  // Test field name conventions.
+  RunValidJsonTest(
+      "FieldNameInSnakeCase",
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+      )");
+  RunValidJsonTest(
+      "FieldNameWithNumbers",
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      R"(
+        field0name5: 5
+        field_0_name6: 6
+      )");
+  RunValidJsonTest(
+      "FieldNameWithMixedCases",
+      R"({
+        "fieldName7": 7,
+        "fieldName8": 8,
+        "fieldName9": 9,
+        "fieldName10": 10,
+        "fIELDNAME11": 11,
+        "fIELDName12": 12
+      })",
+      R"(
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+      )");
+  // Using the original proto field name in JSON is also allowed.
+  RunValidJsonTest(
+      "OriginalProtoFieldName",
+      R"({
+        "fieldname1": 1,
+        "field_name2": 2,
+        "_field_name3": 3,
+        "field0name5": 5,
+        "field_0_name6": 6,
+        "fieldName7": 7,
+        "FieldName8": 8,
+        "field_Name9": 9,
+        "Field_Name10": 10,
+        "FIELD_NAME11": 11,
+        "FIELD_name12": 12
+      })",
+      R"(
+        fieldname1: 1
+        field_name2: 2
+        _field_name3: 3
+        field0name5: 5
+        field_0_name6: 6
+        fieldName7: 7
+        FieldName8: 8
+        field_Name9: 9
+        Field_Name10: 10
+        FIELD_NAME11: 11
+        FIELD_name12: 12
+      )");
+  // Field names can be escaped.
+  RunValidJsonTest(
+      "FieldNameEscaped",
+      R"({"fieldn\u0061me1": 1})",
+      "fieldname1: 1");
+  // Field names must be quoted (or it's not valid JSON).
+  ExpectParseFailureForJson(
+      "FieldNameNotQuoted",
+      "{fieldname1: 1}");
+  // Trailing comma is not allowed (not valid JSON).
+  ExpectParseFailureForJson(
+      "TrailingCommaInAnObject",
+      R"({"fieldname1":1,})");
+  // JSON doesn't support comments.
+  ExpectParseFailureForJson(
+      "JsonWithComments",
+      R"({
+        // This is a comment.
+        "fieldname1": 1
+      })");
+  // Duplicated field names are not allowed.
+  ExpectParseFailureForJson(
+      "FieldNameDuplicate",
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing1",
+      R"({
+        "optional_nested_message": {a: 1},
+        "optionalNestedMessage": {}
+      })");
+  ExpectParseFailureForJson(
+      "FieldNameDuplicateDifferentCasing2",
+      R"({
+        "optionalNestedMessage": {a: 1},
+        "optional_nested_message": {}
+      })");
+  // Serializers should use lowerCamelCase by default.
+  RunValidJsonTestWithValidator(
+      "FieldNameInLowerCamelCase",
+      R"({
+        "fieldname1": 1,
+        "fieldName2": 2,
+        "FieldName3": 3
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldname1") &&
+            value.isMember("fieldName2") &&
+            value.isMember("FieldName3");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithNumbers",
+      R"({
+        "field0name5": 5,
+        "field0Name6": 6
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("field0name5") &&
+            value.isMember("field0Name6");
+      });
+  RunValidJsonTestWithValidator(
+      "FieldNameWithMixedCases",
+      R"({
+        "fieldName7": 7,
+        "fieldName8": 8,
+        "fieldName9": 9,
+        "fieldName10": 10,
+        "fIELDNAME11": 11,
+        "fIELDName12": 12
+      })",
+      [](const Json::Value& value) {
+        return value.isMember("fieldName7") &&
+            value.isMember("fieldName8") &&
+            value.isMember("fieldName9") &&
+            value.isMember("fieldName10") &&
+            value.isMember("fIELDNAME11") &&
+            value.isMember("fIELDName12");
+      });
 
-      CheckSetEmpty(unexpected_failing_tests_,
-                    "These tests failed.  If they can't be fixed right now, "
-                    "you can add them to the failure list so the overall "
-                    "suite can succeed") &&
+  // Integer fields.
+  RunValidJsonTest(
+      "Int32FieldMaxValue",
+      R"({"optionalInt32": 2147483647})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinValue",
+      R"({"optionalInt32": -2147483648})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxValue",
+      R"({"optionalUint32": 4294967295})",
+      "optional_uint32: 4294967295");
+  RunValidJsonTest(
+      "Int64FieldMaxValue",
+      R"({"optionalInt64": "9223372036854775807"})",
+      "optional_int64: 9223372036854775807");
+  RunValidJsonTest(
+      "Int64FieldMinValue",
+      R"({"optionalInt64": "-9223372036854775808"})",
+      "optional_int64: -9223372036854775808");
+  RunValidJsonTest(
+      "Uint64FieldMaxValue",
+      R"({"optionalUint64": "18446744073709551615"})",
+      "optional_uint64: 18446744073709551615");
+  RunValidJsonTest(
+      "Int64FieldMaxValueNotQuoted",
+      R"({"optionalInt64": 9223372036854775807})",
+      "optional_int64: 9223372036854775807");
+  RunValidJsonTest(
+      "Int64FieldMinValueNotQuoted",
+      R"({"optionalInt64": -9223372036854775808})",
+      "optional_int64: -9223372036854775808");
+  RunValidJsonTest(
+      "Uint64FieldMaxValueNotQuoted",
+      R"({"optionalUint64": 18446744073709551615})",
+      "optional_uint64: 18446744073709551615");
+  // Values can be represented as JSON strings.
+  RunValidJsonTest(
+      "Int32FieldStringValue",
+      R"({"optionalInt32": "2147483647"})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldStringValueEscaped",
+      R"({"optionalInt32": "2\u003147483647"})",
+      "optional_int32: 2147483647");
 
-      CheckSetEmpty(unexpected_succeeding_tests_,
-                    "These tests succeeded, even though they were listed in "
-                    "the failure list.  Remove them from the failure list");
+  // Parsers reject out-of-bound integer values.
+  ExpectParseFailureForJson(
+      "Int32FieldTooLarge",
+      R"({"optionalInt32": 2147483648})");
+  ExpectParseFailureForJson(
+      "Int32FieldTooSmall",
+      R"({"optionalInt32": -2147483649})");
+  ExpectParseFailureForJson(
+      "Uint32FieldTooLarge",
+      R"({"optionalUint32": 4294967296})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooLarge",
+      R"({"optionalInt64": "9223372036854775808"})");
+  ExpectParseFailureForJson(
+      "Int64FieldTooSmall",
+      R"({"optionalInt64": "-9223372036854775809"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldTooLarge",
+      R"({"optionalUint64": "18446744073709551616"})");
+  // Parser reject non-integer numeric values as well.
+  ExpectParseFailureForJson(
+      "Int32FieldNotInteger",
+      R"({"optionalInt32": 0.5})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotInteger",
+      R"({"optionalUint32": 0.5})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotInteger",
+      R"({"optionalInt64": "0.5"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotInteger",
+      R"({"optionalUint64": "0.5"})");
 
-  CheckSetEmpty(skipped_,
-                "These tests were skipped (probably because support for some "
-                "features is not implemented)");
+  // Integers but represented as float values are accepted.
+  RunValidJsonTest(
+      "Int32FieldFloatTrailingZero",
+      R"({"optionalInt32": 100000.000})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldExponentialFormat",
+      R"({"optionalInt32": 1e5})",
+      "optional_int32: 100000");
+  RunValidJsonTest(
+      "Int32FieldMaxFloatValue",
+      R"({"optionalInt32": 2.147483647e9})",
+      "optional_int32: 2147483647");
+  RunValidJsonTest(
+      "Int32FieldMinFloatValue",
+      R"({"optionalInt32": -2.147483648e9})",
+      "optional_int32: -2147483648");
+  RunValidJsonTest(
+      "Uint32FieldMaxFloatValue",
+      R"({"optionalUint32": 4.294967295e9})",
+      "optional_uint32: 4294967295");
+
+  // Parser reject non-numeric values.
+  ExpectParseFailureForJson(
+      "Int32FieldNotNumber",
+      R"({"optionalInt32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint32FieldNotNumber",
+      R"({"optionalUint32": "3x3"})");
+  ExpectParseFailureForJson(
+      "Int64FieldNotNumber",
+      R"({"optionalInt64": "3x3"})");
+  ExpectParseFailureForJson(
+      "Uint64FieldNotNumber",
+      R"({"optionalUint64": "3x3"})");
+  // JSON does not allow "+" on numric values.
+  ExpectParseFailureForJson(
+      "Int32FieldPlusSign",
+      R"({"optionalInt32": +1})");
+  // JSON doesn't allow leading 0s.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingZero",
+      R"({"optionalInt32": 01})");
+  ExpectParseFailureForJson(
+      "Int32FieldNegativeWithLeadingZero",
+      R"({"optionalInt32": -01})");
+  // String values must follow the same syntax rule. Specifically leading
+  // or traling spaces are not allowed.
+  ExpectParseFailureForJson(
+      "Int32FieldLeadingSpace",
+      R"({"optionalInt32": " 1"})");
+  ExpectParseFailureForJson(
+      "Int32FieldTrailingSpace",
+      R"({"optionalInt32": "1 "})");
+
+  // 64-bit values are serialized as strings.
+  RunValidJsonTestWithValidator(
+      "Int64FieldBeString",
+      R"({"optionalInt64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalInt64"].type() == Json::stringValue &&
+            value["optionalInt64"].asString() == "1";
+      });
+  RunValidJsonTestWithValidator(
+      "Uint64FieldBeString",
+      R"({"optionalUint64": 1})",
+      [](const Json::Value& value) {
+        return value["optionalUint64"].type() == Json::stringValue &&
+            value["optionalUint64"].asString() == "1";
+      });
+
+  // Bool fields.
+  RunValidJsonTest(
+      "BoolFieldTrue",
+      R"({"optionalBool":true})",
+      "optional_bool: true");
+  RunValidJsonTest(
+      "BoolFieldFalse",
+      R"({"optionalBool":false})",
+      "optional_bool: false");
+
+  // Other forms are not allowed.
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerZero",
+      R"({"optionalBool":0})");
+  ExpectParseFailureForJson(
+      "BoolFieldIntegerOne",
+      R"({"optionalBool":1})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseTrue",
+      R"({"optionalBool":True})");
+  ExpectParseFailureForJson(
+      "BoolFieldCamelCaseFalse",
+      R"({"optionalBool":False})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalTrue",
+      R"({"optionalBool":TRUE})");
+  ExpectParseFailureForJson(
+      "BoolFieldAllCapitalFalse",
+      R"({"optionalBool":FALSE})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedTrue",
+      R"({"optionalBool":"true"})");
+  ExpectParseFailureForJson(
+      "BoolFieldDoubleQuotedFalse",
+      R"({"optionalBool":"false"})");
+
+  // Float fields.
+  RunValidJsonTest(
+      "FloatFieldMinPositiveValue",
+      R"({"optionalFloat": 1.175494e-38})",
+      "optional_float: 1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxNegativeValue",
+      R"({"optionalFloat": -1.175494e-38})",
+      "optional_float: -1.175494e-38");
+  RunValidJsonTest(
+      "FloatFieldMaxPositiveValue",
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  RunValidJsonTest(
+      "FloatFieldMinNegativeValue",
+      R"({"optionalFloat": 3.402823e+38})",
+      "optional_float: 3.402823e+38");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "FloatFieldQuotedValue",
+      R"({"optionalFloat": "1"})",
+      "optional_float: 1");
+  // Special values.
+  RunValidJsonTest(
+      "FloatFieldNan",
+      R"({"optionalFloat": "NaN"})",
+      "optional_float: nan");
+  RunValidJsonTest(
+      "FloatFieldInfinity",
+      R"({"optionalFloat": "Infinity"})",
+      "optional_float: inf");
+  RunValidJsonTest(
+      "FloatFieldNegativeInfinity",
+      R"({"optionalFloat": "-Infinity"})",
+      "optional_float: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypes message;
+    // IEEE floating-point standard 32-bit quiet NaN:
+    //   0111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0x7FA12345));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeQuietNan", message,
+        "optional_float: nan");
+    // IEEE floating-point standard 64-bit signaling NaN:
+    //   1111 1111 1xxx xxxx xxxx xxxx xxxx xxxx
+    message.set_optional_float(
+        WireFormatLite::DecodeFloat(0xFFB54321));
+    RunValidJsonTestWithProtobufInput(
+        "FloatFieldNormalizeSignalingNan", message,
+        "optional_float: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "FloatFieldNanNotQuoted",
+      R"({"optionalFloat": NaN})");
+  ExpectParseFailureForJson(
+      "FloatFieldInfinityNotQuoted",
+      R"({"optionalFloat": Infinity})");
+  ExpectParseFailureForJson(
+      "FloatFieldNegativeInfinityNotQuoted",
+      R"({"optionalFloat": -Infinity})");
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "FloatFieldTooSmall",
+      R"({"optionalFloat": -3.502823e+38})");
+  ExpectParseFailureForJson(
+      "FloatFieldTooLarge",
+      R"({"optionalFloat": 3.502823e+38})");
+
+  // Double fields.
+  RunValidJsonTest(
+      "DoubleFieldMinPositiveValue",
+      R"({"optionalDouble": 2.22507e-308})",
+      "optional_double: 2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxNegativeValue",
+      R"({"optionalDouble": -2.22507e-308})",
+      "optional_double: -2.22507e-308");
+  RunValidJsonTest(
+      "DoubleFieldMaxPositiveValue",
+      R"({"optionalDouble": 1.79769e+308})",
+      "optional_double: 1.79769e+308");
+  RunValidJsonTest(
+      "DoubleFieldMinNegativeValue",
+      R"({"optionalDouble": -1.79769e+308})",
+      "optional_double: -1.79769e+308");
+  // Values can be quoted.
+  RunValidJsonTest(
+      "DoubleFieldQuotedValue",
+      R"({"optionalDouble": "1"})",
+      "optional_double: 1");
+  // Speical values.
+  RunValidJsonTest(
+      "DoubleFieldNan",
+      R"({"optionalDouble": "NaN"})",
+      "optional_double: nan");
+  RunValidJsonTest(
+      "DoubleFieldInfinity",
+      R"({"optionalDouble": "Infinity"})",
+      "optional_double: inf");
+  RunValidJsonTest(
+      "DoubleFieldNegativeInfinity",
+      R"({"optionalDouble": "-Infinity"})",
+      "optional_double: -inf");
+  // Non-cannonical Nan will be correctly normalized.
+  {
+    TestAllTypes message;
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0x7FFA123456789ABCLL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeQuietNan", message,
+        "optional_double: nan");
+    message.set_optional_double(
+        WireFormatLite::DecodeDouble(0xFFFBCBA987654321LL));
+    RunValidJsonTestWithProtobufInput(
+        "DoubleFieldNormalizeSignalingNan", message,
+        "optional_double: nan");
+  }
+
+  // Special values must be quoted.
+  ExpectParseFailureForJson(
+      "DoubleFieldNanNotQuoted",
+      R"({"optionalDouble": NaN})");
+  ExpectParseFailureForJson(
+      "DoubleFieldInfinityNotQuoted",
+      R"({"optionalDouble": Infinity})");
+  ExpectParseFailureForJson(
+      "DoubleFieldNegativeInfinityNotQuoted",
+      R"({"optionalDouble": -Infinity})");
+
+  // Parsers should reject out-of-bound values.
+  ExpectParseFailureForJson(
+      "DoubleFieldTooSmall",
+      R"({"optionalDouble": -1.89769e+308})");
+  ExpectParseFailureForJson(
+      "DoubleFieldTooLarge",
+      R"({"optionalDouble": +1.89769e+308})");
+
+  // Enum fields.
+  RunValidJsonTest(
+      "EnumField",
+      R"({"optionalNestedEnum": "FOO"})",
+      "optional_nested_enum: FOO");
+  // Enum values must be represented as strings.
+  ExpectParseFailureForJson(
+      "EnumFieldNotQuoted",
+      R"({"optionalNestedEnum": FOO})");
+  // Numeric values are allowed.
+  RunValidJsonTest(
+      "EnumFieldNumericValueZero",
+      R"({"optionalNestedEnum": 0})",
+      "optional_nested_enum: FOO");
+  RunValidJsonTest(
+      "EnumFieldNumericValueNonZero",
+      R"({"optionalNestedEnum": 1})",
+      "optional_nested_enum: BAR");
+  // Unknown enum values are represented as numeric values.
+  RunValidJsonTestWithValidator(
+      "EnumFieldUnknownValue",
+      R"({"optionalNestedEnum": 123})",
+      [](const Json::Value& value) {
+        return value["optionalNestedEnum"].type() == Json::intValue &&
+            value["optionalNestedEnum"].asInt() == 123;
+      });
+
+  // String fields.
+  RunValidJsonTest(
+      "StringField",
+      R"({"optionalString": "Hello world!"})",
+      "optional_string: \"Hello world!\"");
+  RunValidJsonTest(
+      "StringFieldUnicode",
+      // Google in Chinese.
+      R"({"optionalString": "谷歌"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldEscape",
+      R"({"optionalString": "\"\\\/\b\f\n\r\t"})",
+      R"(optional_string: "\"\\/\b\f\n\r\t")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscape",
+      R"({"optionalString": "\u8C37\u6B4C"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldUnicodeEscapeWithLowercaseHexLetters",
+      R"({"optionalString": "\u8c37\u6b4c"})",
+      R"(optional_string: "谷歌")");
+  RunValidJsonTest(
+      "StringFieldSurrogatePair",
+      // The character is an emoji: grinning face with smiling eyes. 😁
+      R"({"optionalString": "\uD83D\uDE01"})",
+      R"(optional_string: "\xF0\x9F\x98\x81")");
+
+  // Unicode escapes must start with "\u" (lowercase u).
+  ExpectParseFailureForJson(
+      "StringFieldUppercaseEscapeLetter",
+      R"({"optionalString": "\U8C37\U6b4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldInvalidEscape",
+      R"({"optionalString": "\uXXXX\u6B4C"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnterminatedEscape",
+      R"({"optionalString": "\u8C3"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedHighSurrogate",
+      R"({"optionalString": "\uD800"})");
+  ExpectParseFailureForJson(
+      "StringFieldUnpairedLowSurrogate",
+      R"({"optionalString": "\uDC00"})");
+  ExpectParseFailureForJson(
+      "StringFieldSurrogateInWrongOrder",
+      R"({"optionalString": "\uDE01\uD83D"})");
+  ExpectParseFailureForJson(
+      "StringFieldNotAString",
+      R"({"optionalString": 12345})");
+
+  // Bytes fields.
+  RunValidJsonTest(
+      "BytesField",
+      R"({"optionalBytes": "AQI="})",
+      R"(optional_bytes: "\x01\x02")");
+  ExpectParseFailureForJson(
+      "BytesFieldNoPadding",
+      R"({"optionalBytes": "AQI"})");
+  ExpectParseFailureForJson(
+      "BytesFieldInvalidBase64Characters",
+      R"({"optionalBytes": "-_=="})");
+
+  // Message fields.
+  RunValidJsonTest(
+      "MessageField",
+      R"({"optionalNestedMessage": {"a": 1234}})",
+      "optional_nested_message: {a: 1234}");
+
+  // Oneof fields.
+  ExpectParseFailureForJson(
+      "OneofFieldDuplicate",
+      R"({"oneofUint32": 1, "oneofString": "test"})");
+
+  // Repeated fields.
+  RunValidJsonTest(
+      "PrimitiveRepeatedField",
+      R"({"repeatedInt32": [1, 2, 3, 4]})",
+      "repeated_int32: [1, 2, 3, 4]");
+  RunValidJsonTest(
+      "EnumRepeatedField",
+      R"({"repeatedNestedEnum": ["FOO", "BAR", "BAZ"]})",
+      "repeated_nested_enum: [FOO, BAR, BAZ]");
+  RunValidJsonTest(
+      "StringRepeatedField",
+      R"({"repeatedString": ["Hello", "world"]})",
+      R"(repeated_string: ["Hello", "world"])");
+  RunValidJsonTest(
+      "BytesRepeatedField",
+      R"({"repeatedBytes": ["AAEC", "AQI="]})",
+      R"(repeated_bytes: ["\x00\x01\x02", "\x01\x02"])");
+  RunValidJsonTest(
+      "MessageRepeatedField",
+      R"({"repeatedNestedMessage": [{"a": 1234}, {"a": 5678}]})",
+      "repeated_nested_message: {a: 1234}"
+      "repeated_nested_message: {a: 5678}");
+
+  // Repeated field elements are of incorrect type.
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotBool",
+      R"({"repeatedInt32": [1, false, 3, 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotString",
+      R"({"repeatedInt32": [1, 2, "name", 4]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingIntegersGotMessage",
+      R"({"repeatedInt32": [1, 2, 3, {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotInt",
+      R"({"repeatedString": ["1", 2, "3", "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotBool",
+      R"({"repeatedString": ["1", "2", false, "4"]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingStringsGotMessage",
+      R"({"repeatedString": ["1", 2, "3", {"a": 4}]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotInt",
+      R"({"repeatedNestedMessage": [{"a": 1}, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotBool",
+      R"({"repeatedNestedMessage": [{"a": 1}, false]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldWrongElementTypeExpectingMessagesGotString",
+      R"({"repeatedNestedMessage": [{"a": 1}, "2"]})");
+  // Trailing comma in the repeated field is not allowed.
+  ExpectParseFailureForJson(
+      "RepeatedFieldTrailingComma",
+      R"({"repeatedInt32": [1, 2, 3, 4,]})");
+
+  // Map fields.
+  RunValidJsonTest(
+      "Int32MapField",
+      R"({"mapInt32Int32": {"1": 2, "3": 4}})",
+      "map_int32_int32: {key: 1 value: 2}"
+      "map_int32_int32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int32MapFieldKeyNotQuoted",
+      R"({"mapInt32Int32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint32MapField",
+      R"({"mapUint32Uint32": {"1": 2, "3": 4}})",
+      "map_uint32_uint32: {key: 1 value: 2}"
+      "map_uint32_uint32: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint32MapFieldKeyNotQuoted",
+      R"({"mapUint32Uint32": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Int64MapField",
+      R"({"mapInt64Int64": {"1": 2, "3": 4}})",
+      "map_int64_int64: {key: 1 value: 2}"
+      "map_int64_int64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Int64MapFieldKeyNotQuoted",
+      R"({"mapInt64Int64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "Uint64MapField",
+      R"({"mapUint64Uint64": {"1": 2, "3": 4}})",
+      "map_uint64_uint64: {key: 1 value: 2}"
+      "map_uint64_uint64: {key: 3 value: 4}");
+  ExpectParseFailureForJson(
+      "Uint64MapFieldKeyNotQuoted",
+      R"({"mapUint64Uint64": {1: 2, 3: 4}})");
+  RunValidJsonTest(
+      "BoolMapField",
+      R"({"mapBoolBool": {"true": true, "false": false}})",
+      "map_bool_bool: {key: true value: true}"
+      "map_bool_bool: {key: false value: false}");
+  ExpectParseFailureForJson(
+      "BoolMapFieldKeyNotQuoted",
+      R"({"mapBoolBool": {true: true, false: false}})");
+  RunValidJsonTest(
+      "MessageMapField",
+      R"({
+        "mapStringNestedMessage": {
+          "hello": {"a": 1234},
+          "world": {"a": 5678}
+        }
+      })",
+      R"(
+        map_string_nested_message: {
+          key: "hello"
+          value: {a: 1234}
+        }
+        map_string_nested_message: {
+          key: "world"
+          value: {a: 5678}
+        }
+      )");
+  // Since Map keys are represented as JSON strings, escaping should be allowed.
+  RunValidJsonTest(
+      "Int32MapEscapedKey",
+      R"({"mapInt32Int32": {"\u0031": 2}})",
+      "map_int32_int32: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "Int64MapEscapedKey",
+      R"({"mapInt64Int64": {"\u0031": 2}})",
+      "map_int64_int64: {key: 1 value: 2}");
+  RunValidJsonTest(
+      "BoolMapEscapedKey",
+      R"({"mapBoolBool": {"tr\u0075e": true}})",
+      "map_bool_bool: {key: true value: true}");
+
+  // "null" is accepted for all fields types.
+  RunValidJsonTest(
+      "AllFieldAcceptNull",
+      R"({
+        "optionalInt32": null,
+        "optionalInt64": null,
+        "optionalUint32": null,
+        "optionalUint64": null,
+        "optionalBool": null,
+        "optionalString": null,
+        "optionalBytes": null,
+        "optionalNestedEnum": null,
+        "optionalNestedMessage": null,
+        "repeatedInt32": null,
+        "repeatedInt64": null,
+        "repeatedUint32": null,
+        "repeatedUint64": null,
+        "repeatedBool": null,
+        "repeatedString": null,
+        "repeatedBytes": null,
+        "repeatedNestedEnum": null,
+        "repeatedNestedMessage": null,
+        "mapInt32Int32": null,
+        "mapBoolBool": null,
+        "mapStringNestedMessage": null
+      })",
+      "");
+
+  // Repeated field elements cannot be null.
+  ExpectParseFailureForJson(
+      "RepeatedFieldPrimitiveElementIsNull",
+      R"({"repeatedInt32": [1, null, 2]})");
+  ExpectParseFailureForJson(
+      "RepeatedFieldMessageElementIsNull",
+      R"({"repeatedNestedMessage": [{"a":1}, null, {"a":2}]})");
+  // Map field keys cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldKeyIsNull",
+      R"({"mapInt32Int32": {null: 1}})");
+  // Map field values cannot be null.
+  ExpectParseFailureForJson(
+      "MapFieldValueIsNull",
+      R"({"mapInt32Int32": {"0": null}})");
+
+  // Wrapper types.
+  RunValidJsonTest(
+      "OptionalBoolWrapper",
+      R"({"optionalBoolWrapper": false})",
+      "optional_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "OptionalInt32Wrapper",
+      R"({"optionalInt32Wrapper": 0})",
+      "optional_int32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint32Wrapper",
+      R"({"optionalUint32Wrapper": 0})",
+      "optional_uint32_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalInt64Wrapper",
+      R"({"optionalInt64Wrapper": 0})",
+      "optional_int64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalUint64Wrapper",
+      R"({"optionalUint64Wrapper": 0})",
+      "optional_uint64_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalFloatWrapper",
+      R"({"optionalFloatWrapper": 0})",
+      "optional_float_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalDoubleWrapper",
+      R"({"optionalDoubleWrapper": 0})",
+      "optional_double_wrapper: {value: 0}");
+  RunValidJsonTest(
+      "OptionalStringWrapper",
+      R"({"optionalStringWrapper": ""})",
+      R"(optional_string_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalBytesWrapper",
+      R"({"optionalBytesWrapper": ""})",
+      R"(optional_bytes_wrapper: {value: ""})");
+  RunValidJsonTest(
+      "OptionalWrapperTypesWithNonDefaultValue",
+      R"({
+        "optionalBoolWrapper": true,
+        "optionalInt32Wrapper": 1,
+        "optionalUint32Wrapper": 1,
+        "optionalInt64Wrapper": "1",
+        "optionalUint64Wrapper": "1",
+        "optionalFloatWrapper": 1,
+        "optionalDoubleWrapper": 1,
+        "optionalStringWrapper": "1",
+        "optionalBytesWrapper": "AQI="
+      })",
+      R"(
+        optional_bool_wrapper: {value: true}
+        optional_int32_wrapper: {value: 1}
+        optional_uint32_wrapper: {value: 1}
+        optional_int64_wrapper: {value: 1}
+        optional_uint64_wrapper: {value: 1}
+        optional_float_wrapper: {value: 1}
+        optional_double_wrapper: {value: 1}
+        optional_string_wrapper: {value: "1"}
+        optional_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "RepeatedBoolWrapper",
+      R"({"repeatedBoolWrapper": [true, false]})",
+      "repeated_bool_wrapper: {value: true}"
+      "repeated_bool_wrapper: {value: false}");
+  RunValidJsonTest(
+      "RepeatedInt32Wrapper",
+      R"({"repeatedInt32Wrapper": [0, 1]})",
+      "repeated_int32_wrapper: {value: 0}"
+      "repeated_int32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint32Wrapper",
+      R"({"repeatedUint32Wrapper": [0, 1]})",
+      "repeated_uint32_wrapper: {value: 0}"
+      "repeated_uint32_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedInt64Wrapper",
+      R"({"repeatedInt64Wrapper": [0, 1]})",
+      "repeated_int64_wrapper: {value: 0}"
+      "repeated_int64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedUint64Wrapper",
+      R"({"repeatedUint64Wrapper": [0, 1]})",
+      "repeated_uint64_wrapper: {value: 0}"
+      "repeated_uint64_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedFloatWrapper",
+      R"({"repeatedFloatWrapper": [0, 1]})",
+      "repeated_float_wrapper: {value: 0}"
+      "repeated_float_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedDoubleWrapper",
+      R"({"repeatedDoubleWrapper": [0, 1]})",
+      "repeated_double_wrapper: {value: 0}"
+      "repeated_double_wrapper: {value: 1}");
+  RunValidJsonTest(
+      "RepeatedStringWrapper",
+      R"({"repeatedStringWrapper": ["", "AQI="]})",
+      R"(
+        repeated_string_wrapper: {value: ""}
+        repeated_string_wrapper: {value: "AQI="}
+      )");
+  RunValidJsonTest(
+      "RepeatedBytesWrapper",
+      R"({"repeatedBytesWrapper": ["", "AQI="]})",
+      R"(
+        repeated_bytes_wrapper: {value: ""}
+        repeated_bytes_wrapper: {value: "\x01\x02"}
+      )");
+  RunValidJsonTest(
+      "WrapperTypesWithNullValue",
+      R"({
+        "optionalBoolWrapper": null,
+        "optionalInt32Wrapper": null,
+        "optionalUint32Wrapper": null,
+        "optionalInt64Wrapper": null,
+        "optionalUint64Wrapper": null,
+        "optionalFloatWrapper": null,
+        "optionalDoubleWrapper": null,
+        "optionalStringWrapper": null,
+        "optionalBytesWrapper": null,
+        "repeatedBoolWrapper": null,
+        "repeatedInt32Wrapper": null,
+        "repeatedUint32Wrapper": null,
+        "repeatedInt64Wrapper": null,
+        "repeatedUint64Wrapper": null,
+        "repeatedFloatWrapper": null,
+        "repeatedDoubleWrapper": null,
+        "repeatedStringWrapper": null,
+        "repeatedBytesWrapper": null
+      })",
+      "");
+
+  // Duration
+  RunValidJsonTest(
+      "DurationMinValue",
+      R"({"optionalDuration": "-315576000000.999999999s"})",
+      "optional_duration: {seconds: -315576000000 nanos: -999999999}");
+  RunValidJsonTest(
+      "DurationMaxValue",
+      R"({"optionalDuration": "315576000000.999999999s"})",
+      "optional_duration: {seconds: 315576000000 nanos: 999999999}");
+  RunValidJsonTest(
+      "DurationRepeatedValue",
+      R"({"repeatedDuration": ["1.5s", "-1.5s"]})",
+      "repeated_duration: {seconds: 1 nanos: 500000000}"
+      "repeated_duration: {seconds: -1 nanos: -500000000}");
+
+  ExpectParseFailureForJson(
+      "DurationMissingS",
+      R"({"optionalDuration": "1"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooSmall",
+      R"({"optionalDuration": "-315576000001.000000000s"})");
+  ExpectParseFailureForJson(
+      "DurationJsonInputTooLarge",
+      R"({"optionalDuration": "315576000001.000000000s"})");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooSmall",
+      "optional_duration: {seconds: -315576000001 nanos: 0}");
+  ExpectSerializeFailureForJson(
+      "DurationProtoInputTooLarge",
+      "optional_duration: {seconds: 315576000001 nanos: 0}");
+
+  RunValidJsonTestWithValidator(
+      "DurationHasZeroFractionalDigit",
+      R"({"optionalDuration": "1.000000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas3FractionalDigits",
+      R"({"optionalDuration": "1.010000000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas6FractionalDigits",
+      R"({"optionalDuration": "1.000010000s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000010s";
+      });
+  RunValidJsonTestWithValidator(
+      "DurationHas9FractionalDigits",
+      R"({"optionalDuration": "1.000000010s"})",
+      [](const Json::Value& value) {
+        return value["optionalDuration"].asString() == "1.000000010s";
+      });
+
+  // Timestamp
+  RunValidJsonTest(
+      "TimestampMinValue",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00Z"})",
+      "optional_timestamp: {seconds: -62135596800}");
+  RunValidJsonTest(
+      "TimestampMaxValue",
+      R"({"optionalTimestamp": "9999-12-31T23:59:59.999999999Z"})",
+      "optional_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampRepeatedValue",
+      R"({
+        "repeatedTimestamp": [
+          "0001-01-01T00:00:00Z",
+          "9999-12-31T23:59:59.999999999Z"
+        ]
+      })",
+      "repeated_timestamp: {seconds: -62135596800}"
+      "repeated_timestamp: {seconds: 253402300799 nanos: 999999999}");
+  RunValidJsonTest(
+      "TimestampWithPositiveOffset",
+      R"({"optionalTimestamp": "1970-01-01T08:00:00+08:00"})",
+      "optional_timestamp: {seconds: 0}");
+  RunValidJsonTest(
+      "TimestampWithNegativeOffset",
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      "optional_timestamp: {seconds: 0}");
+
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooSmall",
+      R"({"optionalTimestamp": "0000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputTooLarge",
+      R"({"optionalTimestamp": "10000-01-01T00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingZ",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputMissingT",
+      R"({"optionalTimestamp": "0001-01-01 00:00:00Z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseZ",
+      R"({"optionalTimestamp": "0001-01-01T00:00:00z"})");
+  ExpectParseFailureForJson(
+      "TimestampJsonInputLowercaseT",
+      R"({"optionalTimestamp": "0001-01-01t00:00:00Z"})");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooSmall",
+      "optional_timestamp: {seconds: -62135596801}");
+  ExpectSerializeFailureForJson(
+      "TimestampProtoInputTooLarge",
+      "optional_timestamp: {seconds: 253402300800}");
+  RunValidJsonTestWithValidator(
+      "TimestampZeroNormalized",
+      R"({"optionalTimestamp": "1969-12-31T16:00:00-08:00"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHasZeroFractionalDigit",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas3FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.010000000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas6FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000010000Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000010Z";
+      });
+  RunValidJsonTestWithValidator(
+      "TimestampHas9FractionalDigits",
+      R"({"optionalTimestamp": "1970-01-01T00:00:00.000000010Z"})",
+      [](const Json::Value& value) {
+        return value["optionalTimestamp"].asString() ==
+            "1970-01-01T00:00:00.000000010Z";
+      });
+
+  // FieldMask
+  RunValidJsonTest(
+      "FieldMask",
+      R"({"optionalFieldMask": "foo,barBaz"})",
+      R"(optional_field_mask: {paths: "foo" paths: "bar_baz"})");
+  ExpectParseFailureForJson(
+      "FieldMaskInvalidCharacter",
+      R"({"optionalFieldMask": "foo,bar_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskPathsDontRoundTrip",
+      R"(optional_field_mask: {paths: "fooBar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskNumbersDontRoundTrip",
+      R"(optional_field_mask: {paths: "foo_3_bar"})");
+  ExpectSerializeFailureForJson(
+      "FieldMaskTooManyUnderscore",
+      R"(optional_field_mask: {paths: "foo__bar"})");
+
+  // Struct
+  RunValidJsonTest(
+      "Struct",
+      R"({
+        "optionalStruct": {
+          "nullValue": null,
+          "intValue": 1234,
+          "boolValue": true,
+          "doubleValue": 1234.5678,
+          "stringValue": "Hello world!",
+          "listValue": [1234, "5678"],
+          "objectValue": {
+            "value": 0
+          }
+        }
+      })",
+      R"(
+        optional_struct: {
+          fields: {
+            key: "nullValue"
+            value: {null_value: NULL_VALUE}
+          }
+          fields: {
+            key: "intValue"
+            value: {number_value: 1234}
+          }
+          fields: {
+            key: "boolValue"
+            value: {bool_value: true}
+          }
+          fields: {
+            key: "doubleValue"
+            value: {number_value: 1234.5678}
+          }
+          fields: {
+            key: "stringValue"
+            value: {string_value: "Hello world!"}
+          }
+          fields: {
+            key: "listValue"
+            value: {
+              list_value: {
+                values: {
+                  number_value: 1234
+                }
+                values: {
+                  string_value: "5678"
+                }
+              }
+            }
+          }
+          fields: {
+            key: "objectValue"
+            value: {
+              struct_value: {
+                fields: {
+                  key: "value"
+                  value: {
+                    number_value: 0
+                  }
+                }
+              }
+            }
+          }
+        }
+      )");
+  // Value
+  RunValidJsonTest(
+      "ValueAcceptInteger",
+      R"({"optionalValue": 1})",
+      "optional_value: { number_value: 1}");
+  RunValidJsonTest(
+      "ValueAcceptFloat",
+      R"({"optionalValue": 1.5})",
+      "optional_value: { number_value: 1.5}");
+  RunValidJsonTest(
+      "ValueAcceptBool",
+      R"({"optionalValue": false})",
+      "optional_value: { bool_value: false}");
+  RunValidJsonTest(
+      "ValueAcceptNull",
+      R"({"optionalValue": null})",
+      "optional_value: { null_value: NULL_VALUE}");
+  RunValidJsonTest(
+      "ValueAcceptString",
+      R"({"optionalValue": "hello"})",
+      R"(optional_value: { string_value: "hello"})");
+  RunValidJsonTest(
+      "ValueAcceptList",
+      R"({"optionalValue": [0, "hello"]})",
+      R"(
+        optional_value: {
+          list_value: {
+            values: {
+              number_value: 0
+            }
+            values: {
+              string_value: "hello"
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "ValueAcceptObject",
+      R"({"optionalValue": {"value": 1}})",
+      R"(
+        optional_value: {
+          struct_value: {
+            fields: {
+              key: "value"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+
+  // Any
+  RunValidJsonTest(
+      "Any",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/conformance.TestAllTypes",
+          "optionalInt32": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/conformance.TestAllTypes] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyNested",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Any",
+          "value": {
+            "@type": "type.googleapis.com/conformance.TestAllTypes",
+            "optionalInt32": 12345
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Any] {
+            [type.googleapis.com/conformance.TestAllTypes] {
+              optional_int32: 12345
+            }
+          }
+        }
+      )");
+  // The special "@type" tag is not required to appear first.
+  RunValidJsonTest(
+      "AnyUnorderedTypeTag",
+      R"({
+        "optionalAny": {
+          "optionalInt32": 12345,
+          "@type": "type.googleapis.com/conformance.TestAllTypes"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/conformance.TestAllTypes] {
+            optional_int32: 12345
+          }
+        }
+      )");
+  // Well-known types in Any.
+  RunValidJsonTest(
+      "AnyWithInt32ValueWrapper",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Int32Value",
+          "value": 12345
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Int32Value] {
+            value: 12345
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithDuration",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Duration",
+          "value": "1.5s"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Duration] {
+            seconds: 1
+            nanos: 500000000
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithTimestamp",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Timestamp",
+          "value": "1970-01-01T00:00:00Z"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Timestamp] {
+            seconds: 0
+            nanos: 0
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithFieldMask",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.FieldMask",
+          "value": "foo,barBaz"
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.FieldMask] {
+            paths: ["foo", "bar_baz"]
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithStruct",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Struct",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Struct] {
+            fields: {
+              key: "foo"
+              value: {
+                number_value: 1
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForJsonObject",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": {
+            "foo": 1
+          }
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            struct_value: {
+              fields: {
+                key: "foo"
+                value: {
+                  number_value: 1
+                }
+              }
+            }
+          }
+        }
+      )");
+  RunValidJsonTest(
+      "AnyWithValueForInteger",
+      R"({
+        "optionalAny": {
+          "@type": "type.googleapis.com/google.protobuf.Value",
+          "value": 1
+        }
+      })",
+      R"(
+        optional_any: {
+          [type.googleapis.com/google.protobuf.Value] {
+            number_value: 1
+          }
+        }
+      )");
+
+  bool ok = true;
+  if (!CheckSetEmpty(expected_to_fail_,
+                     "These tests were listed in the failure list, but they "
+                     "don't exist.  Remove them from the failure list")) {
+    ok = false;
+  }
+  if (!CheckSetEmpty(unexpected_failing_tests_,
+                     "These tests failed.  If they can't be fixed right now, "
+                     "you can add them to the failure list so the overall "
+                     "suite can succeed")) {
+    ok = false;
+  }
+
+  // Sometimes the testee may be fixed before we update the failure list (e.g.,
+  // the testee is from a different component). We warn about this case but
+  // don't consider it an overall test failure.
+  CheckSetEmpty(unexpected_succeeding_tests_,
+                "These tests succeeded, even though they were listed in "
+                "the failure list.  Remove them from the failure list");
+
+  if (verbose_) {
+    CheckSetEmpty(skipped_,
+                  "These tests were skipped (probably because support for some "
+                  "features is not implemented)");
+  }
 
   StringAppendF(&output_,
                 "CONFORMANCE SUITE %s: %d successes, %d skipped, "
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index 9e6cdae..75fc97b 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -38,14 +38,18 @@
 #ifndef CONFORMANCE_CONFORMANCE_TEST_H
 #define CONFORMANCE_CONFORMANCE_TEST_H
 
+#include <functional>
 #include <string>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/wire_format_lite.h>
 
+#include "third_party/jsoncpp/json.h"
+
 namespace conformance {
 class ConformanceRequest;
 class ConformanceResponse;
+class TestAllTypes;
 }  // namespace conformance
 
 namespace google {
@@ -53,6 +57,8 @@
 
 class ConformanceTestRunner {
  public:
+  virtual ~ConformanceTestRunner() {}
+
   // Call to run a single conformance test.
   //
   // "input" is a serialized conformance.ConformanceRequest.
@@ -60,7 +66,9 @@
   //
   // If there is any error in running the test itself, set "runtime_error" in
   // the response.
-  virtual void RunTest(const std::string& input, std::string* output) = 0;
+  virtual void RunTest(const std::string& test_name,
+                       const std::string& input,
+                       std::string* output) = 0;
 };
 
 // Class representing the test suite itself.  To run it, implement your own
@@ -118,6 +126,18 @@
                          conformance::WireFormat requested_output);
   void RunValidJsonTest(const string& test_name, const string& input_json,
                         const string& equivalent_text_format);
+  void RunValidJsonTestWithProtobufInput(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,
+                                     const string& input_json,
+                                     const Validator& validator);
+  void ExpectParseFailureForJson(const string& test_name,
+                                 const string& input_json);
+  void ExpectSerializeFailureForJson(const string& test_name,
+                                     const string& text_format);
   void ExpectParseFailureForProto(const std::string& proto,
                                   const std::string& test_name);
   void ExpectHardParseFailureForProto(const std::string& proto,
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
index 780e1c4..376a60b 100644
--- a/conformance/conformance_test_runner.cc
+++ b/conformance/conformance_test_runner.cc
@@ -53,17 +53,23 @@
 //   3. testee sends 4-byte length M (little endian)
 //   4. testee sends M bytes representing a ConformanceResponse proto
 
+#include <algorithm>
 #include <errno.h>
-#include <unistd.h>
 #include <fstream>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 #include <vector>
 
+#include <google/protobuf/stubs/stringprintf.h>
+
 #include "conformance.pb.h"
 #include "conformance_test.h"
 
 using conformance::ConformanceRequest;
 using conformance::ConformanceResponse;
 using google::protobuf::internal::scoped_array;
+using google::protobuf::StringAppendF;
 using std::string;
 using std::vector;
 
@@ -80,17 +86,47 @@
 class ForkPipeRunner : public google::protobuf::ConformanceTestRunner {
  public:
   ForkPipeRunner(const std::string &executable)
-      : executable_(executable), running_(false) {}
+      : child_pid_(-1), executable_(executable) {}
 
-  void RunTest(const std::string& request, std::string* response) {
-    if (!running_) {
+  virtual ~ForkPipeRunner() {}
+
+  void RunTest(const std::string& test_name,
+               const std::string& request,
+               std::string* response) {
+    if (child_pid_ < 0) {
       SpawnTestProgram();
     }
 
+    current_test_name_ = test_name;
+
     uint32_t len = request.size();
     CheckedWrite(write_fd_, &len, sizeof(uint32_t));
     CheckedWrite(write_fd_, request.c_str(), request.size());
-    CheckedRead(read_fd_, &len, sizeof(uint32_t));
+
+    if (!TryRead(read_fd_, &len, sizeof(uint32_t))) {
+      // We failed to read from the child, assume a crash and try to reap.
+      GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_;
+
+      int status;
+      waitpid(child_pid_, &status, WEXITED);
+
+      string error_msg;
+      if (WIFEXITED(status)) {
+        StringAppendF(&error_msg,
+                      "child exited, status=%d", WEXITSTATUS(status));
+      } else if (WIFSIGNALED(status)) {
+        StringAppendF(&error_msg,
+                      "child killed by signal %d", WTERMSIG(status));
+      }
+      GOOGLE_LOG(INFO) << error_msg;
+      child_pid_ = -1;
+
+      conformance::ConformanceResponse response_obj;
+      response_obj.set_runtime_error(error_msg);
+      response_obj.SerializeToString(response);
+      return;
+    }
+
     response->resize(len);
     CheckedRead(read_fd_, (void*)response->c_str(), len);
   }
@@ -134,7 +170,7 @@
       CHECK_SYSCALL(close(fromproc_pipe_fd[1]));
       write_fd_ = toproc_pipe_fd[1];
       read_fd_ = fromproc_pipe_fd[0];
-      running_ = true;
+      child_pid_ = pid;
     } else {
       // Child.
       CHECK_SYSCALL(close(STDIN_FILENO));
@@ -158,30 +194,48 @@
 
   void CheckedWrite(int fd, const void *buf, size_t len) {
     if (write(fd, buf, len) != len) {
-      GOOGLE_LOG(FATAL) << "Error writing to test program: " << strerror(errno);
+      GOOGLE_LOG(FATAL) << current_test_name_
+                        << ": error writing to test program: "
+                        << strerror(errno);
     }
   }
 
-  void CheckedRead(int fd, void *buf, size_t len) {
+  bool TryRead(int fd, void *buf, size_t len) {
     size_t ofs = 0;
     while (len > 0) {
       ssize_t bytes_read = read(fd, (char*)buf + ofs, len);
 
       if (bytes_read == 0) {
-        GOOGLE_LOG(FATAL) << "Unexpected EOF from test program";
+        GOOGLE_LOG(ERROR) << current_test_name_
+                          << ": unexpected EOF from test program";
+        return false;
       } else if (bytes_read < 0) {
-        GOOGLE_LOG(FATAL) << "Error reading from test program: " << strerror(errno);
+        GOOGLE_LOG(ERROR) << current_test_name_
+                          << ": error reading from test program: "
+                          << strerror(errno);
+        return false;
       }
 
       len -= bytes_read;
       ofs += bytes_read;
     }
+
+    return true;
+  }
+
+  void CheckedRead(int fd, void *buf, size_t len) {
+    if (!TryRead(fd, buf, len)) {
+      GOOGLE_LOG(FATAL) << current_test_name_
+                        << ": error reading from test program: "
+                        << strerror(errno);
+    }
   }
 
   int write_fd_;
   int read_fd_;
-  bool running_;
+  pid_t child_pid_;
   std::string executable_;
+  std::string current_test_name_;
 };
 
 void UsageError() {
@@ -202,6 +256,12 @@
 
 void ParseFailureList(const char *filename, vector<string>* failure_list) {
   std::ifstream infile(filename);
+
+  if (!infile.is_open()) {
+    fprintf(stderr, "Couldn't open failure list file: %s\n", filename);
+    exit(1);
+  }
+
   for (string line; getline(infile, line);) {
     // Remove whitespace.
     line.erase(std::remove_if(line.begin(), line.end(), ::isspace),
@@ -217,16 +277,15 @@
 }
 
 int main(int argc, char *argv[]) {
-  int arg = 1;
   char *program;
   google::protobuf::ConformanceTestSuite suite;
 
+  vector<string> failure_list;
+
   for (int arg = 1; arg < argc; ++arg) {
     if (strcmp(argv[arg], "--failure_list") == 0) {
       if (++arg == argc) UsageError();
-      vector<string> failure_list;
       ParseFailureList(argv[arg], &failure_list);
-      suite.SetFailureList(failure_list);
     } else if (strcmp(argv[arg], "--verbose") == 0) {
       suite.SetVerbose(true);
     } else if (argv[arg][0] == '-') {
@@ -241,6 +300,7 @@
     }
   }
 
+  suite.SetFailureList(failure_list);
   ForkPipeRunner runner(program);
 
   std::string output;
diff --git a/conformance/failure_list_cpp.txt b/conformance/failure_list_cpp.txt
index 53d90c9..2ddf831 100644
--- a/conformance/failure_list_cpp.txt
+++ b/conformance/failure_list_cpp.txt
@@ -7,6 +7,89 @@
 # TODO(haberman): insert links to corresponding bugs tracking the issue.
 # Should we use GitHub issues or the Google-internal bug tracker?
 
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolFieldIntegerOne
+JsonInput.BoolFieldIntegerZero
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.BytesFieldNoPadding
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationHasZeroFractionalDigit.Validator
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameDuplicateDifferentCasing1
+JsonInput.FieldNameDuplicateDifferentCasing2
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldLeadingSpace
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldMinValue.ProtobufOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldNotInteger
+JsonInput.Int32FieldNotNumber
+JsonInput.Int32FieldTooLarge
+JsonInput.Int32FieldTooSmall
+JsonInput.Int32FieldTrailingSpace
+JsonInput.Int64FieldNotInteger
+JsonInput.Int64FieldNotNumber
+JsonInput.Int64FieldTooLarge
+JsonInput.Int64FieldTooSmall
+JsonInput.MapFieldValueIsNull
+JsonInput.OneofFieldDuplicate
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldTrailingComma
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
+JsonInput.StringFieldNotAString
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldSurrogatePair.ProtobufOutput
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.TimestampJsonInputLowercaseZ
+JsonInput.TimestampJsonInputMissingT
+JsonInput.TimestampJsonInputMissingZ
+JsonInput.TimestampJsonInputTooLarge
+JsonInput.TimestampJsonInputTooSmall
+JsonInput.TrailingCommaInAnObject
+JsonInput.Uint32FieldNotInteger
+JsonInput.Uint32FieldNotNumber
+JsonInput.Uint32FieldTooLarge
+JsonInput.Uint64FieldNotInteger
+JsonInput.Uint64FieldNotNumber
+JsonInput.Uint64FieldTooLarge
+JsonInput.WrapperTypesWithNullValue.JsonOutput
+JsonInput.WrapperTypesWithNullValue.ProtobufOutput
 ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
 ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
@@ -19,3 +102,5 @@
 ProtobufInput.PrematureEofInPackedField.UINT32
 ProtobufInput.PrematureEofInPackedField.UINT64
 ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_csharp.txt b/conformance/failure_list_csharp.txt
index e69de29..a46cee4 100644
--- a/conformance/failure_list_csharp.txt
+++ b/conformance/failure_list_csharp.txt
@@ -0,0 +1,16 @@
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.JsonOutput
+JsonInput.FieldNameWithMixedCases.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.Validator
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
diff --git a/conformance/failure_list_java.txt b/conformance/failure_list_java.txt
new file mode 100644
index 0000000..552c0cc
--- /dev/null
+++ b/conformance/failure_list_java.txt
@@ -0,0 +1,49 @@
+# This is the list of conformance tests that are known to fail for the Java
+# implementation right now.  These should be fixed.
+#
+# By listing them here we can keep tabs on which ones are failing and be sure
+# that we don't introduce regressions in other tests.
+
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.BoolFieldAllCapitalFalse
+JsonInput.BoolFieldAllCapitalTrue
+JsonInput.BoolFieldCamelCaseFalse
+JsonInput.BoolFieldCamelCaseTrue
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolMapFieldKeyNotQuoted
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.EnumFieldNotQuoted
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldPlusSign
+JsonInput.Int32MapFieldKeyNotQuoted
+JsonInput.Int64MapFieldKeyNotQuoted
+JsonInput.JsonWithComments
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.StringFieldNotAString
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.Uint32MapFieldKeyNotQuoted
+JsonInput.Uint64MapFieldKeyNotQuoted
diff --git a/conformance/failure_list_objc.txt b/conformance/failure_list_objc.txt
new file mode 100644
index 0000000..5dac350
--- /dev/null
+++ b/conformance/failure_list_objc.txt
@@ -0,0 +1,4 @@
+# No tests currently failing.
+#
+# 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-post26.txt b/conformance/failure_list_python-post26.txt
new file mode 100644
index 0000000..19d99b0
--- /dev/null
+++ b/conformance/failure_list_python-post26.txt
@@ -0,0 +1,2 @@
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldUnpairedHighSurrogate
diff --git a/conformance/failure_list_python.txt b/conformance/failure_list_python.txt
new file mode 100644
index 0000000..d2e5263
--- /dev/null
+++ b/conformance/failure_list_python.txt
@@ -0,0 +1,85 @@
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.Any.JsonOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.OriginalProtoFieldName.ProtobufOutput
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_python_cpp.txt b/conformance/failure_list_python_cpp.txt
new file mode 100644
index 0000000..7b5e45f
--- /dev/null
+++ b/conformance/failure_list_python_cpp.txt
@@ -0,0 +1,110 @@
+# This is the list of conformance tests that are known to fail for the
+# Python/C++ implementation right now.  These should be fixed.
+#
+# By listing them here we can keep tabs on which ones are failing and be sure
+# that we don't introduce regressions in other tests.
+#
+# TODO(haberman): insert links to corresponding bugs tracking the issue.
+# Should we use GitHub issues or the Google-internal bug tracker?
+
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.Any.JsonOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMissingS
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.OriginalProtoFieldName.ProtobufOutput
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+ProtobufInput.PrematureEofInPackedField.BOOL
+ProtobufInput.PrematureEofInPackedField.DOUBLE
+ProtobufInput.PrematureEofInPackedField.ENUM
+ProtobufInput.PrematureEofInPackedField.FIXED32
+ProtobufInput.PrematureEofInPackedField.FIXED64
+ProtobufInput.PrematureEofInPackedField.FLOAT
+ProtobufInput.PrematureEofInPackedField.INT32
+ProtobufInput.PrematureEofInPackedField.INT64
+ProtobufInput.PrematureEofInPackedField.SFIXED32
+ProtobufInput.PrematureEofInPackedField.SFIXED64
+ProtobufInput.PrematureEofInPackedField.SINT32
+ProtobufInput.PrematureEofInPackedField.SINT64
+ProtobufInput.PrematureEofInPackedField.UINT32
+ProtobufInput.PrematureEofInPackedField.UINT64
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt
index ff220cb..1b2e7d9 100644
--- a/conformance/failure_list_ruby.txt
+++ b/conformance/failure_list_ruby.txt
@@ -1,2 +1,337 @@
+# Many of the JSON tests are failing due to a simple bug:
+# fields are not camel-cased at all right now.  Once this
+# is fixed, this list should grow a lot shorter.
+
+DurationProtoInputTooLarge.JsonOutput
+DurationProtoInputTooSmall.JsonOutput
+FieldMaskNumbersDontRoundTrip.JsonOutput
+FieldMaskPathsDontRoundTrip.JsonOutput
+FieldMaskTooManyUnderscore.JsonOutput
+JsonInput.AllFieldAcceptNull.JsonOutput
+JsonInput.AllFieldAcceptNull.ProtobufOutput
+JsonInput.Any.JsonOutput
+JsonInput.AnyNested.JsonOutput
+JsonInput.AnyNested.ProtobufOutput
+JsonInput.Any.ProtobufOutput
+JsonInput.AnyUnorderedTypeTag.JsonOutput
+JsonInput.AnyUnorderedTypeTag.ProtobufOutput
+JsonInput.AnyWithDuration.JsonOutput
+JsonInput.AnyWithDuration.ProtobufOutput
+JsonInput.AnyWithFieldMask.JsonOutput
+JsonInput.AnyWithFieldMask.ProtobufOutput
+JsonInput.AnyWithInt32ValueWrapper.JsonOutput
+JsonInput.AnyWithInt32ValueWrapper.ProtobufOutput
+JsonInput.AnyWithStruct.JsonOutput
+JsonInput.AnyWithStruct.ProtobufOutput
+JsonInput.AnyWithTimestamp.JsonOutput
+JsonInput.AnyWithTimestamp.ProtobufOutput
+JsonInput.AnyWithValueForInteger.JsonOutput
+JsonInput.AnyWithValueForInteger.ProtobufOutput
+JsonInput.AnyWithValueForJsonObject.JsonOutput
+JsonInput.AnyWithValueForJsonObject.ProtobufOutput
+JsonInput.BoolFieldAllCapitalFalse
+JsonInput.BoolFieldAllCapitalTrue
+JsonInput.BoolFieldCamelCaseFalse
+JsonInput.BoolFieldCamelCaseTrue
+JsonInput.BoolFieldDoubleQuotedFalse
+JsonInput.BoolFieldDoubleQuotedTrue
+JsonInput.BoolFieldFalse.JsonOutput
+JsonInput.BoolFieldFalse.ProtobufOutput
+JsonInput.BoolFieldIntegerOne
+JsonInput.BoolFieldIntegerZero
+JsonInput.BoolFieldTrue.JsonOutput
+JsonInput.BoolFieldTrue.ProtobufOutput
+JsonInput.BoolMapEscapedKey.JsonOutput
+JsonInput.BoolMapEscapedKey.ProtobufOutput
+JsonInput.BoolMapField.JsonOutput
+JsonInput.BoolMapFieldKeyNotQuoted
+JsonInput.BoolMapField.ProtobufOutput
+JsonInput.BytesFieldInvalidBase64Characters
+JsonInput.BytesField.JsonOutput
+JsonInput.BytesFieldNoPadding
+JsonInput.BytesField.ProtobufOutput
+JsonInput.BytesRepeatedField.JsonOutput
+JsonInput.BytesRepeatedField.ProtobufOutput
+JsonInput.DoubleFieldInfinity.JsonOutput
+JsonInput.DoubleFieldInfinityNotQuoted
+JsonInput.DoubleFieldInfinity.ProtobufOutput
+JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
+JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
+JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
+JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
+JsonInput.DoubleFieldMinNegativeValue.JsonOutput
+JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
+JsonInput.DoubleFieldMinPositiveValue.JsonOutput
+JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
+JsonInput.DoubleFieldNan.JsonOutput
+JsonInput.DoubleFieldNanNotQuoted
+JsonInput.DoubleFieldNan.ProtobufOutput
+JsonInput.DoubleFieldNegativeInfinity.JsonOutput
+JsonInput.DoubleFieldNegativeInfinityNotQuoted
+JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
+JsonInput.DoubleFieldQuotedValue.JsonOutput
+JsonInput.DoubleFieldQuotedValue.ProtobufOutput
+JsonInput.DoubleFieldTooLarge
+JsonInput.DoubleFieldTooSmall
+JsonInput.DurationHas3FractionalDigits.Validator
+JsonInput.DurationHas6FractionalDigits.Validator
+JsonInput.DurationHas9FractionalDigits.Validator
+JsonInput.DurationHasZeroFractionalDigit.Validator
+JsonInput.DurationJsonInputTooLarge
+JsonInput.DurationJsonInputTooSmall
+JsonInput.DurationMaxValue.JsonOutput
+JsonInput.DurationMaxValue.ProtobufOutput
+JsonInput.DurationMinValue.JsonOutput
+JsonInput.DurationMinValue.ProtobufOutput
+JsonInput.DurationMissingS
+JsonInput.DurationRepeatedValue.JsonOutput
+JsonInput.DurationRepeatedValue.ProtobufOutput
+JsonInput.EnumField.JsonOutput
+JsonInput.EnumFieldNotQuoted
+JsonInput.EnumFieldNumericValueNonZero.JsonOutput
+JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
+JsonInput.EnumFieldNumericValueZero.JsonOutput
+JsonInput.EnumFieldNumericValueZero.ProtobufOutput
+JsonInput.EnumField.ProtobufOutput
+JsonInput.EnumFieldUnknownValue.Validator
+JsonInput.EnumRepeatedField.JsonOutput
+JsonInput.EnumRepeatedField.ProtobufOutput
+JsonInput.FieldMaskInvalidCharacter
+JsonInput.FieldMask.JsonOutput
+JsonInput.FieldMask.ProtobufOutput
+JsonInput.FieldNameDuplicate
+JsonInput.FieldNameDuplicateDifferentCasing1
+JsonInput.FieldNameDuplicateDifferentCasing2
+JsonInput.FieldNameEscaped.JsonOutput
+JsonInput.FieldNameInLowerCamelCase.Validator
+JsonInput.FieldNameInSnakeCase.JsonOutput
+JsonInput.FieldNameInSnakeCase.ProtobufOutput
+JsonInput.FieldNameNotQuoted
+JsonInput.FieldNameWithMixedCases.JsonOutput
+JsonInput.FieldNameWithMixedCases.ProtobufOutput
+JsonInput.FieldNameWithMixedCases.Validator
+JsonInput.FieldNameWithNumbers.JsonOutput
+JsonInput.FieldNameWithNumbers.ProtobufOutput
+JsonInput.FieldNameWithNumbers.Validator
+JsonInput.FloatFieldInfinity.JsonOutput
+JsonInput.FloatFieldInfinityNotQuoted
+JsonInput.FloatFieldInfinity.ProtobufOutput
+JsonInput.FloatFieldMaxNegativeValue.JsonOutput
+JsonInput.FloatFieldMaxNegativeValue.ProtobufOutput
+JsonInput.FloatFieldMaxPositiveValue.JsonOutput
+JsonInput.FloatFieldMaxPositiveValue.ProtobufOutput
+JsonInput.FloatFieldMinNegativeValue.JsonOutput
+JsonInput.FloatFieldMinNegativeValue.ProtobufOutput
+JsonInput.FloatFieldMinPositiveValue.JsonOutput
+JsonInput.FloatFieldMinPositiveValue.ProtobufOutput
+JsonInput.FloatFieldNan.JsonOutput
+JsonInput.FloatFieldNanNotQuoted
+JsonInput.FloatFieldNan.ProtobufOutput
+JsonInput.FloatFieldNegativeInfinity.JsonOutput
+JsonInput.FloatFieldNegativeInfinityNotQuoted
+JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
+JsonInput.FloatFieldQuotedValue.JsonOutput
+JsonInput.FloatFieldQuotedValue.ProtobufOutput
+JsonInput.FloatFieldTooLarge
+JsonInput.FloatFieldTooSmall
 JsonInput.HelloWorld.JsonOutput
 JsonInput.HelloWorld.ProtobufOutput
+JsonInput.Int32FieldExponentialFormat.JsonOutput
+JsonInput.Int32FieldExponentialFormat.ProtobufOutput
+JsonInput.Int32FieldFloatTrailingZero.JsonOutput
+JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
+JsonInput.Int32FieldLeadingSpace
+JsonInput.Int32FieldLeadingZero
+JsonInput.Int32FieldMaxFloatValue.JsonOutput
+JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Int32FieldMaxValue.JsonOutput
+JsonInput.Int32FieldMaxValue.ProtobufOutput
+JsonInput.Int32FieldMinFloatValue.JsonOutput
+JsonInput.Int32FieldMinFloatValue.ProtobufOutput
+JsonInput.Int32FieldMinValue.JsonOutput
+JsonInput.Int32FieldMinValue.ProtobufOutput
+JsonInput.Int32FieldNegativeWithLeadingZero
+JsonInput.Int32FieldNotInteger
+JsonInput.Int32FieldNotNumber
+JsonInput.Int32FieldPlusSign
+JsonInput.Int32FieldStringValueEscaped.JsonOutput
+JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
+JsonInput.Int32FieldStringValue.JsonOutput
+JsonInput.Int32FieldStringValue.ProtobufOutput
+JsonInput.Int32FieldTooLarge
+JsonInput.Int32FieldTooSmall
+JsonInput.Int32FieldTrailingSpace
+JsonInput.Int32MapEscapedKey.JsonOutput
+JsonInput.Int32MapEscapedKey.ProtobufOutput
+JsonInput.Int32MapField.JsonOutput
+JsonInput.Int32MapFieldKeyNotQuoted
+JsonInput.Int32MapField.ProtobufOutput
+JsonInput.Int64FieldBeString.Validator
+JsonInput.Int64FieldMaxValue.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.Int64FieldMaxValue.ProtobufOutput
+JsonInput.Int64FieldMinValue.JsonOutput
+JsonInput.Int64FieldMinValueNotQuoted.JsonOutput
+JsonInput.Int64FieldMinValueNotQuoted.ProtobufOutput
+JsonInput.Int64FieldMinValue.ProtobufOutput
+JsonInput.Int64FieldNotInteger
+JsonInput.Int64FieldNotNumber
+JsonInput.Int64FieldTooLarge
+JsonInput.Int64FieldTooSmall
+JsonInput.Int64MapEscapedKey.JsonOutput
+JsonInput.Int64MapEscapedKey.ProtobufOutput
+JsonInput.Int64MapField.JsonOutput
+JsonInput.Int64MapFieldKeyNotQuoted
+JsonInput.Int64MapField.ProtobufOutput
+JsonInput.JsonWithComments
+JsonInput.MapFieldKeyIsNull
+JsonInput.MapFieldValueIsNull
+JsonInput.MessageField.JsonOutput
+JsonInput.MessageField.ProtobufOutput
+JsonInput.MessageMapField.JsonOutput
+JsonInput.MessageMapField.ProtobufOutput
+JsonInput.MessageRepeatedField.JsonOutput
+JsonInput.MessageRepeatedField.ProtobufOutput
+JsonInput.OneofFieldDuplicate
+JsonInput.OptionalBoolWrapper.JsonOutput
+JsonInput.OptionalBoolWrapper.ProtobufOutput
+JsonInput.OptionalBytesWrapper.JsonOutput
+JsonInput.OptionalBytesWrapper.ProtobufOutput
+JsonInput.OptionalDoubleWrapper.JsonOutput
+JsonInput.OptionalDoubleWrapper.ProtobufOutput
+JsonInput.OptionalFloatWrapper.JsonOutput
+JsonInput.OptionalFloatWrapper.ProtobufOutput
+JsonInput.OptionalInt32Wrapper.JsonOutput
+JsonInput.OptionalInt32Wrapper.ProtobufOutput
+JsonInput.OptionalInt64Wrapper.JsonOutput
+JsonInput.OptionalInt64Wrapper.ProtobufOutput
+JsonInput.OptionalStringWrapper.JsonOutput
+JsonInput.OptionalStringWrapper.ProtobufOutput
+JsonInput.OptionalUint32Wrapper.JsonOutput
+JsonInput.OptionalUint32Wrapper.ProtobufOutput
+JsonInput.OptionalUint64Wrapper.JsonOutput
+JsonInput.OptionalUint64Wrapper.ProtobufOutput
+JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
+JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
+JsonInput.OriginalProtoFieldName.JsonOutput
+JsonInput.PrimitiveRepeatedField.JsonOutput
+JsonInput.PrimitiveRepeatedField.ProtobufOutput
+JsonInput.RepeatedBoolWrapper.JsonOutput
+JsonInput.RepeatedBoolWrapper.ProtobufOutput
+JsonInput.RepeatedBytesWrapper.JsonOutput
+JsonInput.RepeatedBytesWrapper.ProtobufOutput
+JsonInput.RepeatedDoubleWrapper.JsonOutput
+JsonInput.RepeatedDoubleWrapper.ProtobufOutput
+JsonInput.RepeatedFieldMessageElementIsNull
+JsonInput.RepeatedFieldPrimitiveElementIsNull
+JsonInput.RepeatedFieldTrailingComma
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotMessage
+JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotString
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
+JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotMessage
+JsonInput.RepeatedFloatWrapper.JsonOutput
+JsonInput.RepeatedFloatWrapper.ProtobufOutput
+JsonInput.RepeatedInt32Wrapper.JsonOutput
+JsonInput.RepeatedInt32Wrapper.ProtobufOutput
+JsonInput.RepeatedInt64Wrapper.JsonOutput
+JsonInput.RepeatedInt64Wrapper.ProtobufOutput
+JsonInput.RepeatedStringWrapper.JsonOutput
+JsonInput.RepeatedStringWrapper.ProtobufOutput
+JsonInput.RepeatedUint32Wrapper.JsonOutput
+JsonInput.RepeatedUint32Wrapper.ProtobufOutput
+JsonInput.RepeatedUint64Wrapper.JsonOutput
+JsonInput.RepeatedUint64Wrapper.ProtobufOutput
+JsonInput.StringFieldEscape.JsonOutput
+JsonInput.StringFieldEscape.ProtobufOutput
+JsonInput.StringFieldInvalidEscape
+JsonInput.StringField.JsonOutput
+JsonInput.StringFieldNotAString
+JsonInput.StringField.ProtobufOutput
+JsonInput.StringFieldSurrogateInWrongOrder
+JsonInput.StringFieldSurrogatePair.JsonOutput
+JsonInput.StringFieldSurrogatePair.ProtobufOutput
+JsonInput.StringFieldUnicodeEscape.JsonOutput
+JsonInput.StringFieldUnicodeEscape.ProtobufOutput
+JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
+JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
+JsonInput.StringFieldUnicode.JsonOutput
+JsonInput.StringFieldUnicode.ProtobufOutput
+JsonInput.StringFieldUnpairedHighSurrogate
+JsonInput.StringFieldUnpairedLowSurrogate
+JsonInput.StringFieldUnterminatedEscape
+JsonInput.StringFieldUppercaseEscapeLetter
+JsonInput.StringRepeatedField.JsonOutput
+JsonInput.StringRepeatedField.ProtobufOutput
+JsonInput.Struct.JsonOutput
+JsonInput.Struct.ProtobufOutput
+JsonInput.TimestampHas3FractionalDigits.Validator
+JsonInput.TimestampHas6FractionalDigits.Validator
+JsonInput.TimestampHas9FractionalDigits.Validator
+JsonInput.TimestampHasZeroFractionalDigit.Validator
+JsonInput.TimestampJsonInputLowercaseT
+JsonInput.TimestampJsonInputLowercaseZ
+JsonInput.TimestampJsonInputMissingT
+JsonInput.TimestampJsonInputMissingZ
+JsonInput.TimestampJsonInputTooLarge
+JsonInput.TimestampJsonInputTooSmall
+JsonInput.TimestampMaxValue.JsonOutput
+JsonInput.TimestampMaxValue.ProtobufOutput
+JsonInput.TimestampMinValue.JsonOutput
+JsonInput.TimestampMinValue.ProtobufOutput
+JsonInput.TimestampRepeatedValue.JsonOutput
+JsonInput.TimestampRepeatedValue.ProtobufOutput
+JsonInput.TimestampWithNegativeOffset.JsonOutput
+JsonInput.TimestampWithNegativeOffset.ProtobufOutput
+JsonInput.TimestampWithPositiveOffset.JsonOutput
+JsonInput.TimestampWithPositiveOffset.ProtobufOutput
+JsonInput.TimestampZeroNormalized.Validator
+JsonInput.TrailingCommaInAnObject
+JsonInput.Uint32FieldMaxFloatValue.JsonOutput
+JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
+JsonInput.Uint32FieldMaxValue.JsonOutput
+JsonInput.Uint32FieldMaxValue.ProtobufOutput
+JsonInput.Uint32FieldNotInteger
+JsonInput.Uint32FieldNotNumber
+JsonInput.Uint32FieldTooLarge
+JsonInput.Uint32MapField.JsonOutput
+JsonInput.Uint32MapFieldKeyNotQuoted
+JsonInput.Uint32MapField.ProtobufOutput
+JsonInput.Uint64FieldBeString.Validator
+JsonInput.Uint64FieldMaxValue.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput
+JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput
+JsonInput.Uint64FieldMaxValue.ProtobufOutput
+JsonInput.Uint64FieldNotInteger
+JsonInput.Uint64FieldNotNumber
+JsonInput.Uint64FieldTooLarge
+JsonInput.Uint64MapField.JsonOutput
+JsonInput.Uint64MapFieldKeyNotQuoted
+JsonInput.Uint64MapField.ProtobufOutput
+JsonInput.ValueAcceptBool.JsonOutput
+JsonInput.ValueAcceptBool.ProtobufOutput
+JsonInput.ValueAcceptFloat.JsonOutput
+JsonInput.ValueAcceptFloat.ProtobufOutput
+JsonInput.ValueAcceptInteger.JsonOutput
+JsonInput.ValueAcceptInteger.ProtobufOutput
+JsonInput.ValueAcceptList.JsonOutput
+JsonInput.ValueAcceptList.ProtobufOutput
+JsonInput.ValueAcceptNull.JsonOutput
+JsonInput.ValueAcceptNull.ProtobufOutput
+JsonInput.ValueAcceptObject.JsonOutput
+JsonInput.ValueAcceptObject.ProtobufOutput
+JsonInput.ValueAcceptString.JsonOutput
+JsonInput.ValueAcceptString.ProtobufOutput
+JsonInput.WrapperTypesWithNullValue.JsonOutput
+JsonInput.WrapperTypesWithNullValue.ProtobufOutput
+ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
+ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
+ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
+ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
+TimestampProtoInputTooLarge.JsonOutput
+TimestampProtoInputTooSmall.JsonOutput
diff --git a/conformance/third_party/jsoncpp/json.h b/conformance/third_party/jsoncpp/json.h
new file mode 100644
index 0000000..42e7e7f
--- /dev/null
+++ b/conformance/third_party/jsoncpp/json.h
@@ -0,0 +1,2075 @@
+/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation, 
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all 
+jurisdictions which recognize such a disclaimer. In such jurisdictions, 
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this 
+software may choose to accept it either as 1) Public Domain, 2) under the 
+conditions of the MIT License (see below), or 3) under the terms of dual 
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+   
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_AMALGATED_H_INCLUDED
+# define JSON_AMALGATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// DO NOT EDIT. This file (and "version") is generated by CMake.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+# define JSON_VERSION_H_INCLUDED
+
+# define JSONCPP_VERSION_STRING "1.6.5"
+# define JSONCPP_VERSION_MAJOR 1
+# define JSONCPP_VERSION_MINOR 6
+# define JSONCPP_VERSION_PATCH 5
+# define JSONCPP_VERSION_QUALIFIER
+# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//#  define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//#  define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) // MSVC
+#  if _MSC_VER <= 1200 // MSVC 6
+    // Microsoft Visual Studio 6 only support conversion from __int64 to double
+    // (no conversion from unsigned __int64).
+#    define JSON_USE_INT64_DOUBLE_CONVERSION 1
+    // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+    // characters in the debug information)
+    // All projects I've ever seen with VS6 were using this globally (not bothering
+    // with pragma push/pop).
+#    pragma warning(disable : 4786)
+#  endif // MSVC 6
+
+#  if _MSC_VER >= 1500 // MSVC 2008
+    /// Indicates that the following function is deprecated.
+#    define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#  endif
+
+#endif // defined(_MSC_VER)
+
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+
+#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif // MSVC >= 2010
+
+#ifdef __clang__
+#if __has_feature(cxx_rvalue_references)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif  // has_feature
+
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define JSON_HAS_RVALUE_REFERENCES 1
+#endif  // GXX_EXPERIMENTAL
+
+#endif // __clang__ || __GNUC__
+
+#endif // not defined JSON_HAS_RVALUE_REFERENCES
+
+#ifndef JSON_HAS_RVALUE_REFERENCES
+#define JSON_HAS_RVALUE_REFERENCES 0
+#endif
+
+#ifdef __clang__
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#    define JSONCPP_DEPRECATED(message)  __attribute__ ((deprecated(message)))
+#  elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#    define JSONCPP_DEPRECATED(message)  __attribute__((__deprecated__))
+#  endif  // GNUC version
+#endif // __clang__ || __GNUC__
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else                 // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else                 // if defined(_MSC_VER) // Other platforms, use long long
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+  /** \brief A configuration that allows all features and assumes all strings
+   * are UTF-8.
+   * - C & C++ comments are allowed
+   * - Root object can be any JSON value
+   * - Assumes Value strings are encoded in UTF-8
+   */
+  static Features all();
+
+  /** \brief A configuration that is strictly compatible with the JSON
+   * specification.
+   * - Comments are forbidden.
+   * - Root object must be either an array or an object value.
+   * - Assumes Value strings are encoded in UTF-8
+   */
+  static Features strictMode();
+
+  /** \brief Initialize the configuration like JsonConfig::allFeatures;
+   */
+  Features();
+
+  /// \c true if comments are allowed. Default: \c true.
+  bool allowComments_;
+
+  /// \c true if root must be either an array or an object value. Default: \c
+  /// false.
+  bool strictRoot_;
+
+  /// \c true if dropped null placeholders are allowed. Default: \c false.
+  bool allowDroppedNullPlaceholders_;
+
+  /// \c true if numeric object key are allowed. Default: \c false.
+  bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <string>
+#include <vector>
+#include <exception>
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include <map>
+#else
+#include <cpptl/smallmap.h>
+#endif
+#ifdef JSON_USE_CPPTL
+#include <cpptl/forwards.h>
+#endif
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+/** Base class for all exceptions we throw.
+ *
+ * We use nothing but these internally. Of course, STL can throw others.
+ */
+class JSON_API Exception : public std::exception {
+public:
+  Exception(std::string const& msg);
+  ~Exception() throw() override;
+  char const* what() const throw() override;
+protected:
+  std::string msg_;
+};
+
+/** Exceptions which the user cannot easily avoid.
+ *
+ * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
+ * 
+ * \remark derived from Json::Exception
+ */
+class JSON_API RuntimeError : public Exception {
+public:
+  RuntimeError(std::string const& msg);
+};
+
+/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
+ *
+ * These are precondition-violations (user bugs) and internal errors (our bugs).
+ * 
+ * \remark derived from Json::Exception
+ */
+class JSON_API LogicError : public Exception {
+public:
+  LogicError(std::string const& msg);
+};
+
+/// used internally
+void throwRuntimeError(std::string const& msg);
+/// used internally
+void throwLogicError(std::string const& msg);
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType {
+  nullValue = 0, ///< 'null' value
+  intValue,      ///< signed integer value
+  uintValue,     ///< unsigned integer value
+  realValue,     ///< double value
+  stringValue,   ///< UTF-8 string value
+  booleanValue,  ///< bool value
+  arrayValue,    ///< array value (ordered list)
+  objectValue    ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement {
+  commentBefore = 0,      ///< a comment placed on the line before a value
+  commentAfterOnSameLine, ///< a comment just after a value on the same line
+  commentAfter, ///< a comment on the line after a value (only make sense for
+  /// root value)
+  numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString {
+public:
+  explicit StaticString(const char* czstring) : c_str_(czstring) {}
+
+  operator const char*() const { return c_str_; }
+
+  const char* c_str() const { return c_str_; }
+
+private:
+  const char* c_str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * Values of an #objectValue or #arrayValue can be accessed using operator[]()
+ * methods.
+ * Non-const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resized and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtain default value in the case the
+ * required element does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ *
+ * \note #Value string-length fit in size_t, but keys must be < 2^30.
+ * (The reason is an implementation detail.) A #CharReader will raise an
+ * exception if a bound is exceeded to avoid security holes in your app,
+ * but the Value API does *not* check bounds. That is the responsibility
+ * of the caller.
+ */
+class JSON_API Value {
+  friend class ValueIteratorBase;
+public:
+  typedef std::vector<std::string> Members;
+  typedef ValueIterator iterator;
+  typedef ValueConstIterator const_iterator;
+  typedef Json::UInt UInt;
+  typedef Json::Int Int;
+#if defined(JSON_HAS_INT64)
+  typedef Json::UInt64 UInt64;
+  typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+  typedef Json::LargestInt LargestInt;
+  typedef Json::LargestUInt LargestUInt;
+  typedef Json::ArrayIndex ArrayIndex;
+
+  static const Value& null;  ///< We regret this reference to a global instance; prefer the simpler Value().
+  static const Value& nullRef;  ///< just a kludge for binary-compatibility; same as null
+  /// Minimum signed integer value that can be stored in a Json::Value.
+  static const LargestInt minLargestInt;
+  /// Maximum signed integer value that can be stored in a Json::Value.
+  static const LargestInt maxLargestInt;
+  /// Maximum unsigned integer value that can be stored in a Json::Value.
+  static const LargestUInt maxLargestUInt;
+
+  /// Minimum signed int value that can be stored in a Json::Value.
+  static const Int minInt;
+  /// Maximum signed int value that can be stored in a Json::Value.
+  static const Int maxInt;
+  /// Maximum unsigned int value that can be stored in a Json::Value.
+  static const UInt maxUInt;
+
+#if defined(JSON_HAS_INT64)
+  /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+  static const Int64 minInt64;
+  /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+  static const Int64 maxInt64;
+  /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+  static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+  class CZString {
+  public:
+    enum DuplicationPolicy {
+      noDuplication = 0,
+      duplicate,
+      duplicateOnCopy
+    };
+    CZString(ArrayIndex index);
+    CZString(char const* str, unsigned length, DuplicationPolicy allocate);
+    CZString(CZString const& other);
+#if JSON_HAS_RVALUE_REFERENCES
+    CZString(CZString&& other);
+#endif
+    ~CZString();
+    CZString& operator=(CZString other);
+    bool operator<(CZString const& other) const;
+    bool operator==(CZString const& other) const;
+    ArrayIndex index() const;
+    //const char* c_str() const; ///< \deprecated
+    char const* data() const;
+    unsigned length() const;
+    bool isStaticString() const;
+
+  private:
+    void swap(CZString& other);
+
+    struct StringStorage {
+      unsigned policy_: 2;
+      unsigned length_: 30; // 1GB max
+    };
+
+    char const* cstr_;  // actually, a prefixed string, unless policy is noDup
+    union {
+      ArrayIndex index_;
+      StringStorage storage_;
+    };
+  };
+
+public:
+#ifndef JSON_USE_CPPTL_SMALLMAP
+  typedef std::map<CZString, Value> ObjectValues;
+#else
+  typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#endif // ifndef JSON_USE_CPPTL_SMALLMAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+public:
+  /** \brief Create a default Value of the given type.
+
+    This is a very useful constructor.
+    To create an empty array, pass arrayValue.
+    To create an empty object, pass objectValue.
+    Another Value can then be set to this one by assignment.
+This is useful since clear() and resize() will not alter types.
+
+    Examples:
+\code
+Json::Value null_value; // null
+Json::Value arr_value(Json::arrayValue); // []
+Json::Value obj_value(Json::objectValue); // {}
+\endcode
+  */
+  Value(ValueType type = nullValue);
+  Value(Int value);
+  Value(UInt value);
+#if defined(JSON_HAS_INT64)
+  Value(Int64 value);
+  Value(UInt64 value);
+#endif // if defined(JSON_HAS_INT64)
+  Value(double value);
+  Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
+  Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
+  /** \brief Constructs a value from a static string.
+
+   * Like other value string constructor but do not duplicate the string for
+   * internal storage. The given string must remain alive after the call to this
+   * constructor.
+   * \note This works only for null-terminated strings. (We cannot change the
+   *   size of this class, so we have nowhere to store the length,
+   *   which might be computed later for various operations.)
+   *
+   * Example of usage:
+   * \code
+   * static StaticString foo("some text");
+   * Json::Value aValue(foo);
+   * \endcode
+   */
+  Value(const StaticString& value);
+  Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too.
+#ifdef JSON_USE_CPPTL
+  Value(const CppTL::ConstString& value);
+#endif
+  Value(bool value);
+  /// Deep copy.
+  Value(const Value& other);
+#if JSON_HAS_RVALUE_REFERENCES
+  /// Move constructor
+  Value(Value&& other);
+#endif
+  ~Value();
+
+  /// Deep copy, then swap(other).
+  /// \note Over-write existing comments. To preserve comments, use #swapPayload().
+  Value& operator=(Value other);
+  /// Swap everything.
+  void swap(Value& other);
+  /// Swap values but leave comments and source offsets in place.
+  void swapPayload(Value& other);
+
+  ValueType type() const;
+
+  /// Compare payload only, not comments etc.
+  bool operator<(const Value& other) const;
+  bool operator<=(const Value& other) const;
+  bool operator>=(const Value& other) const;
+  bool operator>(const Value& other) const;
+  bool operator==(const Value& other) const;
+  bool operator!=(const Value& other) const;
+  int compare(const Value& other) const;
+
+  const char* asCString() const; ///< Embedded zeroes could cause you trouble!
+  std::string asString() const; ///< Embedded zeroes are possible.
+  /** Get raw char* of string-value.
+   *  \return false if !string. (Seg-fault if str or end are NULL.)
+   */
+  bool getString(
+      char const** begin, char const** end) const;
+#ifdef JSON_USE_CPPTL
+  CppTL::ConstString asConstString() const;
+#endif
+  Int asInt() const;
+  UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+  Int64 asInt64() const;
+  UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+  LargestInt asLargestInt() const;
+  LargestUInt asLargestUInt() const;
+  float asFloat() const;
+  double asDouble() const;
+  bool asBool() const;
+
+  bool isNull() const;
+  bool isBool() const;
+  bool isInt() const;
+  bool isInt64() const;
+  bool isUInt() const;
+  bool isUInt64() const;
+  bool isIntegral() const;
+  bool isDouble() const;
+  bool isNumeric() const;
+  bool isString() const;
+  bool isArray() const;
+  bool isObject() const;
+
+  bool isConvertibleTo(ValueType other) const;
+
+  /// Number of values in array or object
+  ArrayIndex size() const;
+
+  /// \brief Return true if empty array, empty object, or null;
+  /// otherwise, false.
+  bool empty() const;
+
+  /// Return isNull()
+  bool operator!() const;
+
+  /// Remove all object members and array elements.
+  /// \pre type() is arrayValue, objectValue, or nullValue
+  /// \post type() is unchanged
+  void clear();
+
+  /// Resize the array to size elements.
+  /// New elements are initialized to null.
+  /// May only be called on nullValue or arrayValue.
+  /// \pre type() is arrayValue or nullValue
+  /// \post type() is arrayValue
+  void resize(ArrayIndex size);
+
+  /// Access an array element (zero based index ).
+  /// If the array contains less than index element, then null value are
+  /// inserted
+  /// in the array so that its size is index+1.
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  Value& operator[](ArrayIndex index);
+
+  /// Access an array element (zero based index ).
+  /// If the array contains less than index element, then null value are
+  /// inserted
+  /// in the array so that its size is index+1.
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  Value& operator[](int index);
+
+  /// Access an array element (zero based index )
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  const Value& operator[](ArrayIndex index) const;
+
+  /// Access an array element (zero based index )
+  /// (You may need to say 'value[0u]' to get your compiler to distinguish
+  ///  this from the operator[] which takes a string.)
+  const Value& operator[](int index) const;
+
+  /// If the array contains at least index+1 elements, returns the element
+  /// value,
+  /// otherwise returns defaultValue.
+  Value get(ArrayIndex index, const Value& defaultValue) const;
+  /// Return true if index < size().
+  bool isValidIndex(ArrayIndex index) const;
+  /// \brief Append value to array at the end.
+  ///
+  /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+  Value& append(const Value& value);
+
+  /// Access an object value by name, create a null member if it does not exist.
+  /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
+  ///  Exceeding that will cause an exception.
+  Value& operator[](const char* key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  const Value& operator[](const char* key) const;
+  /// Access an object value by name, create a null member if it does not exist.
+  /// \param key may contain embedded nulls.
+  Value& operator[](const std::string& key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  /// \param key may contain embedded nulls.
+  const Value& operator[](const std::string& key) const;
+  /** \brief Access an object value by name, create a null member if it does not
+   exist.
+
+   * If the object has no entry for that name, then the member name used to store
+   * the new entry is not duplicated.
+   * Example of use:
+   * \code
+   * Json::Value object;
+   * static const StaticString code("code");
+   * object[code] = 1234;
+   * \endcode
+   */
+  Value& operator[](const StaticString& key);
+#ifdef JSON_USE_CPPTL
+  /// Access an object value by name, create a null member if it does not exist.
+  Value& operator[](const CppTL::ConstString& key);
+  /// Access an object value by name, returns null if there is no member with
+  /// that name.
+  const Value& operator[](const CppTL::ConstString& key) const;
+#endif
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  Value get(const char* key, const Value& defaultValue) const;
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  /// \note key may contain embedded nulls.
+  Value get(const char* begin, const char* end, const Value& defaultValue) const;
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  /// \param key may contain embedded nulls.
+  Value get(const std::string& key, const Value& defaultValue) const;
+#ifdef JSON_USE_CPPTL
+  /// Return the member named key if it exist, defaultValue otherwise.
+  /// \note deep copy
+  Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
+#endif
+  /// Most general and efficient version of isMember()const, get()const,
+  /// and operator[]const
+  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+  Value const* find(char const* begin, char const* end) const;
+  /// Most general and efficient version of object-mutators.
+  /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
+  /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
+  Value const* demand(char const* begin, char const* end);
+  /// \brief Remove and return the named member.
+  ///
+  /// Do nothing if it did not exist.
+  /// \return the removed Value, or null.
+  /// \pre type() is objectValue or nullValue
+  /// \post type() is unchanged
+  /// \deprecated
+  Value removeMember(const char* key);
+  /// Same as removeMember(const char*)
+  /// \param key may contain embedded nulls.
+  /// \deprecated
+  Value removeMember(const std::string& key);
+  /// Same as removeMember(const char* begin, const char* end, Value* removed),
+  /// but 'key' is null-terminated.
+  bool removeMember(const char* key, Value* removed);
+  /** \brief Remove the named map member.
+
+      Update 'removed' iff removed.
+      \param key may contain embedded nulls.
+      \return true iff removed (no exceptions)
+  */
+  bool removeMember(std::string const& key, Value* removed);
+  /// Same as removeMember(std::string const& key, Value* removed)
+  bool removeMember(const char* begin, const char* end, Value* removed);
+  /** \brief Remove the indexed array element.
+
+      O(n) expensive operations.
+      Update 'removed' iff removed.
+      \return true iff removed (no exceptions)
+  */
+  bool removeIndex(ArrayIndex i, Value* removed);
+
+  /// Return true if the object has a member named key.
+  /// \note 'key' must be null-terminated.
+  bool isMember(const char* key) const;
+  /// Return true if the object has a member named key.
+  /// \param key may contain embedded nulls.
+  bool isMember(const std::string& key) const;
+  /// Same as isMember(std::string const& key)const
+  bool isMember(const char* begin, const char* end) const;
+#ifdef JSON_USE_CPPTL
+  /// Return true if the object has a member named key.
+  bool isMember(const CppTL::ConstString& key) const;
+#endif
+
+  /// \brief Return a list of the member names.
+  ///
+  /// If null, return an empty list.
+  /// \pre type() is objectValue or nullValue
+  /// \post if type() was nullValue, it remains nullValue
+  Members getMemberNames() const;
+
+  //# ifdef JSON_USE_CPPTL
+  //      EnumMemberNames enumMemberNames() const;
+  //      EnumValues enumValues() const;
+  //# endif
+
+  /// \deprecated Always pass len.
+  JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.")
+  void setComment(const char* comment, CommentPlacement placement);
+  /// Comments must be //... or /* ... */
+  void setComment(const char* comment, size_t len, CommentPlacement placement);
+  /// Comments must be //... or /* ... */
+  void setComment(const std::string& comment, CommentPlacement placement);
+  bool hasComment(CommentPlacement placement) const;
+  /// Include delimiters and embedded newlines.
+  std::string getComment(CommentPlacement placement) const;
+
+  std::string toStyledString() const;
+
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  iterator begin();
+  iterator end();
+
+  // Accessors for the [start, limit) range of bytes within the JSON text from
+  // which this value was parsed, if any.
+  void setOffsetStart(size_t start);
+  void setOffsetLimit(size_t limit);
+  size_t getOffsetStart() const;
+  size_t getOffsetLimit() const;
+
+private:
+  void initBasic(ValueType type, bool allocated = false);
+
+  Value& resolveReference(const char* key);
+  Value& resolveReference(const char* key, const char* end);
+
+  struct CommentInfo {
+    CommentInfo();
+    ~CommentInfo();
+
+    void setComment(const char* text, size_t len);
+
+    char* comment_;
+  };
+
+  // struct MemberNamesTransform
+  //{
+  //   typedef const char *result_type;
+  //   const char *operator()( const CZString &name ) const
+  //   {
+  //      return name.c_str();
+  //   }
+  //};
+
+  union ValueHolder {
+    LargestInt int_;
+    LargestUInt uint_;
+    double real_;
+    bool bool_;
+    char* string_;  // actually ptr to unsigned, followed by str, unless !allocated_
+    ObjectValues* map_;
+  } value_;
+  ValueType type_ : 8;
+  unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+                               // If not allocated_, string_ must be null-terminated.
+  CommentInfo* comments_;
+
+  // [start, limit) byte offsets in the source JSON text from which this Value
+  // was extracted.
+  size_t start_;
+  size_t limit_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to
+ * access a node.
+ */
+class JSON_API PathArgument {
+public:
+  friend class Path;
+
+  PathArgument();
+  PathArgument(ArrayIndex index);
+  PathArgument(const char* key);
+  PathArgument(const std::string& key);
+
+private:
+  enum Kind {
+    kindNone = 0,
+    kindIndex,
+    kindKey
+  };
+  std::string key_;
+  ArrayIndex index_;
+  Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class JSON_API Path {
+public:
+  Path(const std::string& path,
+       const PathArgument& a1 = PathArgument(),
+       const PathArgument& a2 = PathArgument(),
+       const PathArgument& a3 = PathArgument(),
+       const PathArgument& a4 = PathArgument(),
+       const PathArgument& a5 = PathArgument());
+
+  const Value& resolve(const Value& root) const;
+  Value resolve(const Value& root, const Value& defaultValue) const;
+  /// Creates the "path" to access the specified node and returns a reference on
+  /// the node.
+  Value& make(Value& root) const;
+
+private:
+  typedef std::vector<const PathArgument*> InArgs;
+  typedef std::vector<PathArgument> Args;
+
+  void makePath(const std::string& path, const InArgs& in);
+  void addPathInArg(const std::string& path,
+                    const InArgs& in,
+                    InArgs::const_iterator& itInArg,
+                    PathArgument::Kind kind);
+  void invalidPath(const std::string& path, int location);
+
+  Args args_;
+};
+
+/** \brief base class for Value iterators.
+ *
+ */
+class JSON_API ValueIteratorBase {
+public:
+  typedef std::bidirectional_iterator_tag iterator_category;
+  typedef unsigned int size_t;
+  typedef int difference_type;
+  typedef ValueIteratorBase SelfType;
+
+  bool operator==(const SelfType& other) const { return isEqual(other); }
+
+  bool operator!=(const SelfType& other) const { return !isEqual(other); }
+
+  difference_type operator-(const SelfType& other) const {
+    return other.computeDistance(*this);
+  }
+
+  /// Return either the index or the member name of the referenced value as a
+  /// Value.
+  Value key() const;
+
+  /// Return the index of the referenced Value, or -1 if it is not an arrayValue.
+  UInt index() const;
+
+  /// Return the member name of the referenced Value, or "" if it is not an
+  /// objectValue.
+  /// \note Avoid `c_str()` on result, as embedded zeroes are possible.
+  std::string name() const;
+
+  /// Return the member name of the referenced Value. "" if it is not an
+  /// objectValue.
+  /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
+  JSONCPP_DEPRECATED("Use `key = name();` instead.")
+  char const* memberName() const;
+  /// Return the member name of the referenced Value, or NULL if it is not an
+  /// objectValue.
+  /// \note Better version than memberName(). Allows embedded nulls.
+  char const* memberName(char const** end) const;
+
+protected:
+  Value& deref() const;
+
+  void increment();
+
+  void decrement();
+
+  difference_type computeDistance(const SelfType& other) const;
+
+  bool isEqual(const SelfType& other) const;
+
+  void copy(const SelfType& other);
+
+private:
+  Value::ObjectValues::iterator current_;
+  // Indicates that iterator is for a null value.
+  bool isNull_;
+
+public:
+  // For some reason, BORLAND needs these at the end, rather
+  // than earlier. No idea why.
+  ValueIteratorBase();
+  explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class JSON_API ValueConstIterator : public ValueIteratorBase {
+  friend class Value;
+
+public:
+  typedef const Value value_type;
+  //typedef unsigned int size_t;
+  //typedef int difference_type;
+  typedef const Value& reference;
+  typedef const Value* pointer;
+  typedef ValueConstIterator SelfType;
+
+  ValueConstIterator();
+  ValueConstIterator(ValueIterator const& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+  explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
+public:
+  SelfType& operator=(const ValueIteratorBase& other);
+
+  SelfType operator++(int) {
+    SelfType temp(*this);
+    ++*this;
+    return temp;
+  }
+
+  SelfType operator--(int) {
+    SelfType temp(*this);
+    --*this;
+    return temp;
+  }
+
+  SelfType& operator--() {
+    decrement();
+    return *this;
+  }
+
+  SelfType& operator++() {
+    increment();
+    return *this;
+  }
+
+  reference operator*() const { return deref(); }
+
+  pointer operator->() const { return &deref(); }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class JSON_API ValueIterator : public ValueIteratorBase {
+  friend class Value;
+
+public:
+  typedef Value value_type;
+  typedef unsigned int size_t;
+  typedef int difference_type;
+  typedef Value& reference;
+  typedef Value* pointer;
+  typedef ValueIterator SelfType;
+
+  ValueIterator();
+  explicit ValueIterator(const ValueConstIterator& other);
+  ValueIterator(const ValueIterator& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+  explicit ValueIterator(const Value::ObjectValues::iterator& current);
+public:
+  SelfType& operator=(const SelfType& other);
+
+  SelfType operator++(int) {
+    SelfType temp(*this);
+    ++*this;
+    return temp;
+  }
+
+  SelfType operator--(int) {
+    SelfType temp(*this);
+    --*this;
+    return temp;
+  }
+
+  SelfType& operator--() {
+    decrement();
+    return *this;
+  }
+
+  SelfType& operator++() {
+    increment();
+    return *this;
+  }
+
+  reference operator*() const { return deref(); }
+
+  pointer operator->() const { return &deref(); }
+};
+
+} // namespace Json
+
+
+namespace std {
+/// Specialize std::swap() for Json::Value.
+template<>
+inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
+}
+
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+#define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "features.h"
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <deque>
+#include <iosfwd>
+#include <stack>
+#include <string>
+#include <istream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
+ *Value.
+ *
+ * \deprecated Use CharReader and CharReaderBuilder.
+ */
+class JSON_API Reader {
+public:
+  typedef char Char;
+  typedef const Char* Location;
+
+  /** \brief An error tagged with where in the JSON text it was encountered.
+   *
+   * The offsets give the [start, limit) range of bytes within the text. Note
+   * that this is bytes, not codepoints.
+   *
+   */
+  struct StructuredError {
+    size_t offset_start;
+    size_t offset_limit;
+    std::string message;
+  };
+
+  /** \brief Constructs a Reader allowing all features
+   * for parsing.
+   */
+  Reader();
+
+  /** \brief Constructs a Reader allowing the specified feature set
+   * for parsing.
+   */
+  Reader(const Features& features);
+
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   * document.
+   * \param document UTF-8 encoded string containing the document to read.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param collectComments \c true to collect comment and allow writing them
+   * back during
+   *                        serialization, \c false to discard comments.
+   *                        This parameter is ignored if
+   * Features::allowComments_
+   *                        is \c false.
+   * \return \c true if the document was successfully parsed, \c false if an
+   * error occurred.
+   */
+  bool
+  parse(const std::string& document, Value& root, bool collectComments = true);
+
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   document.
+   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+   document to read.
+   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+   document to read.
+   *               Must be >= beginDoc.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param collectComments \c true to collect comment and allow writing them
+   back during
+   *                        serialization, \c false to discard comments.
+   *                        This parameter is ignored if
+   Features::allowComments_
+   *                        is \c false.
+   * \return \c true if the document was successfully parsed, \c false if an
+   error occurred.
+   */
+  bool parse(const char* beginDoc,
+             const char* endDoc,
+             Value& root,
+             bool collectComments = true);
+
+  /// \brief Parse from input stream.
+  /// \see Json::operator>>(std::istream&, Json::Value&).
+  bool parse(std::istream& is, Value& root, bool collectComments = true);
+
+  /** \brief Returns a user friendly string that list errors in the parsed
+   * document.
+   * \return Formatted error message with the list of errors with their location
+   * in
+   *         the parsed document. An empty string is returned if no error
+   * occurred
+   *         during parsing.
+   * \deprecated Use getFormattedErrorMessages() instead (typo fix).
+   */
+  JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
+  std::string getFormatedErrorMessages() const;
+
+  /** \brief Returns a user friendly string that list errors in the parsed
+   * document.
+   * \return Formatted error message with the list of errors with their location
+   * in
+   *         the parsed document. An empty string is returned if no error
+   * occurred
+   *         during parsing.
+   */
+  std::string getFormattedErrorMessages() const;
+
+  /** \brief Returns a vector of structured erros encounted while parsing.
+   * \return A (possibly empty) vector of StructuredError objects. Currently
+   *         only one error can be returned, but the caller should tolerate
+   * multiple
+   *         errors.  This can occur if the parser recovers from a non-fatal
+   *         parse error and then encounters additional errors.
+   */
+  std::vector<StructuredError> getStructuredErrors() const;
+
+  /** \brief Add a semantic error message.
+   * \param value JSON Value location associated with the error
+   * \param message The error message.
+   * \return \c true if the error was successfully added, \c false if the
+   * Value offset exceeds the document size.
+   */
+  bool pushError(const Value& value, const std::string& message);
+
+  /** \brief Add a semantic error message with extra context.
+   * \param value JSON Value location associated with the error
+   * \param message The error message.
+   * \param extra Additional JSON Value location to contextualize the error
+   * \return \c true if the error was successfully added, \c false if either
+   * Value offset exceeds the document size.
+   */
+  bool pushError(const Value& value, const std::string& message, const Value& extra);
+
+  /** \brief Return whether there are any errors.
+   * \return \c true if there are no errors to report \c false if
+   * errors have occurred.
+   */
+  bool good() const;
+
+private:
+  enum TokenType {
+    tokenEndOfStream = 0,
+    tokenObjectBegin,
+    tokenObjectEnd,
+    tokenArrayBegin,
+    tokenArrayEnd,
+    tokenString,
+    tokenNumber,
+    tokenTrue,
+    tokenFalse,
+    tokenNull,
+    tokenArraySeparator,
+    tokenMemberSeparator,
+    tokenComment,
+    tokenError
+  };
+
+  class Token {
+  public:
+    TokenType type_;
+    Location start_;
+    Location end_;
+  };
+
+  class ErrorInfo {
+  public:
+    Token token_;
+    std::string message_;
+    Location extra_;
+  };
+
+  typedef std::deque<ErrorInfo> Errors;
+
+  bool readToken(Token& token);
+  void skipSpaces();
+  bool match(Location pattern, int patternLength);
+  bool readComment();
+  bool readCStyleComment();
+  bool readCppStyleComment();
+  bool readString();
+  void readNumber();
+  bool readValue();
+  bool readObject(Token& token);
+  bool readArray(Token& token);
+  bool decodeNumber(Token& token);
+  bool decodeNumber(Token& token, Value& decoded);
+  bool decodeString(Token& token);
+  bool decodeString(Token& token, std::string& decoded);
+  bool decodeDouble(Token& token);
+  bool decodeDouble(Token& token, Value& decoded);
+  bool decodeUnicodeCodePoint(Token& token,
+                              Location& current,
+                              Location end,
+                              unsigned int& unicode);
+  bool decodeUnicodeEscapeSequence(Token& token,
+                                   Location& current,
+                                   Location end,
+                                   unsigned int& unicode);
+  bool addError(const std::string& message, Token& token, Location extra = 0);
+  bool recoverFromError(TokenType skipUntilToken);
+  bool addErrorAndRecover(const std::string& message,
+                          Token& token,
+                          TokenType skipUntilToken);
+  void skipUntilSpace();
+  Value& currentValue();
+  Char getNextChar();
+  void
+  getLocationLineAndColumn(Location location, int& line, int& column) const;
+  std::string getLocationLineAndColumn(Location location) const;
+  void addComment(Location begin, Location end, CommentPlacement placement);
+  void skipCommentTokens(Token& token);
+
+  typedef std::stack<Value*> Nodes;
+  Nodes nodes_;
+  Errors errors_;
+  std::string document_;
+  Location begin_;
+  Location end_;
+  Location current_;
+  Location lastValueEnd_;
+  Value* lastValue_;
+  std::string commentsBefore_;
+  Features features_;
+  bool collectComments_;
+};  // Reader
+
+/** Interface for reading JSON from a char array.
+ */
+class JSON_API CharReader {
+public:
+  virtual ~CharReader() {}
+  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+   document.
+   * The document must be a UTF-8 encoded string containing the document to read.
+   *
+   * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+   document to read.
+   * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+   document to read.
+   *        Must be >= beginDoc.
+   * \param root [out] Contains the root value of the document if it was
+   *             successfully parsed.
+   * \param errs [out] Formatted error messages (if not NULL)
+   *        a user friendly string that lists errors in the parsed
+   * document.
+   * \return \c true if the document was successfully parsed, \c false if an
+   error occurred.
+   */
+  virtual bool parse(
+      char const* beginDoc, char const* endDoc,
+      Value* root, std::string* errs) = 0;
+
+  class JSON_API Factory {
+  public:
+    virtual ~Factory() {}
+    /** \brief Allocate a CharReader via operator new().
+     * \throw std::exception if something goes wrong (e.g. invalid settings)
+     */
+    virtual CharReader* newCharReader() const = 0;
+  };  // Factory
+};  // CharReader
+
+/** \brief Build a CharReader implementation.
+
+Usage:
+\code
+  using namespace Json;
+  CharReaderBuilder builder;
+  builder["collectComments"] = false;
+  Value value;
+  std::string errs;
+  bool ok = parseFromStream(builder, std::cin, &value, &errs);
+\endcode
+*/
+class JSON_API CharReaderBuilder : public CharReader::Factory {
+public:
+  // Note: We use a Json::Value so that we can add data-members to this class
+  // without a major version bump.
+  /** Configuration of this builder.
+    These are case-sensitive.
+    Available settings (case-sensitive):
+    - `"collectComments": false or true`
+      - true to collect comment and allow writing them
+        back during serialization, false to discard comments.
+        This parameter is ignored if allowComments is false.
+    - `"allowComments": false or true`
+      - true if comments are allowed.
+    - `"strictRoot": false or true`
+      - true if root must be either an array or an object value
+    - `"allowDroppedNullPlaceholders": false or true`
+      - true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
+    - `"allowNumericKeys": false or true`
+      - true if numeric object keys are allowed.
+    - `"allowSingleQuotes": false or true`
+      - true if '' are allowed for strings (both keys and values)
+    - `"stackLimit": integer`
+      - Exceeding stackLimit (recursive depth of `readValue()`) will
+        cause an exception.
+      - This is a security issue (seg-faults caused by deeply nested JSON),
+        so the default is low.
+    - `"failIfExtra": false or true`
+      - If true, `parse()` returns false when extra non-whitespace trails
+        the JSON value in the input string.
+    - `"rejectDupKeys": false or true`
+      - If true, `parse()` returns false when a key is duplicated within an object.
+    - `"allowSpecialFloats": false or true`
+      - If true, special float values (NaNs and infinities) are allowed 
+        and their values are lossfree restorable.
+
+    You can examine 'settings_` yourself
+    to see the defaults. You can also write and read them just like any
+    JSON Value.
+    \sa setDefaults()
+    */
+  Json::Value settings_;
+
+  CharReaderBuilder();
+  ~CharReaderBuilder() override;
+
+  CharReader* newCharReader() const override;
+
+  /** \return true if 'settings' are legal and consistent;
+   *   otherwise, indicate bad settings via 'invalid'.
+   */
+  bool validate(Json::Value* invalid) const;
+
+  /** A simple way to update a specific setting.
+   */
+  Value& operator[](std::string key);
+
+  /** Called by ctor, but you can use this to reset settings_.
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
+   */
+  static void setDefaults(Json::Value* settings);
+  /** Same as old Features::strictMode().
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
+   */
+  static void strictMode(Json::Value* settings);
+};
+
+/** Consume entire stream and use its begin/end.
+  * Someday we might have a real StreamReader, but for now this
+  * is convenient.
+  */
+bool JSON_API parseFromStream(
+    CharReader::Factory const&,
+    std::istream&,
+    Value* root, std::string* errs);
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+     "file": {
+     // The input stream JSON would be nested here.
+     }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+*/
+JSON_API std::istream& operator>>(std::istream&, Value&);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/reader.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+#define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <vector>
+#include <string>
+#include <ostream>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+class Value;
+
+/**
+
+Usage:
+\code
+  using namespace Json;
+  void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
+    std::unique_ptr<StreamWriter> const writer(
+      factory.newStreamWriter());
+    writer->write(value, &std::cout);
+    std::cout << std::endl;  // add lf and flush
+  }
+\endcode
+*/
+class JSON_API StreamWriter {
+protected:
+  std::ostream* sout_;  // not owned; will not delete
+public:
+  StreamWriter();
+  virtual ~StreamWriter();
+  /** Write Value into document as configured in sub-class.
+      Do not take ownership of sout, but maintain a reference during function.
+      \pre sout != NULL
+      \return zero on success (For now, we always return zero, so check the stream instead.)
+      \throw std::exception possibly, depending on configuration
+   */
+  virtual int write(Value const& root, std::ostream* sout) = 0;
+
+  /** \brief A simple abstract factory.
+   */
+  class JSON_API Factory {
+  public:
+    virtual ~Factory();
+    /** \brief Allocate a CharReader via operator new().
+     * \throw std::exception if something goes wrong (e.g. invalid settings)
+     */
+    virtual StreamWriter* newStreamWriter() const = 0;
+  };  // Factory
+};  // StreamWriter
+
+/** \brief Write into stringstream, then return string, for convenience.
+ * A StreamWriter will be created from the factory, used, and then deleted.
+ */
+std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
+
+
+/** \brief Build a StreamWriter implementation.
+
+Usage:
+\code
+  using namespace Json;
+  Value value = ...;
+  StreamWriterBuilder builder;
+  builder["commentStyle"] = "None";
+  builder["indentation"] = "   ";  // or whatever you like
+  std::unique_ptr<Json::StreamWriter> writer(
+      builder.newStreamWriter());
+  writer->write(value, &std::cout);
+  std::cout << std::endl;  // add lf and flush
+\endcode
+*/
+class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
+public:
+  // Note: We use a Json::Value so that we can add data-members to this class
+  // without a major version bump.
+  /** Configuration of this builder.
+    Available settings (case-sensitive):
+    - "commentStyle": "None" or "All"
+    - "indentation":  "<anything>"
+    - "enableYAMLCompatibility": false or true
+      - slightly change the whitespace around colons
+    - "dropNullPlaceholders": false or true
+      - Drop the "null" string from the writer's output for nullValues.
+        Strictly speaking, this is not valid JSON. But when the output is being
+        fed to a browser's Javascript, it makes for smaller output and the
+        browser can handle the output just fine.
+    - "useSpecialFloats": false or true
+      - If true, outputs non-finite floating point values in the following way:
+        NaN values as "NaN", positive infinity as "Infinity", and negative infinity
+        as "-Infinity".
+
+    You can examine 'settings_` yourself
+    to see the defaults. You can also write and read them just like any
+    JSON Value.
+    \sa setDefaults()
+    */
+  Json::Value settings_;
+
+  StreamWriterBuilder();
+  ~StreamWriterBuilder() override;
+
+  /**
+   * \throw std::exception if something goes wrong (e.g. invalid settings)
+   */
+  StreamWriter* newStreamWriter() const override;
+
+  /** \return true if 'settings' are legal and consistent;
+   *   otherwise, indicate bad settings via 'invalid'.
+   */
+  bool validate(Json::Value* invalid) const;
+  /** A simple way to update a specific setting.
+   */
+  Value& operator[](std::string key);
+
+  /** Called by ctor, but you can use this to reset settings_.
+   * \pre 'settings' != NULL (but Json::null is fine)
+   * \remark Defaults:
+   * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
+   */
+  static void setDefaults(Json::Value* settings);
+};
+
+/** \brief Abstract class for writers.
+ * \deprecated Use StreamWriter. (And really, this is an implementation detail.)
+ */
+class JSON_API Writer {
+public:
+  virtual ~Writer();
+
+  virtual std::string write(const Value& root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
+ *without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human'
+ *consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API FastWriter : public Writer {
+
+public:
+  FastWriter();
+  ~FastWriter() override {}
+
+  void enableYAMLCompatibility();
+
+  /** \brief Drop the "null" string from the writer's output for nullValues.
+   * Strictly speaking, this is not valid JSON. But when the output is being
+   * fed to a browser's Javascript, it makes for smaller output and the
+   * browser can handle the output just fine.
+   */
+  void dropNullPlaceholders();
+
+  void omitEndingLineFeed();
+
+public: // overridden from Writer
+  std::string write(const Value& root) override;
+
+private:
+  void writeValue(const Value& value);
+
+  std::string document_;
+  bool yamlCompatiblityEnabled_;
+  bool dropNullPlaceholders_;
+  bool omitEndingLineFeed_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ *human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per
+ *line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value
+ *types,
+ *       and all the values fit on one lines, then print the array on a single
+ *line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ *#CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledWriter : public Writer {
+public:
+  StyledWriter();
+  ~StyledWriter() override {}
+
+public: // overridden from Writer
+  /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+   * \param root Value to serialize.
+   * \return String containing the JSON document that represents the root value.
+   */
+  std::string write(const Value& root) override;
+
+private:
+  void writeValue(const Value& value);
+  void writeArrayValue(const Value& value);
+  bool isMultineArray(const Value& value);
+  void pushValue(const std::string& value);
+  void writeIndent();
+  void writeWithIndent(const std::string& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(const Value& root);
+  void writeCommentAfterValueOnSameLine(const Value& root);
+  bool hasCommentForValue(const Value& value);
+  static std::string normalizeEOL(const std::string& text);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::string document_;
+  std::string indentString_;
+  int rightMargin_;
+  int indentSize_;
+  bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ human friendly way,
+     to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ *     - if empty then print {} without indent and line break
+ *     - if not empty the print '{', line break & indent, print one value per
+ line
+ *       and then unindent and line break and print '}'.
+ * - Array value:
+ *     - if empty then print [] without indent and line break
+ *     - if the array contains no object value, empty array or some other value
+ types,
+ *       and all the values fit on one lines, then print the array on a single
+ line.
+ *     - otherwise, it the values do not fit on one line, or the array contains
+ *       object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ * \deprecated Use StreamWriterBuilder.
+ */
+class JSON_API StyledStreamWriter {
+public:
+  StyledStreamWriter(std::string indentation = "\t");
+  ~StyledStreamWriter() {}
+
+public:
+  /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+   * \param out Stream to write to. (Can be ostringstream, e.g.)
+   * \param root Value to serialize.
+   * \note There is no point in deriving from Writer, since write() should not
+   * return a value.
+   */
+  void write(std::ostream& out, const Value& root);
+
+private:
+  void writeValue(const Value& value);
+  void writeArrayValue(const Value& value);
+  bool isMultineArray(const Value& value);
+  void pushValue(const std::string& value);
+  void writeIndent();
+  void writeWithIndent(const std::string& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(const Value& root);
+  void writeCommentAfterValueOnSameLine(const Value& root);
+  bool hasCommentForValue(const Value& value);
+  static std::string normalizeEOL(const std::string& text);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::ostream* document_;
+  std::string indentString_;
+  int rightMargin_;
+  std::string indentation_;
+  bool addChildValues_ : 1;
+  bool indented_ : 1;
+};
+
+#if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(Int value);
+std::string JSON_API valueToString(UInt value);
+#endif // if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(LargestInt value);
+std::string JSON_API valueToString(LargestUInt value);
+std::string JSON_API valueToString(double value);
+std::string JSON_API valueToString(bool value);
+std::string JSON_API valueToQuotedString(const char* value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // JSON_WRITER_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/writer.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#include <stdlib.h>
+#include <sstream>
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+/** It should not be possible for a maliciously designed file to
+ *  cause an abort() or seg-fault, so these macros are used only
+ *  for pre-condition violations and internal logic errors.
+ */
+#if JSON_USE_EXCEPTION
+
+// @todo <= add detail about condition in exception
+# define JSON_ASSERT(condition)                                                \
+  {if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
+
+# define JSON_FAIL_MESSAGE(message)                                            \
+  {                                                                            \
+    std::ostringstream oss; oss << message;                                    \
+    Json::throwLogicError(oss.str());                                          \
+    abort();                                                                   \
+  }
+
+#else // JSON_USE_EXCEPTION
+
+# define JSON_ASSERT(condition) assert(condition)
+
+// The call to assert() will show the failure message in debug builds. In
+// release builds we abort, for a core-dump or debugger.
+# define JSON_FAIL_MESSAGE(message)                                            \
+  {                                                                            \
+    std::ostringstream oss; oss << message;                                    \
+    assert(false && oss.str().c_str());                                        \
+    abort();                                                                   \
+  }
+
+
+#endif
+
+#define JSON_ASSERT_MESSAGE(condition, message)                                \
+  if (!(condition)) {                                                          \
+    JSON_FAIL_MESSAGE(message);                                                \
+  }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/assertions.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#endif //ifndef JSON_AMALGATED_H_INCLUDED
diff --git a/conformance/third_party/jsoncpp/jsoncpp.cpp b/conformance/third_party/jsoncpp/jsoncpp.cpp
new file mode 100644
index 0000000..f803962
--- /dev/null
+++ b/conformance/third_party/jsoncpp/jsoncpp.cpp
@@ -0,0 +1,5192 @@
+/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation, 
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all 
+jurisdictions which recognize such a disclaimer. In such jurisdictions, 
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this 
+software may choose to accept it either as 1) Public Domain, 2) under the 
+conditions of the MIT License (see below), or 3) under the terms of dual 
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+   
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+#include "third_party/jsoncpp/json.h"
+
+#ifndef JSON_IS_AMALGAMATION
+#error "Compile with -I PATH_TO_JSON_DIRECTORY"
+#endif
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json {
+
+/// Converts a unicode code-point to UTF-8.
+static inline std::string codePointToUTF8(unsigned int cp) {
+  std::string result;
+
+  // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+  if (cp <= 0x7f) {
+    result.resize(1);
+    result[0] = static_cast<char>(cp);
+  } else if (cp <= 0x7FF) {
+    result.resize(2);
+    result[1] = static_cast<char>(0x80 | (0x3f & cp));
+    result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+  } else if (cp <= 0xFFFF) {
+    result.resize(3);
+    result[2] = static_cast<char>(0x80 | (0x3f & cp));
+    result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+    result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
+  } else if (cp <= 0x10FFFF) {
+    result.resize(4);
+    result[3] = static_cast<char>(0x80 | (0x3f & cp));
+    result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+    result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+    result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+  }
+
+  return result;
+}
+
+/// Returns true if ch is a control character (in range [1,31]).
+static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
+
+enum {
+  /// Constant that specify the size of the buffer that must be passed to
+  /// uintToString.
+  uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer.
+ *        Must have at least uintToStringBufferSize chars free.
+ */
+static inline void uintToString(LargestUInt value, char*& current) {
+  *--current = 0;
+  do {
+    *--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
+    value /= 10;
+  } while (value != 0);
+}
+
+/** Change ',' to '.' everywhere in buffer.
+ *
+ * We had a sophisticated way, but it did not work in WinCE.
+ * @see https://github.com/open-source-parsers/jsoncpp/pull/9
+ */
+static inline void fixNumericLocale(char* begin, char* end) {
+  while (begin < end) {
+    if (*begin == ',') {
+      *begin = '.';
+    }
+    ++begin;
+  }
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_tool.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <istream>
+#include <sstream>
+#include <memory>
+#include <set>
+#include <limits>
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above 
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#define snprintf std::snprintf
+#endif
+
+#if defined(__QNXNTO__)
+#define sscanf std::sscanf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+static int const stackLimit_g = 1000;
+static int       stackDepth_g = 0;  // see readValue()
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<CharReader> CharReaderPtr;
+#else
+typedef std::auto_ptr<CharReader>   CharReaderPtr;
+#endif
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+    : allowComments_(true), strictRoot_(false),
+      allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+
+Features Features::all() { return Features(); }
+
+Features Features::strictMode() {
+  Features features;
+  features.allowComments_ = false;
+  features.strictRoot_ = true;
+  features.allowDroppedNullPlaceholders_ = false;
+  features.allowNumericKeys_ = false;
+  return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end) {
+  for (; begin < end; ++begin)
+    if (*begin == '\n' || *begin == '\r')
+      return true;
+  return false;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(), features_(Features::all()),
+      collectComments_() {}
+
+Reader::Reader(const Features& features)
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(), features_(features), collectComments_() {
+}
+
+bool
+Reader::parse(const std::string& document, Value& root, bool collectComments) {
+  document_ = document;
+  const char* begin = document_.c_str();
+  const char* end = begin + document_.length();
+  return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
+  // std::istream_iterator<char> begin(sin);
+  // std::istream_iterator<char> end;
+  // Those would allow streamed input from a file, if parse() were a
+  // template function.
+
+  // Since std::string is reference-counted, this at least does not
+  // create an extra copy.
+  std::string doc;
+  std::getline(sin, doc, (char)EOF);
+  return parse(doc, root, collectComments);
+}
+
+bool Reader::parse(const char* beginDoc,
+                   const char* endDoc,
+                   Value& root,
+                   bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = 0;
+  lastValue_ = 0;
+  commentsBefore_ = "";
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  stackDepth_g = 0;  // Yes, this is bad coding, but options are limited.
+  bool successful = readValue();
+  Token token;
+  skipCommentTokens(token);
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool Reader::readValue() {
+  // This is a non-reentrant way to support a stackLimit. Terrible!
+  // But this deprecated class has a security problem: Bad input can
+  // cause a seg-fault. This seems like a fair, binary-compatible way
+  // to prevent the problem.
+  if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
+  ++stackDepth_g;
+
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_ = "";
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue:
+    {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenFalse:
+    {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNull:
+    {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // Else, fall through...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValue_ = &currentValue();
+  }
+
+  --stackDepth_g;
+  return successful;
+}
+
+void Reader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool Reader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+  case '-':
+    token.type_ = tokenNumber;
+    readNumber();
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return true;
+}
+
+void Reader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+bool Reader::match(Location pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool Reader::readComment() {
+  Location commentBegin = current_ - 1;
+  Char c = getNextChar();
+  bool successful = false;
+  if (c == '*')
+    successful = readCStyleComment();
+  else if (c == '/')
+    successful = readCppStyleComment();
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, current_))
+        placement = commentAfterOnSameLine;
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+static std::string normalizeEOL(Reader::Location begin, Reader::Location end) {
+  std::string normalized;
+  normalized.reserve(end - begin);
+  Reader::Location current = begin;
+  while (current != end) {
+    char c = *current++;
+    if (c == '\r') {
+      if (current != end && *current == '\n')
+         // convert dos EOL
+         ++current;
+      // convert Mac EOL
+      normalized += '\n';
+    } else {
+      normalized += c;
+    }
+  }
+  return normalized;
+}
+
+void
+Reader::addComment(Location begin, Location end, CommentPlacement placement) {
+  assert(collectComments_);
+  const std::string& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != 0);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool Reader::readCStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+  }
+  return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+void Reader::readNumber() {
+  const char *p = current_;
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : 0;
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+}
+
+bool Reader::readString() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+bool Reader::readObject(Token& tokenStart) {
+  Token tokenName;
+  std::string name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+      return true;
+    name = "";
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover(
+          "Missing ':' after object member name", colon, tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover(
+          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover(
+      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool Reader::readArray(Token& tokenStart) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  skipSpaces();
+  if (*current_ == ']') // empty array
+  {
+    Token endArray;
+    readToken(endArray);
+    return true;
+  }
+  int index = 0;
+  for (;;) {
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token token;
+    // Accept Comment after last item in the array.
+    ok = readToken(token);
+    while (token.type_ == tokenComment && ok) {
+      ok = readToken(token);
+    }
+    bool badTokenType =
+        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover(
+          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+    }
+    if (token.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  bool isNegative = *current == '-';
+  if (isNegative)
+    ++current;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+  Value::LargestUInt maxIntegerValue =
+      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
+                 : Value::maxLargestUInt;
+  Value::LargestUInt threshold = maxIntegerValue / 10;
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+    Value::UInt digit(c - '0');
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, b) this is the last digit, and
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > maxIntegerValue % 10) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+  if (isNegative && value == maxIntegerValue)
+    decoded = Value::minLargestInt;
+  else if (isNegative)
+    decoded = -Value::LargestInt(value);
+  else if (value <= Value::LargestUInt(Value::maxInt))
+    decoded = Value::LargestInt(value);
+  else
+    decoded = value;
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  std::string buffer(token.start_, token.end_);
+  std::istringstream is(buffer);
+  if (!(is >> value))
+    return addError("'" + std::string(token.start_, token.end_) +
+                        "' is not a number.",
+                    token);
+  decoded = value;
+  return true;
+}
+
+bool Reader::decodeString(Token& token) {
+  std::string decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeString(Token& token, std::string& decoded) {
+  decoded.reserve(token.end_ - token.start_ - 2);
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    else if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token& token,
+                                    Location& current,
+                                    Location end,
+                                    unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token,
+          current);
+    unsigned int surrogatePair;
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token,
+                      current);
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token& token,
+                                         Location& current,
+                                         Location end,
+                                         unsigned int& unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.",
+        token,
+        current);
+  unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token,
+          current);
+  }
+  return true;
+}
+
+bool
+Reader::addError(const std::string& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken) {
+  int errorCount = int(errors_.size());
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool Reader::addErrorAndRecover(const std::string& message,
+                                Token& token,
+                                TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& Reader::currentValue() { return *(nodes_.top()); }
+
+Reader::Char Reader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location,
+                                      int& line,
+                                      int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+std::string Reader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+std::string Reader::getFormatedErrorMessages() const {
+  return getFormattedErrorMessages();
+}
+
+std::string Reader::getFormattedErrorMessages() const {
+  std::string formattedMessage;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+  std::vector<Reader::StructuredError> allErrors;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    Reader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = end_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = 0;
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length
+    || extra.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = begin_ + extra.getOffsetStart();
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::good() const {
+  return !errors_.size();
+}
+
+// exact copy of Features
+class OurFeatures {
+public:
+  static OurFeatures all();
+  bool allowComments_;
+  bool strictRoot_;
+  bool allowDroppedNullPlaceholders_;
+  bool allowNumericKeys_;
+  bool allowSingleQuotes_;
+  bool failIfExtra_;
+  bool rejectDupKeys_;
+  bool allowSpecialFloats_;
+  int stackLimit_;
+};  // OurFeatures
+
+// exact copy of Implementation of class Features
+// ////////////////////////////////
+
+OurFeatures OurFeatures::all() { return OurFeatures(); }
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+// exact copy of Reader, renamed to OurReader
+class OurReader {
+public:
+  typedef char Char;
+  typedef const Char* Location;
+  struct StructuredError {
+    size_t offset_start;
+    size_t offset_limit;
+    std::string message;
+  };
+
+  OurReader(OurFeatures const& features);
+  bool parse(const char* beginDoc,
+             const char* endDoc,
+             Value& root,
+             bool collectComments = true);
+  std::string getFormattedErrorMessages() const;
+  std::vector<StructuredError> getStructuredErrors() const;
+  bool pushError(const Value& value, const std::string& message);
+  bool pushError(const Value& value, const std::string& message, const Value& extra);
+  bool good() const;
+
+private:
+  OurReader(OurReader const&);  // no impl
+  void operator=(OurReader const&);  // no impl
+
+  enum TokenType {
+    tokenEndOfStream = 0,
+    tokenObjectBegin,
+    tokenObjectEnd,
+    tokenArrayBegin,
+    tokenArrayEnd,
+    tokenString,
+    tokenNumber,
+    tokenTrue,
+    tokenFalse,
+    tokenNull,
+    tokenNaN,
+    tokenPosInf,
+    tokenNegInf,
+    tokenArraySeparator,
+    tokenMemberSeparator,
+    tokenComment,
+    tokenError
+  };
+
+  class Token {
+  public:
+    TokenType type_;
+    Location start_;
+    Location end_;
+  };
+
+  class ErrorInfo {
+  public:
+    Token token_;
+    std::string message_;
+    Location extra_;
+  };
+
+  typedef std::deque<ErrorInfo> Errors;
+
+  bool readToken(Token& token);
+  void skipSpaces();
+  bool match(Location pattern, int patternLength);
+  bool readComment();
+  bool readCStyleComment();
+  bool readCppStyleComment();
+  bool readString();
+  bool readStringSingleQuote();
+  bool readNumber(bool checkInf);
+  bool readValue();
+  bool readObject(Token& token);
+  bool readArray(Token& token);
+  bool decodeNumber(Token& token);
+  bool decodeNumber(Token& token, Value& decoded);
+  bool decodeString(Token& token);
+  bool decodeString(Token& token, std::string& decoded);
+  bool decodeDouble(Token& token);
+  bool decodeDouble(Token& token, Value& decoded);
+  bool decodeUnicodeCodePoint(Token& token,
+                              Location& current,
+                              Location end,
+                              unsigned int& unicode);
+  bool decodeUnicodeEscapeSequence(Token& token,
+                                   Location& current,
+                                   Location end,
+                                   unsigned int& unicode);
+  bool addError(const std::string& message, Token& token, Location extra = 0);
+  bool recoverFromError(TokenType skipUntilToken);
+  bool addErrorAndRecover(const std::string& message,
+                          Token& token,
+                          TokenType skipUntilToken);
+  void skipUntilSpace();
+  Value& currentValue();
+  Char getNextChar();
+  void
+  getLocationLineAndColumn(Location location, int& line, int& column) const;
+  std::string getLocationLineAndColumn(Location location) const;
+  void addComment(Location begin, Location end, CommentPlacement placement);
+  void skipCommentTokens(Token& token);
+
+  typedef std::stack<Value*> Nodes;
+  Nodes nodes_;
+  Errors errors_;
+  std::string document_;
+  Location begin_;
+  Location end_;
+  Location current_;
+  Location lastValueEnd_;
+  Value* lastValue_;
+  std::string commentsBefore_;
+  int stackDepth_;
+
+  OurFeatures const features_;
+  bool collectComments_;
+};  // OurReader
+
+// complete copy of Read impl, for OurReader
+
+OurReader::OurReader(OurFeatures const& features)
+    : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+      lastValue_(), commentsBefore_(),
+      stackDepth_(0),
+      features_(features), collectComments_() {
+}
+
+bool OurReader::parse(const char* beginDoc,
+                   const char* endDoc,
+                   Value& root,
+                   bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = 0;
+  lastValue_ = 0;
+  commentsBefore_ = "";
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  stackDepth_ = 0;
+  bool successful = readValue();
+  Token token;
+  skipCommentTokens(token);
+  if (features_.failIfExtra_) {
+    if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
+      addError("Extra non-whitespace after JSON value.", token);
+      return false;
+    }
+  }
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool OurReader::readValue() {
+  if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
+  ++stackDepth_;
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_ = "";
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue:
+    {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenFalse:
+    {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNull:
+    {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNaN:
+    {
+    Value v(std::numeric_limits<double>::quiet_NaN());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenPosInf:
+    {
+    Value v(std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenNegInf:
+    {
+    Value v(-std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    }
+    break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // else, fall through ...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValue_ = &currentValue();
+  }
+
+  --stackDepth_;
+  return successful;
+}
+
+void OurReader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool OurReader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '\'':
+    if (features_.allowSingleQuotes_) {
+    token.type_ = tokenString;
+    ok = readStringSingleQuote();
+    break;
+    } // else continue
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    token.type_ = tokenNumber;
+    readNumber(false);
+    break;
+  case '-':
+    if (readNumber(true)) {
+      token.type_ = tokenNumber;
+    } else {
+      token.type_ = tokenNegInf;
+      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+    }
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case 'N':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenNaN;
+      ok = match("aN", 2);
+    } else {
+      ok = false;
+    }
+    break;
+  case 'I':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenPosInf;
+      ok = match("nfinity", 7);
+    } else {
+      ok = false;
+    }
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return true;
+}
+
+void OurReader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+bool OurReader::match(Location pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool OurReader::readComment() {
+  Location commentBegin = current_ - 1;
+  Char c = getNextChar();
+  bool successful = false;
+  if (c == '*')
+    successful = readCStyleComment();
+  else if (c == '/')
+    successful = readCppStyleComment();
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, current_))
+        placement = commentAfterOnSameLine;
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+void
+OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
+  assert(collectComments_);
+  const std::string& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != 0);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool OurReader::readCStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+  }
+  return getNextChar() == '/';
+}
+
+bool OurReader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+bool OurReader::readNumber(bool checkInf) {
+  const char *p = current_;
+  if (checkInf && p != end_ && *p == 'I') {
+    current_ = ++p;
+    return false;
+  }
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : 0;
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : 0;
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : 0;
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : 0;
+  }
+  return true;
+}
+bool OurReader::readString() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+
+bool OurReader::readStringSingleQuote() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '\'')
+      break;
+  }
+  return c == '\'';
+}
+
+bool OurReader::readObject(Token& tokenStart) {
+  Token tokenName;
+  std::string name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+      return true;
+    name = "";
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover(
+          "Missing ':' after object member name", colon, tokenObjectEnd);
+    }
+    if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
+    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
+      std::string msg = "Duplicate key: '" + name + "'";
+      return addErrorAndRecover(
+          msg, tokenName, tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover(
+          "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover(
+      "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool OurReader::readArray(Token& tokenStart) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(tokenStart.start_ - begin_);
+  skipSpaces();
+  if (*current_ == ']') // empty array
+  {
+    Token endArray;
+    readToken(endArray);
+    return true;
+  }
+  int index = 0;
+  for (;;) {
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token token;
+    // Accept Comment after last item in the array.
+    ok = readToken(token);
+    while (token.type_ == tokenComment && ok) {
+      ok = readToken(token);
+    }
+    bool badTokenType =
+        (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover(
+          "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+    }
+    if (token.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  bool isNegative = *current == '-';
+  if (isNegative)
+    ++current;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of them.
+  Value::LargestUInt maxIntegerValue =
+      isNegative ? Value::LargestUInt(-Value::minLargestInt)
+                 : Value::maxLargestUInt;
+  Value::LargestUInt threshold = maxIntegerValue / 10;
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+    Value::UInt digit(c - '0');
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, b) this is the last digit, and
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > maxIntegerValue % 10) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+  if (isNegative)
+    decoded = -Value::LargestInt(value);
+  else if (value <= Value::LargestUInt(Value::maxInt))
+    decoded = Value::LargestInt(value);
+  else
+    decoded = value;
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  const int bufferSize = 32;
+  int count;
+  int length = int(token.end_ - token.start_);
+
+  // Sanity check to avoid buffer overflow exploits.
+  if (length < 0) {
+    return addError("Unable to parse token length", token);
+  }
+
+  // Avoid using a string constant for the format control string given to
+  // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+  // info:
+  //
+  //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+  char format[] = "%lf";
+
+  if (length <= bufferSize) {
+    Char buffer[bufferSize + 1];
+    memcpy(buffer, token.start_, length);
+    buffer[length] = 0;
+    count = sscanf(buffer, format, &value);
+  } else {
+    std::string buffer(token.start_, token.end_);
+    count = sscanf(buffer.c_str(), format, &value);
+  }
+
+  if (count != 1)
+    return addError("'" + std::string(token.start_, token.end_) +
+                        "' is not a number.",
+                    token);
+  decoded = value;
+  return true;
+}
+
+bool OurReader::decodeString(Token& token) {
+  std::string decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeString(Token& token, std::string& decoded) {
+  decoded.reserve(token.end_ - token.start_ - 2);
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    else if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeCodePoint(Token& token,
+                                    Location& current,
+                                    Location end,
+                                    unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token,
+          current);
+    unsigned int surrogatePair;
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token,
+                      current);
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeEscapeSequence(Token& token,
+                                         Location& current,
+                                         Location end,
+                                         unsigned int& unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.",
+        token,
+        current);
+  unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token,
+          current);
+  }
+  return true;
+}
+
+bool
+OurReader::addError(const std::string& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool OurReader::recoverFromError(TokenType skipUntilToken) {
+  int errorCount = int(errors_.size());
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool OurReader::addErrorAndRecover(const std::string& message,
+                                Token& token,
+                                TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& OurReader::currentValue() { return *(nodes_.top()); }
+
+OurReader::Char OurReader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void OurReader::getLocationLineAndColumn(Location location,
+                                      int& line,
+                                      int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+std::string OurReader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+std::string OurReader::getFormattedErrorMessages() const {
+  std::string formattedMessage;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
+  std::vector<OurReader::StructuredError> allErrors;
+  for (Errors::const_iterator itError = errors_.begin();
+       itError != errors_.end();
+       ++itError) {
+    const ErrorInfo& error = *itError;
+    OurReader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+bool OurReader::pushError(const Value& value, const std::string& message) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = end_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = 0;
+  errors_.push_back(info);
+  return true;
+}
+
+bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) {
+  size_t length = end_ - begin_;
+  if(value.getOffsetStart() > length
+    || value.getOffsetLimit() > length
+    || extra.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = begin_ + extra.getOffsetStart();
+  errors_.push_back(info);
+  return true;
+}
+
+bool OurReader::good() const {
+  return !errors_.size();
+}
+
+
+class OurCharReader : public CharReader {
+  bool const collectComments_;
+  OurReader reader_;
+public:
+  OurCharReader(
+    bool collectComments,
+    OurFeatures const& features)
+  : collectComments_(collectComments)
+  , reader_(features)
+  {}
+  bool parse(
+      char const* beginDoc, char const* endDoc,
+      Value* root, std::string* errs) override {
+    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
+    if (errs) {
+      *errs = reader_.getFormattedErrorMessages();
+    }
+    return ok;
+  }
+};
+
+CharReaderBuilder::CharReaderBuilder()
+{
+  setDefaults(&settings_);
+}
+CharReaderBuilder::~CharReaderBuilder()
+{}
+CharReader* CharReaderBuilder::newCharReader() const
+{
+  bool collectComments = settings_["collectComments"].asBool();
+  OurFeatures features = OurFeatures::all();
+  features.allowComments_ = settings_["allowComments"].asBool();
+  features.strictRoot_ = settings_["strictRoot"].asBool();
+  features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
+  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
+  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
+  features.stackLimit_ = settings_["stackLimit"].asInt();
+  features.failIfExtra_ = settings_["failIfExtra"].asBool();
+  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
+  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+  return new OurCharReader(collectComments, features);
+}
+static void getValidReaderKeys(std::set<std::string>* valid_keys)
+{
+  valid_keys->clear();
+  valid_keys->insert("collectComments");
+  valid_keys->insert("allowComments");
+  valid_keys->insert("strictRoot");
+  valid_keys->insert("allowDroppedNullPlaceholders");
+  valid_keys->insert("allowNumericKeys");
+  valid_keys->insert("allowSingleQuotes");
+  valid_keys->insert("stackLimit");
+  valid_keys->insert("failIfExtra");
+  valid_keys->insert("rejectDupKeys");
+  valid_keys->insert("allowSpecialFloats");
+}
+bool CharReaderBuilder::validate(Json::Value* invalid) const
+{
+  Json::Value my_invalid;
+  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  Json::Value& inv = *invalid;
+  std::set<std::string> valid_keys;
+  getValidReaderKeys(&valid_keys);
+  Value::Members keys = settings_.getMemberNames();
+  size_t n = keys.size();
+  for (size_t i = 0; i < n; ++i) {
+    std::string const& key = keys[i];
+    if (valid_keys.find(key) == valid_keys.end()) {
+      inv[key] = settings_[key];
+    }
+  }
+  return 0u == inv.size();
+}
+Value& CharReaderBuilder::operator[](std::string key)
+{
+  return settings_[key];
+}
+// static
+void CharReaderBuilder::strictMode(Json::Value* settings)
+{
+//! [CharReaderBuilderStrictMode]
+  (*settings)["allowComments"] = false;
+  (*settings)["strictRoot"] = true;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = true;
+  (*settings)["rejectDupKeys"] = true;
+  (*settings)["allowSpecialFloats"] = false;
+//! [CharReaderBuilderStrictMode]
+}
+// static
+void CharReaderBuilder::setDefaults(Json::Value* settings)
+{
+//! [CharReaderBuilderDefaults]
+  (*settings)["collectComments"] = true;
+  (*settings)["allowComments"] = true;
+  (*settings)["strictRoot"] = false;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = false;
+  (*settings)["rejectDupKeys"] = false;
+  (*settings)["allowSpecialFloats"] = false;
+//! [CharReaderBuilderDefaults]
+}
+
+//////////////////////////////////
+// global functions
+
+bool parseFromStream(
+    CharReader::Factory const& fact, std::istream& sin,
+    Value* root, std::string* errs)
+{
+  std::ostringstream ssin;
+  ssin << sin.rdbuf();
+  std::string doc = ssin.str();
+  char const* begin = doc.data();
+  char const* end = begin + doc.size();
+  // Note that we do not actually need a null-terminator.
+  CharReaderPtr const reader(fact.newCharReader());
+  return reader->parse(begin, end, root, errs);
+}
+
+std::istream& operator>>(std::istream& sin, Value& root) {
+  CharReaderBuilder b;
+  std::string errs;
+  bool ok = parseFromStream(b, sin, &root, &errs);
+  if (!ok) {
+    fprintf(stderr,
+            "Error from reader: %s",
+            errs.c_str());
+
+    throwRuntimeError(errs);
+  }
+  return sin;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_reader.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+    : current_(), isNull_(true) {
+}
+
+ValueIteratorBase::ValueIteratorBase(
+    const Value::ObjectValues::iterator& current)
+    : current_(current), isNull_(false) {}
+
+Value& ValueIteratorBase::deref() const {
+  return current_->second;
+}
+
+void ValueIteratorBase::increment() {
+  ++current_;
+}
+
+void ValueIteratorBase::decrement() {
+  --current_;
+}
+
+ValueIteratorBase::difference_type
+ValueIteratorBase::computeDistance(const SelfType& other) const {
+#ifdef JSON_USE_CPPTL_SMALLMAP
+  return other.current_ - current_;
+#else
+  // Iterator for null value are initialized using the default
+  // constructor, which initialize current_ to the default
+  // std::map::iterator. As begin() and end() are two instance
+  // of the default std::map::iterator, they can not be compared.
+  // To allow this, we handle this comparison specifically.
+  if (isNull_ && other.isNull_) {
+    return 0;
+  }
+
+  // Usage of std::distance is not portable (does not compile with Sun Studio 12
+  // RogueWave STL,
+  // which is the one used by default).
+  // Using a portable hand-made version for non random iterator instead:
+  //   return difference_type( std::distance( current_, other.current_ ) );
+  difference_type myDistance = 0;
+  for (Value::ObjectValues::iterator it = current_; it != other.current_;
+       ++it) {
+    ++myDistance;
+  }
+  return myDistance;
+#endif
+}
+
+bool ValueIteratorBase::isEqual(const SelfType& other) const {
+  if (isNull_) {
+    return other.isNull_;
+  }
+  return current_ == other.current_;
+}
+
+void ValueIteratorBase::copy(const SelfType& other) {
+  current_ = other.current_;
+  isNull_ = other.isNull_;
+}
+
+Value ValueIteratorBase::key() const {
+  const Value::CZString czstring = (*current_).first;
+  if (czstring.data()) {
+    if (czstring.isStaticString())
+      return Value(StaticString(czstring.data()));
+    return Value(czstring.data(), czstring.data() + czstring.length());
+  }
+  return Value(czstring.index());
+}
+
+UInt ValueIteratorBase::index() const {
+  const Value::CZString czstring = (*current_).first;
+  if (!czstring.data())
+    return czstring.index();
+  return Value::UInt(-1);
+}
+
+std::string ValueIteratorBase::name() const {
+  char const* keey;
+  char const* end;
+  keey = memberName(&end);
+  if (!keey) return std::string();
+  return std::string(keey, end);
+}
+
+char const* ValueIteratorBase::memberName() const {
+  const char* cname = (*current_).first.data();
+  return cname ? cname : "";
+}
+
+char const* ValueIteratorBase::memberName(char const** end) const {
+  const char* cname = (*current_).first.data();
+  if (!cname) {
+    *end = NULL;
+    return NULL;
+  }
+  *end = cname + (*current_).first.length();
+  return cname;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator() {}
+
+ValueConstIterator::ValueConstIterator(
+    const Value::ObjectValues::iterator& current)
+    : ValueIteratorBase(current) {}
+
+ValueConstIterator::ValueConstIterator(ValueIterator const& other)
+    : ValueIteratorBase(other) {}
+
+ValueConstIterator& ValueConstIterator::
+operator=(const ValueIteratorBase& other) {
+  copy(other);
+  return *this;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator() {}
+
+ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
+    : ValueIteratorBase(current) {}
+
+ValueIterator::ValueIterator(const ValueConstIterator& other)
+    : ValueIteratorBase(other) {
+  throwRuntimeError("ConstIterator to Iterator should never be allowed.");
+}
+
+ValueIterator::ValueIterator(const ValueIterator& other)
+    : ValueIteratorBase(other) {}
+
+ValueIterator& ValueIterator::operator=(const SelfType& other) {
+  copy(other);
+  return *this;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_valueiterator.inl
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <sstream>
+#include <utility>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+#include <cpptl/conststring.h>
+#endif
+#include <cstddef> // size_t
+#include <algorithm> // min()
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json {
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+const unsigned char& kNullRef = kNull[0];
+const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+const Value& Value::nullRef = null;
+
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+#if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
+const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
+const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  return d >= min && d <= max;
+}
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value) {
+  return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
+}
+
+template <typename T> static inline double integerToDouble(T value) {
+  return static_cast<double>(value);
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ *              length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ *               computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char* duplicateStringValue(const char* value,
+                                         size_t length) {
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  if (length >= (size_t)Value::maxInt)
+    length = Value::maxInt - 1;
+
+  char* newString = static_cast<char*>(malloc(length + 1));
+  if (newString == NULL) {
+    throwRuntimeError(
+        "in Json::Value::duplicateStringValue(): "
+        "Failed to allocate string value buffer");
+  }
+  memcpy(newString, value, length);
+  newString[length] = 0;
+  return newString;
+}
+
+/* Record the length as a prefix.
+ */
+static inline char* duplicateAndPrefixStringValue(
+    const char* value,
+    unsigned int length)
+{
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
+                      "in Json::Value::duplicateAndPrefixStringValue(): "
+                      "length too big for prefixing");
+  unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
+  char* newString = static_cast<char*>(malloc(actualLength));
+  if (newString == 0) {
+    throwRuntimeError(
+        "in Json::Value::duplicateAndPrefixStringValue(): "
+        "Failed to allocate string value buffer");
+  }
+  *reinterpret_cast<unsigned*>(newString) = length;
+  memcpy(newString + sizeof(unsigned), value, length);
+  newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
+  return newString;
+}
+inline static void decodePrefixedString(
+    bool isPrefixed, char const* prefixed,
+    unsigned* length, char const** value)
+{
+  if (!isPrefixed) {
+    *length = static_cast<unsigned>(strlen(prefixed));
+    *value = prefixed;
+  } else {
+    *length = *reinterpret_cast<unsigned const*>(prefixed);
+    *value = prefixed + sizeof(unsigned);
+  }
+}
+/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
+ */
+static inline void releaseStringValue(char* value) { free(value); }
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+Exception::Exception(std::string const& msg)
+  : msg_(msg)
+{}
+Exception::~Exception() throw()
+{}
+char const* Exception::what() const throw()
+{
+  return msg_.c_str();
+}
+RuntimeError::RuntimeError(std::string const& msg)
+  : Exception(msg)
+{}
+LogicError::LogicError(std::string const& msg)
+  : Exception(msg)
+{}
+void throwRuntimeError(std::string const& msg)
+{
+  throw RuntimeError(msg);
+}
+void throwLogicError(std::string const& msg)
+{
+  throw LogicError(msg);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() : comment_(0) {}
+
+Value::CommentInfo::~CommentInfo() {
+  if (comment_)
+    releaseStringValue(comment_);
+}
+
+void Value::CommentInfo::setComment(const char* text, size_t len) {
+  if (comment_) {
+    releaseStringValue(comment_);
+    comment_ = 0;
+  }
+  JSON_ASSERT(text != 0);
+  JSON_ASSERT_MESSAGE(
+      text[0] == '\0' || text[0] == '/',
+      "in Json::Value::setComment(): Comments must start with /");
+  // It seems that /**/ style comments are acceptable as well.
+  comment_ = duplicateStringValue(text, len);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+// Notes: policy_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {}
+
+Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate)
+    : cstr_(str) {
+  // allocate != duplicate
+  storage_.policy_ = allocate & 0x3;
+  storage_.length_ = ulength & 0x3FFFFFFF;
+}
+
+Value::CZString::CZString(const CZString& other)
+    : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
+                ? duplicateStringValue(other.cstr_, other.storage_.length_)
+                : other.cstr_) {
+  storage_.policy_ = (other.cstr_
+                 ? (static_cast<DuplicationPolicy>(other.storage_.policy_) == noDuplication
+                     ? noDuplication : duplicate)
+                 : static_cast<DuplicationPolicy>(other.storage_.policy_));
+  storage_.length_ = other.storage_.length_;
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+Value::CZString::CZString(CZString&& other)
+  : cstr_(other.cstr_), index_(other.index_) {
+  other.cstr_ = nullptr;
+}
+#endif
+
+Value::CZString::~CZString() {
+  if (cstr_ && storage_.policy_ == duplicate)
+    releaseStringValue(const_cast<char*>(cstr_));
+}
+
+void Value::CZString::swap(CZString& other) {
+  std::swap(cstr_, other.cstr_);
+  std::swap(index_, other.index_);
+}
+
+Value::CZString& Value::CZString::operator=(CZString other) {
+  swap(other);
+  return *this;
+}
+
+bool Value::CZString::operator<(const CZString& other) const {
+  if (!cstr_) return index_ < other.index_;
+  //return strcmp(cstr_, other.cstr_) < 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  unsigned min_len = std::min(this_len, other_len);
+  int comp = memcmp(this->cstr_, other.cstr_, min_len);
+  if (comp < 0) return true;
+  if (comp > 0) return false;
+  return (this_len < other_len);
+}
+
+bool Value::CZString::operator==(const CZString& other) const {
+  if (!cstr_) return index_ == other.index_;
+  //return strcmp(cstr_, other.cstr_) == 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  if (this_len != other_len) return false;
+  int comp = memcmp(this->cstr_, other.cstr_, this_len);
+  return comp == 0;
+}
+
+ArrayIndex Value::CZString::index() const { return index_; }
+
+//const char* Value::CZString::c_str() const { return cstr_; }
+const char* Value::CZString::data() const { return cstr_; }
+unsigned Value::CZString::length() const { return storage_.length_; }
+bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType vtype) {
+  initBasic(vtype);
+  switch (vtype) {
+  case nullValue:
+    break;
+  case intValue:
+  case uintValue:
+    value_.int_ = 0;
+    break;
+  case realValue:
+    value_.real_ = 0.0;
+    break;
+  case stringValue:
+    value_.string_ = 0;
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues();
+    break;
+  case booleanValue:
+    value_.bool_ = false;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+Value::Value(Int value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+
+Value::Value(UInt value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+Value::Value(UInt64 value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value) {
+  initBasic(realValue);
+  value_.real_ = value;
+}
+
+Value::Value(const char* value) {
+  initBasic(stringValue, true);
+  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
+}
+
+Value::Value(const char* beginValue, const char* endValue) {
+  initBasic(stringValue, true);
+  value_.string_ =
+      duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
+}
+
+Value::Value(const std::string& value) {
+  initBasic(stringValue, true);
+  value_.string_ =
+      duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
+}
+
+Value::Value(const StaticString& value) {
+  initBasic(stringValue);
+  value_.string_ = const_cast<char*>(value.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value::Value(const CppTL::ConstString& value) {
+  initBasic(stringValue, true);
+  value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
+}
+#endif
+
+Value::Value(bool value) {
+  initBasic(booleanValue);
+  value_.bool_ = value;
+}
+
+Value::Value(Value const& other)
+    : type_(other.type_), allocated_(false)
+      ,
+      comments_(0), start_(other.start_), limit_(other.limit_)
+{
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    value_ = other.value_;
+    break;
+  case stringValue:
+    if (other.value_.string_ && other.allocated_) {
+      unsigned len;
+      char const* str;
+      decodePrefixedString(other.allocated_, other.value_.string_,
+          &len, &str);
+      value_.string_ = duplicateAndPrefixStringValue(str, len);
+      allocated_ = true;
+    } else {
+      value_.string_ = other.value_.string_;
+      allocated_ = false;
+    }
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues(*other.value_.map_);
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  if (other.comments_) {
+    comments_ = new CommentInfo[numberOfCommentPlacement];
+    for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
+      const CommentInfo& otherComment = other.comments_[comment];
+      if (otherComment.comment_)
+        comments_[comment].setComment(
+            otherComment.comment_, strlen(otherComment.comment_));
+    }
+  }
+}
+
+#if JSON_HAS_RVALUE_REFERENCES
+// Move constructor
+Value::Value(Value&& other) {
+  initBasic(nullValue);
+  swap(other);
+}
+#endif
+
+Value::~Value() {
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    break;
+  case stringValue:
+    if (allocated_)
+      releaseStringValue(value_.string_);
+    break;
+  case arrayValue:
+  case objectValue:
+    delete value_.map_;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+
+  if (comments_)
+    delete[] comments_;
+}
+
+Value& Value::operator=(Value other) {
+  swap(other);
+  return *this;
+}
+
+void Value::swapPayload(Value& other) {
+  ValueType temp = type_;
+  type_ = other.type_;
+  other.type_ = temp;
+  std::swap(value_, other.value_);
+  int temp2 = allocated_;
+  allocated_ = other.allocated_;
+  other.allocated_ = temp2 & 0x1;
+}
+
+void Value::swap(Value& other) {
+  swapPayload(other);
+  std::swap(comments_, other.comments_);
+  std::swap(start_, other.start_);
+  std::swap(limit_, other.limit_);
+}
+
+ValueType Value::type() const { return type_; }
+
+int Value::compare(const Value& other) const {
+  if (*this < other)
+    return -1;
+  if (*this > other)
+    return 1;
+  return 0;
+}
+
+bool Value::operator<(const Value& other) const {
+  int typeDelta = type_ - other.type_;
+  if (typeDelta)
+    return typeDelta < 0 ? true : false;
+  switch (type_) {
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ < other.value_.int_;
+  case uintValue:
+    return value_.uint_ < other.value_.uint_;
+  case realValue:
+    return value_.real_ < other.value_.real_;
+  case booleanValue:
+    return value_.bool_ < other.value_.bool_;
+  case stringValue:
+  {
+    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
+      if (other.value_.string_) return true;
+      else return false;
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+    unsigned min_len = std::min(this_len, other_len);
+    int comp = memcmp(this_str, other_str, min_len);
+    if (comp < 0) return true;
+    if (comp > 0) return false;
+    return (this_len < other_len);
+  }
+  case arrayValue:
+  case objectValue: {
+    int delta = int(value_.map_->size() - other.value_.map_->size());
+    if (delta)
+      return delta < 0;
+    return (*value_.map_) < (*other.value_.map_);
+  }
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator<=(const Value& other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value& other) const { return !(*this < other); }
+
+bool Value::operator>(const Value& other) const { return other < *this; }
+
+bool Value::operator==(const Value& other) const {
+  // if ( type_ != other.type_ )
+  // GCC 2.95.3 says:
+  // attempt to take address of bit-field structure member `Json::Value::type_'
+  // Beats me, but a temp solves the problem.
+  int temp = other.type_;
+  if (type_ != temp)
+    return false;
+  switch (type_) {
+  case nullValue:
+    return true;
+  case intValue:
+    return value_.int_ == other.value_.int_;
+  case uintValue:
+    return value_.uint_ == other.value_.uint_;
+  case realValue:
+    return value_.real_ == other.value_.real_;
+  case booleanValue:
+    return value_.bool_ == other.value_.bool_;
+  case stringValue:
+  {
+    if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
+      return (value_.string_ == other.value_.string_);
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
+    if (this_len != other_len) return false;
+    int comp = memcmp(this_str, other_str, this_len);
+    return comp == 0;
+  }
+  case arrayValue:
+  case objectValue:
+    return value_.map_->size() == other.value_.map_->size() &&
+           (*value_.map_) == (*other.value_.map_);
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator!=(const Value& other) const { return !(*this == other); }
+
+const char* Value::asCString() const {
+  JSON_ASSERT_MESSAGE(type_ == stringValue,
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == 0) return 0;
+  unsigned this_len;
+  char const* this_str;
+  decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+  return this_str;
+}
+
+bool Value::getString(char const** str, char const** cend) const {
+  if (type_ != stringValue) return false;
+  if (value_.string_ == 0) return false;
+  unsigned length;
+  decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
+  *cend = *str + length;
+  return true;
+}
+
+std::string Value::asString() const {
+  switch (type_) {
+  case nullValue:
+    return "";
+  case stringValue:
+  {
+    if (value_.string_ == 0) return "";
+    unsigned this_len;
+    char const* this_str;
+    decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
+    return std::string(this_str, this_len);
+  }
+  case booleanValue:
+    return value_.bool_ ? "true" : "false";
+  case intValue:
+    return valueToString(value_.int_);
+  case uintValue:
+    return valueToString(value_.uint_);
+  case realValue:
+    return valueToString(value_.real_);
+  default:
+    JSON_FAIL_MESSAGE("Type is not convertible to string");
+  }
+}
+
+#ifdef JSON_USE_CPPTL
+CppTL::ConstString Value::asConstString() const {
+  unsigned len;
+  char const* str;
+  decodePrefixedString(allocated_, value_.string_,
+      &len, &str);
+  return CppTL::ConstString(str, len);
+}
+#endif
+
+Value::Int Value::asInt() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+    return Int(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+    return Int(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+                        "double out of Int range");
+    return Int(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+    return UInt(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+    return UInt(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+                        "double out of UInt range");
+    return UInt(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const {
+  switch (type_) {
+  case intValue:
+    return Int64(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+    return Int64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+                        "double out of Int64 range");
+    return Int64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const {
+  switch (type_) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+    return UInt64(value_.int_);
+  case uintValue:
+    return UInt64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+                        "double out of UInt64 range");
+    return UInt64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const {
+#if defined(JSON_NO_INT64)
+  return asInt();
+#else
+  return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const {
+#if defined(JSON_NO_INT64)
+  return asUInt();
+#else
+  return asUInt64();
+#endif
+}
+
+double Value::asDouble() const {
+  switch (type_) {
+  case intValue:
+    return static_cast<double>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<double>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return value_.real_;
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0 : 0.0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const {
+  switch (type_) {
+  case intValue:
+    return static_cast<float>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<float>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return static_cast<float>(value_.real_);
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0f : 0.0f;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const {
+  switch (type_) {
+  case booleanValue:
+    return value_.bool_;
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ ? true : false;
+  case uintValue:
+    return value_.uint_ ? true : false;
+  case realValue:
+    // This is kind of strange. Not recommended.
+    return (value_.real_ != 0.0) ? true : false;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+  switch (other) {
+  case nullValue:
+    return (isNumeric() && asDouble() == 0.0) ||
+           (type_ == booleanValue && value_.bool_ == false) ||
+           (type_ == stringValue && asString() == "") ||
+           (type_ == arrayValue && value_.map_->size() == 0) ||
+           (type_ == objectValue && value_.map_->size() == 0) ||
+           type_ == nullValue;
+  case intValue:
+    return isInt() ||
+           (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
+           type_ == booleanValue || type_ == nullValue;
+  case uintValue:
+    return isUInt() ||
+           (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
+           type_ == booleanValue || type_ == nullValue;
+  case realValue:
+    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+  case booleanValue:
+    return isNumeric() || type_ == booleanValue || type_ == nullValue;
+  case stringValue:
+    return isNumeric() || type_ == booleanValue || type_ == stringValue ||
+           type_ == nullValue;
+  case arrayValue:
+    return type_ == arrayValue || type_ == nullValue;
+  case objectValue:
+    return type_ == objectValue || type_ == nullValue;
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return false;
+}
+
+/// Number of values in array or object
+ArrayIndex Value::size() const {
+  switch (type_) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+  case stringValue:
+    return 0;
+  case arrayValue: // size of the array is highest index + 1
+    if (!value_.map_->empty()) {
+      ObjectValues::const_iterator itLast = value_.map_->end();
+      --itLast;
+      return (*itLast).first.index() + 1;
+    }
+    return 0;
+  case objectValue:
+    return ArrayIndex(value_.map_->size());
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return 0; // unreachable;
+}
+
+bool Value::empty() const {
+  if (isNull() || isArray() || isObject())
+    return size() == 0u;
+  else
+    return false;
+}
+
+bool Value::operator!() const { return isNull(); }
+
+void Value::clear() {
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
+                          type_ == objectValue,
+                      "in Json::Value::clear(): requires complex value");
+  start_ = 0;
+  limit_ = 0;
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    value_.map_->clear();
+    break;
+  default:
+    break;
+  }
+}
+
+void Value::resize(ArrayIndex newSize) {
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+                      "in Json::Value::resize(): requires arrayValue");
+  if (type_ == nullValue)
+    *this = Value(arrayValue);
+  ArrayIndex oldSize = size();
+  if (newSize == 0)
+    clear();
+  else if (newSize > oldSize)
+    (*this)[newSize - 1];
+  else {
+    for (ArrayIndex index = newSize; index < oldSize; ++index) {
+      value_.map_->erase(index);
+    }
+    assert(size() == newSize);
+  }
+}
+
+Value& Value::operator[](ArrayIndex index) {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == arrayValue,
+      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+  if (type_ == nullValue)
+    *this = Value(arrayValue);
+  CZString key(index);
+  ObjectValues::iterator it = value_.map_->lower_bound(key);
+  if (it != value_.map_->end() && (*it).first == key)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(key, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  return (*it).second;
+}
+
+Value& Value::operator[](int index) {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index): index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+const Value& Value::operator[](ArrayIndex index) const {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == arrayValue,
+      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+  if (type_ == nullValue)
+    return nullRef;
+  CZString key(index);
+  ObjectValues::const_iterator it = value_.map_->find(key);
+  if (it == value_.map_->end())
+    return nullRef;
+  return (*it).second;
+}
+
+const Value& Value::operator[](int index) const {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index) const: index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+void Value::initBasic(ValueType vtype, bool allocated) {
+  type_ = vtype;
+  allocated_ = allocated;
+  comments_ = 0;
+  start_ = 0;
+  limit_ = 0;
+}
+
+// Access an object value by name, create a null member if it does not exist.
+// @pre Type of '*this' is object or null.
+// @param key is null-terminated.
+Value& Value::resolveReference(const char* key) {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::resolveReference(): requires objectValue");
+  if (type_ == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(
+      key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
+  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+// @param key is not null-terminated.
+Value& Value::resolveReference(char const* key, char const* cend)
+{
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::resolveReference(key, end): requires objectValue");
+  if (type_ == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(
+      key, static_cast<unsigned>(cend-key), CZString::duplicateOnCopy);
+  ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullRef);
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+Value Value::get(ArrayIndex index, const Value& defaultValue) const {
+  const Value* value = &((*this)[index]);
+  return value == &nullRef ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+Value const* Value::find(char const* key, char const* cend) const
+{
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::find(key, end, found): requires objectValue or nullValue");
+  if (type_ == nullValue) return NULL;
+  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
+  ObjectValues::const_iterator it = value_.map_->find(actualKey);
+  if (it == value_.map_->end()) return NULL;
+  return &(*it).second;
+}
+const Value& Value::operator[](const char* key) const
+{
+  Value const* found = find(key, key + strlen(key));
+  if (!found) return nullRef;
+  return *found;
+}
+Value const& Value::operator[](std::string const& key) const
+{
+  Value const* found = find(key.data(), key.data() + key.length());
+  if (!found) return nullRef;
+  return *found;
+}
+
+Value& Value::operator[](const char* key) {
+  return resolveReference(key, key + strlen(key));
+}
+
+Value& Value::operator[](const std::string& key) {
+  return resolveReference(key.data(), key.data() + key.length());
+}
+
+Value& Value::operator[](const StaticString& key) {
+  return resolveReference(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value& Value::operator[](const CppTL::ConstString& key) {
+  return resolveReference(key.c_str(), key.end_c_str());
+}
+Value const& Value::operator[](CppTL::ConstString const& key) const
+{
+  Value const* found = find(key.c_str(), key.end_c_str());
+  if (!found) return nullRef;
+  return *found;
+}
+#endif
+
+Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+
+Value Value::get(char const* key, char const* cend, Value const& defaultValue) const
+{
+  Value const* found = find(key, cend);
+  return !found ? defaultValue : *found;
+}
+Value Value::get(char const* key, Value const& defaultValue) const
+{
+  return get(key, key + strlen(key), defaultValue);
+}
+Value Value::get(std::string const& key, Value const& defaultValue) const
+{
+  return get(key.data(), key.data() + key.length(), defaultValue);
+}
+
+
+bool Value::removeMember(const char* key, const char* cend, Value* removed)
+{
+  if (type_ != objectValue) {
+    return false;
+  }
+  CZString actualKey(key, static_cast<unsigned>(cend-key), CZString::noDuplication);
+  ObjectValues::iterator it = value_.map_->find(actualKey);
+  if (it == value_.map_->end())
+    return false;
+  *removed = it->second;
+  value_.map_->erase(it);
+  return true;
+}
+bool Value::removeMember(const char* key, Value* removed)
+{
+  return removeMember(key, key + strlen(key), removed);
+}
+bool Value::removeMember(std::string const& key, Value* removed)
+{
+  return removeMember(key.data(), key.data() + key.length(), removed);
+}
+Value Value::removeMember(const char* key)
+{
+  JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+                      "in Json::Value::removeMember(): requires objectValue");
+  if (type_ == nullValue)
+    return nullRef;
+
+  Value removed;  // null
+  removeMember(key, key + strlen(key), &removed);
+  return removed; // still null if removeMember() did nothing
+}
+Value Value::removeMember(const std::string& key)
+{
+  return removeMember(key.c_str());
+}
+
+bool Value::removeIndex(ArrayIndex index, Value* removed) {
+  if (type_ != arrayValue) {
+    return false;
+  }
+  CZString key(index);
+  ObjectValues::iterator it = value_.map_->find(key);
+  if (it == value_.map_->end()) {
+    return false;
+  }
+  *removed = it->second;
+  ArrayIndex oldSize = size();
+  // shift left all items left, into the place of the "removed"
+  for (ArrayIndex i = index; i < (oldSize - 1); ++i){
+    CZString keey(i);
+    (*value_.map_)[keey] = (*this)[i + 1];
+  }
+  // erase the last one ("leftover")
+  CZString keyLast(oldSize - 1);
+  ObjectValues::iterator itLast = value_.map_->find(keyLast);
+  value_.map_->erase(itLast);
+  return true;
+}
+
+#ifdef JSON_USE_CPPTL
+Value Value::get(const CppTL::ConstString& key,
+                 const Value& defaultValue) const {
+  return get(key.c_str(), key.end_c_str(), defaultValue);
+}
+#endif
+
+bool Value::isMember(char const* key, char const* cend) const
+{
+  Value const* value = find(key, cend);
+  return NULL != value;
+}
+bool Value::isMember(char const* key) const
+{
+  return isMember(key, key + strlen(key));
+}
+bool Value::isMember(std::string const& key) const
+{
+  return isMember(key.data(), key.data() + key.length());
+}
+
+#ifdef JSON_USE_CPPTL
+bool Value::isMember(const CppTL::ConstString& key) const {
+  return isMember(key.c_str(), key.end_c_str());
+}
+#endif
+
+Value::Members Value::getMemberNames() const {
+  JSON_ASSERT_MESSAGE(
+      type_ == nullValue || type_ == objectValue,
+      "in Json::Value::getMemberNames(), value must be objectValue");
+  if (type_ == nullValue)
+    return Value::Members();
+  Members members;
+  members.reserve(value_.map_->size());
+  ObjectValues::const_iterator it = value_.map_->begin();
+  ObjectValues::const_iterator itEnd = value_.map_->end();
+  for (; it != itEnd; ++it) {
+    members.push_back(std::string((*it).first.data(),
+                                  (*it).first.length()));
+  }
+  return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames
+// Value::enumMemberNames() const
+//{
+//   if ( type_ == objectValue )
+//   {
+//      return CppTL::Enum::any(  CppTL::Enum::transform(
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+//         MemberNamesTransform() ) );
+//   }
+//   return EnumMemberNames();
+//}
+//
+//
+// EnumValues
+// Value::enumValues() const
+//{
+//   if ( type_ == objectValue  ||  type_ == arrayValue )
+//      return CppTL::Enum::anyValues( *(value_.map_),
+//                                     CppTL::Type<const Value &>() );
+//   return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d) {
+  double integral_part;
+  return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type_ == nullValue; }
+
+bool Value::isBool() const { return type_ == booleanValue; }
+
+bool Value::isInt() const {
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= minInt && value_.int_ <= maxInt;
+  case uintValue:
+    return value_.uint_ <= UInt(maxInt);
+  case realValue:
+    return value_.real_ >= minInt && value_.real_ <= maxInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isUInt() const {
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+  case uintValue:
+    return value_.uint_ <= maxUInt;
+  case realValue:
+    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type_) {
+  case intValue:
+    return true;
+  case uintValue:
+    return value_.uint_ <= UInt64(maxInt64);
+  case realValue:
+    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= double(minInt64) &&
+           value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isUInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type_) {
+  case intValue:
+    return value_.int_ >= 0;
+  case uintValue:
+    return true;
+  case realValue:
+    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isIntegral() const {
+#if defined(JSON_HAS_INT64)
+  return isInt64() || isUInt64();
+#else
+  return isInt() || isUInt();
+#endif
+}
+
+bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
+
+bool Value::isNumeric() const { return isIntegral() || isDouble(); }
+
+bool Value::isString() const { return type_ == stringValue; }
+
+bool Value::isArray() const { return type_ == arrayValue; }
+
+bool Value::isObject() const { return type_ == objectValue; }
+
+void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
+  if (!comments_)
+    comments_ = new CommentInfo[numberOfCommentPlacement];
+  if ((len > 0) && (comment[len-1] == '\n')) {
+    // Always discard trailing newline, to aid indentation.
+    len -= 1;
+  }
+  comments_[placement].setComment(comment, len);
+}
+
+void Value::setComment(const char* comment, CommentPlacement placement) {
+  setComment(comment, strlen(comment), placement);
+}
+
+void Value::setComment(const std::string& comment, CommentPlacement placement) {
+  setComment(comment.c_str(), comment.length(), placement);
+}
+
+bool Value::hasComment(CommentPlacement placement) const {
+  return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+std::string Value::getComment(CommentPlacement placement) const {
+  if (hasComment(placement))
+    return comments_[placement].comment_;
+  return "";
+}
+
+void Value::setOffsetStart(size_t start) { start_ = start; }
+
+void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
+
+size_t Value::getOffsetStart() const { return start_; }
+
+size_t Value::getOffsetLimit() const { return limit_; }
+
+std::string Value::toStyledString() const {
+  StyledWriter writer;
+  return writer.write(*this);
+}
+
+Value::const_iterator Value::begin() const {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return const_iterator();
+}
+
+Value::const_iterator Value::end() const {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return const_iterator();
+}
+
+Value::iterator Value::begin() {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+Value::iterator Value::end() {
+  switch (type_) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+
+PathArgument::PathArgument(ArrayIndex index)
+    : key_(), index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char* key)
+    : key_(key), index_(), kind_(kindKey) {}
+
+PathArgument::PathArgument(const std::string& key)
+    : key_(key.c_str()), index_(), kind_(kindKey) {}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const std::string& path,
+           const PathArgument& a1,
+           const PathArgument& a2,
+           const PathArgument& a3,
+           const PathArgument& a4,
+           const PathArgument& a5) {
+  InArgs in;
+  in.push_back(&a1);
+  in.push_back(&a2);
+  in.push_back(&a3);
+  in.push_back(&a4);
+  in.push_back(&a5);
+  makePath(path, in);
+}
+
+void Path::makePath(const std::string& path, const InArgs& in) {
+  const char* current = path.c_str();
+  const char* end = current + path.length();
+  InArgs::const_iterator itInArg = in.begin();
+  while (current != end) {
+    if (*current == '[') {
+      ++current;
+      if (*current == '%')
+        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+      else {
+        ArrayIndex index = 0;
+        for (; current != end && *current >= '0' && *current <= '9'; ++current)
+          index = index * 10 + ArrayIndex(*current - '0');
+        args_.push_back(index);
+      }
+      if (current == end || *current++ != ']')
+        invalidPath(path, int(current - path.c_str()));
+    } else if (*current == '%') {
+      addPathInArg(path, in, itInArg, PathArgument::kindKey);
+      ++current;
+    } else if (*current == '.') {
+      ++current;
+    } else {
+      const char* beginName = current;
+      while (current != end && !strchr("[.", *current))
+        ++current;
+      args_.push_back(std::string(beginName, current));
+    }
+  }
+}
+
+void Path::addPathInArg(const std::string& /*path*/,
+                        const InArgs& in,
+                        InArgs::const_iterator& itInArg,
+                        PathArgument::Kind kind) {
+  if (itInArg == in.end()) {
+    // Error: missing argument %d
+  } else if ((*itInArg)->kind_ != kind) {
+    // Error: bad argument type
+  } else {
+    args_.push_back(**itInArg);
+  }
+}
+
+void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
+  // Error: invalid path.
+}
+
+const Value& Path::resolve(const Value& root) const {
+  const Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
+        // Error: unable to resolve path (array value expected at position...
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: unable to resolve path (object value expected at position...)
+      }
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullRef) {
+        // Error: unable to resolve path (object has no member named '' at
+        // position...)
+      }
+    }
+  }
+  return *node;
+}
+
+Value Path::resolve(const Value& root, const Value& defaultValue) const {
+  const Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_))
+        return defaultValue;
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject())
+        return defaultValue;
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullRef)
+        return defaultValue;
+    }
+  }
+  return *node;
+}
+
+Value& Path::make(Value& root) const {
+  Value* node = &root;
+  for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+    const PathArgument& arg = *it;
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray()) {
+        // Error: node is not an array at position ...
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: node is not an object at position...
+      }
+      node = &((*node)[arg.key_]);
+    }
+  }
+  return *node;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_value.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/writer.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <iomanip>
+#include <memory>
+#include <sstream>
+#include <utility>
+#include <set>
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0
+#include <float.h>
+#define isfinite _finite
+#elif defined(__sun) && defined(__SVR4) //Solaris
+#if !defined(isfinite)
+#include <ieeefp.h>
+#define isfinite finite
+#endif
+#elif defined(_AIX)
+#if !defined(isfinite)
+#include <math.h>
+#define isfinite finite
+#endif
+#elif defined(__hpux)
+#if !defined(isfinite)
+#if defined(__ia64) && !defined(finite)
+#define isfinite(x) ((sizeof(x) == sizeof(float) ? \
+                     _Isfinitef(x) : _IsFinite(x)))
+#else
+#include <math.h>
+#define isfinite finite
+#endif
+#endif
+#else
+#include <cmath>
+#if !(defined(__QNXNTO__)) // QNX already defines isfinite
+#define isfinite std::isfinite
+#endif
+#endif
+
+#if defined(_MSC_VER)
+#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
+#define snprintf sprintf_s
+#elif _MSC_VER >= 1900 // VC++ 14.0 and above
+#define snprintf std::snprintf
+#else
+#define snprintf _snprintf
+#endif
+#elif defined(__ANDROID__) || defined(__QNXNTO__)
+#define snprintf snprintf
+#elif __cplusplus >= 201103L
+#define snprintf std::snprintf
+#endif
+
+#if defined(__BORLANDC__)  
+#include <float.h>
+#define isfinite _finite
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
+#else
+typedef std::auto_ptr<StreamWriter>   StreamWriterPtr;
+#endif
+
+static bool containsControlCharacter(const char* str) {
+  while (*str) {
+    if (isControlCharacter(*(str++)))
+      return true;
+  }
+  return false;
+}
+
+static bool containsControlCharacter0(const char* str, unsigned len) {
+  char const* end = str + len;
+  while (end != str) {
+    if (isControlCharacter(*str) || 0==*str)
+      return true;
+    ++str;
+  }
+  return false;
+}
+
+std::string valueToString(LargestInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  if (value == Value::minLargestInt) {
+    uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
+    *--current = '-';
+  } else if (value < 0) {
+    uintToString(LargestUInt(-value), current);
+    *--current = '-';
+  } else {
+    uintToString(LargestUInt(value), current);
+  }
+  assert(current >= buffer);
+  return current;
+}
+
+std::string valueToString(LargestUInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  uintToString(value, current);
+  assert(current >= buffer);
+  return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+std::string valueToString(Int value) {
+  return valueToString(LargestInt(value));
+}
+
+std::string valueToString(UInt value) {
+  return valueToString(LargestUInt(value));
+}
+
+#endif // # if defined(JSON_HAS_INT64)
+
+std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {
+  // Allocate a buffer that is more than large enough to store the 16 digits of
+  // precision requested below.
+  char buffer[32];
+  int len = -1;
+
+  char formatString[6];
+  sprintf(formatString, "%%.%dg", precision);
+
+  // Print into the buffer. We need not request the alternative representation
+  // that always has a decimal point because JSON doesn't distingish the
+  // concepts of reals and integers.
+  if (isfinite(value)) {
+    len = snprintf(buffer, sizeof(buffer), formatString, value);
+  } else {
+    // IEEE standard states that NaN values will not compare to themselves
+    if (value != value) {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
+    } else if (value < 0) {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
+    } else {
+      len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
+    }
+    // For those, we do not need to call fixNumLoc, but it is fast.
+  }
+  assert(len >= 0);
+  fixNumericLocale(buffer, buffer + len);
+  return buffer;
+}
+
+std::string valueToString(double value) { return valueToString(value, false, 17); }
+
+std::string valueToString(bool value) { return value ? "true" : "false"; }
+
+std::string valueToQuotedString(const char* value) {
+  if (value == NULL)
+    return "";
+  // Not sure how to handle unicode...
+  if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
+      !containsControlCharacter(value))
+    return std::string("\"") + value + "\"";
+  // We have to walk value and escape any special characters.
+  // Appending to std::string is not efficient, but this should be rare.
+  // (Note: forward slashes are *not* rare, but I am not escaping them.)
+  std::string::size_type maxsize =
+      strlen(value) * 2 + 3; // allescaped+quotes+NULL
+  std::string result;
+  result.reserve(maxsize); // to avoid lots of mallocs
+  result += "\"";
+  for (const char* c = value; *c != 0; ++c) {
+    switch (*c) {
+    case '\"':
+      result += "\\\"";
+      break;
+    case '\\':
+      result += "\\\\";
+      break;
+    case '\b':
+      result += "\\b";
+      break;
+    case '\f':
+      result += "\\f";
+      break;
+    case '\n':
+      result += "\\n";
+      break;
+    case '\r':
+      result += "\\r";
+      break;
+    case '\t':
+      result += "\\t";
+      break;
+    // case '/':
+    // Even though \/ is considered a legal escape in JSON, a bare
+    // slash is also legal, so I see no reason to escape it.
+    // (I hope I am not misunderstanding something.
+    // blep notes: actually escaping \/ may be useful in javascript to avoid </
+    // sequence.
+    // Should add a flag to allow this compatibility mode and prevent this
+    // sequence from occurring.
+    default:
+      if (isControlCharacter(*c)) {
+        std::ostringstream oss;
+        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+            << std::setw(4) << static_cast<int>(*c);
+        result += oss.str();
+      } else {
+        result += *c;
+      }
+      break;
+    }
+  }
+  result += "\"";
+  return result;
+}
+
+// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp
+static char const* strnpbrk(char const* s, char const* accept, size_t n) {
+  assert((s || !n) && accept);
+
+  char const* const end = s + n;
+  for (char const* cur = s; cur < end; ++cur) {
+    int const c = *cur;
+    for (char const* a = accept; *a; ++a) {
+      if (*a == c) {
+        return cur;
+      }
+    }
+  }
+  return NULL;
+}
+static std::string valueToQuotedStringN(const char* value, unsigned length) {
+  if (value == NULL)
+    return "";
+  // Not sure how to handle unicode...
+  if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL &&
+      !containsControlCharacter0(value, length))
+    return std::string("\"") + value + "\"";
+  // We have to walk value and escape any special characters.
+  // Appending to std::string is not efficient, but this should be rare.
+  // (Note: forward slashes are *not* rare, but I am not escaping them.)
+  std::string::size_type maxsize =
+      length * 2 + 3; // allescaped+quotes+NULL
+  std::string result;
+  result.reserve(maxsize); // to avoid lots of mallocs
+  result += "\"";
+  char const* end = value + length;
+  for (const char* c = value; c != end; ++c) {
+    switch (*c) {
+    case '\"':
+      result += "\\\"";
+      break;
+    case '\\':
+      result += "\\\\";
+      break;
+    case '\b':
+      result += "\\b";
+      break;
+    case '\f':
+      result += "\\f";
+      break;
+    case '\n':
+      result += "\\n";
+      break;
+    case '\r':
+      result += "\\r";
+      break;
+    case '\t':
+      result += "\\t";
+      break;
+    // case '/':
+    // Even though \/ is considered a legal escape in JSON, a bare
+    // slash is also legal, so I see no reason to escape it.
+    // (I hope I am not misunderstanding something.)
+    // blep notes: actually escaping \/ may be useful in javascript to avoid </
+    // sequence.
+    // Should add a flag to allow this compatibility mode and prevent this
+    // sequence from occurring.
+    default:
+      if ((isControlCharacter(*c)) || (*c == 0)) {
+        std::ostringstream oss;
+        oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+            << std::setw(4) << static_cast<int>(*c);
+        result += oss.str();
+      } else {
+        result += *c;
+      }
+      break;
+    }
+  }
+  result += "\"";
+  return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+    : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
+      omitEndingLineFeed_(false) {}
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+std::string FastWriter::write(const Value& root) {
+  document_ = "";
+  writeValue(root);
+  if (!omitEndingLineFeed_)
+    document_ += "\n";
+  return document_;
+}
+
+void FastWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    if (!dropNullPlaceholders_)
+      document_ += "null";
+    break;
+  case intValue:
+    document_ += valueToString(value.asLargestInt());
+    break;
+  case uintValue:
+    document_ += valueToString(value.asLargestUInt());
+    break;
+  case realValue:
+    document_ += valueToString(value.asDouble());
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) document_ += valueToQuotedStringN(str, static_cast<unsigned>(end-str));
+    break;
+  }
+  case booleanValue:
+    document_ += valueToString(value.asBool());
+    break;
+  case arrayValue: {
+    document_ += '[';
+    int size = value.size();
+    for (int index = 0; index < size; ++index) {
+      if (index > 0)
+        document_ += ',';
+      writeValue(value[index]);
+    }
+    document_ += ']';
+  } break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    document_ += '{';
+    for (Value::Members::iterator it = members.begin(); it != members.end();
+         ++it) {
+      const std::string& name = *it;
+      if (it != members.begin())
+        document_ += ',';
+      document_ += valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length()));
+      document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+      writeValue(value[name]);
+    }
+    document_ += '}';
+  } break;
+  }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+    : rightMargin_(74), indentSize_(3), addChildValues_() {}
+
+std::string StyledWriter::write(const Value& root) {
+  document_ = "";
+  addChildValues_ = false;
+  indentString_ = "";
+  writeCommentBeforeValue(root);
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  document_ += "\n";
+  return document_;
+}
+
+void StyledWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        const std::string& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        document_ += " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledWriter::writeArrayValue(const Value& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          writeIndent();
+          writeValue(childValue);
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      document_ += "[ ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          document_ += ", ";
+        document_ += childValues_[index];
+      }
+      document_ += " ]";
+    }
+  }
+}
+
+bool StyledWriter::isMultineArray(const Value& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledWriter::pushValue(const std::string& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    document_ += value;
+}
+
+void StyledWriter::writeIndent() {
+  if (!document_.empty()) {
+    char last = document_[document_.length() - 1];
+    if (last == ' ') // already indented
+      return;
+    if (last != '\n') // Comments may add new-line
+      document_ += '\n';
+  }
+  document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const std::string& value) {
+  writeIndent();
+  document_ += value;
+}
+
+void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
+
+void StyledWriter::unindent() {
+  assert(int(indentString_.size()) >= indentSize_);
+  indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  document_ += "\n";
+  writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    document_ += *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      writeIndent();
+    ++iter;
+  }
+
+  // Comments are stripped of trailing newlines, so add one here
+  document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    document_ += " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    document_ += "\n";
+    document_ += root.getComment(commentAfter);
+    document_ += "\n";
+  }
+}
+
+bool StyledWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(std::string indentation)
+    : document_(NULL), rightMargin_(74), indentation_(indentation),
+      addChildValues_() {}
+
+void StyledStreamWriter::write(std::ostream& out, const Value& root) {
+  document_ = &out;
+  addChildValues_ = false;
+  indentString_ = "";
+  indented_ = true;
+  writeCommentBeforeValue(root);
+  if (!indented_) writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *document_ << "\n";
+  document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue:
+  {
+    // Is NULL possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        const std::string& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        *document_ << " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_) writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *document_ << "[ ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *document_ << ", ";
+        *document_ << childValues_[index];
+      }
+      *document_ << " ]";
+    }
+  }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const std::string& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+  *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const std::string& value) {
+  if (!indented_) writeIndent();
+  *document_ << value;
+  indented_ = false;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_) writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *document_ << *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would include newline
+      *document_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    *document_ << ' ' << root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *document_ << root.getComment(commentAfter);
+  }
+  indented_ = false;
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+//////////////////////////
+// BuiltStyledStreamWriter
+
+/// Scoped enums are not available until C++11.
+struct CommentStyle {
+  /// Decide whether to write comments.
+  enum Enum {
+    None,  ///< Drop all comments.
+    Most,  ///< Recover odd behavior of previous versions (not implemented yet).
+    All  ///< Keep all comments.
+  };
+};
+
+struct BuiltStyledStreamWriter : public StreamWriter
+{
+  BuiltStyledStreamWriter(
+      std::string const& indentation,
+      CommentStyle::Enum cs,
+      std::string const& colonSymbol,
+      std::string const& nullSymbol,
+      std::string const& endingLineFeedSymbol,
+      bool useSpecialFloats,
+      unsigned int precision);
+  int write(Value const& root, std::ostream* sout) override;
+private:
+  void writeValue(Value const& value);
+  void writeArrayValue(Value const& value);
+  bool isMultineArray(Value const& value);
+  void pushValue(std::string const& value);
+  void writeIndent();
+  void writeWithIndent(std::string const& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(Value const& root);
+  void writeCommentAfterValueOnSameLine(Value const& root);
+  static bool hasCommentForValue(const Value& value);
+
+  typedef std::vector<std::string> ChildValues;
+
+  ChildValues childValues_;
+  std::string indentString_;
+  int rightMargin_;
+  std::string indentation_;
+  CommentStyle::Enum cs_;
+  std::string colonSymbol_;
+  std::string nullSymbol_;
+  std::string endingLineFeedSymbol_;
+  bool addChildValues_ : 1;
+  bool indented_ : 1;
+  bool useSpecialFloats_ : 1;
+  unsigned int precision_;
+};
+BuiltStyledStreamWriter::BuiltStyledStreamWriter(
+      std::string const& indentation,
+      CommentStyle::Enum cs,
+      std::string const& colonSymbol,
+      std::string const& nullSymbol,
+      std::string const& endingLineFeedSymbol,
+      bool useSpecialFloats,
+      unsigned int precision)
+  : rightMargin_(74)
+  , indentation_(indentation)
+  , cs_(cs)
+  , colonSymbol_(colonSymbol)
+  , nullSymbol_(nullSymbol)
+  , endingLineFeedSymbol_(endingLineFeedSymbol)
+  , addChildValues_(false)
+  , indented_(false)
+  , useSpecialFloats_(useSpecialFloats)
+  , precision_(precision)
+{
+}
+int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
+{
+  sout_ = sout;
+  addChildValues_ = false;
+  indented_ = true;
+  indentString_ = "";
+  writeCommentBeforeValue(root);
+  if (!indented_) writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *sout_ << endingLineFeedSymbol_;
+  sout_ = NULL;
+  return 0;
+}
+void BuiltStyledStreamWriter::writeValue(Value const& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue(nullSymbol_);
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
+    break;
+  case stringValue:
+  {
+    // Is NULL is possible for value.string_?
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok) pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end-str)));
+    else pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      Value::Members::iterator it = members.begin();
+      for (;;) {
+        std::string const& name = *it;
+        Value const& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedStringN(name.data(), static_cast<unsigned>(name.length())));
+        *sout_ << colonSymbol_;
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value);
+    if (isMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        Value const& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_) writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *sout_ << "[";
+      if (!indentation_.empty()) *sout_ << " ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *sout_ << ", ";
+        *sout_ << childValues_[index];
+      }
+      if (!indentation_.empty()) *sout_ << " ";
+      *sout_ << "]";
+    }
+  }
+}
+
+bool BuiltStyledStreamWriter::isMultineArray(Value const& value) {
+  int size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (int index = 0; index < size && !isMultiLine; ++index) {
+    Value const& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                        childValue.size() > 0);
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (int index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += int(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void BuiltStyledStreamWriter::pushValue(std::string const& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *sout_ << value;
+}
+
+void BuiltStyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+
+  if (!indentation_.empty()) {
+    // In this case, drop newlines too.
+    *sout_ << '\n' << indentString_;
+  }
+}
+
+void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) {
+  if (!indented_) writeIndent();
+  *sout_ << value;
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void BuiltStyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
+  if (cs_ == CommentStyle::None) return;
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_) writeIndent();
+  const std::string& comment = root.getComment(commentBefore);
+  std::string::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *sout_ << *iter;
+    if (*iter == '\n' &&
+       (iter != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would write extra newline
+      *sout_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) {
+  if (cs_ == CommentStyle::None) return;
+  if (root.hasComment(commentAfterOnSameLine))
+    *sout_ << " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *sout_ << root.getComment(commentAfter);
+  }
+}
+
+// static
+bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+///////////////
+// StreamWriter
+
+StreamWriter::StreamWriter()
+    : sout_(NULL)
+{
+}
+StreamWriter::~StreamWriter()
+{
+}
+StreamWriter::Factory::~Factory()
+{}
+StreamWriterBuilder::StreamWriterBuilder()
+{
+  setDefaults(&settings_);
+}
+StreamWriterBuilder::~StreamWriterBuilder()
+{}
+StreamWriter* StreamWriterBuilder::newStreamWriter() const
+{
+  std::string indentation = settings_["indentation"].asString();
+  std::string cs_str = settings_["commentStyle"].asString();
+  bool eyc = settings_["enableYAMLCompatibility"].asBool();
+  bool dnp = settings_["dropNullPlaceholders"].asBool();
+  bool usf = settings_["useSpecialFloats"].asBool(); 
+  unsigned int pre = settings_["precision"].asUInt();
+  CommentStyle::Enum cs = CommentStyle::All;
+  if (cs_str == "All") {
+    cs = CommentStyle::All;
+  } else if (cs_str == "None") {
+    cs = CommentStyle::None;
+  } else {
+    throwRuntimeError("commentStyle must be 'All' or 'None'");
+  }
+  std::string colonSymbol = " : ";
+  if (eyc) {
+    colonSymbol = ": ";
+  } else if (indentation.empty()) {
+    colonSymbol = ":";
+  }
+  std::string nullSymbol = "null";
+  if (dnp) {
+    nullSymbol = "";
+  }
+  if (pre > 17) pre = 17;
+  std::string endingLineFeedSymbol = "";
+  return new BuiltStyledStreamWriter(
+      indentation, cs,
+      colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
+}
+static void getValidWriterKeys(std::set<std::string>* valid_keys)
+{
+  valid_keys->clear();
+  valid_keys->insert("indentation");
+  valid_keys->insert("commentStyle");
+  valid_keys->insert("enableYAMLCompatibility");
+  valid_keys->insert("dropNullPlaceholders");
+  valid_keys->insert("useSpecialFloats");
+  valid_keys->insert("precision");
+}
+bool StreamWriterBuilder::validate(Json::Value* invalid) const
+{
+  Json::Value my_invalid;
+  if (!invalid) invalid = &my_invalid;  // so we do not need to test for NULL
+  Json::Value& inv = *invalid;
+  std::set<std::string> valid_keys;
+  getValidWriterKeys(&valid_keys);
+  Value::Members keys = settings_.getMemberNames();
+  size_t n = keys.size();
+  for (size_t i = 0; i < n; ++i) {
+    std::string const& key = keys[i];
+    if (valid_keys.find(key) == valid_keys.end()) {
+      inv[key] = settings_[key];
+    }
+  }
+  return 0u == inv.size();
+}
+Value& StreamWriterBuilder::operator[](std::string key)
+{
+  return settings_[key];
+}
+// static
+void StreamWriterBuilder::setDefaults(Json::Value* settings)
+{
+  //! [StreamWriterBuilderDefaults]
+  (*settings)["commentStyle"] = "All";
+  (*settings)["indentation"] = "\t";
+  (*settings)["enableYAMLCompatibility"] = false;
+  (*settings)["dropNullPlaceholders"] = false;
+  (*settings)["useSpecialFloats"] = false;
+  (*settings)["precision"] = 17;
+  //! [StreamWriterBuilderDefaults]
+}
+
+std::string writeString(StreamWriter::Factory const& builder, Value const& root) {
+  std::ostringstream sout;
+  StreamWriterPtr const writer(builder.newStreamWriter());
+  writer->write(root, &sout);
+  return sout.str();
+}
+
+std::ostream& operator<<(std::ostream& sout, Value const& root) {
+  StreamWriterBuilder builder;
+  StreamWriterPtr const writer(builder.newStreamWriter());
+  writer->write(root, &sout);
+  return sout;
+}
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: src/lib_json/json_writer.cpp
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
diff --git a/csharp/CHANGES.txt b/csharp/CHANGES.txt
index b29debb..a87cd4d 100644
--- a/csharp/CHANGES.txt
+++ b/csharp/CHANGES.txt
@@ -128,7 +128,7 @@
 - Issue 12:	default value for enumerate fields must be filled out
 
 Other:
-- Rewrite of build using MSBbuild instead of NAnt
+- Rewrite of build using MSbuild instead of NAnt
 - Moved to NUnit Version 2.2.8.0
 - Changed to using secure .snk for releases
 
diff --git a/csharp/README.md b/csharp/README.md
index 305c44b..8c3993e 100644
--- a/csharp/README.md
+++ b/csharp/README.md
@@ -1,18 +1,7 @@
 This directory contains the C# Protocol Buffers runtime library.
 
-Status: Alpha - ready for early adopters
-========================================
-
-This code is still under significant churn. Unlike the original port,
-it only supports proto3 (but not *all* of proto3 yet) - there are no
-unknown fields or extensions, for example. protoc will (eventually)
-deliberately fail if it is asked to generate C# code for proto2
-messages other than descriptor.proto, which is still required for
-reflection. (It's currently exposed publicly, but won't be
-eventually.)
-
-Also unlike the original port, the new version embraces mutability -
-there are no builder types.
+Status: Beta - ready for external testing
+=========================================
 
 Usage
 =====
@@ -36,14 +25,25 @@
 - Windows 8
 - Windows Phone Silverlight 8
 - Windows Phone 8.1
-- .NET Core (dnxcore)
+- .NET Core
+
+You should be able to use Protocol Buffers in Visual Studio 2012 and
+all later versions. This includes all code generated by `protoc`,
+which only uses features from C# 3 and earlier.
 
 Building
 ========
 
-Open the `src/Google.Protobuf.sln` solution in Visual Studio. Click "Build solution" to build the solution. You should be able to run the NUnit test from Test Explorer (you might need to install NUnit Visual Studio add-in).
+Open the `src/Google.Protobuf.sln` solution in Visual Studio 2015 or
+later. You should be able to run the NUnit test from Test Explorer
+(you might need to install NUnit Visual Studio add-in).
 
-Supported Visual Studio versions are VS2013 (update 4) and VS2015. On Linux, you can also use Monodevelop 5.9 (older versions might work fine).
+Although *users* of this project are only expected to have Visual
+Studio 2012 or later, *developers* of the library are required to
+have Visual Studio 2015 or later, as the library uses C# 6 features
+in its implementation. These features have no impact when using the
+compiled code - they're only relevant when building the
+`Google.Protobuf` assembly.
 
 History of C# protobufs
 =======================
@@ -52,3 +52,19 @@
 and represents the latest development version of C# protobufs, that will now be developed
 and maintained by Google. All the development will be done in open, under this repository
 (https://github.com/google/protobuf).
+
+The previous project differs from this project in a number of ways:
+
+- The old code only supported proto2; the new code only supports
+proto3 (so no unknown fields, no required/optional distinction, no
+extensions)
+- The old code was based on immutable message types and builders for
+them
+- The old code did not support maps or `oneof`
+- The old code had its own JSON representation, whereas the new code
+uses the standard protobuf JSON representation
+- The old code had no notion of the "well-known types" which have
+special support in the new code
+- The old project supported some older platforms (such as older
+versions of Silverlight) which are not currently supported in the
+new project
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
index 0d217a9..d979aa5 100755
--- a/csharp/generate_protos.sh
+++ b/csharp/generate_protos.sh
@@ -3,20 +3,10 @@
 # You first need to make sure protoc has been built (see instructions on
 # building protoc in root of this repository)
 
-# This script performs a few fix-ups as part of generation. These are:
-# - descriptor.proto is renamed to descriptor_proto_file.proto before
-#   generation, to avoid the naming collision between the class for the file
-#   descriptor and its Descriptor property
-# - This change also impacts UnittestCustomOptions, which expects to
-#   use a class of Descriptor when it's actually been renamed to
-#   DescriptorProtoFile.
-# - Issue 307 (codegen for double-nested types) breaks Unittest.proto and
-#   its lite equivalents.
-
 set -ex
 
 # cd to repository root
-cd $(dirname $0)/..
+pushd $(dirname $0)/..
 
 # Protocol buffer compiler to use. If the PROTOC variable is set,
 # use that. Otherwise, probe for expected locations under both
@@ -35,11 +25,10 @@
   fi
 fi
 
-# Descriptor proto
-$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf/Reflection \
-    src/google/protobuf/descriptor.proto
-
-$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf/WellKnownTypes \
+# descriptor.proto and well-known types
+$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf \
+    --csharp_opt=base_namespace=Google.Protobuf \
+    src/google/protobuf/descriptor.proto \
     src/google/protobuf/any.proto \
     src/google/protobuf/api.proto \
     src/google/protobuf/duration.proto \
@@ -51,20 +40,23 @@
     src/google/protobuf/type.proto \
     src/google/protobuf/wrappers.proto
 
-$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf.Test/TestProtos \
+# Test protos where the namespace matches the target location
+$PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf.Test \
+    --csharp_opt=base_namespace=Google.Protobuf \
     src/google/protobuf/map_unittest_proto3.proto \
     src/google/protobuf/unittest_proto3.proto \
     src/google/protobuf/unittest_import_proto3.proto \
     src/google/protobuf/unittest_import_public_proto3.proto \
     src/google/protobuf/unittest_well_known_types.proto
 
-
-$PROTOC -Icsharp/protos --csharp_out=csharp/src/Google.Protobuf.Test/TestProtos \
+# Different base namespace to the protos above
+$PROTOC -Icsharp/protos --csharp_out=csharp/src/Google.Protobuf.Test \
+    --csharp_opt=base_namespace=UnitTest.Issues \
     csharp/protos/unittest_issues.proto
 
 # AddressBook sample protos
 $PROTOC -Iexamples --csharp_out=csharp/src/AddressBook \
     examples/addressbook.proto
 
-$PROTOC -Iconformance --csharp_out=csharp/src/Google.Protobuf.Conformance \
+$PROTOC -Iconformance -Isrc --csharp_out=csharp/src/Google.Protobuf.Conformance \
     conformance/conformance.proto
diff --git a/csharp/keys/Google.Protobuf.snk b/csharp/keys/Google.Protobuf.snk
new file mode 100644
index 0000000..7515443
--- /dev/null
+++ b/csharp/keys/Google.Protobuf.snk
Binary files differ
diff --git a/csharp/keys/README.md b/csharp/keys/README.md
index 1a01419..ede6735 100644
--- a/csharp/keys/README.md
+++ b/csharp/keys/README.md
@@ -2,4 +2,8 @@
 --------
 
 - Google.Protobuf.public.snk:
-  Public key to verify strong name of Google.Protobuf assemblies.
\ No newline at end of file
+  Public key to verify strong name of Google.Protobuf assemblies.
+- Google.Protobuf.snk:
+  Signing key to provide strong name of Google.Protobuf assemblies.
+  As per [Microsoft guidance](https://msdn.microsoft.com/en-us/library/wd40t7ad(v=vs.110).aspx)
+  signing key should be checked into the repository.
diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs
index f2be5ba..166dd49 100644
--- a/csharp/src/AddressBook/Addressbook.cs
+++ b/csharp/src/AddressBook/Addressbook.cs
@@ -9,45 +9,50 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.Examples.AddressBook {
 
+  /// <summary>Holder for reflection information generated from addressbook.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class Addressbook {
+  public static partial class AddressbookReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for addressbook.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static Addressbook() {
+    static AddressbookReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "ChFhZGRyZXNzYm9vay5wcm90bxIIdHV0b3JpYWwi1QEKBlBlcnNvbhIMCgRu", 
-            "YW1lGAEgASgJEgoKAmlkGAIgASgFEg0KBWVtYWlsGAMgASgJEiwKBnBob25l", 
-            "cxgEIAMoCzIcLnR1dG9yaWFsLlBlcnNvbi5QaG9uZU51bWJlchpHCgtQaG9u", 
-            "ZU51bWJlchIOCgZudW1iZXIYASABKAkSKAoEdHlwZRgCIAEoDjIaLnR1dG9y", 
-            "aWFsLlBlcnNvbi5QaG9uZVR5cGUiKwoJUGhvbmVUeXBlEgoKBk1PQklMRRAA", 
-            "EggKBEhPTUUQARIICgRXT1JLEAIiLwoLQWRkcmVzc0Jvb2sSIAoGcGVvcGxl", 
-            "GAEgAygLMhAudHV0b3JpYWwuUGVyc29uQlAKFGNvbS5leGFtcGxlLnR1dG9y", 
-            "aWFsQhFBZGRyZXNzQm9va1Byb3Rvc6oCJEdvb2dsZS5Qcm90b2J1Zi5FeGFt", 
+            "ChFhZGRyZXNzYm9vay5wcm90bxIIdHV0b3JpYWwi1QEKBlBlcnNvbhIMCgRu",
+            "YW1lGAEgASgJEgoKAmlkGAIgASgFEg0KBWVtYWlsGAMgASgJEiwKBnBob25l",
+            "cxgEIAMoCzIcLnR1dG9yaWFsLlBlcnNvbi5QaG9uZU51bWJlchpHCgtQaG9u",
+            "ZU51bWJlchIOCgZudW1iZXIYASABKAkSKAoEdHlwZRgCIAEoDjIaLnR1dG9y",
+            "aWFsLlBlcnNvbi5QaG9uZVR5cGUiKwoJUGhvbmVUeXBlEgoKBk1PQklMRRAA",
+            "EggKBEhPTUUQARIICgRXT1JLEAIiLwoLQWRkcmVzc0Jvb2sSIAoGcGVvcGxl",
+            "GAEgAygLMhAudHV0b3JpYWwuUGVyc29uQlAKFGNvbS5leGFtcGxlLnR1dG9y",
+            "aWFsQhFBZGRyZXNzQm9va1Byb3Rvc6oCJEdvb2dsZS5Qcm90b2J1Zi5FeGFt",
             "cGxlcy5BZGRyZXNzQm9va2IGcHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person), new[]{ "Name", "Id", "Email", "Phones" }, null, new[]{ typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber), new[]{ "Number", "Type" }, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.AddressBook), new[]{ "People" }, null, null, null)
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person), global::Google.Protobuf.Examples.AddressBook.Person.Parser, new[]{ "Name", "Id", "Email", "Phones" }, null, new[]{ typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber), global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber.Parser, new[]{ "Number", "Type" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Examples.AddressBook.AddressBook), global::Google.Protobuf.Examples.AddressBook.AddressBook.Parser, new[]{ "People" }, null, null, null)
           }));
     }
     #endregion
 
   }
   #region Messages
+  /// <summary>
+  ///  [START messages]
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Person : pb::IMessage<Person> {
     private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person());
     public static pb::MessageParser<Person> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.Examples.AddressBook.AddressbookReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -71,17 +76,22 @@
       return new Person(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "id" field.</summary>
     public const int IdFieldNumber = 2;
     private int id_;
+    /// <summary>
+    ///  Unique ID number for this person.
+    /// </summary>
     public int Id {
       get { return id_; }
       set {
@@ -89,15 +99,17 @@
       }
     }
 
+    /// <summary>Field number for the "email" field.</summary>
     public const int EmailFieldNumber = 3;
     private string email_ = "";
     public string Email {
       get { return email_; }
       set {
-        email_ = pb::Preconditions.CheckNotNull(value, "value");
+        email_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "phones" field.</summary>
     public const int PhonesFieldNumber = 4;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber> _repeated_phones_codec
         = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneNumber.Parser);
@@ -134,7 +146,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -212,6 +224,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the Person message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       public enum PhoneType {
@@ -248,15 +261,17 @@
           return new PhoneNumber(this);
         }
 
+        /// <summary>Field number for the "number" field.</summary>
         public const int NumberFieldNumber = 1;
         private string number_ = "";
         public string Number {
           get { return number_; }
           set {
-            number_ = pb::Preconditions.CheckNotNull(value, "value");
+            number_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
           }
         }
 
+        /// <summary>Field number for the "type" field.</summary>
         public const int TypeFieldNumber = 2;
         private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE;
         public global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType Type {
@@ -290,7 +305,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -353,13 +368,16 @@
 
   }
 
+  /// <summary>
+  ///  Our address book file is just one of these.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class AddressBook : pb::IMessage<AddressBook> {
     private static readonly pb::MessageParser<AddressBook> _parser = new pb::MessageParser<AddressBook>(() => new AddressBook());
     public static pb::MessageParser<AddressBook> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Examples.AddressBook.Addressbook.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.Examples.AddressBook.AddressbookReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -380,6 +398,7 @@
       return new AddressBook(this);
     }
 
+    /// <summary>Field number for the "people" field.</summary>
     public const int PeopleFieldNumber = 1;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Examples.AddressBook.Person> _repeated_people_codec
         = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Examples.AddressBook.Person.Parser);
@@ -410,7 +429,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/AddressBook/SampleUsage.cs b/csharp/src/AddressBook/SampleUsage.cs
index 936c3be..aaaedda 100644
--- a/csharp/src/AddressBook/SampleUsage.cs
+++ b/csharp/src/AddressBook/SampleUsage.cs
@@ -56,8 +56,11 @@
             }

             Person copy = Person.Parser.ParseFrom(bytes);

 

-            // A more streamlined approach might look like this:

-            bytes = copy.ToByteArray();

+            AddressBook book = new AddressBook

+            {

+                People = { copy }

+            };

+            bytes = book.ToByteArray();

             // And read the address book back again

             AddressBook restored = AddressBook.Parser.ParseFrom(bytes);

             // The message performs a deep-comparison on equality:

diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
index e905d4e..7d85d28 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
@@ -9,137 +9,189 @@
 using scg = global::System.Collections.Generic;
 namespace Conformance {
 
+  /// <summary>Holder for reflection information generated from conformance.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class Conformance {
+  public static partial class ConformanceReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for conformance.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static Conformance() {
+    static ConformanceReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UijQEKEkNvbmZvcm1h", 
-            "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv", 
-            "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY", 
-            "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0QgkKB3BheWxvYWQilgEK", 
-            "E0NvbmZvcm1hbmNlUmVzcG9uc2USFQoLcGFyc2VfZXJyb3IYASABKAlIABIX", 
-            "Cg1ydW50aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgD", 
-            "IAEoDEgAEhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSAB", 
-            "KAlIAEIICgZyZXN1bHQi6yIKDFRlc3RBbGxUeXBlcxIWCg5vcHRpb25hbF9p", 
-            "bnQzMhgBIAEoBRIWCg5vcHRpb25hbF9pbnQ2NBgCIAEoAxIXCg9vcHRpb25h", 
-            "bF91aW50MzIYAyABKA0SFwoPb3B0aW9uYWxfdWludDY0GAQgASgEEhcKD29w", 
-            "dGlvbmFsX3NpbnQzMhgFIAEoERIXCg9vcHRpb25hbF9zaW50NjQYBiABKBIS", 
-            "GAoQb3B0aW9uYWxfZml4ZWQzMhgHIAEoBxIYChBvcHRpb25hbF9maXhlZDY0", 
-            "GAggASgGEhkKEW9wdGlvbmFsX3NmaXhlZDMyGAkgASgPEhkKEW9wdGlvbmFs", 
-            "X3NmaXhlZDY0GAogASgQEhYKDm9wdGlvbmFsX2Zsb2F0GAsgASgCEhcKD29w", 
-            "dGlvbmFsX2RvdWJsZRgMIAEoARIVCg1vcHRpb25hbF9ib29sGA0gASgIEhcK", 
-            "D29wdGlvbmFsX3N0cmluZxgOIAEoCRIWCg5vcHRpb25hbF9ieXRlcxgPIAEo", 
-            "DBJIChdvcHRpb25hbF9uZXN0ZWRfbWVzc2FnZRgSIAEoCzInLmNvbmZvcm1h", 
-            "bmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlEj0KGG9wdGlvbmFsX2Zv", 
-            "cmVpZ25fbWVzc2FnZRgTIAEoCzIbLmNvbmZvcm1hbmNlLkZvcmVpZ25NZXNz", 
-            "YWdlEkIKFG9wdGlvbmFsX25lc3RlZF9lbnVtGBUgASgOMiQuY29uZm9ybWFu", 
-            "Y2UuVGVzdEFsbFR5cGVzLk5lc3RlZEVudW0SNwoVb3B0aW9uYWxfZm9yZWln", 
-            "bl9lbnVtGBYgASgOMhguY29uZm9ybWFuY2UuRm9yZWlnbkVudW0SIQoVb3B0", 
-            "aW9uYWxfc3RyaW5nX3BpZWNlGBggASgJQgIIAhIZCg1vcHRpb25hbF9jb3Jk", 
-            "GBkgASgJQgIIARI0ChFyZWN1cnNpdmVfbWVzc2FnZRgbIAEoCzIZLmNvbmZv", 
-            "cm1hbmNlLlRlc3RBbGxUeXBlcxIWCg5yZXBlYXRlZF9pbnQzMhgfIAMoBRIW", 
-            "Cg5yZXBlYXRlZF9pbnQ2NBggIAMoAxIXCg9yZXBlYXRlZF91aW50MzIYISAD", 
-            "KA0SFwoPcmVwZWF0ZWRfdWludDY0GCIgAygEEhcKD3JlcGVhdGVkX3NpbnQz", 
-            "MhgjIAMoERIXCg9yZXBlYXRlZF9zaW50NjQYJCADKBISGAoQcmVwZWF0ZWRf", 
-            "Zml4ZWQzMhglIAMoBxIYChByZXBlYXRlZF9maXhlZDY0GCYgAygGEhkKEXJl", 
-            "cGVhdGVkX3NmaXhlZDMyGCcgAygPEhkKEXJlcGVhdGVkX3NmaXhlZDY0GCgg", 
-            "AygQEhYKDnJlcGVhdGVkX2Zsb2F0GCkgAygCEhcKD3JlcGVhdGVkX2RvdWJs", 
-            "ZRgqIAMoARIVCg1yZXBlYXRlZF9ib29sGCsgAygIEhcKD3JlcGVhdGVkX3N0", 
-            "cmluZxgsIAMoCRIWCg5yZXBlYXRlZF9ieXRlcxgtIAMoDBJIChdyZXBlYXRl", 
-            "ZF9uZXN0ZWRfbWVzc2FnZRgwIAMoCzInLmNvbmZvcm1hbmNlLlRlc3RBbGxU", 
-            "eXBlcy5OZXN0ZWRNZXNzYWdlEj0KGHJlcGVhdGVkX2ZvcmVpZ25fbWVzc2Fn", 
-            "ZRgxIAMoCzIbLmNvbmZvcm1hbmNlLkZvcmVpZ25NZXNzYWdlEkIKFHJlcGVh", 
-            "dGVkX25lc3RlZF9lbnVtGDMgAygOMiQuY29uZm9ybWFuY2UuVGVzdEFsbFR5", 
-            "cGVzLk5lc3RlZEVudW0SNwoVcmVwZWF0ZWRfZm9yZWlnbl9lbnVtGDQgAygO", 
-            "MhguY29uZm9ybWFuY2UuRm9yZWlnbkVudW0SIQoVcmVwZWF0ZWRfc3RyaW5n", 
-            "X3BpZWNlGDYgAygJQgIIAhIZCg1yZXBlYXRlZF9jb3JkGDcgAygJQgIIARJF", 
-            "Cg9tYXBfaW50MzJfaW50MzIYOCADKAsyLC5jb25mb3JtYW5jZS5UZXN0QWxs", 
-            "VHlwZXMuTWFwSW50MzJJbnQzMkVudHJ5EkUKD21hcF9pbnQ2NF9pbnQ2NBg5", 
-            "IAMoCzIsLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBJbnQ2NEludDY0", 
-            "RW50cnkSSQoRbWFwX3VpbnQzMl91aW50MzIYOiADKAsyLi5jb25mb3JtYW5j", 
-            "ZS5UZXN0QWxsVHlwZXMuTWFwVWludDMyVWludDMyRW50cnkSSQoRbWFwX3Vp", 
-            "bnQ2NF91aW50NjQYOyADKAsyLi5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMu", 
-            "TWFwVWludDY0VWludDY0RW50cnkSSQoRbWFwX3NpbnQzMl9zaW50MzIYPCAD", 
-            "KAsyLi5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwU2ludDMyU2ludDMy", 
-            "RW50cnkSSQoRbWFwX3NpbnQ2NF9zaW50NjQYPSADKAsyLi5jb25mb3JtYW5j", 
-            "ZS5UZXN0QWxsVHlwZXMuTWFwU2ludDY0U2ludDY0RW50cnkSTQoTbWFwX2Zp", 
-            "eGVkMzJfZml4ZWQzMhg+IAMoCzIwLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBl", 
-            "cy5NYXBGaXhlZDMyRml4ZWQzMkVudHJ5Ek0KE21hcF9maXhlZDY0X2ZpeGVk", 
-            "NjQYPyADKAsyMC5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwRml4ZWQ2", 
-            "NEZpeGVkNjRFbnRyeRJRChVtYXBfc2ZpeGVkMzJfc2ZpeGVkMzIYQCADKAsy", 
-            "Mi5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwU2ZpeGVkMzJTZml4ZWQz", 
-            "MkVudHJ5ElEKFW1hcF9zZml4ZWQ2NF9zZml4ZWQ2NBhBIAMoCzIyLmNvbmZv", 
-            "cm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkS", 
-            "RQoPbWFwX2ludDMyX2Zsb2F0GEIgAygLMiwuY29uZm9ybWFuY2UuVGVzdEFs", 
-            "bFR5cGVzLk1hcEludDMyRmxvYXRFbnRyeRJHChBtYXBfaW50MzJfZG91Ymxl", 
-            "GEMgAygLMi0uY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcEludDMyRG91", 
-            "YmxlRW50cnkSQQoNbWFwX2Jvb2xfYm9vbBhEIAMoCzIqLmNvbmZvcm1hbmNl", 
-            "LlRlc3RBbGxUeXBlcy5NYXBCb29sQm9vbEVudHJ5EkkKEW1hcF9zdHJpbmdf", 
-            "c3RyaW5nGEUgAygLMi4uY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcFN0", 
-            "cmluZ1N0cmluZ0VudHJ5EkcKEG1hcF9zdHJpbmdfYnl0ZXMYRiADKAsyLS5j", 
-            "b25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwU3RyaW5nQnl0ZXNFbnRyeRJY", 
-            "ChltYXBfc3RyaW5nX25lc3RlZF9tZXNzYWdlGEcgAygLMjUuY29uZm9ybWFu", 
-            "Y2UuVGVzdEFsbFR5cGVzLk1hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRJa", 
-            "ChptYXBfc3RyaW5nX2ZvcmVpZ25fbWVzc2FnZRhIIAMoCzI2LmNvbmZvcm1h", 
-            "bmNlLlRlc3RBbGxUeXBlcy5NYXBTdHJpbmdGb3JlaWduTWVzc2FnZUVudHJ5", 
-            "ElIKFm1hcF9zdHJpbmdfbmVzdGVkX2VudW0YSSADKAsyMi5jb25mb3JtYW5j", 
-            "ZS5UZXN0QWxsVHlwZXMuTWFwU3RyaW5nTmVzdGVkRW51bUVudHJ5ElQKF21h", 
-            "cF9zdHJpbmdfZm9yZWlnbl9lbnVtGEogAygLMjMuY29uZm9ybWFuY2UuVGVz", 
-            "dEFsbFR5cGVzLk1hcFN0cmluZ0ZvcmVpZ25FbnVtRW50cnkSFgoMb25lb2Zf", 
-            "dWludDMyGG8gASgNSAASRwoUb25lb2ZfbmVzdGVkX21lc3NhZ2UYcCABKAsy", 
-            "Jy5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZUgAEhYK", 
-            "DG9uZW9mX3N0cmluZxhxIAEoCUgAEhUKC29uZW9mX2J5dGVzGHIgASgMSAAa", 
-            "SgoNTmVzdGVkTWVzc2FnZRIJCgFhGAEgASgFEi4KC2NvcmVjdXJzaXZlGAIg", 
-            "ASgLMhkuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzGjQKEk1hcEludDMySW50", 
-            "MzJFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1h", 
-            "cEludDY0SW50NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6", 
-            "AjgBGjYKFE1hcFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2", 
-            "YWx1ZRgCIAEoDToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5", 
-            "GAEgASgEEg0KBXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJF", 
-            "bnRyeRILCgNrZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNp", 
-            "bnQ2NFNpbnQ2NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoC", 
-            "OAEaOAoWTWFwRml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoF", 
-            "dmFsdWUYAiABKAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoD", 
-            "a2V5GAEgASgGEg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNm", 
-            "aXhlZDMyRW50cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6", 
-            "ChhNYXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZh", 
-            "bHVlGAIgASgQOgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEg", 
-            "ASgFEg0KBXZhbHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5", 
-            "EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJv", 
-            "b2xFbnRyeRILCgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGjYKFE1h", 
-            "cFN0cmluZ1N0cmluZ0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEo", 
-            "CToCOAEaNQoTTWFwU3RyaW5nQnl0ZXNFbnRyeRILCgNrZXkYASABKAkSDQoF", 
-            "dmFsdWUYAiABKAw6AjgBGmYKG01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRy", 
-            "eRILCgNrZXkYASABKAkSNgoFdmFsdWUYAiABKAsyJy5jb25mb3JtYW5jZS5U", 
-            "ZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZToCOAEaWwocTWFwU3RyaW5nRm9y", 
-            "ZWlnbk1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAkSKgoFdmFsdWUYAiABKAsy", 
-            "Gy5jb25mb3JtYW5jZS5Gb3JlaWduTWVzc2FnZToCOAEaYAoYTWFwU3RyaW5n", 
-            "TmVzdGVkRW51bUVudHJ5EgsKA2tleRgBIAEoCRIzCgV2YWx1ZRgCIAEoDjIk", 
-            "LmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5OZXN0ZWRFbnVtOgI4ARpVChlN", 
-            "YXBTdHJpbmdGb3JlaWduRW51bUVudHJ5EgsKA2tleRgBIAEoCRInCgV2YWx1", 
-            "ZRgCIAEoDjIYLmNvbmZvcm1hbmNlLkZvcmVpZ25FbnVtOgI4ASI5CgpOZXN0", 
-            "ZWRFbnVtEgcKA0ZPTxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD/////", 
-            "//////8BQg0KC29uZW9mX2ZpZWxkIhsKDkZvcmVpZ25NZXNzYWdlEgkKAWMY", 
-            "ASABKAUqNQoKV2lyZUZvcm1hdBIPCgtVTlNQRUNJRklFRBAAEgwKCFBST1RP", 
-            "QlVGEAESCAoESlNPThACKkAKC0ZvcmVpZ25FbnVtEg8KC0ZPUkVJR05fRk9P", 
-            "EAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACQiEKH2NvbS5n", 
-            "b29nbGUucHJvdG9idWYuY29uZm9ybWFuY2ViBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-          new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.ForeignEnum), }, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Conformance.ConformanceRequest), new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat" }, new[]{ "Payload" }, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Conformance.ConformanceResponse), new[]{ "ParseError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Conformance.TestAllTypes), 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" }, new[]{ "OneofField" }, new[]{ typeof(global::Conformance.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Conformance.TestAllTypes.Types.NestedMessage), new[]{ "A", "Corecursive" }, null, null, null),
+            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UaGWdvb2dsZS9wcm90",
+            "b2J1Zi9hbnkucHJvdG8aHmdvb2dsZS9wcm90b2J1Zi9kdXJhdGlvbi5wcm90",
+            "bxogZ29vZ2xlL3Byb3RvYnVmL2ZpZWxkX21hc2sucHJvdG8aHGdvb2dsZS9w",
+            "cm90b2J1Zi9zdHJ1Y3QucHJvdG8aH2dvb2dsZS9wcm90b2J1Zi90aW1lc3Rh",
+            "bXAucHJvdG8aHmdvb2dsZS9wcm90b2J1Zi93cmFwcGVycy5wcm90byKNAQoS",
+            "Q29uZm9ybWFuY2VSZXF1ZXN0EhoKEHByb3RvYnVmX3BheWxvYWQYASABKAxI",
+            "ABIWCgxqc29uX3BheWxvYWQYAiABKAlIABI4ChdyZXF1ZXN0ZWRfb3V0cHV0",
+            "X2Zvcm1hdBgDIAEoDjIXLmNvbmZvcm1hbmNlLldpcmVGb3JtYXRCCQoHcGF5",
+            "bG9hZCKxAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtwYXJzZV9lcnJvchgB",
+            "IAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgAEhcKDXJ1bnRpbWVf",
+            "ZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2FkGAMgASgMSAASFgoM",
+            "anNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgFIAEoCUgAQggKBnJl",
+            "c3VsdCLVMgoMVGVzdEFsbFR5cGVzEhYKDm9wdGlvbmFsX2ludDMyGAEgASgF",
+            "EhYKDm9wdGlvbmFsX2ludDY0GAIgASgDEhcKD29wdGlvbmFsX3VpbnQzMhgD",
+            "IAEoDRIXCg9vcHRpb25hbF91aW50NjQYBCABKAQSFwoPb3B0aW9uYWxfc2lu",
+            "dDMyGAUgASgREhcKD29wdGlvbmFsX3NpbnQ2NBgGIAEoEhIYChBvcHRpb25h",
+            "bF9maXhlZDMyGAcgASgHEhgKEG9wdGlvbmFsX2ZpeGVkNjQYCCABKAYSGQoR",
+            "b3B0aW9uYWxfc2ZpeGVkMzIYCSABKA8SGQoRb3B0aW9uYWxfc2ZpeGVkNjQY",
+            "CiABKBASFgoOb3B0aW9uYWxfZmxvYXQYCyABKAISFwoPb3B0aW9uYWxfZG91",
+            "YmxlGAwgASgBEhUKDW9wdGlvbmFsX2Jvb2wYDSABKAgSFwoPb3B0aW9uYWxf",
+            "c3RyaW5nGA4gASgJEhYKDm9wdGlvbmFsX2J5dGVzGA8gASgMEkgKF29wdGlv",
+            "bmFsX25lc3RlZF9tZXNzYWdlGBIgASgLMicuY29uZm9ybWFuY2UuVGVzdEFs",
+            "bFR5cGVzLk5lc3RlZE1lc3NhZ2USPQoYb3B0aW9uYWxfZm9yZWlnbl9tZXNz",
+            "YWdlGBMgASgLMhsuY29uZm9ybWFuY2UuRm9yZWlnbk1lc3NhZ2USQgoUb3B0",
+            "aW9uYWxfbmVzdGVkX2VudW0YFSABKA4yJC5jb25mb3JtYW5jZS5UZXN0QWxs",
+            "VHlwZXMuTmVzdGVkRW51bRI3ChVvcHRpb25hbF9mb3JlaWduX2VudW0YFiAB",
+            "KA4yGC5jb25mb3JtYW5jZS5Gb3JlaWduRW51bRIhChVvcHRpb25hbF9zdHJp",
+            "bmdfcGllY2UYGCABKAlCAggCEhkKDW9wdGlvbmFsX2NvcmQYGSABKAlCAggB",
+            "EjQKEXJlY3Vyc2l2ZV9tZXNzYWdlGBsgASgLMhkuY29uZm9ybWFuY2UuVGVz",
+            "dEFsbFR5cGVzEhYKDnJlcGVhdGVkX2ludDMyGB8gAygFEhYKDnJlcGVhdGVk",
+            "X2ludDY0GCAgAygDEhcKD3JlcGVhdGVkX3VpbnQzMhghIAMoDRIXCg9yZXBl",
+            "YXRlZF91aW50NjQYIiADKAQSFwoPcmVwZWF0ZWRfc2ludDMyGCMgAygREhcK",
+            "D3JlcGVhdGVkX3NpbnQ2NBgkIAMoEhIYChByZXBlYXRlZF9maXhlZDMyGCUg",
+            "AygHEhgKEHJlcGVhdGVkX2ZpeGVkNjQYJiADKAYSGQoRcmVwZWF0ZWRfc2Zp",
+            "eGVkMzIYJyADKA8SGQoRcmVwZWF0ZWRfc2ZpeGVkNjQYKCADKBASFgoOcmVw",
+            "ZWF0ZWRfZmxvYXQYKSADKAISFwoPcmVwZWF0ZWRfZG91YmxlGCogAygBEhUK",
+            "DXJlcGVhdGVkX2Jvb2wYKyADKAgSFwoPcmVwZWF0ZWRfc3RyaW5nGCwgAygJ",
+            "EhYKDnJlcGVhdGVkX2J5dGVzGC0gAygMEkgKF3JlcGVhdGVkX25lc3RlZF9t",
+            "ZXNzYWdlGDAgAygLMicuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk5lc3Rl",
+            "ZE1lc3NhZ2USPQoYcmVwZWF0ZWRfZm9yZWlnbl9tZXNzYWdlGDEgAygLMhsu",
+            "Y29uZm9ybWFuY2UuRm9yZWlnbk1lc3NhZ2USQgoUcmVwZWF0ZWRfbmVzdGVk",
+            "X2VudW0YMyADKA4yJC5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTmVzdGVk",
+            "RW51bRI3ChVyZXBlYXRlZF9mb3JlaWduX2VudW0YNCADKA4yGC5jb25mb3Jt",
+            "YW5jZS5Gb3JlaWduRW51bRIhChVyZXBlYXRlZF9zdHJpbmdfcGllY2UYNiAD",
+            "KAlCAggCEhkKDXJlcGVhdGVkX2NvcmQYNyADKAlCAggBEkUKD21hcF9pbnQz",
+            "Ml9pbnQzMhg4IAMoCzIsLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBJ",
+            "bnQzMkludDMyRW50cnkSRQoPbWFwX2ludDY0X2ludDY0GDkgAygLMiwuY29u",
+            "Zm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcEludDY0SW50NjRFbnRyeRJJChFt",
+            "YXBfdWludDMyX3VpbnQzMhg6IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBVaW50MzJVaW50MzJFbnRyeRJJChFtYXBfdWludDY0X3VpbnQ2",
+            "NBg7IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBVaW50NjRV",
+            "aW50NjRFbnRyeRJJChFtYXBfc2ludDMyX3NpbnQzMhg8IAMoCzIuLmNvbmZv",
+            "cm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBTaW50MzJTaW50MzJFbnRyeRJJChFt",
+            "YXBfc2ludDY0X3NpbnQ2NBg9IAMoCzIuLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBTaW50NjRTaW50NjRFbnRyeRJNChNtYXBfZml4ZWQzMl9maXhl",
+            "ZDMyGD4gAygLMjAuY29uZm9ybWFuY2UuVGVzdEFsbFR5cGVzLk1hcEZpeGVk",
+            "MzJGaXhlZDMyRW50cnkSTQoTbWFwX2ZpeGVkNjRfZml4ZWQ2NBg/IAMoCzIw",
+            "LmNvbmZvcm1hbmNlLlRlc3RBbGxUeXBlcy5NYXBGaXhlZDY0Rml4ZWQ2NEVu",
+            "dHJ5ElEKFW1hcF9zZml4ZWQzMl9zZml4ZWQzMhhAIAMoCzIyLmNvbmZvcm1h",
+            "bmNlLlRlc3RBbGxUeXBlcy5NYXBTZml4ZWQzMlNmaXhlZDMyRW50cnkSUQoV",
+            "bWFwX3NmaXhlZDY0X3NmaXhlZDY0GEEgAygLMjIuY29uZm9ybWFuY2UuVGVz",
+            "dEFsbFR5cGVzLk1hcFNmaXhlZDY0U2ZpeGVkNjRFbnRyeRJFCg9tYXBfaW50",
+            "MzJfZmxvYXQYQiADKAsyLC5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFw",
+            "SW50MzJGbG9hdEVudHJ5EkcKEG1hcF9pbnQzMl9kb3VibGUYQyADKAsyLS5j",
+            "b25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwSW50MzJEb3VibGVFbnRyeRJB",
+            "Cg1tYXBfYm9vbF9ib29sGEQgAygLMiouY29uZm9ybWFuY2UuVGVzdEFsbFR5",
+            "cGVzLk1hcEJvb2xCb29sRW50cnkSSQoRbWFwX3N0cmluZ19zdHJpbmcYRSAD",
+            "KAsyLi5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMuTWFwU3RyaW5nU3RyaW5n",
+            "RW50cnkSRwoQbWFwX3N0cmluZ19ieXRlcxhGIAMoCzItLmNvbmZvcm1hbmNl",
+            "LlRlc3RBbGxUeXBlcy5NYXBTdHJpbmdCeXRlc0VudHJ5ElgKGW1hcF9zdHJp",
+            "bmdfbmVzdGVkX21lc3NhZ2UYRyADKAsyNS5jb25mb3JtYW5jZS5UZXN0QWxs",
+            "VHlwZXMuTWFwU3RyaW5nTmVzdGVkTWVzc2FnZUVudHJ5EloKGm1hcF9zdHJp",
+            "bmdfZm9yZWlnbl9tZXNzYWdlGEggAygLMjYuY29uZm9ybWFuY2UuVGVzdEFs",
+            "bFR5cGVzLk1hcFN0cmluZ0ZvcmVpZ25NZXNzYWdlRW50cnkSUgoWbWFwX3N0",
+            "cmluZ19uZXN0ZWRfZW51bRhJIAMoCzIyLmNvbmZvcm1hbmNlLlRlc3RBbGxU",
+            "eXBlcy5NYXBTdHJpbmdOZXN0ZWRFbnVtRW50cnkSVAoXbWFwX3N0cmluZ19m",
+            "b3JlaWduX2VudW0YSiADKAsyMy5jb25mb3JtYW5jZS5UZXN0QWxsVHlwZXMu",
+            "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=="));
+      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),
             null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Conformance.ForeignMessage), new[]{ "C" }, null, null, null)
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ForeignMessage), global::Conformance.ForeignMessage.Parser, new[]{ "C" }, null, null, null)
           }));
     }
     #endregion
@@ -161,13 +213,20 @@
   #endregion
 
   #region Messages
+  /// <summary>
+  ///  Represents a single test case's input.  The testee should:
+  ///
+  ///    1. parse this proto (which should always succeed)
+  ///    2. parse the protobuf or JSON payload in "payload" (which may fail)
+  ///    3. if the parse succeeded, serialize the message in the requested format.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class ConformanceRequest : pb::IMessage<ConformanceRequest> {
     private static readonly pb::MessageParser<ConformanceRequest> _parser = new pb::MessageParser<ConformanceRequest>(() => new ConformanceRequest());
     public static pb::MessageParser<ConformanceRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.Conformance.Descriptor.MessageTypes[0]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -197,26 +256,32 @@
       return new ConformanceRequest(this);
     }
 
+    /// <summary>Field number for the "protobuf_payload" field.</summary>
     public const int ProtobufPayloadFieldNumber = 1;
     public pb::ByteString ProtobufPayload {
       get { return payloadCase_ == PayloadOneofCase.ProtobufPayload ? (pb::ByteString) payload_ : pb::ByteString.Empty; }
       set {
-        payload_ = pb::Preconditions.CheckNotNull(value, "value");
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         payloadCase_ = PayloadOneofCase.ProtobufPayload;
       }
     }
 
+    /// <summary>Field number for the "json_payload" field.</summary>
     public const int JsonPayloadFieldNumber = 2;
     public string JsonPayload {
       get { return payloadCase_ == PayloadOneofCase.JsonPayload ? (string) payload_ : ""; }
       set {
-        payload_ = pb::Preconditions.CheckNotNull(value, "value");
+        payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         payloadCase_ = PayloadOneofCase.JsonPayload;
       }
     }
 
+    /// <summary>Field number for the "requested_output_format" field.</summary>
     public const int RequestedOutputFormatFieldNumber = 3;
     private global::Conformance.WireFormat requestedOutputFormat_ = global::Conformance.WireFormat.UNSPECIFIED;
+    /// <summary>
+    ///  Which format should the testee serialize its message to?
+    /// </summary>
     public global::Conformance.WireFormat RequestedOutputFormat {
       get { return requestedOutputFormat_; }
       set {
@@ -225,6 +290,7 @@
     }
 
     private object payload_;
+    /// <summary>Enum of possible cases for the "payload" oneof.</summary>
     public enum PayloadOneofCase {
       None = 0,
       ProtobufPayload = 1,
@@ -254,6 +320,7 @@
       if (ProtobufPayload != other.ProtobufPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
+      if (PayloadCase != other.PayloadCase) return false;
       return true;
     }
 
@@ -262,11 +329,12 @@
       if (payloadCase_ == PayloadOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) hash ^= RequestedOutputFormat.GetHashCode();
+      hash ^= (int) payloadCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -341,13 +409,16 @@
 
   }
 
+  /// <summary>
+  ///  Represents a single test case's output.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class ConformanceResponse : pb::IMessage<ConformanceResponse> {
     private static readonly pb::MessageParser<ConformanceResponse> _parser = new pb::MessageParser<ConformanceResponse>(() => new ConformanceResponse());
     public static pb::MessageParser<ConformanceResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.Conformance.Descriptor.MessageTypes[1]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -365,6 +436,9 @@
         case ResultOneofCase.ParseError:
           ParseError = other.ParseError;
           break;
+        case ResultOneofCase.SerializeError:
+          SerializeError = other.SerializeError;
+          break;
         case ResultOneofCase.RuntimeError:
           RuntimeError = other.RuntimeError;
           break;
@@ -385,55 +459,101 @@
       return new ConformanceResponse(this);
     }
 
+    /// <summary>Field number for the "parse_error" field.</summary>
     public const int ParseErrorFieldNumber = 1;
+    /// <summary>
+    ///  This string should be set to indicate parsing failed.  The string can
+    ///  provide more information about the parse error if it is available.
+    ///
+    ///  Setting this string does not necessarily mean the testee failed the
+    ///  test.  Some of the test cases are intentionally invalid input.
+    /// </summary>
     public string ParseError {
       get { return resultCase_ == ResultOneofCase.ParseError ? (string) result_ : ""; }
       set {
-        result_ = pb::Preconditions.CheckNotNull(value, "value");
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         resultCase_ = ResultOneofCase.ParseError;
       }
     }
 
+    /// <summary>Field number for the "serialize_error" field.</summary>
+    public const int SerializeErrorFieldNumber = 6;
+    /// <summary>
+    ///  If the input was successfully parsed but errors occurred when
+    ///  serializing it to the requested output format, set the error message in
+    ///  this field.
+    /// </summary>
+    public string SerializeError {
+      get { return resultCase_ == ResultOneofCase.SerializeError ? (string) result_ : ""; }
+      set {
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+        resultCase_ = ResultOneofCase.SerializeError;
+      }
+    }
+
+    /// <summary>Field number for the "runtime_error" field.</summary>
     public const int RuntimeErrorFieldNumber = 2;
+    /// <summary>
+    ///  This should be set if some other error occurred.  This will always
+    ///  indicate that the test failed.  The string can provide more information
+    ///  about the failure.
+    /// </summary>
     public string RuntimeError {
       get { return resultCase_ == ResultOneofCase.RuntimeError ? (string) result_ : ""; }
       set {
-        result_ = pb::Preconditions.CheckNotNull(value, "value");
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         resultCase_ = ResultOneofCase.RuntimeError;
       }
     }
 
+    /// <summary>Field number for the "protobuf_payload" field.</summary>
     public const int ProtobufPayloadFieldNumber = 3;
+    /// <summary>
+    ///  If the input was successfully parsed and the requested output was
+    ///  protobuf, serialize it to protobuf and set it in this field.
+    /// </summary>
     public pb::ByteString ProtobufPayload {
       get { return resultCase_ == ResultOneofCase.ProtobufPayload ? (pb::ByteString) result_ : pb::ByteString.Empty; }
       set {
-        result_ = pb::Preconditions.CheckNotNull(value, "value");
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         resultCase_ = ResultOneofCase.ProtobufPayload;
       }
     }
 
+    /// <summary>Field number for the "json_payload" field.</summary>
     public const int JsonPayloadFieldNumber = 4;
+    /// <summary>
+    ///  If the input was successfully parsed and the requested output was JSON,
+    ///  serialize to JSON and set it in this field.
+    /// </summary>
     public string JsonPayload {
       get { return resultCase_ == ResultOneofCase.JsonPayload ? (string) result_ : ""; }
       set {
-        result_ = pb::Preconditions.CheckNotNull(value, "value");
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         resultCase_ = ResultOneofCase.JsonPayload;
       }
     }
 
+    /// <summary>Field number for the "skipped" field.</summary>
     public const int SkippedFieldNumber = 5;
+    /// <summary>
+    ///  For when the testee skipped the test, likely because a certain feature
+    ///  wasn't supported, like JSON input/output.
+    /// </summary>
     public string Skipped {
       get { return resultCase_ == ResultOneofCase.Skipped ? (string) result_ : ""; }
       set {
-        result_ = pb::Preconditions.CheckNotNull(value, "value");
+        result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         resultCase_ = ResultOneofCase.Skipped;
       }
     }
 
     private object result_;
+    /// <summary>Enum of possible cases for the "result" oneof.</summary>
     public enum ResultOneofCase {
       None = 0,
       ParseError = 1,
+      SerializeError = 6,
       RuntimeError = 2,
       ProtobufPayload = 3,
       JsonPayload = 4,
@@ -461,25 +581,29 @@
         return true;
       }
       if (ParseError != other.ParseError) return false;
+      if (SerializeError != other.SerializeError) return false;
       if (RuntimeError != other.RuntimeError) return false;
       if (ProtobufPayload != other.ProtobufPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
       if (Skipped != other.Skipped) return false;
+      if (ResultCase != other.ResultCase) return false;
       return true;
     }
 
     public override int GetHashCode() {
       int hash = 1;
       if (resultCase_ == ResultOneofCase.ParseError) hash ^= ParseError.GetHashCode();
+      if (resultCase_ == ResultOneofCase.SerializeError) hash ^= SerializeError.GetHashCode();
       if (resultCase_ == ResultOneofCase.RuntimeError) hash ^= RuntimeError.GetHashCode();
       if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
       if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (resultCase_ == ResultOneofCase.Skipped) hash ^= Skipped.GetHashCode();
+      hash ^= (int) resultCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -503,6 +627,10 @@
         output.WriteRawTag(42);
         output.WriteString(Skipped);
       }
+      if (resultCase_ == ResultOneofCase.SerializeError) {
+        output.WriteRawTag(50);
+        output.WriteString(SerializeError);
+      }
     }
 
     public int CalculateSize() {
@@ -510,6 +638,9 @@
       if (resultCase_ == ResultOneofCase.ParseError) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(ParseError);
       }
+      if (resultCase_ == ResultOneofCase.SerializeError) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(SerializeError);
+      }
       if (resultCase_ == ResultOneofCase.RuntimeError) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(RuntimeError);
       }
@@ -533,6 +664,9 @@
         case ResultOneofCase.ParseError:
           ParseError = other.ParseError;
           break;
+        case ResultOneofCase.SerializeError:
+          SerializeError = other.SerializeError;
+          break;
         case ResultOneofCase.RuntimeError:
           RuntimeError = other.RuntimeError;
           break;
@@ -576,19 +710,27 @@
             Skipped = input.ReadString();
             break;
           }
+          case 50: {
+            SerializeError = input.ReadString();
+            break;
+          }
         }
       }
     }
 
   }
 
+  /// <summary>
+  ///  This proto includes every type of field in both singular and repeated
+  ///  forms.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestAllTypes : pb::IMessage<TestAllTypes> {
     private static readonly pb::MessageParser<TestAllTypes> _parser = new pb::MessageParser<TestAllTypes>(() => new TestAllTypes());
     public static pb::MessageParser<TestAllTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.Conformance.Descriptor.MessageTypes[2]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -664,6 +806,48 @@
       mapStringForeignMessage_ = other.mapStringForeignMessage_.Clone();
       mapStringNestedEnum_ = other.mapStringNestedEnum_.Clone();
       mapStringForeignEnum_ = other.mapStringForeignEnum_.Clone();
+      OptionalBoolWrapper = other.OptionalBoolWrapper;
+      OptionalInt32Wrapper = other.OptionalInt32Wrapper;
+      OptionalInt64Wrapper = other.OptionalInt64Wrapper;
+      OptionalUint32Wrapper = other.OptionalUint32Wrapper;
+      OptionalUint64Wrapper = other.OptionalUint64Wrapper;
+      OptionalFloatWrapper = other.OptionalFloatWrapper;
+      OptionalDoubleWrapper = other.OptionalDoubleWrapper;
+      OptionalStringWrapper = other.OptionalStringWrapper;
+      OptionalBytesWrapper = other.OptionalBytesWrapper;
+      repeatedBoolWrapper_ = other.repeatedBoolWrapper_.Clone();
+      repeatedInt32Wrapper_ = other.repeatedInt32Wrapper_.Clone();
+      repeatedInt64Wrapper_ = other.repeatedInt64Wrapper_.Clone();
+      repeatedUint32Wrapper_ = other.repeatedUint32Wrapper_.Clone();
+      repeatedUint64Wrapper_ = other.repeatedUint64Wrapper_.Clone();
+      repeatedFloatWrapper_ = other.repeatedFloatWrapper_.Clone();
+      repeatedDoubleWrapper_ = other.repeatedDoubleWrapper_.Clone();
+      repeatedStringWrapper_ = other.repeatedStringWrapper_.Clone();
+      repeatedBytesWrapper_ = other.repeatedBytesWrapper_.Clone();
+      OptionalDuration = other.optionalDuration_ != null ? other.OptionalDuration.Clone() : null;
+      OptionalTimestamp = other.optionalTimestamp_ != null ? other.OptionalTimestamp.Clone() : null;
+      OptionalFieldMask = other.optionalFieldMask_ != null ? other.OptionalFieldMask.Clone() : null;
+      OptionalStruct = other.optionalStruct_ != null ? other.OptionalStruct.Clone() : null;
+      OptionalAny = other.optionalAny_ != null ? other.OptionalAny.Clone() : null;
+      OptionalValue = other.optionalValue_ != null ? other.OptionalValue.Clone() : null;
+      repeatedDuration_ = other.repeatedDuration_.Clone();
+      repeatedTimestamp_ = other.repeatedTimestamp_.Clone();
+      repeatedFieldmask_ = other.repeatedFieldmask_.Clone();
+      repeatedStruct_ = other.repeatedStruct_.Clone();
+      repeatedAny_ = other.repeatedAny_.Clone();
+      repeatedValue_ = other.repeatedValue_.Clone();
+      fieldname1_ = other.fieldname1_;
+      fieldName2_ = other.fieldName2_;
+      FieldName3_ = other.FieldName3_;
+      fieldName4_ = other.fieldName4_;
+      field0Name5_ = other.field0Name5_;
+      field0Name6_ = other.field0Name6_;
+      fieldName7_ = other.fieldName7_;
+      fieldName8_ = other.fieldName8_;
+      fieldName9_ = other.fieldName9_;
+      fieldName10_ = other.fieldName10_;
+      fIELDNAME11_ = other.fIELDNAME11_;
+      fIELDName12_ = other.fIELDName12_;
       switch (other.OneofFieldCase) {
         case OneofFieldOneofCase.OneofUint32:
           OneofUint32 = other.OneofUint32;
@@ -685,8 +869,12 @@
       return new TestAllTypes(this);
     }
 
+    /// <summary>Field number for the "optional_int32" field.</summary>
     public const int OptionalInt32FieldNumber = 1;
     private int optionalInt32_;
+    /// <summary>
+    ///  Singular
+    /// </summary>
     public int OptionalInt32 {
       get { return optionalInt32_; }
       set {
@@ -694,6 +882,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_int64" field.</summary>
     public const int OptionalInt64FieldNumber = 2;
     private long optionalInt64_;
     public long OptionalInt64 {
@@ -703,6 +892,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_uint32" field.</summary>
     public const int OptionalUint32FieldNumber = 3;
     private uint optionalUint32_;
     public uint OptionalUint32 {
@@ -712,6 +902,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_uint64" field.</summary>
     public const int OptionalUint64FieldNumber = 4;
     private ulong optionalUint64_;
     public ulong OptionalUint64 {
@@ -721,6 +912,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_sint32" field.</summary>
     public const int OptionalSint32FieldNumber = 5;
     private int optionalSint32_;
     public int OptionalSint32 {
@@ -730,6 +922,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_sint64" field.</summary>
     public const int OptionalSint64FieldNumber = 6;
     private long optionalSint64_;
     public long OptionalSint64 {
@@ -739,6 +932,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_fixed32" field.</summary>
     public const int OptionalFixed32FieldNumber = 7;
     private uint optionalFixed32_;
     public uint OptionalFixed32 {
@@ -748,6 +942,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_fixed64" field.</summary>
     public const int OptionalFixed64FieldNumber = 8;
     private ulong optionalFixed64_;
     public ulong OptionalFixed64 {
@@ -757,6 +952,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_sfixed32" field.</summary>
     public const int OptionalSfixed32FieldNumber = 9;
     private int optionalSfixed32_;
     public int OptionalSfixed32 {
@@ -766,6 +962,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_sfixed64" field.</summary>
     public const int OptionalSfixed64FieldNumber = 10;
     private long optionalSfixed64_;
     public long OptionalSfixed64 {
@@ -775,6 +972,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_float" field.</summary>
     public const int OptionalFloatFieldNumber = 11;
     private float optionalFloat_;
     public float OptionalFloat {
@@ -784,6 +982,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_double" field.</summary>
     public const int OptionalDoubleFieldNumber = 12;
     private double optionalDouble_;
     public double OptionalDouble {
@@ -793,6 +992,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_bool" field.</summary>
     public const int OptionalBoolFieldNumber = 13;
     private bool optionalBool_;
     public bool OptionalBool {
@@ -802,24 +1002,27 @@
       }
     }
 
+    /// <summary>Field number for the "optional_string" field.</summary>
     public const int OptionalStringFieldNumber = 14;
     private string optionalString_ = "";
     public string OptionalString {
       get { return optionalString_; }
       set {
-        optionalString_ = pb::Preconditions.CheckNotNull(value, "value");
+        optionalString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "optional_bytes" field.</summary>
     public const int OptionalBytesFieldNumber = 15;
     private pb::ByteString optionalBytes_ = pb::ByteString.Empty;
     public pb::ByteString OptionalBytes {
       get { return optionalBytes_; }
       set {
-        optionalBytes_ = pb::Preconditions.CheckNotNull(value, "value");
+        optionalBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "optional_nested_message" field.</summary>
     public const int OptionalNestedMessageFieldNumber = 18;
     private global::Conformance.TestAllTypes.Types.NestedMessage optionalNestedMessage_;
     public global::Conformance.TestAllTypes.Types.NestedMessage OptionalNestedMessage {
@@ -829,6 +1032,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_foreign_message" field.</summary>
     public const int OptionalForeignMessageFieldNumber = 19;
     private global::Conformance.ForeignMessage optionalForeignMessage_;
     public global::Conformance.ForeignMessage OptionalForeignMessage {
@@ -838,6 +1042,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_nested_enum" field.</summary>
     public const int OptionalNestedEnumFieldNumber = 21;
     private global::Conformance.TestAllTypes.Types.NestedEnum optionalNestedEnum_ = global::Conformance.TestAllTypes.Types.NestedEnum.FOO;
     public global::Conformance.TestAllTypes.Types.NestedEnum OptionalNestedEnum {
@@ -847,6 +1052,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_foreign_enum" field.</summary>
     public const int OptionalForeignEnumFieldNumber = 22;
     private global::Conformance.ForeignEnum optionalForeignEnum_ = global::Conformance.ForeignEnum.FOREIGN_FOO;
     public global::Conformance.ForeignEnum OptionalForeignEnum {
@@ -856,24 +1062,27 @@
       }
     }
 
+    /// <summary>Field number for the "optional_string_piece" field.</summary>
     public const int OptionalStringPieceFieldNumber = 24;
     private string optionalStringPiece_ = "";
     public string OptionalStringPiece {
       get { return optionalStringPiece_; }
       set {
-        optionalStringPiece_ = pb::Preconditions.CheckNotNull(value, "value");
+        optionalStringPiece_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "optional_cord" field.</summary>
     public const int OptionalCordFieldNumber = 25;
     private string optionalCord_ = "";
     public string OptionalCord {
       get { return optionalCord_; }
       set {
-        optionalCord_ = pb::Preconditions.CheckNotNull(value, "value");
+        optionalCord_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "recursive_message" field.</summary>
     public const int RecursiveMessageFieldNumber = 27;
     private global::Conformance.TestAllTypes recursiveMessage_;
     public global::Conformance.TestAllTypes RecursiveMessage {
@@ -883,14 +1092,19 @@
       }
     }
 
+    /// <summary>Field number for the "repeated_int32" field.</summary>
     public const int RepeatedInt32FieldNumber = 31;
     private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
         = pb::FieldCodec.ForInt32(250);
     private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Repeated
+    /// </summary>
     public pbc::RepeatedField<int> RepeatedInt32 {
       get { return repeatedInt32_; }
     }
 
+    /// <summary>Field number for the "repeated_int64" field.</summary>
     public const int RepeatedInt64FieldNumber = 32;
     private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
         = pb::FieldCodec.ForInt64(258);
@@ -899,6 +1113,7 @@
       get { return repeatedInt64_; }
     }
 
+    /// <summary>Field number for the "repeated_uint32" field.</summary>
     public const int RepeatedUint32FieldNumber = 33;
     private static readonly pb::FieldCodec<uint> _repeated_repeatedUint32_codec
         = pb::FieldCodec.ForUInt32(266);
@@ -907,6 +1122,7 @@
       get { return repeatedUint32_; }
     }
 
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
     public const int RepeatedUint64FieldNumber = 34;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
         = pb::FieldCodec.ForUInt64(274);
@@ -915,6 +1131,7 @@
       get { return repeatedUint64_; }
     }
 
+    /// <summary>Field number for the "repeated_sint32" field.</summary>
     public const int RepeatedSint32FieldNumber = 35;
     private static readonly pb::FieldCodec<int> _repeated_repeatedSint32_codec
         = pb::FieldCodec.ForSInt32(282);
@@ -923,6 +1140,7 @@
       get { return repeatedSint32_; }
     }
 
+    /// <summary>Field number for the "repeated_sint64" field.</summary>
     public const int RepeatedSint64FieldNumber = 36;
     private static readonly pb::FieldCodec<long> _repeated_repeatedSint64_codec
         = pb::FieldCodec.ForSInt64(290);
@@ -931,6 +1149,7 @@
       get { return repeatedSint64_; }
     }
 
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
     public const int RepeatedFixed32FieldNumber = 37;
     private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
         = pb::FieldCodec.ForFixed32(298);
@@ -939,6 +1158,7 @@
       get { return repeatedFixed32_; }
     }
 
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
     public const int RepeatedFixed64FieldNumber = 38;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
         = pb::FieldCodec.ForFixed64(306);
@@ -947,6 +1167,7 @@
       get { return repeatedFixed64_; }
     }
 
+    /// <summary>Field number for the "repeated_sfixed32" field.</summary>
     public const int RepeatedSfixed32FieldNumber = 39;
     private static readonly pb::FieldCodec<int> _repeated_repeatedSfixed32_codec
         = pb::FieldCodec.ForSFixed32(314);
@@ -955,6 +1176,7 @@
       get { return repeatedSfixed32_; }
     }
 
+    /// <summary>Field number for the "repeated_sfixed64" field.</summary>
     public const int RepeatedSfixed64FieldNumber = 40;
     private static readonly pb::FieldCodec<long> _repeated_repeatedSfixed64_codec
         = pb::FieldCodec.ForSFixed64(322);
@@ -963,6 +1185,7 @@
       get { return repeatedSfixed64_; }
     }
 
+    /// <summary>Field number for the "repeated_float" field.</summary>
     public const int RepeatedFloatFieldNumber = 41;
     private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
         = pb::FieldCodec.ForFloat(330);
@@ -971,6 +1194,7 @@
       get { return repeatedFloat_; }
     }
 
+    /// <summary>Field number for the "repeated_double" field.</summary>
     public const int RepeatedDoubleFieldNumber = 42;
     private static readonly pb::FieldCodec<double> _repeated_repeatedDouble_codec
         = pb::FieldCodec.ForDouble(338);
@@ -979,6 +1203,7 @@
       get { return repeatedDouble_; }
     }
 
+    /// <summary>Field number for the "repeated_bool" field.</summary>
     public const int RepeatedBoolFieldNumber = 43;
     private static readonly pb::FieldCodec<bool> _repeated_repeatedBool_codec
         = pb::FieldCodec.ForBool(346);
@@ -987,6 +1212,7 @@
       get { return repeatedBool_; }
     }
 
+    /// <summary>Field number for the "repeated_string" field.</summary>
     public const int RepeatedStringFieldNumber = 44;
     private static readonly pb::FieldCodec<string> _repeated_repeatedString_codec
         = pb::FieldCodec.ForString(354);
@@ -995,6 +1221,7 @@
       get { return repeatedString_; }
     }
 
+    /// <summary>Field number for the "repeated_bytes" field.</summary>
     public const int RepeatedBytesFieldNumber = 45;
     private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytes_codec
         = pb::FieldCodec.ForBytes(362);
@@ -1003,6 +1230,7 @@
       get { return repeatedBytes_; }
     }
 
+    /// <summary>Field number for the "repeated_nested_message" field.</summary>
     public const int RepeatedNestedMessageFieldNumber = 48;
     private static readonly pb::FieldCodec<global::Conformance.TestAllTypes.Types.NestedMessage> _repeated_repeatedNestedMessage_codec
         = pb::FieldCodec.ForMessage(386, global::Conformance.TestAllTypes.Types.NestedMessage.Parser);
@@ -1011,6 +1239,7 @@
       get { return repeatedNestedMessage_; }
     }
 
+    /// <summary>Field number for the "repeated_foreign_message" field.</summary>
     public const int RepeatedForeignMessageFieldNumber = 49;
     private static readonly pb::FieldCodec<global::Conformance.ForeignMessage> _repeated_repeatedForeignMessage_codec
         = pb::FieldCodec.ForMessage(394, global::Conformance.ForeignMessage.Parser);
@@ -1019,6 +1248,7 @@
       get { return repeatedForeignMessage_; }
     }
 
+    /// <summary>Field number for the "repeated_nested_enum" field.</summary>
     public const int RepeatedNestedEnumFieldNumber = 51;
     private static readonly pb::FieldCodec<global::Conformance.TestAllTypes.Types.NestedEnum> _repeated_repeatedNestedEnum_codec
         = pb::FieldCodec.ForEnum(410, x => (int) x, x => (global::Conformance.TestAllTypes.Types.NestedEnum) x);
@@ -1027,6 +1257,7 @@
       get { return repeatedNestedEnum_; }
     }
 
+    /// <summary>Field number for the "repeated_foreign_enum" field.</summary>
     public const int RepeatedForeignEnumFieldNumber = 52;
     private static readonly pb::FieldCodec<global::Conformance.ForeignEnum> _repeated_repeatedForeignEnum_codec
         = pb::FieldCodec.ForEnum(418, x => (int) x, x => (global::Conformance.ForeignEnum) x);
@@ -1035,6 +1266,7 @@
       get { return repeatedForeignEnum_; }
     }
 
+    /// <summary>Field number for the "repeated_string_piece" field.</summary>
     public const int RepeatedStringPieceFieldNumber = 54;
     private static readonly pb::FieldCodec<string> _repeated_repeatedStringPiece_codec
         = pb::FieldCodec.ForString(434);
@@ -1043,6 +1275,7 @@
       get { return repeatedStringPiece_; }
     }
 
+    /// <summary>Field number for the "repeated_cord" field.</summary>
     public const int RepeatedCordFieldNumber = 55;
     private static readonly pb::FieldCodec<string> _repeated_repeatedCord_codec
         = pb::FieldCodec.ForString(442);
@@ -1051,14 +1284,19 @@
       get { return repeatedCord_; }
     }
 
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
     public const int MapInt32Int32FieldNumber = 56;
     private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 450);
     private readonly pbc::MapField<int, int> mapInt32Int32_ = new pbc::MapField<int, int>();
+    /// <summary>
+    ///  Map
+    /// </summary>
     public pbc::MapField<int, int> MapInt32Int32 {
       get { return mapInt32Int32_; }
     }
 
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
     public const int MapInt64Int64FieldNumber = 57;
     private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 458);
@@ -1067,6 +1305,7 @@
       get { return mapInt64Int64_; }
     }
 
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
     public const int MapUint32Uint32FieldNumber = 58;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 466);
@@ -1075,6 +1314,7 @@
       get { return mapUint32Uint32_; }
     }
 
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
     public const int MapUint64Uint64FieldNumber = 59;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 474);
@@ -1083,6 +1323,7 @@
       get { return mapUint64Uint64_; }
     }
 
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
     public const int MapSint32Sint32FieldNumber = 60;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 482);
@@ -1091,6 +1332,7 @@
       get { return mapSint32Sint32_; }
     }
 
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
     public const int MapSint64Sint64FieldNumber = 61;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 490);
@@ -1099,6 +1341,7 @@
       get { return mapSint64Sint64_; }
     }
 
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
     public const int MapFixed32Fixed32FieldNumber = 62;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 498);
@@ -1107,6 +1350,7 @@
       get { return mapFixed32Fixed32_; }
     }
 
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
     public const int MapFixed64Fixed64FieldNumber = 63;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 506);
@@ -1115,6 +1359,7 @@
       get { return mapFixed64Fixed64_; }
     }
 
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
     public const int MapSfixed32Sfixed32FieldNumber = 64;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 514);
@@ -1123,6 +1368,7 @@
       get { return mapSfixed32Sfixed32_; }
     }
 
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
     public const int MapSfixed64Sfixed64FieldNumber = 65;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 522);
@@ -1131,6 +1377,7 @@
       get { return mapSfixed64Sfixed64_; }
     }
 
+    /// <summary>Field number for the "map_int32_float" field.</summary>
     public const int MapInt32FloatFieldNumber = 66;
     private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
         = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 530);
@@ -1139,6 +1386,7 @@
       get { return mapInt32Float_; }
     }
 
+    /// <summary>Field number for the "map_int32_double" field.</summary>
     public const int MapInt32DoubleFieldNumber = 67;
     private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
         = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 538);
@@ -1147,6 +1395,7 @@
       get { return mapInt32Double_; }
     }
 
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
     public const int MapBoolBoolFieldNumber = 68;
     private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
         = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 546);
@@ -1155,6 +1404,7 @@
       get { return mapBoolBool_; }
     }
 
+    /// <summary>Field number for the "map_string_string" field.</summary>
     public const int MapStringStringFieldNumber = 69;
     private static readonly pbc::MapField<string, string>.Codec _map_mapStringString_codec
         = new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 554);
@@ -1163,6 +1413,7 @@
       get { return mapStringString_; }
     }
 
+    /// <summary>Field number for the "map_string_bytes" field.</summary>
     public const int MapStringBytesFieldNumber = 70;
     private static readonly pbc::MapField<string, pb::ByteString>.Codec _map_mapStringBytes_codec
         = new pbc::MapField<string, pb::ByteString>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForBytes(18), 562);
@@ -1171,6 +1422,7 @@
       get { return mapStringBytes_; }
     }
 
+    /// <summary>Field number for the "map_string_nested_message" field.</summary>
     public const int MapStringNestedMessageFieldNumber = 71;
     private static readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage>.Codec _map_mapStringNestedMessage_codec
         = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedMessage>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Conformance.TestAllTypes.Types.NestedMessage.Parser), 570);
@@ -1179,6 +1431,7 @@
       get { return mapStringNestedMessage_; }
     }
 
+    /// <summary>Field number for the "map_string_foreign_message" field.</summary>
     public const int MapStringForeignMessageFieldNumber = 72;
     private static readonly pbc::MapField<string, global::Conformance.ForeignMessage>.Codec _map_mapStringForeignMessage_codec
         = new pbc::MapField<string, global::Conformance.ForeignMessage>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Conformance.ForeignMessage.Parser), 578);
@@ -1187,6 +1440,7 @@
       get { return mapStringForeignMessage_; }
     }
 
+    /// <summary>Field number for the "map_string_nested_enum" field.</summary>
     public const int MapStringNestedEnumFieldNumber = 73;
     private static readonly pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum>.Codec _map_mapStringNestedEnum_codec
         = new pbc::MapField<string, global::Conformance.TestAllTypes.Types.NestedEnum>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Conformance.TestAllTypes.Types.NestedEnum) x), 586);
@@ -1195,6 +1449,7 @@
       get { return mapStringNestedEnum_; }
     }
 
+    /// <summary>Field number for the "map_string_foreign_enum" field.</summary>
     public const int MapStringForeignEnumFieldNumber = 74;
     private static readonly pbc::MapField<string, global::Conformance.ForeignEnum>.Codec _map_mapStringForeignEnum_codec
         = new pbc::MapField<string, global::Conformance.ForeignEnum>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Conformance.ForeignEnum) x), 594);
@@ -1203,6 +1458,7 @@
       get { return mapStringForeignEnum_; }
     }
 
+    /// <summary>Field number for the "oneof_uint32" field.</summary>
     public const int OneofUint32FieldNumber = 111;
     public uint OneofUint32 {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
@@ -1212,6 +1468,7 @@
       }
     }
 
+    /// <summary>Field number for the "oneof_nested_message" field.</summary>
     public const int OneofNestedMessageFieldNumber = 112;
     public global::Conformance.TestAllTypes.Types.NestedMessage OneofNestedMessage {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage ? (global::Conformance.TestAllTypes.Types.NestedMessage) oneofField_ : null; }
@@ -1221,25 +1478,448 @@
       }
     }
 
+    /// <summary>Field number for the "oneof_string" field.</summary>
     public const int OneofStringFieldNumber = 113;
     public string OneofString {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
       set {
-        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofString;
       }
     }
 
+    /// <summary>Field number for the "oneof_bytes" field.</summary>
     public const int OneofBytesFieldNumber = 114;
     public pb::ByteString OneofBytes {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
       set {
-        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
       }
     }
 
+    /// <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);
+    private bool? optionalBoolWrapper_;
+    /// <summary>
+    ///  Well-known types
+    /// </summary>
+    public bool? OptionalBoolWrapper {
+      get { return optionalBoolWrapper_; }
+      set {
+        optionalBoolWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int32_wrapper" field.</summary>
+    public const int OptionalInt32WrapperFieldNumber = 202;
+    private static readonly pb::FieldCodec<int?> _single_optionalInt32Wrapper_codec = pb::FieldCodec.ForStructWrapper<int>(1618);
+    private int? optionalInt32Wrapper_;
+    public int? OptionalInt32Wrapper {
+      get { return optionalInt32Wrapper_; }
+      set {
+        optionalInt32Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_int64_wrapper" field.</summary>
+    public const int OptionalInt64WrapperFieldNumber = 203;
+    private static readonly pb::FieldCodec<long?> _single_optionalInt64Wrapper_codec = pb::FieldCodec.ForStructWrapper<long>(1626);
+    private long? optionalInt64Wrapper_;
+    public long? OptionalInt64Wrapper {
+      get { return optionalInt64Wrapper_; }
+      set {
+        optionalInt64Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint32_wrapper" field.</summary>
+    public const int OptionalUint32WrapperFieldNumber = 204;
+    private static readonly pb::FieldCodec<uint?> _single_optionalUint32Wrapper_codec = pb::FieldCodec.ForStructWrapper<uint>(1634);
+    private uint? optionalUint32Wrapper_;
+    public uint? OptionalUint32Wrapper {
+      get { return optionalUint32Wrapper_; }
+      set {
+        optionalUint32Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_uint64_wrapper" field.</summary>
+    public const int OptionalUint64WrapperFieldNumber = 205;
+    private static readonly pb::FieldCodec<ulong?> _single_optionalUint64Wrapper_codec = pb::FieldCodec.ForStructWrapper<ulong>(1642);
+    private ulong? optionalUint64Wrapper_;
+    public ulong? OptionalUint64Wrapper {
+      get { return optionalUint64Wrapper_; }
+      set {
+        optionalUint64Wrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_float_wrapper" field.</summary>
+    public const int OptionalFloatWrapperFieldNumber = 206;
+    private static readonly pb::FieldCodec<float?> _single_optionalFloatWrapper_codec = pb::FieldCodec.ForStructWrapper<float>(1650);
+    private float? optionalFloatWrapper_;
+    public float? OptionalFloatWrapper {
+      get { return optionalFloatWrapper_; }
+      set {
+        optionalFloatWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_double_wrapper" field.</summary>
+    public const int OptionalDoubleWrapperFieldNumber = 207;
+    private static readonly pb::FieldCodec<double?> _single_optionalDoubleWrapper_codec = pb::FieldCodec.ForStructWrapper<double>(1658);
+    private double? optionalDoubleWrapper_;
+    public double? OptionalDoubleWrapper {
+      get { return optionalDoubleWrapper_; }
+      set {
+        optionalDoubleWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_string_wrapper" field.</summary>
+    public const int OptionalStringWrapperFieldNumber = 208;
+    private static readonly pb::FieldCodec<string> _single_optionalStringWrapper_codec = pb::FieldCodec.ForClassWrapper<string>(1666);
+    private string optionalStringWrapper_;
+    public string OptionalStringWrapper {
+      get { return optionalStringWrapper_; }
+      set {
+        optionalStringWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_bytes_wrapper" field.</summary>
+    public const int OptionalBytesWrapperFieldNumber = 209;
+    private static readonly pb::FieldCodec<pb::ByteString> _single_optionalBytesWrapper_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(1674);
+    private pb::ByteString optionalBytesWrapper_;
+    public pb::ByteString OptionalBytesWrapper {
+      get { return optionalBytesWrapper_; }
+      set {
+        optionalBytesWrapper_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_bool_wrapper" field.</summary>
+    public const int RepeatedBoolWrapperFieldNumber = 211;
+    private static readonly pb::FieldCodec<bool?> _repeated_repeatedBoolWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<bool>(1690);
+    private readonly pbc::RepeatedField<bool?> repeatedBoolWrapper_ = new pbc::RepeatedField<bool?>();
+    public pbc::RepeatedField<bool?> RepeatedBoolWrapper {
+      get { return repeatedBoolWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_int32_wrapper" field.</summary>
+    public const int RepeatedInt32WrapperFieldNumber = 212;
+    private static readonly pb::FieldCodec<int?> _repeated_repeatedInt32Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<int>(1698);
+    private readonly pbc::RepeatedField<int?> repeatedInt32Wrapper_ = new pbc::RepeatedField<int?>();
+    public pbc::RepeatedField<int?> RepeatedInt32Wrapper {
+      get { return repeatedInt32Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_int64_wrapper" field.</summary>
+    public const int RepeatedInt64WrapperFieldNumber = 213;
+    private static readonly pb::FieldCodec<long?> _repeated_repeatedInt64Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<long>(1706);
+    private readonly pbc::RepeatedField<long?> repeatedInt64Wrapper_ = new pbc::RepeatedField<long?>();
+    public pbc::RepeatedField<long?> RepeatedInt64Wrapper {
+      get { return repeatedInt64Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint32_wrapper" field.</summary>
+    public const int RepeatedUint32WrapperFieldNumber = 214;
+    private static readonly pb::FieldCodec<uint?> _repeated_repeatedUint32Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<uint>(1714);
+    private readonly pbc::RepeatedField<uint?> repeatedUint32Wrapper_ = new pbc::RepeatedField<uint?>();
+    public pbc::RepeatedField<uint?> RepeatedUint32Wrapper {
+      get { return repeatedUint32Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_uint64_wrapper" field.</summary>
+    public const int RepeatedUint64WrapperFieldNumber = 215;
+    private static readonly pb::FieldCodec<ulong?> _repeated_repeatedUint64Wrapper_codec
+        = pb::FieldCodec.ForStructWrapper<ulong>(1722);
+    private readonly pbc::RepeatedField<ulong?> repeatedUint64Wrapper_ = new pbc::RepeatedField<ulong?>();
+    public pbc::RepeatedField<ulong?> RepeatedUint64Wrapper {
+      get { return repeatedUint64Wrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_float_wrapper" field.</summary>
+    public const int RepeatedFloatWrapperFieldNumber = 216;
+    private static readonly pb::FieldCodec<float?> _repeated_repeatedFloatWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<float>(1730);
+    private readonly pbc::RepeatedField<float?> repeatedFloatWrapper_ = new pbc::RepeatedField<float?>();
+    public pbc::RepeatedField<float?> RepeatedFloatWrapper {
+      get { return repeatedFloatWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_double_wrapper" field.</summary>
+    public const int RepeatedDoubleWrapperFieldNumber = 217;
+    private static readonly pb::FieldCodec<double?> _repeated_repeatedDoubleWrapper_codec
+        = pb::FieldCodec.ForStructWrapper<double>(1738);
+    private readonly pbc::RepeatedField<double?> repeatedDoubleWrapper_ = new pbc::RepeatedField<double?>();
+    public pbc::RepeatedField<double?> RepeatedDoubleWrapper {
+      get { return repeatedDoubleWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_string_wrapper" field.</summary>
+    public const int RepeatedStringWrapperFieldNumber = 218;
+    private static readonly pb::FieldCodec<string> _repeated_repeatedStringWrapper_codec
+        = pb::FieldCodec.ForClassWrapper<string>(1746);
+    private readonly pbc::RepeatedField<string> repeatedStringWrapper_ = new pbc::RepeatedField<string>();
+    public pbc::RepeatedField<string> RepeatedStringWrapper {
+      get { return repeatedStringWrapper_; }
+    }
+
+    /// <summary>Field number for the "repeated_bytes_wrapper" field.</summary>
+    public const int RepeatedBytesWrapperFieldNumber = 219;
+    private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytesWrapper_codec
+        = pb::FieldCodec.ForClassWrapper<pb::ByteString>(1754);
+    private readonly pbc::RepeatedField<pb::ByteString> repeatedBytesWrapper_ = new pbc::RepeatedField<pb::ByteString>();
+    public pbc::RepeatedField<pb::ByteString> RepeatedBytesWrapper {
+      get { return repeatedBytesWrapper_; }
+    }
+
+    /// <summary>Field number for the "optional_duration" field.</summary>
+    public const int OptionalDurationFieldNumber = 301;
+    private global::Google.Protobuf.WellKnownTypes.Duration optionalDuration_;
+    public global::Google.Protobuf.WellKnownTypes.Duration OptionalDuration {
+      get { return optionalDuration_; }
+      set {
+        optionalDuration_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_timestamp" field.</summary>
+    public const int OptionalTimestampFieldNumber = 302;
+    private global::Google.Protobuf.WellKnownTypes.Timestamp optionalTimestamp_;
+    public global::Google.Protobuf.WellKnownTypes.Timestamp OptionalTimestamp {
+      get { return optionalTimestamp_; }
+      set {
+        optionalTimestamp_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_field_mask" field.</summary>
+    public const int OptionalFieldMaskFieldNumber = 303;
+    private global::Google.Protobuf.WellKnownTypes.FieldMask optionalFieldMask_;
+    public global::Google.Protobuf.WellKnownTypes.FieldMask OptionalFieldMask {
+      get { return optionalFieldMask_; }
+      set {
+        optionalFieldMask_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_struct" field.</summary>
+    public const int OptionalStructFieldNumber = 304;
+    private global::Google.Protobuf.WellKnownTypes.Struct optionalStruct_;
+    public global::Google.Protobuf.WellKnownTypes.Struct OptionalStruct {
+      get { return optionalStruct_; }
+      set {
+        optionalStruct_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_any" field.</summary>
+    public const int OptionalAnyFieldNumber = 305;
+    private global::Google.Protobuf.WellKnownTypes.Any optionalAny_;
+    public global::Google.Protobuf.WellKnownTypes.Any OptionalAny {
+      get { return optionalAny_; }
+      set {
+        optionalAny_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "optional_value" field.</summary>
+    public const int OptionalValueFieldNumber = 306;
+    private global::Google.Protobuf.WellKnownTypes.Value optionalValue_;
+    public global::Google.Protobuf.WellKnownTypes.Value OptionalValue {
+      get { return optionalValue_; }
+      set {
+        optionalValue_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "repeated_duration" field.</summary>
+    public const int RepeatedDurationFieldNumber = 311;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Duration> _repeated_repeatedDuration_codec
+        = pb::FieldCodec.ForMessage(2490, global::Google.Protobuf.WellKnownTypes.Duration.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> repeatedDuration_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Duration> RepeatedDuration {
+      get { return repeatedDuration_; }
+    }
+
+    /// <summary>Field number for the "repeated_timestamp" field.</summary>
+    public const int RepeatedTimestampFieldNumber = 312;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Timestamp> _repeated_repeatedTimestamp_codec
+        = pb::FieldCodec.ForMessage(2498, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> repeatedTimestamp_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Timestamp> RepeatedTimestamp {
+      get { return repeatedTimestamp_; }
+    }
+
+    /// <summary>Field number for the "repeated_fieldmask" field.</summary>
+    public const int RepeatedFieldmaskFieldNumber = 313;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.FieldMask> _repeated_repeatedFieldmask_codec
+        = pb::FieldCodec.ForMessage(2506, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> repeatedFieldmask_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.FieldMask> RepeatedFieldmask {
+      get { return repeatedFieldmask_; }
+    }
+
+    /// <summary>Field number for the "repeated_struct" field.</summary>
+    public const int RepeatedStructFieldNumber = 324;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Struct> _repeated_repeatedStruct_codec
+        = pb::FieldCodec.ForMessage(2594, global::Google.Protobuf.WellKnownTypes.Struct.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> repeatedStruct_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Struct> RepeatedStruct {
+      get { return repeatedStruct_; }
+    }
+
+    /// <summary>Field number for the "repeated_any" field.</summary>
+    public const int RepeatedAnyFieldNumber = 315;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Any> _repeated_repeatedAny_codec
+        = pb::FieldCodec.ForMessage(2522, global::Google.Protobuf.WellKnownTypes.Any.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> repeatedAny_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Any> RepeatedAny {
+      get { return repeatedAny_; }
+    }
+
+    /// <summary>Field number for the "repeated_value" field.</summary>
+    public const int RepeatedValueFieldNumber = 316;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_repeatedValue_codec
+        = pb::FieldCodec.ForMessage(2530, global::Google.Protobuf.WellKnownTypes.Value.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> repeatedValue_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> RepeatedValue {
+      get { return repeatedValue_; }
+    }
+
+    /// <summary>Field number for the "fieldname1" field.</summary>
+    public const int Fieldname1FieldNumber = 401;
+    private int fieldname1_;
+    /// <summary>
+    ///  Test field-name-to-JSON-name convention.
+    /// </summary>
+    public int Fieldname1 {
+      get { return fieldname1_; }
+      set {
+        fieldname1_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_name2" field.</summary>
+    public const int FieldName2FieldNumber = 402;
+    private int fieldName2_;
+    public int FieldName2 {
+      get { return fieldName2_; }
+      set {
+        fieldName2_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "_field_name3" field.</summary>
+    public const int FieldName3FieldNumber = 403;
+    private int FieldName3_;
+    public int FieldName3 {
+      get { return FieldName3_; }
+      set {
+        FieldName3_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field__name4_" field.</summary>
+    public const int FieldName4FieldNumber = 404;
+    private int fieldName4_;
+    public int FieldName4 {
+      get { return fieldName4_; }
+      set {
+        fieldName4_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field0name5" field.</summary>
+    public const int Field0Name5FieldNumber = 405;
+    private int field0Name5_;
+    public int Field0Name5 {
+      get { return field0Name5_; }
+      set {
+        field0Name5_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_0_name6" field.</summary>
+    public const int Field0Name6FieldNumber = 406;
+    private int field0Name6_;
+    public int Field0Name6 {
+      get { return field0Name6_; }
+      set {
+        field0Name6_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "fieldName7" field.</summary>
+    public const int FieldName7FieldNumber = 407;
+    private int fieldName7_;
+    public int FieldName7 {
+      get { return fieldName7_; }
+      set {
+        fieldName7_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FieldName8" field.</summary>
+    public const int FieldName8FieldNumber = 408;
+    private int fieldName8_;
+    public int FieldName8 {
+      get { return fieldName8_; }
+      set {
+        fieldName8_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "field_Name9" field.</summary>
+    public const int FieldName9FieldNumber = 409;
+    private int fieldName9_;
+    public int FieldName9 {
+      get { return fieldName9_; }
+      set {
+        fieldName9_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "Field_Name10" field.</summary>
+    public const int FieldName10FieldNumber = 410;
+    private int fieldName10_;
+    public int FieldName10 {
+      get { return fieldName10_; }
+      set {
+        fieldName10_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FIELD_NAME11" field.</summary>
+    public const int FIELDNAME11FieldNumber = 411;
+    private int fIELDNAME11_;
+    public int FIELDNAME11 {
+      get { return fIELDNAME11_; }
+      set {
+        fIELDNAME11_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "FIELD_name12" field.</summary>
+    public const int FIELDName12FieldNumber = 412;
+    private int fIELDName12_;
+    public int FIELDName12 {
+      get { return fIELDName12_; }
+      set {
+        fIELDName12_ = value;
+      }
+    }
+
     private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
     public enum OneofFieldOneofCase {
       None = 0,
       OneofUint32 = 111,
@@ -1334,6 +2014,49 @@
       if (!object.Equals(OneofNestedMessage, other.OneofNestedMessage)) return false;
       if (OneofString != other.OneofString) return false;
       if (OneofBytes != other.OneofBytes) return false;
+      if (OptionalBoolWrapper != other.OptionalBoolWrapper) return false;
+      if (OptionalInt32Wrapper != other.OptionalInt32Wrapper) return false;
+      if (OptionalInt64Wrapper != other.OptionalInt64Wrapper) return false;
+      if (OptionalUint32Wrapper != other.OptionalUint32Wrapper) return false;
+      if (OptionalUint64Wrapper != other.OptionalUint64Wrapper) return false;
+      if (OptionalFloatWrapper != other.OptionalFloatWrapper) return false;
+      if (OptionalDoubleWrapper != other.OptionalDoubleWrapper) return false;
+      if (OptionalStringWrapper != other.OptionalStringWrapper) return false;
+      if (OptionalBytesWrapper != other.OptionalBytesWrapper) return false;
+      if(!repeatedBoolWrapper_.Equals(other.repeatedBoolWrapper_)) return false;
+      if(!repeatedInt32Wrapper_.Equals(other.repeatedInt32Wrapper_)) return false;
+      if(!repeatedInt64Wrapper_.Equals(other.repeatedInt64Wrapper_)) return false;
+      if(!repeatedUint32Wrapper_.Equals(other.repeatedUint32Wrapper_)) return false;
+      if(!repeatedUint64Wrapper_.Equals(other.repeatedUint64Wrapper_)) return false;
+      if(!repeatedFloatWrapper_.Equals(other.repeatedFloatWrapper_)) return false;
+      if(!repeatedDoubleWrapper_.Equals(other.repeatedDoubleWrapper_)) return false;
+      if(!repeatedStringWrapper_.Equals(other.repeatedStringWrapper_)) return false;
+      if(!repeatedBytesWrapper_.Equals(other.repeatedBytesWrapper_)) return false;
+      if (!object.Equals(OptionalDuration, other.OptionalDuration)) return false;
+      if (!object.Equals(OptionalTimestamp, other.OptionalTimestamp)) return false;
+      if (!object.Equals(OptionalFieldMask, other.OptionalFieldMask)) return false;
+      if (!object.Equals(OptionalStruct, other.OptionalStruct)) return false;
+      if (!object.Equals(OptionalAny, other.OptionalAny)) return false;
+      if (!object.Equals(OptionalValue, other.OptionalValue)) return false;
+      if(!repeatedDuration_.Equals(other.repeatedDuration_)) return false;
+      if(!repeatedTimestamp_.Equals(other.repeatedTimestamp_)) return false;
+      if(!repeatedFieldmask_.Equals(other.repeatedFieldmask_)) return false;
+      if(!repeatedStruct_.Equals(other.repeatedStruct_)) return false;
+      if(!repeatedAny_.Equals(other.repeatedAny_)) return false;
+      if(!repeatedValue_.Equals(other.repeatedValue_)) return false;
+      if (Fieldname1 != other.Fieldname1) return false;
+      if (FieldName2 != other.FieldName2) return false;
+      if (FieldName3 != other.FieldName3) return false;
+      if (FieldName4 != other.FieldName4) return false;
+      if (Field0Name5 != other.Field0Name5) return false;
+      if (Field0Name6 != other.Field0Name6) return false;
+      if (FieldName7 != other.FieldName7) return false;
+      if (FieldName8 != other.FieldName8) return false;
+      if (FieldName9 != other.FieldName9) return false;
+      if (FieldName10 != other.FieldName10) return false;
+      if (FIELDNAME11 != other.FIELDNAME11) return false;
+      if (FIELDName12 != other.FIELDName12) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
       return true;
     }
 
@@ -1405,11 +2128,54 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+      if (optionalBoolWrapper_ != null) hash ^= OptionalBoolWrapper.GetHashCode();
+      if (optionalInt32Wrapper_ != null) hash ^= OptionalInt32Wrapper.GetHashCode();
+      if (optionalInt64Wrapper_ != null) hash ^= OptionalInt64Wrapper.GetHashCode();
+      if (optionalUint32Wrapper_ != null) hash ^= OptionalUint32Wrapper.GetHashCode();
+      if (optionalUint64Wrapper_ != null) hash ^= OptionalUint64Wrapper.GetHashCode();
+      if (optionalFloatWrapper_ != null) hash ^= OptionalFloatWrapper.GetHashCode();
+      if (optionalDoubleWrapper_ != null) hash ^= OptionalDoubleWrapper.GetHashCode();
+      if (optionalStringWrapper_ != null) hash ^= OptionalStringWrapper.GetHashCode();
+      if (optionalBytesWrapper_ != null) hash ^= OptionalBytesWrapper.GetHashCode();
+      hash ^= repeatedBoolWrapper_.GetHashCode();
+      hash ^= repeatedInt32Wrapper_.GetHashCode();
+      hash ^= repeatedInt64Wrapper_.GetHashCode();
+      hash ^= repeatedUint32Wrapper_.GetHashCode();
+      hash ^= repeatedUint64Wrapper_.GetHashCode();
+      hash ^= repeatedFloatWrapper_.GetHashCode();
+      hash ^= repeatedDoubleWrapper_.GetHashCode();
+      hash ^= repeatedStringWrapper_.GetHashCode();
+      hash ^= repeatedBytesWrapper_.GetHashCode();
+      if (optionalDuration_ != null) hash ^= OptionalDuration.GetHashCode();
+      if (optionalTimestamp_ != null) hash ^= OptionalTimestamp.GetHashCode();
+      if (optionalFieldMask_ != null) hash ^= OptionalFieldMask.GetHashCode();
+      if (optionalStruct_ != null) hash ^= OptionalStruct.GetHashCode();
+      if (optionalAny_ != null) hash ^= OptionalAny.GetHashCode();
+      if (optionalValue_ != null) hash ^= OptionalValue.GetHashCode();
+      hash ^= repeatedDuration_.GetHashCode();
+      hash ^= repeatedTimestamp_.GetHashCode();
+      hash ^= repeatedFieldmask_.GetHashCode();
+      hash ^= repeatedStruct_.GetHashCode();
+      hash ^= repeatedAny_.GetHashCode();
+      hash ^= repeatedValue_.GetHashCode();
+      if (Fieldname1 != 0) hash ^= Fieldname1.GetHashCode();
+      if (FieldName2 != 0) hash ^= FieldName2.GetHashCode();
+      if (FieldName3 != 0) hash ^= FieldName3.GetHashCode();
+      if (FieldName4 != 0) hash ^= FieldName4.GetHashCode();
+      if (Field0Name5 != 0) hash ^= Field0Name5.GetHashCode();
+      if (Field0Name6 != 0) hash ^= Field0Name6.GetHashCode();
+      if (FieldName7 != 0) hash ^= FieldName7.GetHashCode();
+      if (FieldName8 != 0) hash ^= FieldName8.GetHashCode();
+      if (FieldName9 != 0) hash ^= FieldName9.GetHashCode();
+      if (FieldName10 != 0) hash ^= FieldName10.GetHashCode();
+      if (FIELDNAME11 != 0) hash ^= FIELDNAME11.GetHashCode();
+      if (FIELDName12 != 0) hash ^= FIELDName12.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1557,6 +2323,120 @@
         output.WriteRawTag(146, 7);
         output.WriteBytes(OneofBytes);
       }
+      if (optionalBoolWrapper_ != null) {
+        _single_optionalBoolWrapper_codec.WriteTagAndValue(output, OptionalBoolWrapper);
+      }
+      if (optionalInt32Wrapper_ != null) {
+        _single_optionalInt32Wrapper_codec.WriteTagAndValue(output, OptionalInt32Wrapper);
+      }
+      if (optionalInt64Wrapper_ != null) {
+        _single_optionalInt64Wrapper_codec.WriteTagAndValue(output, OptionalInt64Wrapper);
+      }
+      if (optionalUint32Wrapper_ != null) {
+        _single_optionalUint32Wrapper_codec.WriteTagAndValue(output, OptionalUint32Wrapper);
+      }
+      if (optionalUint64Wrapper_ != null) {
+        _single_optionalUint64Wrapper_codec.WriteTagAndValue(output, OptionalUint64Wrapper);
+      }
+      if (optionalFloatWrapper_ != null) {
+        _single_optionalFloatWrapper_codec.WriteTagAndValue(output, OptionalFloatWrapper);
+      }
+      if (optionalDoubleWrapper_ != null) {
+        _single_optionalDoubleWrapper_codec.WriteTagAndValue(output, OptionalDoubleWrapper);
+      }
+      if (optionalStringWrapper_ != null) {
+        _single_optionalStringWrapper_codec.WriteTagAndValue(output, OptionalStringWrapper);
+      }
+      if (optionalBytesWrapper_ != null) {
+        _single_optionalBytesWrapper_codec.WriteTagAndValue(output, OptionalBytesWrapper);
+      }
+      repeatedBoolWrapper_.WriteTo(output, _repeated_repeatedBoolWrapper_codec);
+      repeatedInt32Wrapper_.WriteTo(output, _repeated_repeatedInt32Wrapper_codec);
+      repeatedInt64Wrapper_.WriteTo(output, _repeated_repeatedInt64Wrapper_codec);
+      repeatedUint32Wrapper_.WriteTo(output, _repeated_repeatedUint32Wrapper_codec);
+      repeatedUint64Wrapper_.WriteTo(output, _repeated_repeatedUint64Wrapper_codec);
+      repeatedFloatWrapper_.WriteTo(output, _repeated_repeatedFloatWrapper_codec);
+      repeatedDoubleWrapper_.WriteTo(output, _repeated_repeatedDoubleWrapper_codec);
+      repeatedStringWrapper_.WriteTo(output, _repeated_repeatedStringWrapper_codec);
+      repeatedBytesWrapper_.WriteTo(output, _repeated_repeatedBytesWrapper_codec);
+      if (optionalDuration_ != null) {
+        output.WriteRawTag(234, 18);
+        output.WriteMessage(OptionalDuration);
+      }
+      if (optionalTimestamp_ != null) {
+        output.WriteRawTag(242, 18);
+        output.WriteMessage(OptionalTimestamp);
+      }
+      if (optionalFieldMask_ != null) {
+        output.WriteRawTag(250, 18);
+        output.WriteMessage(OptionalFieldMask);
+      }
+      if (optionalStruct_ != null) {
+        output.WriteRawTag(130, 19);
+        output.WriteMessage(OptionalStruct);
+      }
+      if (optionalAny_ != null) {
+        output.WriteRawTag(138, 19);
+        output.WriteMessage(OptionalAny);
+      }
+      if (optionalValue_ != null) {
+        output.WriteRawTag(146, 19);
+        output.WriteMessage(OptionalValue);
+      }
+      repeatedDuration_.WriteTo(output, _repeated_repeatedDuration_codec);
+      repeatedTimestamp_.WriteTo(output, _repeated_repeatedTimestamp_codec);
+      repeatedFieldmask_.WriteTo(output, _repeated_repeatedFieldmask_codec);
+      repeatedAny_.WriteTo(output, _repeated_repeatedAny_codec);
+      repeatedValue_.WriteTo(output, _repeated_repeatedValue_codec);
+      repeatedStruct_.WriteTo(output, _repeated_repeatedStruct_codec);
+      if (Fieldname1 != 0) {
+        output.WriteRawTag(136, 25);
+        output.WriteInt32(Fieldname1);
+      }
+      if (FieldName2 != 0) {
+        output.WriteRawTag(144, 25);
+        output.WriteInt32(FieldName2);
+      }
+      if (FieldName3 != 0) {
+        output.WriteRawTag(152, 25);
+        output.WriteInt32(FieldName3);
+      }
+      if (FieldName4 != 0) {
+        output.WriteRawTag(160, 25);
+        output.WriteInt32(FieldName4);
+      }
+      if (Field0Name5 != 0) {
+        output.WriteRawTag(168, 25);
+        output.WriteInt32(Field0Name5);
+      }
+      if (Field0Name6 != 0) {
+        output.WriteRawTag(176, 25);
+        output.WriteInt32(Field0Name6);
+      }
+      if (FieldName7 != 0) {
+        output.WriteRawTag(184, 25);
+        output.WriteInt32(FieldName7);
+      }
+      if (FieldName8 != 0) {
+        output.WriteRawTag(192, 25);
+        output.WriteInt32(FieldName8);
+      }
+      if (FieldName9 != 0) {
+        output.WriteRawTag(200, 25);
+        output.WriteInt32(FieldName9);
+      }
+      if (FieldName10 != 0) {
+        output.WriteRawTag(208, 25);
+        output.WriteInt32(FieldName10);
+      }
+      if (FIELDNAME11 != 0) {
+        output.WriteRawTag(216, 25);
+        output.WriteInt32(FIELDNAME11);
+      }
+      if (FIELDName12 != 0) {
+        output.WriteRawTag(224, 25);
+        output.WriteInt32(FIELDName12);
+      }
     }
 
     public int CalculateSize() {
@@ -1679,6 +2559,102 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
         size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
       }
+      if (optionalBoolWrapper_ != null) {
+        size += _single_optionalBoolWrapper_codec.CalculateSizeWithTag(OptionalBoolWrapper);
+      }
+      if (optionalInt32Wrapper_ != null) {
+        size += _single_optionalInt32Wrapper_codec.CalculateSizeWithTag(OptionalInt32Wrapper);
+      }
+      if (optionalInt64Wrapper_ != null) {
+        size += _single_optionalInt64Wrapper_codec.CalculateSizeWithTag(OptionalInt64Wrapper);
+      }
+      if (optionalUint32Wrapper_ != null) {
+        size += _single_optionalUint32Wrapper_codec.CalculateSizeWithTag(OptionalUint32Wrapper);
+      }
+      if (optionalUint64Wrapper_ != null) {
+        size += _single_optionalUint64Wrapper_codec.CalculateSizeWithTag(OptionalUint64Wrapper);
+      }
+      if (optionalFloatWrapper_ != null) {
+        size += _single_optionalFloatWrapper_codec.CalculateSizeWithTag(OptionalFloatWrapper);
+      }
+      if (optionalDoubleWrapper_ != null) {
+        size += _single_optionalDoubleWrapper_codec.CalculateSizeWithTag(OptionalDoubleWrapper);
+      }
+      if (optionalStringWrapper_ != null) {
+        size += _single_optionalStringWrapper_codec.CalculateSizeWithTag(OptionalStringWrapper);
+      }
+      if (optionalBytesWrapper_ != null) {
+        size += _single_optionalBytesWrapper_codec.CalculateSizeWithTag(OptionalBytesWrapper);
+      }
+      size += repeatedBoolWrapper_.CalculateSize(_repeated_repeatedBoolWrapper_codec);
+      size += repeatedInt32Wrapper_.CalculateSize(_repeated_repeatedInt32Wrapper_codec);
+      size += repeatedInt64Wrapper_.CalculateSize(_repeated_repeatedInt64Wrapper_codec);
+      size += repeatedUint32Wrapper_.CalculateSize(_repeated_repeatedUint32Wrapper_codec);
+      size += repeatedUint64Wrapper_.CalculateSize(_repeated_repeatedUint64Wrapper_codec);
+      size += repeatedFloatWrapper_.CalculateSize(_repeated_repeatedFloatWrapper_codec);
+      size += repeatedDoubleWrapper_.CalculateSize(_repeated_repeatedDoubleWrapper_codec);
+      size += repeatedStringWrapper_.CalculateSize(_repeated_repeatedStringWrapper_codec);
+      size += repeatedBytesWrapper_.CalculateSize(_repeated_repeatedBytesWrapper_codec);
+      if (optionalDuration_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalDuration);
+      }
+      if (optionalTimestamp_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalTimestamp);
+      }
+      if (optionalFieldMask_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalFieldMask);
+      }
+      if (optionalStruct_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalStruct);
+      }
+      if (optionalAny_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalAny);
+      }
+      if (optionalValue_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalValue);
+      }
+      size += repeatedDuration_.CalculateSize(_repeated_repeatedDuration_codec);
+      size += repeatedTimestamp_.CalculateSize(_repeated_repeatedTimestamp_codec);
+      size += repeatedFieldmask_.CalculateSize(_repeated_repeatedFieldmask_codec);
+      size += repeatedStruct_.CalculateSize(_repeated_repeatedStruct_codec);
+      size += repeatedAny_.CalculateSize(_repeated_repeatedAny_codec);
+      size += repeatedValue_.CalculateSize(_repeated_repeatedValue_codec);
+      if (Fieldname1 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Fieldname1);
+      }
+      if (FieldName2 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName2);
+      }
+      if (FieldName3 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName3);
+      }
+      if (FieldName4 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName4);
+      }
+      if (Field0Name5 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Field0Name5);
+      }
+      if (Field0Name6 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Field0Name6);
+      }
+      if (FieldName7 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName7);
+      }
+      if (FieldName8 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName8);
+      }
+      if (FieldName9 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName9);
+      }
+      if (FieldName10 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FieldName10);
+      }
+      if (FIELDNAME11 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FIELDNAME11);
+      }
+      if (FIELDName12 != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(FIELDName12);
+      }
       return size;
     }
 
@@ -1801,6 +2777,138 @@
       mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
       mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
       mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
+      if (other.optionalBoolWrapper_ != null) {
+        if (optionalBoolWrapper_ == null || other.OptionalBoolWrapper != false) {
+          OptionalBoolWrapper = other.OptionalBoolWrapper;
+        }
+      }
+      if (other.optionalInt32Wrapper_ != null) {
+        if (optionalInt32Wrapper_ == null || other.OptionalInt32Wrapper != 0) {
+          OptionalInt32Wrapper = other.OptionalInt32Wrapper;
+        }
+      }
+      if (other.optionalInt64Wrapper_ != null) {
+        if (optionalInt64Wrapper_ == null || other.OptionalInt64Wrapper != 0L) {
+          OptionalInt64Wrapper = other.OptionalInt64Wrapper;
+        }
+      }
+      if (other.optionalUint32Wrapper_ != null) {
+        if (optionalUint32Wrapper_ == null || other.OptionalUint32Wrapper != 0) {
+          OptionalUint32Wrapper = other.OptionalUint32Wrapper;
+        }
+      }
+      if (other.optionalUint64Wrapper_ != null) {
+        if (optionalUint64Wrapper_ == null || other.OptionalUint64Wrapper != 0UL) {
+          OptionalUint64Wrapper = other.OptionalUint64Wrapper;
+        }
+      }
+      if (other.optionalFloatWrapper_ != null) {
+        if (optionalFloatWrapper_ == null || other.OptionalFloatWrapper != 0F) {
+          OptionalFloatWrapper = other.OptionalFloatWrapper;
+        }
+      }
+      if (other.optionalDoubleWrapper_ != null) {
+        if (optionalDoubleWrapper_ == null || other.OptionalDoubleWrapper != 0D) {
+          OptionalDoubleWrapper = other.OptionalDoubleWrapper;
+        }
+      }
+      if (other.optionalStringWrapper_ != null) {
+        if (optionalStringWrapper_ == null || other.OptionalStringWrapper != "") {
+          OptionalStringWrapper = other.OptionalStringWrapper;
+        }
+      }
+      if (other.optionalBytesWrapper_ != null) {
+        if (optionalBytesWrapper_ == null || other.OptionalBytesWrapper != pb::ByteString.Empty) {
+          OptionalBytesWrapper = other.OptionalBytesWrapper;
+        }
+      }
+      repeatedBoolWrapper_.Add(other.repeatedBoolWrapper_);
+      repeatedInt32Wrapper_.Add(other.repeatedInt32Wrapper_);
+      repeatedInt64Wrapper_.Add(other.repeatedInt64Wrapper_);
+      repeatedUint32Wrapper_.Add(other.repeatedUint32Wrapper_);
+      repeatedUint64Wrapper_.Add(other.repeatedUint64Wrapper_);
+      repeatedFloatWrapper_.Add(other.repeatedFloatWrapper_);
+      repeatedDoubleWrapper_.Add(other.repeatedDoubleWrapper_);
+      repeatedStringWrapper_.Add(other.repeatedStringWrapper_);
+      repeatedBytesWrapper_.Add(other.repeatedBytesWrapper_);
+      if (other.optionalDuration_ != null) {
+        if (optionalDuration_ == null) {
+          optionalDuration_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+        }
+        OptionalDuration.MergeFrom(other.OptionalDuration);
+      }
+      if (other.optionalTimestamp_ != null) {
+        if (optionalTimestamp_ == null) {
+          optionalTimestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+        }
+        OptionalTimestamp.MergeFrom(other.OptionalTimestamp);
+      }
+      if (other.optionalFieldMask_ != null) {
+        if (optionalFieldMask_ == null) {
+          optionalFieldMask_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+        }
+        OptionalFieldMask.MergeFrom(other.OptionalFieldMask);
+      }
+      if (other.optionalStruct_ != null) {
+        if (optionalStruct_ == null) {
+          optionalStruct_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+        }
+        OptionalStruct.MergeFrom(other.OptionalStruct);
+      }
+      if (other.optionalAny_ != null) {
+        if (optionalAny_ == null) {
+          optionalAny_ = new global::Google.Protobuf.WellKnownTypes.Any();
+        }
+        OptionalAny.MergeFrom(other.OptionalAny);
+      }
+      if (other.optionalValue_ != null) {
+        if (optionalValue_ == null) {
+          optionalValue_ = new global::Google.Protobuf.WellKnownTypes.Value();
+        }
+        OptionalValue.MergeFrom(other.OptionalValue);
+      }
+      repeatedDuration_.Add(other.repeatedDuration_);
+      repeatedTimestamp_.Add(other.repeatedTimestamp_);
+      repeatedFieldmask_.Add(other.repeatedFieldmask_);
+      repeatedStruct_.Add(other.repeatedStruct_);
+      repeatedAny_.Add(other.repeatedAny_);
+      repeatedValue_.Add(other.repeatedValue_);
+      if (other.Fieldname1 != 0) {
+        Fieldname1 = other.Fieldname1;
+      }
+      if (other.FieldName2 != 0) {
+        FieldName2 = other.FieldName2;
+      }
+      if (other.FieldName3 != 0) {
+        FieldName3 = other.FieldName3;
+      }
+      if (other.FieldName4 != 0) {
+        FieldName4 = other.FieldName4;
+      }
+      if (other.Field0Name5 != 0) {
+        Field0Name5 = other.Field0Name5;
+      }
+      if (other.Field0Name6 != 0) {
+        Field0Name6 = other.Field0Name6;
+      }
+      if (other.FieldName7 != 0) {
+        FieldName7 = other.FieldName7;
+      }
+      if (other.FieldName8 != 0) {
+        FieldName8 = other.FieldName8;
+      }
+      if (other.FieldName9 != 0) {
+        FieldName9 = other.FieldName9;
+      }
+      if (other.FieldName10 != 0) {
+        FieldName10 = other.FieldName10;
+      }
+      if (other.FIELDNAME11 != 0) {
+        FIELDNAME11 = other.FIELDNAME11;
+      }
+      if (other.FIELDName12 != 0) {
+        FIELDName12 = other.FIELDName12;
+      }
       switch (other.OneofFieldCase) {
         case OneofFieldOneofCase.OneofUint32:
           OneofUint32 = other.OneofUint32;
@@ -2118,17 +3226,234 @@
             OneofBytes = input.ReadBytes();
             break;
           }
+          case 1610: {
+            bool? value = _single_optionalBoolWrapper_codec.Read(input);
+            if (optionalBoolWrapper_ == null || value != false) {
+              OptionalBoolWrapper = value;
+            }
+            break;
+          }
+          case 1618: {
+            int? value = _single_optionalInt32Wrapper_codec.Read(input);
+            if (optionalInt32Wrapper_ == null || value != 0) {
+              OptionalInt32Wrapper = value;
+            }
+            break;
+          }
+          case 1626: {
+            long? value = _single_optionalInt64Wrapper_codec.Read(input);
+            if (optionalInt64Wrapper_ == null || value != 0L) {
+              OptionalInt64Wrapper = value;
+            }
+            break;
+          }
+          case 1634: {
+            uint? value = _single_optionalUint32Wrapper_codec.Read(input);
+            if (optionalUint32Wrapper_ == null || value != 0) {
+              OptionalUint32Wrapper = value;
+            }
+            break;
+          }
+          case 1642: {
+            ulong? value = _single_optionalUint64Wrapper_codec.Read(input);
+            if (optionalUint64Wrapper_ == null || value != 0UL) {
+              OptionalUint64Wrapper = value;
+            }
+            break;
+          }
+          case 1650: {
+            float? value = _single_optionalFloatWrapper_codec.Read(input);
+            if (optionalFloatWrapper_ == null || value != 0F) {
+              OptionalFloatWrapper = value;
+            }
+            break;
+          }
+          case 1658: {
+            double? value = _single_optionalDoubleWrapper_codec.Read(input);
+            if (optionalDoubleWrapper_ == null || value != 0D) {
+              OptionalDoubleWrapper = value;
+            }
+            break;
+          }
+          case 1666: {
+            string value = _single_optionalStringWrapper_codec.Read(input);
+            if (optionalStringWrapper_ == null || value != "") {
+              OptionalStringWrapper = value;
+            }
+            break;
+          }
+          case 1674: {
+            pb::ByteString value = _single_optionalBytesWrapper_codec.Read(input);
+            if (optionalBytesWrapper_ == null || value != pb::ByteString.Empty) {
+              OptionalBytesWrapper = value;
+            }
+            break;
+          }
+          case 1690: {
+            repeatedBoolWrapper_.AddEntriesFrom(input, _repeated_repeatedBoolWrapper_codec);
+            break;
+          }
+          case 1698: {
+            repeatedInt32Wrapper_.AddEntriesFrom(input, _repeated_repeatedInt32Wrapper_codec);
+            break;
+          }
+          case 1706: {
+            repeatedInt64Wrapper_.AddEntriesFrom(input, _repeated_repeatedInt64Wrapper_codec);
+            break;
+          }
+          case 1714: {
+            repeatedUint32Wrapper_.AddEntriesFrom(input, _repeated_repeatedUint32Wrapper_codec);
+            break;
+          }
+          case 1722: {
+            repeatedUint64Wrapper_.AddEntriesFrom(input, _repeated_repeatedUint64Wrapper_codec);
+            break;
+          }
+          case 1730: {
+            repeatedFloatWrapper_.AddEntriesFrom(input, _repeated_repeatedFloatWrapper_codec);
+            break;
+          }
+          case 1738: {
+            repeatedDoubleWrapper_.AddEntriesFrom(input, _repeated_repeatedDoubleWrapper_codec);
+            break;
+          }
+          case 1746: {
+            repeatedStringWrapper_.AddEntriesFrom(input, _repeated_repeatedStringWrapper_codec);
+            break;
+          }
+          case 1754: {
+            repeatedBytesWrapper_.AddEntriesFrom(input, _repeated_repeatedBytesWrapper_codec);
+            break;
+          }
+          case 2410: {
+            if (optionalDuration_ == null) {
+              optionalDuration_ = new global::Google.Protobuf.WellKnownTypes.Duration();
+            }
+            input.ReadMessage(optionalDuration_);
+            break;
+          }
+          case 2418: {
+            if (optionalTimestamp_ == null) {
+              optionalTimestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
+            }
+            input.ReadMessage(optionalTimestamp_);
+            break;
+          }
+          case 2426: {
+            if (optionalFieldMask_ == null) {
+              optionalFieldMask_ = new global::Google.Protobuf.WellKnownTypes.FieldMask();
+            }
+            input.ReadMessage(optionalFieldMask_);
+            break;
+          }
+          case 2434: {
+            if (optionalStruct_ == null) {
+              optionalStruct_ = new global::Google.Protobuf.WellKnownTypes.Struct();
+            }
+            input.ReadMessage(optionalStruct_);
+            break;
+          }
+          case 2442: {
+            if (optionalAny_ == null) {
+              optionalAny_ = new global::Google.Protobuf.WellKnownTypes.Any();
+            }
+            input.ReadMessage(optionalAny_);
+            break;
+          }
+          case 2450: {
+            if (optionalValue_ == null) {
+              optionalValue_ = new global::Google.Protobuf.WellKnownTypes.Value();
+            }
+            input.ReadMessage(optionalValue_);
+            break;
+          }
+          case 2490: {
+            repeatedDuration_.AddEntriesFrom(input, _repeated_repeatedDuration_codec);
+            break;
+          }
+          case 2498: {
+            repeatedTimestamp_.AddEntriesFrom(input, _repeated_repeatedTimestamp_codec);
+            break;
+          }
+          case 2506: {
+            repeatedFieldmask_.AddEntriesFrom(input, _repeated_repeatedFieldmask_codec);
+            break;
+          }
+          case 2522: {
+            repeatedAny_.AddEntriesFrom(input, _repeated_repeatedAny_codec);
+            break;
+          }
+          case 2530: {
+            repeatedValue_.AddEntriesFrom(input, _repeated_repeatedValue_codec);
+            break;
+          }
+          case 2594: {
+            repeatedStruct_.AddEntriesFrom(input, _repeated_repeatedStruct_codec);
+            break;
+          }
+          case 3208: {
+            Fieldname1 = input.ReadInt32();
+            break;
+          }
+          case 3216: {
+            FieldName2 = input.ReadInt32();
+            break;
+          }
+          case 3224: {
+            FieldName3 = input.ReadInt32();
+            break;
+          }
+          case 3232: {
+            FieldName4 = input.ReadInt32();
+            break;
+          }
+          case 3240: {
+            Field0Name5 = input.ReadInt32();
+            break;
+          }
+          case 3248: {
+            Field0Name6 = input.ReadInt32();
+            break;
+          }
+          case 3256: {
+            FieldName7 = input.ReadInt32();
+            break;
+          }
+          case 3264: {
+            FieldName8 = input.ReadInt32();
+            break;
+          }
+          case 3272: {
+            FieldName9 = input.ReadInt32();
+            break;
+          }
+          case 3280: {
+            FieldName10 = input.ReadInt32();
+            break;
+          }
+          case 3288: {
+            FIELDNAME11 = input.ReadInt32();
+            break;
+          }
+          case 3296: {
+            FIELDName12 = input.ReadInt32();
+            break;
+          }
         }
       }
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the TestAllTypes message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       public enum NestedEnum {
         FOO = 0,
         BAR = 1,
         BAZ = 2,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
         NEG = -1,
       }
 
@@ -2160,6 +3485,7 @@
           return new NestedMessage(this);
         }
 
+        /// <summary>Field number for the "a" field.</summary>
         public const int AFieldNumber = 1;
         private int a_;
         public int A {
@@ -2169,6 +3495,7 @@
           }
         }
 
+        /// <summary>Field number for the "corecursive" field.</summary>
         public const int CorecursiveFieldNumber = 2;
         private global::Conformance.TestAllTypes corecursive_;
         public global::Conformance.TestAllTypes Corecursive {
@@ -2202,7 +3529,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -2277,7 +3604,7 @@
     public static pb::MessageParser<ForeignMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Conformance.Conformance.Descriptor.MessageTypes[3]; }
+      get { return global::Conformance.ConformanceReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2298,6 +3625,7 @@
       return new ForeignMessage(this);
     }
 
+    /// <summary>Field number for the "c" field.</summary>
     public const int CFieldNumber = 1;
     private int c_;
     public int C {
@@ -2329,7 +3657,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Conformance/Program.cs b/csharp/src/Google.Protobuf.Conformance/Program.cs
index af92da9..f3f7e29 100644
--- a/csharp/src/Google.Protobuf.Conformance/Program.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Program.cs
@@ -31,6 +31,7 @@
 #endregion
 
 using Conformance;
+using Google.Protobuf.Reflection;
 using System;
 using System.IO;
 
@@ -47,16 +48,17 @@
             // This way we get the binary streams instead of readers/writers.
             var input = new BinaryReader(Console.OpenStandardInput());
             var output = new BinaryWriter(Console.OpenStandardOutput());
+            var typeRegistry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
 
             int count = 0;
-            while (RunTest(input, output))
+            while (RunTest(input, output, typeRegistry))
             {
                 count++;
             }
             Console.Error.WriteLine("Received EOF after {0} tests", count);
         }
 
-        private static bool RunTest(BinaryReader input, BinaryWriter output)
+        private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry)
         {
             int? size = ReadInt32(input);
             if (size == null)
@@ -69,7 +71,7 @@
                 throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size);
             }
             ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData);
-            ConformanceResponse response = PerformRequest(request);
+            ConformanceResponse response = PerformRequest(request, typeRegistry);
             byte[] outputData = response.ToByteArray();
             output.Write(outputData.Length);
             output.Write(outputData);
@@ -77,34 +79,48 @@
             return true;
         }
 
-        private static ConformanceResponse PerformRequest(ConformanceRequest request)
+        private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry)
         {
             TestAllTypes message;
-            switch (request.PayloadCase)
+            try
             {
-                case ConformanceRequest.PayloadOneofCase.JsonPayload:
-                    return new ConformanceResponse { Skipped = "JSON parsing not implemented in C# yet" };
-                case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
-                    try
-                    {
+                switch (request.PayloadCase)
+                {
+                    case ConformanceRequest.PayloadOneofCase.JsonPayload:
+                        var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
+                        message = parser.Parse<TestAllTypes>(request.JsonPayload);
+                        break;
+                    case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
                         message = TestAllTypes.Parser.ParseFrom(request.ProtobufPayload);
-                    }
-                    catch (InvalidProtocolBufferException e)
-                    {
-                        return new ConformanceResponse { ParseError = e.Message };
-                    }
-                    break;
-                default:
-                    throw new Exception("Unsupported request payload: " + request.PayloadCase);
+                        break;
+                    default:
+                        throw new Exception("Unsupported request payload: " + request.PayloadCase);
+                }
             }
-            switch (request.RequestedOutputFormat)
+            catch (InvalidProtocolBufferException e)
             {
-                case global::Conformance.WireFormat.JSON:
-                    return new ConformanceResponse { JsonPayload = JsonFormatter.Default.Format(message) };
-                case global::Conformance.WireFormat.PROTOBUF:
-                    return new ConformanceResponse { ProtobufPayload = message.ToByteString() };
-                default:
-                    throw new Exception("Unsupported request output format: " + request.PayloadCase);
+                return new ConformanceResponse { ParseError = e.Message };
+            }
+            catch (InvalidJsonException e)
+            {
+                return new ConformanceResponse { ParseError = e.Message };
+            }
+            try
+            {
+                switch (request.RequestedOutputFormat)
+                {
+                    case global::Conformance.WireFormat.JSON:
+                        var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry));
+                        return new ConformanceResponse { JsonPayload = formatter.Format(message) };
+                    case global::Conformance.WireFormat.PROTOBUF:
+                        return new ConformanceResponse { ProtobufPayload = message.ToByteString() };
+                    default:
+                        throw new Exception("Unsupported request output format: " + request.PayloadCase);
+                }
+            }
+            catch (InvalidOperationException e)
+            {
+                return new ConformanceResponse { SerializeError = e.Message };
             }
         }
 
diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
index 54c44e4..0e7cf04 100644
--- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
@@ -284,7 +284,7 @@
             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());

         }

 

-        private static TestRecursiveMessage MakeRecursiveMessage(int depth)

+        internal static TestRecursiveMessage MakeRecursiveMessage(int depth)

         {

             if (depth == 0)

             {

@@ -296,7 +296,7 @@
             }

         }

 

-        private static void AssertMessageDepth(TestRecursiveMessage message, int depth)

+        internal static void AssertMessageDepth(TestRecursiveMessage message, int depth)

         {

             if (depth == 0)

             {

@@ -470,6 +470,52 @@
         }

 

         [Test]

+        public void SkipGroup_WrongEndGroupTag()

+        {

+            // Create an output stream with:

+            // Field 1: string "field 1"

+            // Start group 2

+            //   Field 3: fixed int32

+            // End group 4 (should give an error)

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.LengthDelimited);

+            output.WriteString("field 1");

+

+            // The outer group...

+            output.WriteTag(2, WireFormat.WireType.StartGroup);

+            output.WriteTag(3, WireFormat.WireType.Fixed32);

+            output.WriteFixed32(100);

+            output.WriteTag(4, WireFormat.WireType.EndGroup);

+            output.Flush();

+            stream.Position = 0;

+

+            // Now act like a generated client

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());

+            Assert.AreEqual("field 1", input.ReadString());

+            Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

+        public void RogueEndGroupTag()

+        {

+            // If we have an end-group tag without a leading start-group tag, generated

+            // code will just call SkipLastField... so that should fail.

+

+            var stream = new MemoryStream();

+            var output = new CodedOutputStream(stream);

+            output.WriteTag(1, WireFormat.WireType.EndGroup);

+            output.Flush();

+            stream.Position = 0;

+

+            var input = new CodedInputStream(stream);

+            Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

+        }

+

+        [Test]

         public void EndOfStreamReachedWhileSkippingGroup()

         {

             var stream = new MemoryStream();

@@ -484,7 +530,7 @@
             // Now act like a generated client

             var input = new CodedInputStream(stream);

             input.ReadTag();

-            Assert.Throws<InvalidProtocolBufferException>(() => input.SkipLastField());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

         }

 

         [Test]

@@ -506,7 +552,7 @@
             // Now act like a generated client

             var input = new CodedInputStream(stream);

             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag());

-            Assert.Throws<InvalidProtocolBufferException>(() => input.SkipLastField());

+            Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);

         }

 

         [Test]

diff --git a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
index 29c4c2a..9c84590 100644
--- a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
@@ -56,7 +56,7 @@
         }
 
         [Test]
-        public void NullValues()
+        public void NullValuesProhibited()
         {
             TestNullValues<int?>(0);
             TestNullValues("");
@@ -65,19 +65,12 @@
 
         private void TestNullValues<T>(T nonNullValue)
         {
-            var map = new MapField<int, T>(false);
+            var map = new MapField<int, T>();
             var nullValue = (T) (object) null;
             Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
             Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
             map.Add(1, nonNullValue);
             map[1] = nonNullValue;
-
-            // Doesn't throw...
-            map = new MapField<int, T>(true);
-            map.Add(0, nullValue);
-            map[0] = nullValue;
-            map.Add(1, nonNullValue);
-            map[1] = nonNullValue;
         }
 
         [Test]
@@ -161,27 +154,6 @@
         }
 
         [Test]
-        public void EqualityHandlesNullValues()
-        {
-            var map1 = new MapField<string, ForeignMessage>();
-            map1.Add("a", new ForeignMessage { C = 10 });
-            map1.Add("b", null);
-
-            var map2 = new MapField<string, ForeignMessage>();
-            map2.Add("a", new ForeignMessage { C = 10 });
-            map2.Add("b", null);
-
-            EqualityTester.AssertEquality(map1, map2);
-            // Check the null value isn't ignored entirely...
-            Assert.IsTrue(map1.Remove("b"));
-            EqualityTester.AssertInequality(map1, map2);
-            map1.Add("b", new ForeignMessage());
-            EqualityTester.AssertInequality(map1, map2);
-            map1["b"] = null;
-            EqualityTester.AssertEquality(map1, map2);
-        }
-
-        [Test]
         public void Add_Dictionary()
         {
             var map1 = new MapField<string, string>
@@ -454,30 +426,6 @@
         }
 
         [Test]
-        public void AllowNullValues_Property()
-        {
-            // Non-message reference type values are non-nullable by default, but can be overridden
-            Assert.IsFalse(new MapField<int, string>().AllowsNullValues);
-            Assert.IsFalse(new MapField<int, string>(false).AllowsNullValues);
-            Assert.IsTrue(new MapField<int, string>(true).AllowsNullValues);
-
-            // Non-nullable value type values are never nullable
-            Assert.IsFalse(new MapField<int, int>().AllowsNullValues);
-            Assert.IsFalse(new MapField<int, int>(false).AllowsNullValues);
-            Assert.Throws<ArgumentException>(() => new MapField<int, int>(true));
-
-            // Message type values are nullable by default, but can be overridden
-            Assert.IsTrue(new MapField<int, TestAllTypes>().AllowsNullValues);
-            Assert.IsFalse(new MapField<int, TestAllTypes>(false).AllowsNullValues);
-            Assert.IsTrue(new MapField<int, TestAllTypes>(true).AllowsNullValues);
-
-            // Nullable value type values are nullable by default, but can be overridden
-            Assert.IsTrue(new MapField<int, int?>().AllowsNullValues);
-            Assert.IsFalse(new MapField<int, int?>(false).AllowsNullValues);
-            Assert.IsTrue(new MapField<int, int?>(true).AllowsNullValues);
-        }
-
-        [Test]
         public void KeysReturnsLiveView()
         {
             var map = new MapField<string, string>();
@@ -562,6 +510,20 @@
             Assert.IsFalse(values.Contains(null));
         }
 
+        [Test]
+        public void ToString_StringToString()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            Assert.AreEqual("{ \"foo\": \"bar\", \"x\": \"y\" }", map.ToString());
+        }
+
+        [Test]
+        public void ToString_UnsupportedKeyType()
+        {
+            var map = new MapField<byte, string> { { 10, "foo" } };
+            Assert.Throws<ArgumentException>(() => map.ToString());
+        }
+
         private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
         {
             return new KeyValuePair<TKey, TValue>(key, value);
diff --git a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
index 8c804fd..8ed54cf 100644
--- a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
@@ -37,6 +37,7 @@
 using System.Linq;
 using System.Text;
 using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
 using NUnit.Framework;
 
 namespace Google.Protobuf.Collections
@@ -599,5 +600,61 @@
             list.Insert(1, "middle");
             CollectionAssert.AreEqual(new[] { "first", "middle", "second" }, list);
         }
+
+        [Test]
+        public void ToString_Integers()
+        {
+            var list = new RepeatedField<int> { 5, 10, 20 };
+            var text = list.ToString();
+            Assert.AreEqual("[ 5, 10, 20 ]", text);
+        }
+
+        [Test]
+        public void ToString_Strings()
+        {
+            var list = new RepeatedField<string> { "x", "y", "z" };
+            var text = list.ToString();
+            Assert.AreEqual("[ \"x\", \"y\", \"z\" ]", text);
+        }
+
+        [Test]
+        public void ToString_Messages()
+        {
+            var list = new RepeatedField<TestAllTypes> { new TestAllTypes { SingleDouble = 1.5 }, new TestAllTypes { SingleInt32 = 10 } };
+            var text = list.ToString();
+            Assert.AreEqual("[ { \"singleDouble\": 1.5 }, { \"singleInt32\": 10 } ]", text);
+        }
+
+        [Test]
+        public void ToString_Empty()
+        {
+            var list = new RepeatedField<TestAllTypes> { };
+            var text = list.ToString();
+            Assert.AreEqual("[ ]", text);
+        }
+
+        [Test]
+        public void ToString_InvalidElementType()
+        {
+            var list = new RepeatedField<decimal> { 15m };
+            Assert.Throws<ArgumentException>(() => list.ToString());
+        }
+
+        [Test]
+        public void ToString_Timestamp()
+        {
+            var list = new RepeatedField<Timestamp> { Timestamp.FromDateTime(new DateTime(2015, 10, 1, 12, 34, 56, DateTimeKind.Utc)) };
+            var text = list.ToString();
+            Assert.AreEqual("[ \"2015-10-01T12:34:56Z\" ]", text);
+        }
+
+        [Test]
+        public void ToString_Struct()
+        {
+            var message = new Struct { Fields = { { "foo", new Value { NumberValue = 20 } } } };
+            var list = new RepeatedField<Struct> { message };
+            var text = list.ToString();
+            Assert.AreEqual(text, "[ { \"foo\": 20 } ]", message.ToString());
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
index 575d458..6706995 100644
--- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -221,7 +221,7 @@
                 },

                 MapInt32ForeignMessage = {

                     { 0, new ForeignMessage { C = 10 } },

-                    { 5, null },

+                    { 5, new ForeignMessage() },

                 },

                 MapInt32Enum = {

                     { 1, MapEnum.MAP_ENUM_BAR },

@@ -269,6 +269,40 @@
         }

 

         [Test]

+        public void MapWithOnlyKey_PrimitiveValue()

+        {

+            // Hand-craft the stream to contain a single entry with just a key.

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+            output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited);

+            int key = 10;

+            output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(0.0, parsed.MapInt32Double[key]);

+        }

+

+        [Test]

+        public void MapWithOnlyKey_MessageValue()

+        {

+            // Hand-craft the stream to contain a single entry with just a key.

+            var memoryStream = new MemoryStream();

+            var output = new CodedOutputStream(memoryStream);

+            output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);

+            int key = 10;

+            output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));

+            output.WriteTag(1, WireFormat.WireType.Varint);

+            output.WriteInt32(key);

+            output.Flush();

+

+            var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());

+            Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]);

+        }

+

+        [Test]

         public void MapIgnoresExtraFieldsWithinEntryMessages()

         {

             // Hand-craft the stream to contain a single entry with three fields

@@ -566,6 +600,16 @@
         }

 

         [Test]

+        public void Oneof_DefaultValuesNotEqual()

+        {

+            var message1 = new TestAllTypes { OneofString = "" };

+            var message2 = new TestAllTypes { OneofUint32 = 0 };

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase);

+            Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);

+            Assert.AreNotEqual(message1, message2);

+        }

+

+        [Test]

         public void OneofSerialization_NonDefaultValue()

         {

             var message = new TestAllTypes();

@@ -635,21 +679,36 @@
         /// for details; we may want to change this.

         /// </summary>

         [Test]

-        public void ExtraEndGroupSkipped()

+        public void ExtraEndGroupThrows()

         {

             var message = SampleMessages.CreateFullTestAllTypes();

             var stream = new MemoryStream();

             var output = new CodedOutputStream(stream);

 

-            output.WriteTag(100, WireFormat.WireType.EndGroup);

             output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32);

             output.WriteFixed32(123);

+            output.WriteTag(100, WireFormat.WireType.EndGroup);

 

             output.Flush();

 

             stream.Position = 0;

-            var parsed = TestAllTypes.Parser.ParseFrom(stream);

-            Assert.AreEqual(new TestAllTypes { SingleFixed32 = 123 }, parsed);

+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream));

+        }

+

+        [Test]

+        public void CustomDiagnosticMessage_DirectToStringCall()

+        {

+            var message = new ForeignMessage { C = 31 };

+            Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString());

+            Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message));

+        }

+

+        [Test]

+        public void CustomDiagnosticMessage_Nested()

+        {

+            var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } };

+            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString());

+            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message));

         }

     }

 }

diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
index 33be5da..4f37c5e 100644
--- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -55,7 +55,7 @@
     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

     <Prefer32Bit>false</Prefer32Bit>

     <SignAssembly>True</SignAssembly>

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

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

   </PropertyGroup>

   <ItemGroup>

     <Reference Include="mscorlib" />

@@ -95,10 +95,14 @@
     <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" />

@@ -111,6 +115,7 @@
     <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>

diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
index 3e7a3d2..4245504 100644
--- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
@@ -35,6 +35,9 @@
 using NUnit.Framework;
 using UnitTest.Issues.TestProtos;
 using Google.Protobuf.WellKnownTypes;
+using Google.Protobuf.Reflection;
+
+using static Google.Protobuf.JsonParserTest; // For WrapInQuotes
 
 namespace Google.Protobuf
 {
@@ -162,41 +165,31 @@
         }
 
         [Test]
-        public void UnknownEnumValueOmitted_SingleField()
+        public void UnknownEnumValueNumeric_SingleField()
         {
             var message = new TestAllTypes { SingleForeignEnum = (ForeignEnum) 100 };
-            AssertJson("{ }", JsonFormatter.Default.Format(message));
+            AssertJson("{ 'singleForeignEnum': 100 }", JsonFormatter.Default.Format(message));
         }
 
         [Test]
-        public void UnknownEnumValueOmitted_RepeatedField()
+        public void UnknownEnumValueNumeric_RepeatedField()
         {
             var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.FOREIGN_BAZ, (ForeignEnum) 100, ForeignEnum.FOREIGN_FOO } };
-            AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message));
+            AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message));
         }
 
         [Test]
-        public void UnknownEnumValueOmitted_MapField()
+        public void UnknownEnumValueNumeric_MapField()
         {
-            // This matches the C++ behaviour.
             var message = new TestMap { MapInt32Enum = { { 1, MapEnum.MAP_ENUM_FOO }, { 2, (MapEnum) 100 }, { 3, MapEnum.MAP_ENUM_BAR } } };
-            AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message));
+            AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message));
         }
 
         [Test]
-        public void UnknownEnumValueOmitted_RepeatedField_AllEntriesUnknown()
+        public void UnknownEnumValue_RepeatedField_AllEntriesUnknown()
         {
-            // *Maybe* we should hold off on writing the "[" until we find that we've got at least one value to write...
-            // but this is what happens at the moment, and it doesn't seem too awful.
             var message = new TestAllTypes { RepeatedForeignEnum = { (ForeignEnum) 200, (ForeignEnum) 100 } };
-            AssertJson("{ 'repeatedForeignEnum': [ ] }", JsonFormatter.Default.Format(message));
-        }
-
-        [Test]
-        public void NullValueForMessage()
-        {
-            var message = new TestMap { MapInt32ForeignMessage = { { 10, null } } };
-            AssertJson("{ 'mapInt32ForeignMessage': { '10': null } }", JsonFormatter.Default.Format(message));
+            AssertJson("{ 'repeatedForeignEnum': [ 200, 100 ] }", JsonFormatter.Default.Format(message));
         }
 
         [Test]
@@ -276,6 +269,13 @@
         }
 
         [Test]
+        public void WrapperFormatting_Message()
+        {
+            Assert.AreEqual("\"\"", JsonFormatter.Default.Format(new StringValue()));
+            Assert.AreEqual("0", JsonFormatter.Default.Format(new Int32Value()));
+        }
+
+        [Test]
         public void WrapperFormatting_IncludeNull()
         {
             // The actual JSON here is very large because there are lots of fields. Just test a couple of them.
@@ -311,27 +311,52 @@
         }
 
         [Test]
-        public void TimestampStandalone()
+        [TestCase("1970-01-01T00:00:00Z", 0)]
+        [TestCase("1970-01-01T00:00:00.000000001Z", 1)]
+        [TestCase("1970-01-01T00:00:00.000000010Z", 10)]
+        [TestCase("1970-01-01T00:00:00.000000100Z", 100)]
+        [TestCase("1970-01-01T00:00:00.000001Z", 1000)]
+        [TestCase("1970-01-01T00:00:00.000010Z", 10000)]
+        [TestCase("1970-01-01T00:00:00.000100Z", 100000)]
+        [TestCase("1970-01-01T00:00:00.001Z", 1000000)]
+        [TestCase("1970-01-01T00:00:00.010Z", 10000000)]
+        [TestCase("1970-01-01T00:00:00.100Z", 100000000)]
+        [TestCase("1970-01-01T00:00:00.100Z", 100000000)]
+        [TestCase("1970-01-01T00:00:00.120Z", 120000000)]
+        [TestCase("1970-01-01T00:00:00.123Z", 123000000)]
+        [TestCase("1970-01-01T00:00:00.123400Z", 123400000)]
+        [TestCase("1970-01-01T00:00:00.123450Z", 123450000)]
+        [TestCase("1970-01-01T00:00:00.123456Z", 123456000)]
+        [TestCase("1970-01-01T00:00:00.123456700Z", 123456700)]
+        [TestCase("1970-01-01T00:00:00.123456780Z", 123456780)]
+        [TestCase("1970-01-01T00:00:00.123456789Z", 123456789)]
+        public void TimestampStandalone(string expected, int nanos)
         {
-            Assert.AreEqual("1970-01-01T00:00:00Z", new Timestamp().ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.100Z", new Timestamp { Nanos = 100000000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.120Z", new Timestamp { Nanos = 120000000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123Z", new Timestamp { Nanos = 123000000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123400Z", new Timestamp { Nanos = 123400000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123450Z", new Timestamp { Nanos = 123450000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123456Z", new Timestamp { Nanos = 123456000 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123456700Z", new Timestamp { Nanos = 123456700 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123456780Z", new Timestamp { Nanos = 123456780 }.ToString());
-            Assert.AreEqual("1970-01-01T00:00:00.123456789Z", new Timestamp { Nanos = 123456789 }.ToString());
+            Assert.AreEqual(WrapInQuotes(expected), new Timestamp { Nanos = nanos }.ToString());
+        }
 
-            // One before and one after the Unix epoch
-            Assert.AreEqual("1673-06-19T12:34:56Z",
+        [Test]
+        public void TimestampStandalone_FromDateTime()
+        {
+            // One before and one after the Unix epoch, more easily represented via DateTime.
+            Assert.AreEqual("\"1673-06-19T12:34:56Z\"",
                 new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp().ToString());
-            Assert.AreEqual("2015-07-31T10:29:34Z",
+            Assert.AreEqual("\"2015-07-31T10:29:34Z\"",
                 new DateTime(2015, 7, 31, 10, 29, 34, DateTimeKind.Utc).ToTimestamp().ToString());
         }
 
         [Test]
+        [TestCase(-1, -1)] // Would be valid as duration
+        [TestCase(1, Timestamp.MaxNanos + 1)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, 0)]
+        public void TimestampStandalone_NonNormalized(long seconds, int nanoseconds)
+        {
+            var timestamp = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(timestamp));
+        }
+
+        [Test]
         public void TimestampField()
         {
             var message = new TestWellKnownTypes { TimestampField = new Timestamp() };
@@ -342,6 +367,14 @@
         [TestCase(0, 0, "0s")]
         [TestCase(1, 0, "1s")]
         [TestCase(-1, 0, "-1s")]
+        [TestCase(0, 1, "0.000000001s")]
+        [TestCase(0, 10, "0.000000010s")]
+        [TestCase(0, 100, "0.000000100s")]
+        [TestCase(0, 1000, "0.000001s")]
+        [TestCase(0, 10000, "0.000010s")]
+        [TestCase(0, 100000, "0.000100s")]
+        [TestCase(0, 1000000, "0.001s")]
+        [TestCase(0, 10000000, "0.010s")]
         [TestCase(0, 100000000, "0.100s")]
         [TestCase(0, 120000000, "0.120s")]
         [TestCase(0, 123000000, "0.123s")]
@@ -354,12 +387,19 @@
         [TestCase(0, -100000000, "-0.100s")]
         [TestCase(1, 100000000, "1.100s")]
         [TestCase(-1, -100000000, "-1.100s")]
-        // Non-normalized examples
-        [TestCase(1, 2123456789, "3.123456789s")]
-        [TestCase(1, -100000000, "0.900s")]
         public void DurationStandalone(long seconds, int nanoseconds, string expected)
         {
-            Assert.AreEqual(expected, new Duration { Seconds = seconds, Nanos = nanoseconds }.ToString());
+            var json = JsonFormatter.Default.Format(new Duration { Seconds = seconds, Nanos = nanoseconds });
+            Assert.AreEqual(WrapInQuotes(expected), json);
+        }
+
+        [Test]
+        [TestCase(1, 2123456789)]
+        [TestCase(1, -100000000)]
+        public void DurationStandalone_NonNormalized(long seconds, int nanoseconds)
+        {
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(duration));
         }
 
         [Test]
@@ -376,26 +416,36 @@
             {
                 Fields =
                 {
-                    { "a", new Value { NullValue = new NullValue() } },
-                    { "b", new Value { BoolValue = false } },
-                    { "c", new Value { NumberValue = 10.5 } },
-                    { "d", new Value { StringValue = "text" } },
-                    { "e", new Value { ListValue = new ListValue { Values = { new Value { StringValue = "t1" }, new Value { NumberValue = 5 } } } } },
-                    { "f", new Value { StructValue = new Struct { Fields = { { "nested", new Value { StringValue = "value" } } } } } }
+                    { "a", Value.ForNull() },
+                    { "b", Value.ForBool(false) },
+                    { "c", Value.ForNumber(10.5) },
+                    { "d", Value.ForString("text") },
+                    { "e", Value.ForList(Value.ForString("t1"), Value.ForNumber(5)) },
+                    { "f", Value.ForStruct(new Struct { Fields = { { "nested", Value.ForString("value") } } }) }
                 }
             };
             AssertJson("{ 'a': null, 'b': false, 'c': 10.5, 'd': 'text', 'e': [ 't1', 5 ], 'f': { 'nested': 'value' } }", message.ToString());
         }
 
         [Test]
+        [TestCase("foo__bar")]
+        [TestCase("foo_3_ar")]
+        [TestCase("fooBar")]
+        public void FieldMaskInvalid(string input)
+        {
+            var mask = new FieldMask { Paths = { input } };
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(mask));
+        }
+
+        [Test]
         public void FieldMaskStandalone()
         {
             var fieldMask = new FieldMask { Paths = { "", "single", "with_underscore", "nested.field.name", "nested..double_dot" } };
-            Assert.AreEqual(",single,withUnderscore,nested.field.name,nested..doubleDot", fieldMask.ToString());
+            Assert.AreEqual("\",single,withUnderscore,nested.field.name,nested..doubleDot\"", fieldMask.ToString());
 
             // Invalid, but we shouldn't create broken JSON...
             fieldMask = new FieldMask { Paths = { "x\\y" } };
-            Assert.AreEqual(@"x\\y", fieldMask.ToString());
+            Assert.AreEqual(@"""x\\y""", fieldMask.ToString());
         }
 
         [Test]
@@ -405,6 +455,55 @@
             AssertJson("{ 'fieldMaskField': 'user.displayName,photo' }", JsonFormatter.Default.Format(message));
         }
 
+        // SourceContext is an example of a well-known type with no special JSON handling
+        [Test]
+        public void SourceContextStandalone()
+        {
+            var message = new SourceContext { FileName = "foo.proto" };
+            AssertJson("{ 'fileName': 'foo.proto' }", JsonFormatter.Default.Format(message));
+        }
+
+        [Test]
+        public void AnyWellKnownType()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(Timestamp.Descriptor)));
+            var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp();
+            var any = Any.Pack(timestamp);
+            AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any));
+        }
+
+        [Test]
+        public void AnyMessageType()
+        {
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
+            var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } };
+            var any = Any.Pack(message);
+            AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any));
+        }
+
+        [Test]
+        public void AnyNested()
+        {
+            var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+
+            // Nest an Any as the value of an Any.
+            var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 };
+            var nestedMessage = Any.Pack(doubleNestedMessage);
+            var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
+            AssertJson("{ 'anyField': { '@type': 'type.googleapis.com/google.protobuf.Any', 'value': { '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 20 } } }",
+                formatter.Format(message));
+        }
+
+        [Test]
+        public void AnyUnknownType()
+        {
+            // The default type registry doesn't have any types in it.
+            var message = new TestAllTypes();
+            var any = Any.Pack(message);
+            Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(any));
+        }
+
         /// <summary>
         /// Checks that the actual JSON is the same as the expected JSON - but after replacing
         /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier
diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
new file mode 100644
index 0000000..d21da58
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -0,0 +1,925 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using Google.Protobuf.Reflection;
+using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework;
+using System;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Unit tests for JSON parsing.
+    /// </summary>
+    public class JsonParserTest
+    {
+        // Sanity smoke test
+        [Test]
+        public void AllTypesRoundtrip()
+        {
+            AssertRoundtrip(SampleMessages.CreateFullTestAllTypes());
+        }
+
+        [Test]
+        public void Maps()
+        {
+            AssertRoundtrip(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } });
+            AssertRoundtrip(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } });
+            AssertRoundtrip(new TestMap { MapBoolBool = { { false, true }, { true, false } } });
+        }
+
+        [Test]
+        [TestCase(" 1 ")]
+        [TestCase("+1")]
+        [TestCase("1,000")]
+        [TestCase("1.5")]
+        public void IntegerMapKeysAreStrict(string keyText)
+        {
+            // Test that integer parsing is strict. We assume that if this is correct for int32,
+            // it's correct for other numeric key types.
+            var json = "{ \"mapInt32Int32\": { \"" + keyText + "\" : \"1\" } }";
+            Assert.Throws<InvalidProtocolBufferException>(() => JsonParser.Default.Parse<TestMap>(json));
+        }
+
+        [Test]
+        public void OriginalFieldNameAccepted()
+        {
+            var json = "{ \"single_int32\": 10 }";
+            var expected = new TestAllTypes { SingleInt32 = 10 };
+            Assert.AreEqual(expected, TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void SourceContextRoundtrip()
+        {
+            AssertRoundtrip(new SourceContext { FileName = "foo.proto" });
+        }
+
+        [Test]
+        public void SingularWrappers_DefaultNonNullValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "",
+                BytesField = ByteString.Empty,
+                BoolField = false,
+                FloatField = 0f,
+                DoubleField = 0d,
+                Int32Field = 0,
+                Int64Field = 0,
+                Uint32Field = 0,
+                Uint64Field = 0
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void SingularWrappers_NonDefaultValues()
+        {
+            var message = new TestWellKnownTypes
+            {
+                StringField = "x",
+                BytesField = ByteString.CopyFrom(1, 2, 3),
+                BoolField = true,
+                FloatField = 12.5f,
+                DoubleField = 12.25d,
+                Int32Field = 1,
+                Int64Field = 2,
+                Uint32Field = 3,
+                Uint64Field = 4
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void SingularWrappers_ExplicitNulls()
+        {
+            // When we parse the "valueField": null part, we remember it... basically, it's one case
+            // where explicit default values don't fully roundtrip.
+            var message = new TestWellKnownTypes { ValueField = Value.ForNull() };
+            var json = new JsonFormatter(new JsonFormatter.Settings(true)).Format(message);
+            var parsed = JsonParser.Default.Parse<TestWellKnownTypes>(json);
+            Assert.AreEqual(message, parsed);
+        }
+
+        [Test]
+        [TestCase(typeof(Int32Value), "32", 32)]
+        [TestCase(typeof(Int64Value), "32", 32L)]
+        [TestCase(typeof(UInt32Value), "32", 32U)]
+        [TestCase(typeof(UInt64Value), "32", 32UL)]
+        [TestCase(typeof(StringValue), "\"foo\"", "foo")]
+        [TestCase(typeof(FloatValue), "1.5", 1.5f)]
+        [TestCase(typeof(DoubleValue), "1.5", 1.5d)]
+        public void Wrappers_Standalone(System.Type wrapperType, string json, object expectedValue)
+        {
+            IMessage parsed = (IMessage) Activator.CreateInstance(wrapperType);
+            IMessage expected = (IMessage) Activator.CreateInstance(wrapperType);
+            JsonParser.Default.Merge(parsed, "null");
+            Assert.AreEqual(expected, parsed);
+
+            JsonParser.Default.Merge(parsed, json);
+            expected.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(expected, expectedValue);
+            Assert.AreEqual(expected, parsed);
+        }
+
+        [Test]
+        public void ExplicitNullValue()
+        {
+            string json = "{\"valueField\": null}";
+            var message = JsonParser.Default.Parse<TestWellKnownTypes>(json);
+            Assert.AreEqual(new TestWellKnownTypes { ValueField = Value.ForNull() }, message);
+        }
+
+        [Test]
+        public void BytesWrapper_Standalone()
+        {
+            ByteString data = ByteString.CopyFrom(1, 2, 3);
+            // Can't do this with attributes...
+            var parsed = JsonParser.Default.Parse<BytesValue>(WrapInQuotes(data.ToBase64()));
+            var expected = new BytesValue { Value = data };
+            Assert.AreEqual(expected, parsed);
+        }
+
+        [Test]
+        public void RepeatedWrappers()
+        {
+            var message = new RepeatedWellKnownTypes
+            {
+                BoolField = { true, false },
+                BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
+                DoubleField = { 12.5, -1.5, 0d },
+                FloatField = { 123.25f, -20f, 0f },
+                Int32Field = { int.MaxValue, int.MinValue, 0 },
+                Int64Field = { long.MaxValue, long.MinValue, 0L },
+                StringField = { "First", "Second", "" },
+                Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
+                Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
+            };
+            AssertRoundtrip(message);
+        }
+
+        [Test]
+        public void RepeatedField_NullElementProhibited()
+        {
+            string json = "{ \"repeated_foreign_message\": [null] }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void RepeatedField_NullOverallValueAllowed()
+        {
+            string json = "{ \"repeated_foreign_message\": null }";
+            Assert.AreEqual(new TestAllTypes(), TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("{ \"mapInt32Int32\": { \"10\": null }")]
+        [TestCase("{ \"mapStringString\": { \"abc\": null }")]
+        [TestCase("{ \"mapInt32ForeignMessage\": { \"10\": null }")]
+        public void MapField_NullValueProhibited(string json)
+        {
+            Assert.Throws<InvalidProtocolBufferException>(() => TestMap.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void MapField_NullOverallValueAllowed()
+        {
+            string json = "{ \"mapInt32Int32\": null }";
+            Assert.AreEqual(new TestMap(), TestMap.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void IndividualWrapperTypes()
+        {
+            Assert.AreEqual(new StringValue { Value = "foo" }, StringValue.Parser.ParseJson("\"foo\""));
+            Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("1"));
+            // Can parse strings directly too
+            Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("\"1\""));
+        }
+
+        private static void AssertRoundtrip<T>(T message) where T : IMessage<T>, new()
+        {
+            var clone = message.Clone();
+            var json = JsonFormatter.Default.Format(message);
+            var parsed = JsonParser.Default.Parse<T>(json);
+            Assert.AreEqual(clone, parsed);
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        [TestCase("2147483647", 2147483647)]
+        [TestCase("-2147483648", -2147483648)]
+        public void StringToInt32_Valid(string jsonValue, int expectedParsedValue)
+        {
+            string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
+        }
+
+        [Test]
+        [TestCase("+0")]
+        [TestCase(" 1")]
+        [TestCase("1 ")]
+        [TestCase("00")]
+        [TestCase("-00")]
+        [TestCase("--1")]
+        [TestCase("+1")]
+        [TestCase("1.5")]
+        [TestCase("1e10")]
+        [TestCase("2147483648")]
+        [TestCase("-2147483649")]
+        public void StringToInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0U)]
+        [TestCase("1", 1U)]
+        [TestCase("4294967295", 4294967295U)]
+        public void StringToUInt32_Valid(string jsonValue, uint expectedParsedValue)
+        {
+            string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("4294967296")]
+        public void StringToUInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0L)]
+        [TestCase("1", 1L)]
+        [TestCase("-1", -1L)]
+        [TestCase("9223372036854775807", 9223372036854775807)]
+        [TestCase("-9223372036854775808", -9223372036854775808)]
+        public void StringToInt64_Valid(string jsonValue, long expectedParsedValue)
+        {
+            string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-9223372036854775809")]
+        [TestCase("9223372036854775808")]
+        public void StringToInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0UL)]
+        [TestCase("1", 1UL)]
+        [TestCase("18446744073709551615", 18446744073709551615)]
+        public void StringToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
+        {
+            string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("18446744073709551616")]
+        public void StringToUInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0d)]
+        [TestCase("1", 1d)]
+        [TestCase("1.000000", 1d)]
+        [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
+        [TestCase("-1", -1d)]
+        [TestCase("1e1", 10d)]
+        [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
+        [TestCase("1E1", 10d)] // Either case is fine
+        [TestCase("-1e1", -10d)]
+        [TestCase("1.5e1", 15d)]
+        [TestCase("-1.5e1", -15d)]
+        [TestCase("15e-1", 1.5d)]
+        [TestCase("-15e-1", -1.5d)]
+        [TestCase("1.79769e308", 1.79769e308)]
+        [TestCase("-1.79769e308", -1.79769e308)]
+        [TestCase("Infinity", double.PositiveInfinity)]
+        [TestCase("-Infinity", double.NegativeInfinity)]
+        [TestCase("NaN", double.NaN)]
+        public void StringToDouble_Valid(string jsonValue, double expectedParsedValue)
+        {
+            string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
+        }
+
+        [Test]
+        [TestCase("1.7977e308")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1e309")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("01")]
+        [TestCase("-00")]
+        [TestCase("-01")]
+        [TestCase("--1")]
+        [TestCase(" Infinity")]
+        [TestCase(" -Infinity")]
+        [TestCase("NaN ")]
+        [TestCase("Infinity ")]
+        [TestCase("-Infinity ")]
+        [TestCase(" NaN")]
+        [TestCase("INFINITY")]
+        [TestCase("nan")]
+        [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
+        public void StringToDouble_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0f)]
+        [TestCase("1", 1f)]
+        [TestCase("1.000000", 1f)]
+        [TestCase("-1", -1f)]
+        [TestCase("3.402823e38", 3.402823e38f)]
+        [TestCase("-3.402823e38", -3.402823e38f)]
+        [TestCase("1.5e1", 15f)]
+        [TestCase("15e-1", 1.5f)]
+        public void StringToFloat_Valid(string jsonValue, float expectedParsedValue)
+        {
+            string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
+        }
+
+        [Test]
+        [TestCase("3.402824e38")]
+        [TestCase("-3.402824e38")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("--1")]
+        public void StringToFloat_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        [TestCase("2147483647", 2147483647)]
+        [TestCase("-2147483648", -2147483648)]
+        [TestCase("1e1", 10)]
+        [TestCase("-1e1", -10)]
+        [TestCase("10.00", 10)]
+        [TestCase("-10.00", -10)]
+        public void NumberToInt32_Valid(string jsonValue, int expectedParsedValue)
+        {
+            string json = "{ \"singleInt32\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
+        }
+
+        [Test]
+        [TestCase("+0", typeof(InvalidJsonException))]
+        [TestCase("00", typeof(InvalidJsonException))]
+        [TestCase("-00", typeof(InvalidJsonException))]
+        [TestCase("--1", typeof(InvalidJsonException))]
+        [TestCase("+1", typeof(InvalidJsonException))]
+        [TestCase("1.5", typeof(InvalidProtocolBufferException))]
+        // Value is out of range
+        [TestCase("1e10", typeof(InvalidProtocolBufferException))]
+        [TestCase("2147483648", typeof(InvalidProtocolBufferException))]
+        [TestCase("-2147483649", typeof(InvalidProtocolBufferException))]
+        public void NumberToInt32_Invalid(string jsonValue, System.Type expectedExceptionType)
+        {
+            string json = "{ \"singleInt32\": " + jsonValue + "}";
+            Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0U)]
+        [TestCase("1", 1U)]
+        [TestCase("4294967295", 4294967295U)]
+        public void NumberToUInt32_Valid(string jsonValue, uint expectedParsedValue)
+        {
+            string json = "{ \"singleUint32\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("4294967296")]
+        public void NumberToUInt32_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint32\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0L)]
+        [TestCase("1", 1L)]
+        [TestCase("-1", -1L)]
+        // long.MaxValue isn't actually representable as a double. This string value is the highest
+        // representable value which isn't greater than long.MaxValue.
+        [TestCase("9223372036854774784", 9223372036854774784)]
+        [TestCase("-9223372036854775808", -9223372036854775808)]
+        public void NumberToInt64_Valid(string jsonValue, long expectedParsedValue)
+        {
+            string json = "{ \"singleInt64\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("9223372036854775808")]
+        // Theoretical bound would be -9223372036854775809, but when that is parsed to a double
+        // we end up with the exact value of long.MinValue due to lack of precision. The value here
+        // is the "next double down".
+        [TestCase("-9223372036854780000")]
+        public void NumberToInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleInt64\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0UL)]
+        [TestCase("1", 1UL)]
+        // ulong.MaxValue isn't representable as a double. This value is the largest double within
+        // the range of ulong.
+        [TestCase("18446744073709549568", 18446744073709549568UL)]
+        public void NumberToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
+        {
+            string json = "{ \"singleUint64\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
+        }
+
+        // Assume that anything non-bounds-related is covered in the Int32 case
+        [Test]
+        [TestCase("-1")]
+        [TestCase("18446744073709551616")]
+        public void NumberToUInt64_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleUint64\": " + jsonValue + "}";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0d)]
+        [TestCase("1", 1d)]
+        [TestCase("1.000000", 1d)]
+        [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
+        [TestCase("-1", -1d)]
+        [TestCase("1e1", 10d)]
+        [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
+        [TestCase("1E1", 10d)] // Either case is fine
+        [TestCase("-1e1", -10d)]
+        [TestCase("1.5e1", 15d)]
+        [TestCase("-1.5e1", -15d)]
+        [TestCase("15e-1", 1.5d)]
+        [TestCase("-15e-1", -1.5d)]
+        [TestCase("1.79769e308", 1.79769e308)]
+        [TestCase("-1.79769e308", -1.79769e308)]
+        public void NumberToDouble_Valid(string jsonValue, double expectedParsedValue)
+        {
+            string json = "{ \"singleDouble\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
+        }
+
+        [Test]
+        [TestCase("1.7977e308")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1e309")]
+        [TestCase("1,0")]
+        [TestCase("1.0.0")]
+        [TestCase("+1")]
+        [TestCase("00")]
+        [TestCase("--1")]
+        [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
+        public void NumberToDouble_Invalid(string jsonValue)
+        {
+            string json = "{ \"singleDouble\": " + jsonValue + "}";
+            Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("0", 0f)]
+        [TestCase("1", 1f)]
+        [TestCase("1.000000", 1f)]
+        [TestCase("-1", -1f)]
+        [TestCase("3.402823e38", 3.402823e38f)]
+        [TestCase("-3.402823e38", -3.402823e38f)]
+        [TestCase("1.5e1", 15f)]
+        [TestCase("15e-1", 1.5f)]
+        public void NumberToFloat_Valid(string jsonValue, float expectedParsedValue)
+        {
+            string json = "{ \"singleFloat\": " + jsonValue + "}";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
+        }
+
+        [Test]
+        [TestCase("3.402824e38", typeof(InvalidProtocolBufferException))]
+        [TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))]
+        [TestCase("1,0", typeof(InvalidJsonException))]
+        [TestCase("1.0.0", typeof(InvalidJsonException))]
+        [TestCase("+1", typeof(InvalidJsonException))]
+        [TestCase("00", typeof(InvalidJsonException))]
+        [TestCase("--1", typeof(InvalidJsonException))]
+        public void NumberToFloat_Invalid(string jsonValue, System.Type expectedExceptionType)
+        {
+            string json = "{ \"singleFloat\": " + jsonValue + "}";
+            Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        // The simplest way of testing that the value has parsed correctly is to reformat it,
+        // as we trust the formatting. In many cases that will give the same result as the input,
+        // so in those cases we accept an expectedFormatted value of null. Sometimes the results
+        // will be different though, due to a different number of digits being provided.
+        [Test]
+        // Z offset
+        [TestCase("2015-10-09T14:46:23.123456789Z", null)]
+        [TestCase("2015-10-09T14:46:23.123456Z", null)]
+        [TestCase("2015-10-09T14:46:23.123Z", null)]
+        [TestCase("2015-10-09T14:46:23Z", null)]
+        [TestCase("2015-10-09T14:46:23.123456000Z", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.1234560Z", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123000000Z", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.1230Z", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.00Z", "2015-10-09T14:46:23Z")]
+
+        // +00:00 offset
+        [TestCase("2015-10-09T14:46:23.123456789+00:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T14:46:23.123456+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23+00:00", "2015-10-09T14:46:23Z")]
+        [TestCase("2015-10-09T14:46:23.123456000+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.1234560+00:00", "2015-10-09T14:46:23.123456Z")]
+        [TestCase("2015-10-09T14:46:23.123000000+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.1230+00:00", "2015-10-09T14:46:23.123Z")]
+        [TestCase("2015-10-09T14:46:23.00+00:00", "2015-10-09T14:46:23Z")]
+
+        // Other offsets (assume by now that the subsecond handling is okay)
+        [TestCase("2015-10-09T15:46:23.123456789+01:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T13:46:23.123456789-01:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T15:16:23.123456789+00:30", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T14:16:23.123456789-00:30", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T16:31:23.123456789+01:45", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-09T13:01:23.123456789-01:45", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-10T08:46:23.123456789+18:00", "2015-10-09T14:46:23.123456789Z")]
+        [TestCase("2015-10-08T20:46:23.123456789-18:00", "2015-10-09T14:46:23.123456789Z")]
+
+        // Leap years and min/max
+        [TestCase("2016-02-29T14:46:23.123456789Z", null)]
+        [TestCase("2000-02-29T14:46:23.123456789Z", null)]
+        [TestCase("0001-01-01T00:00:00Z", null)]
+        [TestCase("9999-12-31T23:59:59.999999999Z", null)]
+        public void Timestamp_Valid(string jsonValue, string expectedFormatted)
+        {
+            expectedFormatted = expectedFormatted ?? jsonValue;
+            string json = WrapInQuotes(jsonValue);
+            var parsed = Timestamp.Parser.ParseJson(json);
+            Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
+        }
+        
+        [Test]
+        [TestCase("2015-10-09 14:46:23.123456789Z", Description = "No T between date and time")]
+        [TestCase("2015/10/09T14:46:23.123456789Z", Description = "Wrong date separators")]
+        [TestCase("2015-10-09T14.46.23.123456789Z", Description = "Wrong time separators")]
+        [TestCase("2015-10-09T14:46:23,123456789Z", Description = "Wrong fractional second separators (valid ISO-8601 though)")]
+        [TestCase(" 2015-10-09T14:46:23.123456789Z", Description = "Whitespace at start")]
+        [TestCase("2015-10-09T14:46:23.123456789Z ", Description = "Whitespace at end")]
+        [TestCase("2015-10-09T14:46:23.1234567890", Description = "Too many digits")]
+        [TestCase("2015-10-09T14:46:23.123456789", Description = "No offset")]
+        [TestCase("2015-13-09T14:46:23.123456789Z", Description = "Invalid month")]
+        [TestCase("2015-10-32T14:46:23.123456789Z", Description = "Invalid day")]
+        [TestCase("2015-10-09T24:00:00.000000000Z", Description = "Invalid hour (valid ISO-8601 though)")]
+        [TestCase("2015-10-09T14:60:23.123456789Z", Description = "Invalid minutes")]
+        [TestCase("2015-10-09T14:46:60.123456789Z", Description = "Invalid seconds")]
+        [TestCase("2015-10-09T14:46:23.123456789+18:01", Description = "Offset too large (positive)")]
+        [TestCase("2015-10-09T14:46:23.123456789-18:01", Description = "Offset too large (negative)")]
+        [TestCase("2015-10-09T14:46:23.123456789-00:00", Description = "Local offset (-00:00) makes no sense here")]
+        [TestCase("0001-01-01T00:00:00+00:01", Description = "Value before earliest when offset applied")]
+        [TestCase("9999-12-31T23:59:59.999999999-00:01", Description = "Value after latest when offset applied")]
+        [TestCase("2100-02-29T14:46:23.123456789Z", Description = "Feb 29th on a non-leap-year")]
+        public void Timestamp_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => Timestamp.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void StructValue_Null()
+        {
+            Assert.AreEqual(new Value { NullValue = 0 }, Value.Parser.ParseJson("null"));
+        }
+
+        [Test]
+        public void StructValue_String()
+        {
+            Assert.AreEqual(new Value { StringValue = "hi" }, Value.Parser.ParseJson("\"hi\""));
+        }
+
+        [Test]
+        public void StructValue_Bool()
+        {
+            Assert.AreEqual(new Value { BoolValue = true }, Value.Parser.ParseJson("true"));
+            Assert.AreEqual(new Value { BoolValue = false }, Value.Parser.ParseJson("false"));
+        }
+
+        [Test]
+        public void StructValue_List()
+        {
+            Assert.AreEqual(Value.ForList(Value.ForNumber(1), Value.ForString("x")), Value.Parser.ParseJson("[1, \"x\"]"));
+        }
+
+        [Test]
+        public void ParseListValue()
+        {
+            Assert.AreEqual(new ListValue { Values = { Value.ForNumber(1), Value.ForString("x") } }, ListValue.Parser.ParseJson("[1, \"x\"]"));
+        }
+
+        [Test]
+        public void StructValue_Struct()
+        {
+            Assert.AreEqual(
+                Value.ForStruct(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } }),
+                Value.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
+        }
+
+        [Test]
+        public void ParseStruct()
+        {
+            Assert.AreEqual(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } },
+                Struct.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
+        }
+
+        // TODO for duration parsing: upper and lower bounds.
+        // +/- 315576000000 seconds
+
+        [Test]
+        [TestCase("1.123456789s", null)]
+        [TestCase("1.123456s", null)]
+        [TestCase("1.123s", null)]
+        [TestCase("1.12300s", "1.123s")]
+        [TestCase("1.12345s", "1.123450s")]
+        [TestCase("1s", null)]
+        [TestCase("-1.123456789s", null)]
+        [TestCase("-1.123456s", null)]
+        [TestCase("-1.123s", null)]
+        [TestCase("-1s", null)]
+        [TestCase("0.123s", null)]
+        [TestCase("-0.123s", null)]
+        [TestCase("123456.123s", null)]
+        [TestCase("-123456.123s", null)]
+        // Upper and lower bounds
+        [TestCase("315576000000s", null)]
+        [TestCase("-315576000000s", null)]
+        public void Duration_Valid(string jsonValue, string expectedFormatted)
+        {
+            expectedFormatted = expectedFormatted ?? jsonValue;
+            string json = WrapInQuotes(jsonValue);
+            var parsed = Duration.Parser.ParseJson(json);
+            Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
+        }
+
+        // The simplest way of testing that the value has parsed correctly is to reformat it,
+        // as we trust the formatting. In many cases that will give the same result as the input,
+        // so in those cases we accept an expectedFormatted value of null. Sometimes the results
+        // will be different though, due to a different number of digits being provided.
+        [Test]
+        [TestCase("1.1234567890s", Description = "Too many digits")]
+        [TestCase("1.123456789", Description = "No suffix")]
+        [TestCase("1.123456789ss", Description = "Too much suffix")]
+        [TestCase("1.123456789S", Description = "Upper case suffix")]
+        [TestCase("+1.123456789s", Description = "Leading +")]
+        [TestCase(".123456789s", Description = "No integer before the fraction")]
+        [TestCase("1,123456789s", Description = "Comma as decimal separator")]
+        [TestCase("1x1.123456789s", Description = "Non-digit in integer part")]
+        [TestCase("1.1x3456789s", Description = "Non-digit in fractional part")]
+        [TestCase(" 1.123456789s", Description = "Whitespace before fraction")]
+        [TestCase("1.123456789s ", Description = "Whitespace after value")]
+        [TestCase("01.123456789s", Description = "Leading zero (positive)")]
+        [TestCase("-01.123456789s", Description = "Leading zero (negative)")]
+        [TestCase("--0.123456789s", Description = "Double minus sign")]
+        // Violate upper/lower bounds in various ways
+        [TestCase("315576000001s", Description = "Integer part too large")]
+        [TestCase("3155760000000s", Description = "Integer part too long (positive)")]
+        [TestCase("-3155760000000s", Description = "Integer part too long (negative)")]
+        public void Duration_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => Duration.Parser.ParseJson(json));
+        }
+
+        // Not as many tests for field masks as I'd like; more to be added when we have more
+        // detailed specifications.
+
+        [Test]
+        [TestCase("")]
+        [TestCase("foo", "foo")]
+        [TestCase("foo,bar", "foo", "bar")]
+        [TestCase("foo.bar", "foo.bar")]
+        [TestCase("fooBar", "foo_bar")]
+        [TestCase("fooBar.bazQux", "foo_bar.baz_qux")]
+        public void FieldMask_Valid(string jsonValue, params string[] expectedPaths)
+        {
+            string json = WrapInQuotes(jsonValue);
+            var parsed = FieldMask.Parser.ParseJson(json);
+            CollectionAssert.AreEqual(expectedPaths, parsed.Paths);
+        }
+
+        [Test]
+        [TestCase("foo_bar")]
+        public void FieldMask_Invalid(string jsonValue)
+        {
+            string json = WrapInQuotes(jsonValue);
+            Assert.Throws<InvalidProtocolBufferException>(() => FieldMask.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_RegularMessage()
+        {
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
+            var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } };
+            var original = Any.Pack(message);
+            var json = formatter.Format(original); // This is tested in JsonFormatterTest
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            Assert.AreEqual(original, parser.Parse<Any>(json));
+            string valueFirstJson = "{ \"singleInt32\": 10, \"singleNestedMessage\": { \"bb\": 20 }, \"@type\": \"type.googleapis.com/protobuf_unittest.TestAllTypes\" }";
+            Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
+        }
+
+        [Test]
+        public void Any_UnknownType()
+        {
+            string json = "{ \"@type\": \"type.googleapis.com/bogus\" }";
+            Assert.Throws<InvalidOperationException>(() => Any.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_NoTypeUrl()
+        {
+            string json = "{ \"foo\": \"bar\" }";
+            Assert.Throws<InvalidProtocolBufferException>(() => Any.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void Any_WellKnownType()
+        {
+            var registry = TypeRegistry.FromMessages(Timestamp.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+            var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp();
+            var original = Any.Pack(timestamp);
+            var json = formatter.Format(original); // This is tested in JsonFormatterTest
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            Assert.AreEqual(original, parser.Parse<Any>(json));
+            string valueFirstJson = "{ \"value\": \"1673-06-19T12:34:56Z\", \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\" }";
+            Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
+        }
+
+        [Test]
+        public void Any_Nested()
+        {
+            var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor);
+            var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
+            var parser = new JsonParser(new JsonParser.Settings(10, registry));
+            var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 };
+            var nestedMessage = Any.Pack(doubleNestedMessage);
+            var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
+            var json = formatter.Format(message);
+            // Use the descriptor-based parser just for a change.
+            Assert.AreEqual(message, parser.Parse(json, TestWellKnownTypes.Descriptor));
+        }
+
+        [Test]
+        public void DataAfterObject()
+        {
+            string json = "{} 10";
+            Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        /// <summary>
+        /// JSON equivalent to <see cref="CodedInputStreamTest.MaliciousRecursion"/>
+        /// </summary>
+        [Test]
+        public void MaliciousRecursion()
+        {
+            string data64 = CodedInputStreamTest.MakeRecursiveMessage(64).ToString();
+            string data65 = CodedInputStreamTest.MakeRecursiveMessage(65).ToString();
+
+            var parser64 = new JsonParser(new JsonParser.Settings(64));
+            CodedInputStreamTest.AssertMessageDepth(parser64.Parse<TestRecursiveMessage>(data64), 64);
+            Assert.Throws<InvalidProtocolBufferException>(() => parser64.Parse<TestRecursiveMessage>(data65));
+
+            var parser63 = new JsonParser(new JsonParser.Settings(63));
+            Assert.Throws<InvalidProtocolBufferException>(() => parser63.Parse<TestRecursiveMessage>(data64));
+        }
+
+        [Test]
+        [TestCase("AQI")]
+        [TestCase("_-==")]
+        public void Bytes_InvalidBase64(string badBase64)
+        {
+            string json = "{ \"singleBytes\": \"" + badBase64 + "\" }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        [TestCase("\"FOREIGN_BAR\"", ForeignEnum.FOREIGN_BAR)]
+        [TestCase("5", ForeignEnum.FOREIGN_BAR)]
+        [TestCase("100", (ForeignEnum) 100)]
+        public void EnumValid(string value, ForeignEnum expectedValue)
+        {
+            string json = "{ \"singleForeignEnum\": " + value + " }";
+            var parsed = TestAllTypes.Parser.ParseJson(json);
+            Assert.AreEqual(new TestAllTypes { SingleForeignEnum = expectedValue }, parsed);
+        }
+
+        [Test]
+        [TestCase("\"NOT_A_VALID_VALUE\"")]
+        [TestCase("5.5")]
+        public void Enum_Invalid(string value)
+        {
+            string json = "{ \"singleForeignEnum\": " + value + " }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        [Test]
+        public void OneofDuplicate_Invalid()
+        {
+            string json = "{ \"oneofString\": \"x\", \"oneofUint32\": 10 }";
+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+        }
+
+        /// <summary>
+        /// Various tests use strings which have quotes round them for parsing or as the result
+        /// of formatting, but without those quotes being specified in the tests (for the sake of readability).
+        /// This method simply returns the input, wrapped in double quotes.
+        /// </summary>
+        internal static string WrapInQuotes(string text)
+        {
+            return '"' + text + '"';
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
new file mode 100644
index 0000000..a0a6222
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -0,0 +1,409 @@
+#region Copyright notice and license
+// 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.
+#endregion
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace Google.Protobuf
+{
+    public class JsonTokenizerTest
+    {
+        [Test]
+        public void EmptyObjectValue()
+        {
+            AssertTokens("{}", JsonToken.StartObject, JsonToken.EndObject);
+        }
+
+        [Test]
+        public void EmptyArrayValue()
+        {
+            AssertTokens("[]", JsonToken.StartArray, JsonToken.EndArray);
+        }
+
+        [Test]
+        [TestCase("foo", "foo")]
+        [TestCase("tab\\t", "tab\t")]
+        [TestCase("line\\nfeed", "line\nfeed")]
+        [TestCase("carriage\\rreturn", "carriage\rreturn")]
+        [TestCase("back\\bspace", "back\bspace")]
+        [TestCase("form\\ffeed", "form\ffeed")]
+        [TestCase("escaped\\/slash", "escaped/slash")]
+        [TestCase("escaped\\\\backslash", "escaped\\backslash")]
+        [TestCase("escaped\\\"quote", "escaped\"quote")]
+        [TestCase("foo {}[] bar", "foo {}[] bar")]
+        [TestCase("foo\\u09aFbar", "foo\u09afbar")] // Digits, upper hex, lower hex
+        [TestCase("ab\ud800\udc00cd", "ab\ud800\udc00cd")]
+        [TestCase("ab\\ud800\\udc00cd", "ab\ud800\udc00cd")]
+        public void StringValue(string json, string expectedValue)
+        {
+            AssertTokensNoReplacement("\"" + json + "\"", JsonToken.Value(expectedValue));
+        }
+
+        // Valid surrogate pairs, with mixed escaping. These test cases can't be expressed
+        // using TestCase as they have no valid UTF-8 representation.
+        // It's unclear exactly how we should handle a mixture of escaped or not: that can't
+        // come from UTF-8 text, but could come from a .NET string. For the moment,
+        // treat it as valid in the obvious way.
+        [Test]
+        public void MixedSurrogatePairs()
+        {
+            string expected = "\ud800\udc00";
+            AssertTokens("'\\ud800\udc00'", JsonToken.Value(expected));
+            AssertTokens("'\ud800\\udc00'", JsonToken.Value(expected));
+        }
+
+        [Test]
+        public void ObjectDepth()
+        {
+            string json = "{ \"foo\": { \"x\": 1, \"y\": [ 0 ] } }";
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader(json));
+            // If we had more tests like this, I'd introduce a helper method... but for one test, it's not worth it.
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartObject, tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("foo"), tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartObject, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("x"), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Value(1), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.Name("y"), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.StartArray, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth); // Depth hasn't changed in array
+            Assert.AreEqual(JsonToken.Value(0), tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndArray, tokenizer.Next());
+            Assert.AreEqual(2, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndObject, tokenizer.Next());
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndObject, tokenizer.Next());
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+        }
+
+        [Test]
+        public void ObjectDepth_WithPushBack()
+        {
+            string json = "{}";
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader(json));
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            var token = tokenizer.Next();
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            // When we push back a "start object", we should effectively be back to the previous depth.
+            tokenizer.PushBack(token);
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            // Read the same token again, and get back to depth 1
+            token = tokenizer.Next();
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+
+            // Now the same in reverse, with EndObject
+            token = tokenizer.Next();
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+            tokenizer.PushBack(token);
+            Assert.AreEqual(1, tokenizer.ObjectDepth);
+            tokenizer.Next();
+            Assert.AreEqual(0, tokenizer.ObjectDepth);
+        }
+
+        [Test]
+        [TestCase("embedded tab\t")]
+        [TestCase("embedded CR\r")]
+        [TestCase("embedded LF\n")]
+        [TestCase("embedded bell\u0007")]
+        [TestCase("bad escape\\a")]
+        [TestCase("incomplete escape\\")]
+        [TestCase("incomplete Unicode escape\\u000")]
+        [TestCase("invalid Unicode escape\\u000H")]
+        // Surrogate pair handling, both in raw .NET strings and escaped. We only need
+        // to detect this in strings, as non-ASCII characters anywhere other than in strings
+        // will already lead to parsing errors.
+        [TestCase("\\ud800")]
+        [TestCase("\\udc00")]
+        [TestCase("\\ud800x")]
+        [TestCase("\\udc00x")]
+        [TestCase("\\udc00\\ud800y")]
+        public void InvalidStringValue(string json)
+        {
+            AssertThrowsAfter("\"" + json + "\"");
+        }
+
+        // Tests for invalid strings that can't be expressed in attributes,
+        // as the constants can't be expressed as UTF-8 strings.
+        [Test]
+        public void InvalidSurrogatePairs()
+        {
+            AssertThrowsAfter("\"\ud800x\"");
+            AssertThrowsAfter("\"\udc00y\"");
+            AssertThrowsAfter("\"\udc00\ud800y\"");
+        }
+
+        [Test]
+        [TestCase("0", 0)]
+        [TestCase("-0", 0)] // We don't distinguish between positive and negative 0
+        [TestCase("1", 1)]
+        [TestCase("-1", -1)]
+        // From here on, assume leading sign is okay...
+        [TestCase("1.125", 1.125)]
+        [TestCase("1.0", 1)]
+        [TestCase("1e5", 100000)]
+        [TestCase("1e000000", 1)] // Weird, but not prohibited by the spec
+        [TestCase("1E5", 100000)]
+        [TestCase("1e+5", 100000)]
+        [TestCase("1E-5", 0.00001)]
+        [TestCase("123E-2", 1.23)]
+        [TestCase("123.45E3", 123450)]
+        [TestCase("   1   ", 1)]
+        public void NumberValue(string json, double expectedValue)
+        {
+            AssertTokens(json, JsonToken.Value(expectedValue));
+        }
+
+        [Test]
+        [TestCase("00")]
+        [TestCase(".5")]
+        [TestCase("1.")]
+        [TestCase("1e")]
+        [TestCase("1e-")]
+        [TestCase("--")]
+        [TestCase("--1")]
+        [TestCase("-1.7977e308")]
+        [TestCase("1.7977e308")]
+        public void InvalidNumberValue(string json)
+        {
+            AssertThrowsAfter(json);
+        }
+
+        [Test]
+        [TestCase("nul")]
+        [TestCase("nothing")]
+        [TestCase("truth")]
+        [TestCase("fALSEhood")]
+        public void InvalidLiterals(string json)
+        {
+            AssertThrowsAfter(json);
+        }
+
+        [Test]
+        public void NullValue()
+        {
+            AssertTokens("null", JsonToken.Null);
+        }
+
+        [Test]
+        public void TrueValue()
+        {
+            AssertTokens("true", JsonToken.True);
+        }
+
+        [Test]
+        public void FalseValue()
+        {
+            AssertTokens("false", JsonToken.False);
+        }
+
+        [Test]
+        public void SimpleObject()
+        {
+            AssertTokens("{'x': 'y'}",
+                JsonToken.StartObject, JsonToken.Name("x"), JsonToken.Value("y"), JsonToken.EndObject);
+        }
+        
+        [Test]
+        [TestCase("[10, 20", 3)]
+        [TestCase("[10,", 2)]
+        [TestCase("[10:20]", 2)]
+        [TestCase("[", 1)]
+        [TestCase("[,", 1)]
+        [TestCase("{", 1)]
+        [TestCase("{,", 1)]
+        [TestCase("{", 1)]
+        [TestCase("{[", 1)]
+        [TestCase("{{", 1)]
+        [TestCase("{0", 1)]
+        [TestCase("{null", 1)]
+        [TestCase("{false", 1)]
+        [TestCase("{true", 1)]
+        [TestCase("}", 0)]
+        [TestCase("]", 0)]
+        [TestCase(",", 0)]
+        [TestCase("'foo' 'bar'", 1)]
+        [TestCase(":", 0)]
+        [TestCase("'foo", 0)] // Incomplete string
+        [TestCase("{ 'foo' }", 2)]
+        [TestCase("{ x:1", 1)] // Property names must be quoted
+        [TestCase("{]", 1)]
+        [TestCase("[}", 1)]
+        [TestCase("[1,", 2)]
+        [TestCase("{'x':0]", 3)]
+        [TestCase("{ 'foo': }", 2)]
+        [TestCase("{ 'foo':'bar', }", 3)]
+        public void InvalidStructure(string json, int expectedValidTokens)
+        {
+            // Note: we don't test that the earlier tokens are exactly as expected,
+            // partly because that's hard to parameterize.
+            var reader = new StringReader(json.Replace('\'', '"'));
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedValidTokens; i++)
+            {
+                Assert.IsNotNull(tokenizer.Next());
+            }
+            Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
+        }
+
+        [Test]
+        public void ArrayMixedType()
+        {
+            AssertTokens("[1, 'foo', null, false, true, [2], {'x':'y' }]",
+                JsonToken.StartArray,
+                JsonToken.Value(1),
+                JsonToken.Value("foo"),
+                JsonToken.Null,
+                JsonToken.False,
+                JsonToken.True,
+                JsonToken.StartArray,
+                JsonToken.Value(2),
+                JsonToken.EndArray,
+                JsonToken.StartObject,
+                JsonToken.Name("x"),
+                JsonToken.Value("y"),
+                JsonToken.EndObject,
+                JsonToken.EndArray);
+        }
+
+        [Test]
+        public void ObjectMixedType()
+        {
+            AssertTokens(@"{'a': 1, 'b': 'bar', 'c': null, 'd': false, 'e': true, 
+                           'f': [2], 'g': {'x':'y' }}",
+                JsonToken.StartObject,
+                JsonToken.Name("a"),
+                JsonToken.Value(1),
+                JsonToken.Name("b"),
+                JsonToken.Value("bar"),
+                JsonToken.Name("c"),
+                JsonToken.Null,
+                JsonToken.Name("d"),
+                JsonToken.False,
+                JsonToken.Name("e"),
+                JsonToken.True,
+                JsonToken.Name("f"),
+                JsonToken.StartArray,
+                JsonToken.Value(2),
+                JsonToken.EndArray,
+                JsonToken.Name("g"),
+                JsonToken.StartObject,
+                JsonToken.Name("x"),
+                JsonToken.Value("y"),
+                JsonToken.EndObject,
+                JsonToken.EndObject);
+        }
+
+        [Test]
+        public void NextAfterEndDocumentThrows()
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader("null"));
+            Assert.AreEqual(JsonToken.Null, tokenizer.Next());
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.Throws<InvalidOperationException>(() => tokenizer.Next());
+        }
+
+        [Test]
+        public void CanPushBackEndDocument()
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(new StringReader("null"));
+            Assert.AreEqual(JsonToken.Null, tokenizer.Next());
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            tokenizer.PushBack(JsonToken.EndDocument);
+            Assert.AreEqual(JsonToken.EndDocument, tokenizer.Next());
+            Assert.Throws<InvalidOperationException>(() => tokenizer.Next());
+        }
+       
+        /// <summary>
+        /// Asserts that the specified JSON is tokenized into the given sequence of tokens.
+        /// All apostrophes are first converted to double quotes, allowing any tests
+        /// that don't need to check actual apostrophe handling to use apostrophes in the JSON, avoiding
+        /// messy string literal escaping. The "end document" token is not specified in the list of 
+        /// expected tokens, but is implicit.
+        /// </summary>
+        private static void AssertTokens(string json, params JsonToken[] expectedTokens)
+        {
+            AssertTokensNoReplacement(json.Replace('\'', '"'), expectedTokens);
+        }
+
+        /// <summary>
+        /// Asserts that the specified JSON is tokenized into the given sequence of tokens.
+        /// Unlike <see cref="AssertTokens(string, JsonToken[])"/>, this does not perform any character
+        /// replacement on the specified JSON, and should be used when the text contains apostrophes which
+        /// are expected to be used *as* apostrophes. The "end document" token is not specified in the list of 
+        /// expected tokens, but is implicit.
+        /// </summary>
+        private static void AssertTokensNoReplacement(string json, params JsonToken[] expectedTokens)
+        {
+            var reader = new StringReader(json);
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedTokens.Length; i++)
+            {
+                var actualToken = tokenizer.Next();
+                if (actualToken == JsonToken.EndDocument)
+                {
+                    Assert.Fail("Expected {0} but reached end of token stream", expectedTokens[i]);
+                }
+                Assert.AreEqual(expectedTokens[i], actualToken);
+            }
+            var finalToken = tokenizer.Next();
+            if (finalToken != JsonToken.EndDocument)
+            {
+                Assert.Fail("Expected token stream to be exhausted; received {0}", finalToken);
+            }
+        }
+
+        private static void AssertThrowsAfter(string json, params JsonToken[] expectedTokens)
+        {
+            var reader = new StringReader(json);
+            var tokenizer = JsonTokenizer.FromTextReader(reader);
+            for (int i = 0; i < expectedTokens.Length; i++)
+            {
+                var actualToken = tokenizer.Next();
+                if (actualToken == JsonToken.EndDocument)
+                {
+                    Assert.Fail("Expected {0} but reached end of document", expectedTokens[i]);
+                }
+                Assert.AreEqual(expectedTokens[i], actualToken);
+            }
+            Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
index 5f3aba1..086a4e9 100644
--- a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
@@ -46,7 +46,7 @@
         [Test]
         public void FileDescriptor()
         {
-            FileDescriptor file = UnittestProto3.Descriptor;
+            FileDescriptor file = UnittestProto3Reflection.Descriptor;
 
             Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Name);
             Assert.AreEqual("protobuf_unittest", file.Package);
@@ -56,14 +56,15 @@
 
             // unittest.proto doesn't have any public imports, but unittest_import.proto does.
             Assert.AreEqual(0, file.PublicDependencies.Count);
-            Assert.AreEqual(1, UnittestImportProto3.Descriptor.PublicDependencies.Count);
-            Assert.AreEqual(UnittestImportPublicProto3.Descriptor, UnittestImportProto3.Descriptor.PublicDependencies[0]);
+            Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.PublicDependencies.Count);
+            Assert.AreEqual(UnittestImportPublicProto3Reflection.Descriptor, UnittestImportProto3Reflection.Descriptor.PublicDependencies[0]);
 
             Assert.AreEqual(1, file.Dependencies.Count);
-            Assert.AreEqual(UnittestImportProto3.Descriptor, file.Dependencies[0]);
+            Assert.AreEqual(UnittestImportProto3Reflection.Descriptor, file.Dependencies[0]);
 
             MessageDescriptor messageType = TestAllTypes.Descriptor;
-            Assert.AreSame(typeof(TestAllTypes), messageType.GeneratedType);
+            Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
+            Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
             Assert.AreEqual(messageType, file.MessageTypes[0]);
             Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
             Assert.Null(file.FindTypeByName<MessageDescriptor>("NoSuchType"));
@@ -76,8 +77,8 @@
             Assert.AreEqual(file.EnumTypes[0], file.FindTypeByName<EnumDescriptor>("ForeignEnum"));
             Assert.Null(file.FindTypeByName<EnumDescriptor>("NoSuchType"));
             Assert.Null(file.FindTypeByName<EnumDescriptor>("protobuf_unittest.ForeignEnum"));
-            Assert.AreEqual(1, UnittestImportProto3.Descriptor.EnumTypes.Count);
-            Assert.AreEqual("ImportEnum", UnittestImportProto3.Descriptor.EnumTypes[0].Name);
+            Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.EnumTypes.Count);
+            Assert.AreEqual("ImportEnum", UnittestImportProto3Reflection.Descriptor.EnumTypes[0].Name);
             for (int i = 0; i < file.EnumTypes.Count; i++)
             {
                 Assert.AreEqual(i, file.EnumTypes[i].Index);
@@ -94,7 +95,7 @@
 
             Assert.AreEqual("TestAllTypes", messageType.Name);
             Assert.AreEqual("protobuf_unittest.TestAllTypes", messageType.FullName);
-            Assert.AreEqual(UnittestProto3.Descriptor, messageType.File);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, messageType.File);
             Assert.IsNull(messageType.ContainingType);
             Assert.IsNull(messageType.Proto.Options);
 
@@ -102,7 +103,7 @@
 
             Assert.AreEqual("NestedMessage", nestedType.Name);
             Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.FullName);
-            Assert.AreEqual(UnittestProto3.Descriptor, nestedType.File);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
             Assert.AreEqual(messageType, nestedType.ContainingType);
 
             FieldDescriptor field = messageType.Fields.InDeclarationOrder()[0];
@@ -146,7 +147,7 @@
                             primitiveField.FullName);
             Assert.AreEqual(1, primitiveField.FieldNumber);
             Assert.AreEqual(messageType, primitiveField.ContainingType);
-            Assert.AreEqual(UnittestProto3.Descriptor, primitiveField.File);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, primitiveField.File);
             Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
             Assert.IsNull(primitiveField.Proto.Options);
             
@@ -175,19 +176,19 @@
         public void EnumDescriptor()
         {
             // Note: this test is a bit different to the Java version because there's no static way of getting to the descriptor
-            EnumDescriptor enumType = UnittestProto3.Descriptor.FindTypeByName<EnumDescriptor>("ForeignEnum");
+            EnumDescriptor enumType = UnittestProto3Reflection.Descriptor.FindTypeByName<EnumDescriptor>("ForeignEnum");
             EnumDescriptor nestedType = TestAllTypes.Descriptor.FindDescriptor<EnumDescriptor>("NestedEnum");
 
             Assert.AreEqual("ForeignEnum", enumType.Name);
             Assert.AreEqual("protobuf_unittest.ForeignEnum", enumType.FullName);
-            Assert.AreEqual(UnittestProto3.Descriptor, enumType.File);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, enumType.File);
             Assert.Null(enumType.ContainingType);
             Assert.Null(enumType.Proto.Options);
 
             Assert.AreEqual("NestedEnum", nestedType.Name);
             Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedEnum",
                             nestedType.FullName);
-            Assert.AreEqual(UnittestProto3.Descriptor, nestedType.File);
+            Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
             Assert.AreEqual(TestAllTypes.Descriptor, nestedType.ContainingType);
 
             EnumValueDescriptor value = enumType.FindValueByName("FOREIGN_FOO");
@@ -226,17 +227,12 @@
         }
 
         [Test]
-        public void ConstructionWithoutGeneratedCodeInfo()
+        public void MapEntryMessageDescriptor()
         {
-            var data = UnittestIssues.Descriptor.Proto.ToByteArray();
-            var newDescriptor = Google.Protobuf.Reflection.FileDescriptor.InternalBuildGeneratedFileFrom(data, new Reflection.FileDescriptor[] { }, null);
-
-            // We should still be able to get at a field...
-            var messageDescriptor = newDescriptor.FindTypeByName<MessageDescriptor>("ItemField");
-            var fieldDescriptor = messageDescriptor.FindFieldByName("item");
-            // But there shouldn't be an accessor (or a generated type for the message)
-            Assert.IsNull(fieldDescriptor.Accessor);
-            Assert.IsNull(messageDescriptor.GeneratedType);
+            var descriptor = MapWellKnownTypes.Descriptor.NestedTypes[0];
+            Assert.IsNull(descriptor.Parser);
+            Assert.IsNull(descriptor.ClrType);
+            Assert.IsNull(descriptor.Fields[1].Accessor);
         }
 
         // From TestFieldOrdering:
@@ -257,6 +253,7 @@
         public void DescriptorProtoFileDescriptor()
         {
             var descriptor = Google.Protobuf.Reflection.FileDescriptor.DescriptorProtoFileDescriptor;
+            Assert.AreEqual("google/protobuf/descriptor.proto", descriptor.Name);
         }
     }
 }
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs
new file mode 100644
index 0000000..5be7ca2
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs
@@ -0,0 +1,94 @@
+#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/
+//
+// 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.
+#endregion
+
+using Google.Protobuf.TestProtos;
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework;
+
+namespace Google.Protobuf.Reflection
+{
+    public class TypeRegistryTest
+    {
+        // Most of our tests use messages. Simple test that we really can use files...
+        [Test]
+        public void CreateWithFileDescriptor()
+        {
+            var registry = TypeRegistry.FromFiles(DurationReflection.Descriptor, StructReflection.Descriptor);
+            AssertDescriptorPresent(registry, Duration.Descriptor);
+            AssertDescriptorPresent(registry, ListValue.Descriptor);
+            AssertDescriptorAbsent(registry, Timestamp.Descriptor);
+        }
+
+        [Test]
+        public void TypesFromSameFile()
+        {
+            // Just for kicks, let's start with a nested type
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Types.NestedMessage.Descriptor);
+            // Top-level...
+            AssertDescriptorPresent(registry, TestFieldOrderings.Descriptor);
+            // ... and nested (not the same as the original NestedMessage!)
+            AssertDescriptorPresent(registry, TestFieldOrderings.Types.NestedMessage.Descriptor);
+        }
+
+        [Test]
+        public void DependenciesAreIncluded()
+        {
+            var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
+            // Direct dependencies
+            AssertDescriptorPresent(registry, ImportMessage.Descriptor);
+            // Public dependencies
+            AssertDescriptorPresent(registry, PublicImportMessage.Descriptor);
+        }
+
+        [Test]
+        public void DuplicateFiles()
+        {
+            // Duplicates via dependencies and simply via repetition
+            var registry = TypeRegistry.FromFiles(
+                UnittestProto3Reflection.Descriptor, UnittestImportProto3Reflection.Descriptor,
+                TimestampReflection.Descriptor, TimestampReflection.Descriptor);
+            AssertDescriptorPresent(registry, TestAllTypes.Descriptor);
+            AssertDescriptorPresent(registry, ImportMessage.Descriptor);
+            AssertDescriptorPresent(registry, Timestamp.Descriptor);
+        }
+
+        private static void AssertDescriptorPresent(TypeRegistry registry, MessageDescriptor descriptor)
+        {
+            Assert.AreSame(descriptor, registry.Find(descriptor.FullName));
+        }
+
+        private static void AssertDescriptorAbsent(TypeRegistry registry, MessageDescriptor descriptor)
+        {
+            Assert.IsNull(registry.Find(descriptor.FullName));
+        }
+    }
+}
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs
similarity index 77%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs
index cb6ca1b..5663a69 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs
@@ -1,5 +1,6 @@
+#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2008 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
@@ -27,17 +28,18 @@
 // 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
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
-
-package protobuf_unittest;
-
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
+namespace Google.Protobuf.TestProtos
+{
+    /// <summary>
+    /// A message with custom diagnostics (to test that they work).
+    /// </summary>
+    public partial class ForeignMessage : ICustomDiagnosticMessage
+    {
+        public string ToDiagnosticString()
+        {
+            return $"{{ \"c\": {C}, \"@cInHex\": \"{C:x}\" }}";
+        }
+    }
 }
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
index e9e1819..27c0478 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
@@ -9,152 +9,154 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.TestProtos {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/map_unittest_proto3.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class MapUnittestProto3 {
+  public static partial class MapUnittestProto3Reflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/map_unittest_proto3.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static MapUnittestProto3() {
+    static MapUnittestProto3Reflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "Cilnb29nbGUvcHJvdG9idWYvbWFwX3VuaXR0ZXN0X3Byb3RvMy5wcm90bxIR", 
-            "cHJvdG9idWZfdW5pdHRlc3QaJWdvb2dsZS9wcm90b2J1Zi91bml0dGVzdF9w", 
-            "cm90bzMucHJvdG8ilhIKB1Rlc3RNYXASRgoPbWFwX2ludDMyX2ludDMyGAEg", 
-            "AygLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkludDMy", 
-            "RW50cnkSRgoPbWFwX2ludDY0X2ludDY0GAIgAygLMi0ucHJvdG9idWZfdW5p", 
-            "dHRlc3QuVGVzdE1hcC5NYXBJbnQ2NEludDY0RW50cnkSSgoRbWFwX3VpbnQz", 
-            "Ml91aW50MzIYAyADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h", 
-            "cFVpbnQzMlVpbnQzMkVudHJ5EkoKEW1hcF91aW50NjRfdWludDY0GAQgAygL", 
-            "Mi8ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBVaW50NjRVaW50NjRF", 
-            "bnRyeRJKChFtYXBfc2ludDMyX3NpbnQzMhgFIAMoCzIvLnByb3RvYnVmX3Vu", 
-            "aXR0ZXN0LlRlc3RNYXAuTWFwU2ludDMyU2ludDMyRW50cnkSSgoRbWFwX3Np", 
-            "bnQ2NF9zaW50NjQYBiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFw", 
-            "Lk1hcFNpbnQ2NFNpbnQ2NEVudHJ5Ek4KE21hcF9maXhlZDMyX2ZpeGVkMzIY", 
-            "ByADKAsyMS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcEZpeGVkMzJG", 
-            "aXhlZDMyRW50cnkSTgoTbWFwX2ZpeGVkNjRfZml4ZWQ2NBgIIAMoCzIxLnBy", 
-            "b3RvYnVmX3VuaXR0ZXN0LlRlc3RNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRy", 
-            "eRJSChVtYXBfc2ZpeGVkMzJfc2ZpeGVkMzIYCSADKAsyMy5wcm90b2J1Zl91", 
-            "bml0dGVzdC5UZXN0TWFwLk1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRJSChVt", 
-            "YXBfc2ZpeGVkNjRfc2ZpeGVkNjQYCiADKAsyMy5wcm90b2J1Zl91bml0dGVz", 
-            "dC5UZXN0TWFwLk1hcFNmaXhlZDY0U2ZpeGVkNjRFbnRyeRJGCg9tYXBfaW50", 
-            "MzJfZmxvYXQYCyADKAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h", 
-            "cEludDMyRmxvYXRFbnRyeRJIChBtYXBfaW50MzJfZG91YmxlGAwgAygLMi4u", 
-            "cHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkRvdWJsZUVudHJ5", 
-            "EkIKDW1hcF9ib29sX2Jvb2wYDSADKAsyKy5wcm90b2J1Zl91bml0dGVzdC5U", 
-            "ZXN0TWFwLk1hcEJvb2xCb29sRW50cnkSSgoRbWFwX3N0cmluZ19zdHJpbmcY", 
-            "DiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcFN0cmluZ1N0", 
-            "cmluZ0VudHJ5EkYKD21hcF9pbnQzMl9ieXRlcxgPIAMoCzItLnByb3RvYnVm", 
-            "X3VuaXR0ZXN0LlRlc3RNYXAuTWFwSW50MzJCeXRlc0VudHJ5EkQKDm1hcF9p", 
-            "bnQzMl9lbnVtGBAgAygLMiwucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5N", 
-            "YXBJbnQzMkVudW1FbnRyeRJZChltYXBfaW50MzJfZm9yZWlnbl9tZXNzYWdl", 
-            "GBEgAygLMjYucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkZv", 
-            "cmVpZ25NZXNzYWdlRW50cnkaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tl", 
-            "eRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVu", 
-            "dHJ5EgsKA2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWlu", 
-            "dDMyVWludDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4", 
-            "ARo2ChRNYXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFs", 
-            "dWUYAiABKAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgB", 
-            "IAEoERINCgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50", 
-            "cnkSCwoDa2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhl", 
-            "ZDMyRml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoC", 
-            "OAEaOAoWTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoF", 
-            "dmFsdWUYAiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRIL", 
-            "CgNrZXkYASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0", 
-            "U2ZpeGVkNjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgB", 
-            "GjQKEk1hcEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUY", 
-            "AiABKAI6AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgF", 
-            "Eg0KBXZhbHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tl", 
-            "eRgBIAEoCBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5n", 
-            "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo0ChJNYXBJ", 
-            "bnQzMkJ5dGVzRW50cnkSCwoDa2V5GAEgASgFEg0KBXZhbHVlGAIgASgMOgI4", 
-            "ARpPChFNYXBJbnQzMkVudW1FbnRyeRILCgNrZXkYASABKAUSKQoFdmFsdWUY", 
-            "AiABKA4yGi5wcm90b2J1Zl91bml0dGVzdC5NYXBFbnVtOgI4ARpgChtNYXBJ", 
-            "bnQzMkZvcmVpZ25NZXNzYWdlRW50cnkSCwoDa2V5GAEgASgFEjAKBXZhbHVl", 
-            "GAIgASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2U6AjgB", 
-            "IkEKEVRlc3RNYXBTdWJtZXNzYWdlEiwKCHRlc3RfbWFwGAEgASgLMhoucHJv", 
-            "dG9idWZfdW5pdHRlc3QuVGVzdE1hcCK8AQoOVGVzdE1lc3NhZ2VNYXASUQoR", 
-            "bWFwX2ludDMyX21lc3NhZ2UYASADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5U", 
-            "ZXN0TWVzc2FnZU1hcC5NYXBJbnQzMk1lc3NhZ2VFbnRyeRpXChRNYXBJbnQz", 
-            "Mk1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAUSLgoFdmFsdWUYAiABKAsyHy5w", 
-            "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXM6AjgBIuMBCg9UZXN0U2Ft", 
-            "ZVR5cGVNYXASOgoEbWFwMRgBIAMoCzIsLnByb3RvYnVmX3VuaXR0ZXN0LlRl", 
-            "c3RTYW1lVHlwZU1hcC5NYXAxRW50cnkSOgoEbWFwMhgCIAMoCzIsLnByb3Rv", 
-            "YnVmX3VuaXR0ZXN0LlRlc3RTYW1lVHlwZU1hcC5NYXAyRW50cnkaKwoJTWFw", 
-            "MUVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaKwoJTWFw", 
-            "MkVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEi5BAKDFRl", 
-            "c3RBcmVuYU1hcBJLCg9tYXBfaW50MzJfaW50MzIYASADKAsyMi5wcm90b2J1", 
-            "Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50MzJJbnQzMkVudHJ5EksK", 
-            "D21hcF9pbnQ2NF9pbnQ2NBgCIAMoCzIyLnByb3RvYnVmX3VuaXR0ZXN0LlRl", 
-            "c3RBcmVuYU1hcC5NYXBJbnQ2NEludDY0RW50cnkSTwoRbWFwX3VpbnQzMl91", 
-            "aW50MzIYAyADKAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAu", 
-            "TWFwVWludDMyVWludDMyRW50cnkSTwoRbWFwX3VpbnQ2NF91aW50NjQYBCAD", 
-            "KAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwVWludDY0", 
-            "VWludDY0RW50cnkSTwoRbWFwX3NpbnQzMl9zaW50MzIYBSADKAsyNC5wcm90", 
-            "b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDMyU2ludDMyRW50", 
-            "cnkSTwoRbWFwX3NpbnQ2NF9zaW50NjQYBiADKAsyNC5wcm90b2J1Zl91bml0", 
-            "dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDY0U2ludDY0RW50cnkSUwoTbWFw", 
-            "X2ZpeGVkMzJfZml4ZWQzMhgHIAMoCzI2LnByb3RvYnVmX3VuaXR0ZXN0LlRl", 
-            "c3RBcmVuYU1hcC5NYXBGaXhlZDMyRml4ZWQzMkVudHJ5ElMKE21hcF9maXhl", 
-            "ZDY0X2ZpeGVkNjQYCCADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJl", 
-            "bmFNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRJXChVtYXBfc2ZpeGVkMzJf", 
-            "c2ZpeGVkMzIYCSADKAsyOC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFN", 
-            "YXAuTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5ElcKFW1hcF9zZml4ZWQ2NF9z", 
-            "Zml4ZWQ2NBgKIAMoCzI4LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBcmVuYU1h", 
-            "cC5NYXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSSwoPbWFwX2ludDMyX2Zsb2F0", 
-            "GAsgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcElu", 
-            "dDMyRmxvYXRFbnRyeRJNChBtYXBfaW50MzJfZG91YmxlGAwgAygLMjMucHJv", 
-            "dG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcEludDMyRG91YmxlRW50", 
-            "cnkSRwoNbWFwX2Jvb2xfYm9vbBgNIAMoCzIwLnByb3RvYnVmX3VuaXR0ZXN0", 
-            "LlRlc3RBcmVuYU1hcC5NYXBCb29sQm9vbEVudHJ5EkkKDm1hcF9pbnQzMl9l", 
-            "bnVtGA4gAygLMjEucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1h", 
-            "cEludDMyRW51bUVudHJ5El4KGW1hcF9pbnQzMl9mb3JlaWduX21lc3NhZ2UY", 
-            "DyADKAsyOy5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50", 
-            "MzJGb3JlaWduTWVzc2FnZUVudHJ5GjQKEk1hcEludDMySW50MzJFbnRyeRIL", 
-            "CgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcEludDY0SW50", 
-            "NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgBGjYKFE1h", 
-            "cFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1ZRgCIAEo", 
-            "DToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEgASgEEg0K", 
-            "BXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRyeRILCgNr", 
-            "ZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2NFNpbnQ2", 
-            "NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEaOAoWTWFw", 
-            "Rml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFsdWUYAiAB", 
-            "KAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5GAEgASgG", 
-            "Eg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhlZDMyRW50", 
-            "cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhNYXBTZml4", 
-            "ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVlGAIgASgQ", 
-            "OgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgFEg0KBXZh", 
-            "bHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsKA2tleRgB", 
-            "IAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xFbnRyeRIL", 
-            "CgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGk8KEU1hcEludDMyRW51", 
-            "bUVudHJ5EgsKA2tleRgBIAEoBRIpCgV2YWx1ZRgCIAEoDjIaLnByb3RvYnVm", 
-            "X3VuaXR0ZXN0Lk1hcEVudW06AjgBGmAKG01hcEludDMyRm9yZWlnbk1lc3Nh", 
-            "Z2VFbnRyeRILCgNrZXkYASABKAUSMAoFdmFsdWUYAiABKAsyIS5wcm90b2J1", 
-            "Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZToCOAEi5AEKH01lc3NhZ2VDb250", 
-            "YWluaW5nRW51bUNhbGxlZFR5cGUSSgoEdHlwZRgBIAMoCzI8LnByb3RvYnVm", 
-            "X3VuaXR0ZXN0Lk1lc3NhZ2VDb250YWluaW5nRW51bUNhbGxlZFR5cGUuVHlw", 
-            "ZUVudHJ5Gl8KCVR5cGVFbnRyeRILCgNrZXkYASABKAUSQQoFdmFsdWUYAiAB", 
-            "KAsyMi5wcm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ0VudW1D", 
-            "YWxsZWRUeXBlOgI4ASIUCgRUeXBlEgwKCFRZUEVfRk9PEAAinQEKH01lc3Nh", 
-            "Z2VDb250YWluaW5nTWFwQ2FsbGVkRW50cnkSTAoFZW50cnkYASADKAsyPS5w", 
-            "cm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ01hcENhbGxlZEVu", 
-            "dHJ5LkVudHJ5RW50cnkaLAoKRW50cnlFbnRyeRILCgNrZXkYASABKAUSDQoF", 
-            "dmFsdWUYAiABKAU6AjgBKj8KB01hcEVudW0SEAoMTUFQX0VOVU1fRk9PEAAS", 
-            "EAoMTUFQX0VOVU1fQkFSEAESEAoMTUFQX0VOVU1fQkFaEAJCIPgBAaoCGkdv", 
+            "Cilnb29nbGUvcHJvdG9idWYvbWFwX3VuaXR0ZXN0X3Byb3RvMy5wcm90bxIR",
+            "cHJvdG9idWZfdW5pdHRlc3QaJWdvb2dsZS9wcm90b2J1Zi91bml0dGVzdF9w",
+            "cm90bzMucHJvdG8ilhIKB1Rlc3RNYXASRgoPbWFwX2ludDMyX2ludDMyGAEg",
+            "AygLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkludDMy",
+            "RW50cnkSRgoPbWFwX2ludDY0X2ludDY0GAIgAygLMi0ucHJvdG9idWZfdW5p",
+            "dHRlc3QuVGVzdE1hcC5NYXBJbnQ2NEludDY0RW50cnkSSgoRbWFwX3VpbnQz",
+            "Ml91aW50MzIYAyADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h",
+            "cFVpbnQzMlVpbnQzMkVudHJ5EkoKEW1hcF91aW50NjRfdWludDY0GAQgAygL",
+            "Mi8ucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBVaW50NjRVaW50NjRF",
+            "bnRyeRJKChFtYXBfc2ludDMyX3NpbnQzMhgFIAMoCzIvLnByb3RvYnVmX3Vu",
+            "aXR0ZXN0LlRlc3RNYXAuTWFwU2ludDMyU2ludDMyRW50cnkSSgoRbWFwX3Np",
+            "bnQ2NF9zaW50NjQYBiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFw",
+            "Lk1hcFNpbnQ2NFNpbnQ2NEVudHJ5Ek4KE21hcF9maXhlZDMyX2ZpeGVkMzIY",
+            "ByADKAsyMS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcEZpeGVkMzJG",
+            "aXhlZDMyRW50cnkSTgoTbWFwX2ZpeGVkNjRfZml4ZWQ2NBgIIAMoCzIxLnBy",
+            "b3RvYnVmX3VuaXR0ZXN0LlRlc3RNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRy",
+            "eRJSChVtYXBfc2ZpeGVkMzJfc2ZpeGVkMzIYCSADKAsyMy5wcm90b2J1Zl91",
+            "bml0dGVzdC5UZXN0TWFwLk1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRJSChVt",
+            "YXBfc2ZpeGVkNjRfc2ZpeGVkNjQYCiADKAsyMy5wcm90b2J1Zl91bml0dGVz",
+            "dC5UZXN0TWFwLk1hcFNmaXhlZDY0U2ZpeGVkNjRFbnRyeRJGCg9tYXBfaW50",
+            "MzJfZmxvYXQYCyADKAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1h",
+            "cEludDMyRmxvYXRFbnRyeRJIChBtYXBfaW50MzJfZG91YmxlGAwgAygLMi4u",
+            "cHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkRvdWJsZUVudHJ5",
+            "EkIKDW1hcF9ib29sX2Jvb2wYDSADKAsyKy5wcm90b2J1Zl91bml0dGVzdC5U",
+            "ZXN0TWFwLk1hcEJvb2xCb29sRW50cnkSSgoRbWFwX3N0cmluZ19zdHJpbmcY",
+            "DiADKAsyLy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWFwLk1hcFN0cmluZ1N0",
+            "cmluZ0VudHJ5EkYKD21hcF9pbnQzMl9ieXRlcxgPIAMoCzItLnByb3RvYnVm",
+            "X3VuaXR0ZXN0LlRlc3RNYXAuTWFwSW50MzJCeXRlc0VudHJ5EkQKDm1hcF9p",
+            "bnQzMl9lbnVtGBAgAygLMiwucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5N",
+            "YXBJbnQzMkVudW1FbnRyeRJZChltYXBfaW50MzJfZm9yZWlnbl9tZXNzYWdl",
+            "GBEgAygLMjYucHJvdG9idWZfdW5pdHRlc3QuVGVzdE1hcC5NYXBJbnQzMkZv",
+            "cmVpZ25NZXNzYWdlRW50cnkaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tl",
+            "eRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVu",
+            "dHJ5EgsKA2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWlu",
+            "dDMyVWludDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4",
+            "ARo2ChRNYXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFs",
+            "dWUYAiABKAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgB",
+            "IAEoERINCgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50",
+            "cnkSCwoDa2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhl",
+            "ZDMyRml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoC",
+            "OAEaOAoWTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoF",
+            "dmFsdWUYAiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRIL",
+            "CgNrZXkYASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0",
+            "U2ZpeGVkNjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgB",
+            "GjQKEk1hcEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUY",
+            "AiABKAI6AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgF",
+            "Eg0KBXZhbHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tl",
+            "eRgBIAEoCBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5n",
+            "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo0ChJNYXBJ",
+            "bnQzMkJ5dGVzRW50cnkSCwoDa2V5GAEgASgFEg0KBXZhbHVlGAIgASgMOgI4",
+            "ARpPChFNYXBJbnQzMkVudW1FbnRyeRILCgNrZXkYASABKAUSKQoFdmFsdWUY",
+            "AiABKA4yGi5wcm90b2J1Zl91bml0dGVzdC5NYXBFbnVtOgI4ARpgChtNYXBJ",
+            "bnQzMkZvcmVpZ25NZXNzYWdlRW50cnkSCwoDa2V5GAEgASgFEjAKBXZhbHVl",
+            "GAIgASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2U6AjgB",
+            "IkEKEVRlc3RNYXBTdWJtZXNzYWdlEiwKCHRlc3RfbWFwGAEgASgLMhoucHJv",
+            "dG9idWZfdW5pdHRlc3QuVGVzdE1hcCK8AQoOVGVzdE1lc3NhZ2VNYXASUQoR",
+            "bWFwX2ludDMyX21lc3NhZ2UYASADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5U",
+            "ZXN0TWVzc2FnZU1hcC5NYXBJbnQzMk1lc3NhZ2VFbnRyeRpXChRNYXBJbnQz",
+            "Mk1lc3NhZ2VFbnRyeRILCgNrZXkYASABKAUSLgoFdmFsdWUYAiABKAsyHy5w",
+            "cm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXM6AjgBIuMBCg9UZXN0U2Ft",
+            "ZVR5cGVNYXASOgoEbWFwMRgBIAMoCzIsLnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RTYW1lVHlwZU1hcC5NYXAxRW50cnkSOgoEbWFwMhgCIAMoCzIsLnByb3Rv",
+            "YnVmX3VuaXR0ZXN0LlRlc3RTYW1lVHlwZU1hcC5NYXAyRW50cnkaKwoJTWFw",
+            "MUVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaKwoJTWFw",
+            "MkVudHJ5EgsKA2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEi5BAKDFRl",
+            "c3RBcmVuYU1hcBJLCg9tYXBfaW50MzJfaW50MzIYASADKAsyMi5wcm90b2J1",
+            "Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50MzJJbnQzMkVudHJ5EksK",
+            "D21hcF9pbnQ2NF9pbnQ2NBgCIAMoCzIyLnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RBcmVuYU1hcC5NYXBJbnQ2NEludDY0RW50cnkSTwoRbWFwX3VpbnQzMl91",
+            "aW50MzIYAyADKAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAu",
+            "TWFwVWludDMyVWludDMyRW50cnkSTwoRbWFwX3VpbnQ2NF91aW50NjQYBCAD",
+            "KAsyNC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwVWludDY0",
+            "VWludDY0RW50cnkSTwoRbWFwX3NpbnQzMl9zaW50MzIYBSADKAsyNC5wcm90",
+            "b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDMyU2ludDMyRW50",
+            "cnkSTwoRbWFwX3NpbnQ2NF9zaW50NjQYBiADKAsyNC5wcm90b2J1Zl91bml0",
+            "dGVzdC5UZXN0QXJlbmFNYXAuTWFwU2ludDY0U2ludDY0RW50cnkSUwoTbWFw",
+            "X2ZpeGVkMzJfZml4ZWQzMhgHIAMoCzI2LnByb3RvYnVmX3VuaXR0ZXN0LlRl",
+            "c3RBcmVuYU1hcC5NYXBGaXhlZDMyRml4ZWQzMkVudHJ5ElMKE21hcF9maXhl",
+            "ZDY0X2ZpeGVkNjQYCCADKAsyNi5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJl",
+            "bmFNYXAuTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRJXChVtYXBfc2ZpeGVkMzJf",
+            "c2ZpeGVkMzIYCSADKAsyOC5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFN",
+            "YXAuTWFwU2ZpeGVkMzJTZml4ZWQzMkVudHJ5ElcKFW1hcF9zZml4ZWQ2NF9z",
+            "Zml4ZWQ2NBgKIAMoCzI4LnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RBcmVuYU1h",
+            "cC5NYXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSSwoPbWFwX2ludDMyX2Zsb2F0",
+            "GAsgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcElu",
+            "dDMyRmxvYXRFbnRyeRJNChBtYXBfaW50MzJfZG91YmxlGAwgAygLMjMucHJv",
+            "dG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1hcEludDMyRG91YmxlRW50",
+            "cnkSRwoNbWFwX2Jvb2xfYm9vbBgNIAMoCzIwLnByb3RvYnVmX3VuaXR0ZXN0",
+            "LlRlc3RBcmVuYU1hcC5NYXBCb29sQm9vbEVudHJ5EkkKDm1hcF9pbnQzMl9l",
+            "bnVtGA4gAygLMjEucHJvdG9idWZfdW5pdHRlc3QuVGVzdEFyZW5hTWFwLk1h",
+            "cEludDMyRW51bUVudHJ5El4KGW1hcF9pbnQzMl9mb3JlaWduX21lc3NhZ2UY",
+            "DyADKAsyOy5wcm90b2J1Zl91bml0dGVzdC5UZXN0QXJlbmFNYXAuTWFwSW50",
+            "MzJGb3JlaWduTWVzc2FnZUVudHJ5GjQKEk1hcEludDMySW50MzJFbnRyeRIL",
+            "CgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcEludDY0SW50",
+            "NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgBGjYKFE1h",
+            "cFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1ZRgCIAEo",
+            "DToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEgASgEEg0K",
+            "BXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRyeRILCgNr",
+            "ZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2NFNpbnQ2",
+            "NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEaOAoWTWFw",
+            "Rml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFsdWUYAiAB",
+            "KAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5GAEgASgG",
+            "Eg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhlZDMyRW50",
+            "cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhNYXBTZml4",
+            "ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVlGAIgASgQ",
+            "OgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgFEg0KBXZh",
+            "bHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsKA2tleRgB",
+            "IAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xFbnRyeRIL",
+            "CgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGk8KEU1hcEludDMyRW51",
+            "bUVudHJ5EgsKA2tleRgBIAEoBRIpCgV2YWx1ZRgCIAEoDjIaLnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1hcEVudW06AjgBGmAKG01hcEludDMyRm9yZWlnbk1lc3Nh",
+            "Z2VFbnRyeRILCgNrZXkYASABKAUSMAoFdmFsdWUYAiABKAsyIS5wcm90b2J1",
+            "Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZToCOAEi5AEKH01lc3NhZ2VDb250",
+            "YWluaW5nRW51bUNhbGxlZFR5cGUSSgoEdHlwZRgBIAMoCzI8LnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1lc3NhZ2VDb250YWluaW5nRW51bUNhbGxlZFR5cGUuVHlw",
+            "ZUVudHJ5Gl8KCVR5cGVFbnRyeRILCgNrZXkYASABKAUSQQoFdmFsdWUYAiAB",
+            "KAsyMi5wcm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ0VudW1D",
+            "YWxsZWRUeXBlOgI4ASIUCgRUeXBlEgwKCFRZUEVfRk9PEAAinQEKH01lc3Nh",
+            "Z2VDb250YWluaW5nTWFwQ2FsbGVkRW50cnkSTAoFZW50cnkYASADKAsyPS5w",
+            "cm90b2J1Zl91bml0dGVzdC5NZXNzYWdlQ29udGFpbmluZ01hcENhbGxlZEVu",
+            "dHJ5LkVudHJ5RW50cnkaLAoKRW50cnlFbnRyeRILCgNrZXkYASABKAUSDQoF",
+            "dmFsdWUYAiABKAU6AjgBKj8KB01hcEVudW0SEAoMTUFQX0VOVU1fRk9PEAAS",
+            "EAoMTUFQX0VOVU1fQkFSEAESEAoMTUFQX0VOVU1fQkFaEAJCIPgBAaoCGkdv",
             "b2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zYgZwcm90bzM="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor, },
-          new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.MapEnum), }, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMap), new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapInt32Bytes", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedCodeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMapSubmessage), new[]{ "TestMap" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMessageMap), new[]{ "MapInt32Message" }, null, null, new pbr::GeneratedCodeInfo[] { null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestSameTypeMap), new[]{ "Map1", "Map2" }, null, null, new pbr::GeneratedCodeInfo[] { null, null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestArenaMap), new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedCodeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType), new[]{ "Type" }, null, new[]{ typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Types.Type) }, new pbr::GeneratedCodeInfo[] { null, }),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingMapCalledEntry), new[]{ "Entry" }, null, null, new pbr::GeneratedCodeInfo[] { null, })
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.MapEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMap), global::Google.Protobuf.TestProtos.TestMap.Parser, new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapInt32Bytes", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMapSubmessage), global::Google.Protobuf.TestProtos.TestMapSubmessage.Parser, new[]{ "TestMap" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMessageMap), global::Google.Protobuf.TestProtos.TestMessageMap.Parser, new[]{ "MapInt32Message" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestSameTypeMap), global::Google.Protobuf.TestProtos.TestSameTypeMap.Parser, new[]{ "Map1", "Map2" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestArenaMap), global::Google.Protobuf.TestProtos.TestArenaMap.Parser, new[]{ "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapInt32Enum", "MapInt32ForeignMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType), global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Parser, new[]{ "Type" }, null, new[]{ typeof(global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Types.Type) }, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MessageContainingMapCalledEntry), global::Google.Protobuf.TestProtos.MessageContainingMapCalledEntry.Parser, new[]{ "Entry" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, })
           }));
     }
     #endregion
@@ -170,13 +172,16 @@
   #endregion
 
   #region Messages
+  /// <summary>
+  ///  Tests maps.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestMap : pb::IMessage<TestMap> {
     private static readonly pb::MessageParser<TestMap> _parser = new pb::MessageParser<TestMap>(() => new TestMap());
     public static pb::MessageParser<TestMap> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -213,6 +218,7 @@
       return new TestMap(this);
     }
 
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
     public const int MapInt32Int32FieldNumber = 1;
     private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
@@ -221,6 +227,7 @@
       get { return mapInt32Int32_; }
     }
 
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
     public const int MapInt64Int64FieldNumber = 2;
     private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 18);
@@ -229,6 +236,7 @@
       get { return mapInt64Int64_; }
     }
 
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
     public const int MapUint32Uint32FieldNumber = 3;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 26);
@@ -237,6 +245,7 @@
       get { return mapUint32Uint32_; }
     }
 
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
     public const int MapUint64Uint64FieldNumber = 4;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 34);
@@ -245,6 +254,7 @@
       get { return mapUint64Uint64_; }
     }
 
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
     public const int MapSint32Sint32FieldNumber = 5;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 42);
@@ -253,6 +263,7 @@
       get { return mapSint32Sint32_; }
     }
 
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
     public const int MapSint64Sint64FieldNumber = 6;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 50);
@@ -261,6 +272,7 @@
       get { return mapSint64Sint64_; }
     }
 
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
     public const int MapFixed32Fixed32FieldNumber = 7;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 58);
@@ -269,6 +281,7 @@
       get { return mapFixed32Fixed32_; }
     }
 
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
     public const int MapFixed64Fixed64FieldNumber = 8;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 66);
@@ -277,6 +290,7 @@
       get { return mapFixed64Fixed64_; }
     }
 
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
     public const int MapSfixed32Sfixed32FieldNumber = 9;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 74);
@@ -285,6 +299,7 @@
       get { return mapSfixed32Sfixed32_; }
     }
 
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
     public const int MapSfixed64Sfixed64FieldNumber = 10;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 82);
@@ -293,6 +308,7 @@
       get { return mapSfixed64Sfixed64_; }
     }
 
+    /// <summary>Field number for the "map_int32_float" field.</summary>
     public const int MapInt32FloatFieldNumber = 11;
     private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
         = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 90);
@@ -301,6 +317,7 @@
       get { return mapInt32Float_; }
     }
 
+    /// <summary>Field number for the "map_int32_double" field.</summary>
     public const int MapInt32DoubleFieldNumber = 12;
     private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
         = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 98);
@@ -309,6 +326,7 @@
       get { return mapInt32Double_; }
     }
 
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
     public const int MapBoolBoolFieldNumber = 13;
     private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
         = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 106);
@@ -317,6 +335,7 @@
       get { return mapBoolBool_; }
     }
 
+    /// <summary>Field number for the "map_string_string" field.</summary>
     public const int MapStringStringFieldNumber = 14;
     private static readonly pbc::MapField<string, string>.Codec _map_mapStringString_codec
         = new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForString(18), 114);
@@ -325,6 +344,7 @@
       get { return mapStringString_; }
     }
 
+    /// <summary>Field number for the "map_int32_bytes" field.</summary>
     public const int MapInt32BytesFieldNumber = 15;
     private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_mapInt32Bytes_codec
         = new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForBytes(18), 122);
@@ -333,6 +353,7 @@
       get { return mapInt32Bytes_; }
     }
 
+    /// <summary>Field number for the "map_int32_enum" field.</summary>
     public const int MapInt32EnumFieldNumber = 16;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec _map_mapInt32Enum_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Google.Protobuf.TestProtos.MapEnum) x), 130);
@@ -341,6 +362,7 @@
       get { return mapInt32Enum_; }
     }
 
+    /// <summary>Field number for the "map_int32_foreign_message" field.</summary>
     public const int MapInt32ForeignMessageFieldNumber = 17;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec _map_mapInt32ForeignMessage_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.ForeignMessage.Parser), 138);
@@ -403,7 +425,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -558,7 +580,7 @@
     public static pb::MessageParser<TestMapSubmessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -579,6 +601,7 @@
       return new TestMapSubmessage(this);
     }
 
+    /// <summary>Field number for the "test_map" field.</summary>
     public const int TestMapFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestMap testMap_;
     public global::Google.Protobuf.TestProtos.TestMap TestMap {
@@ -610,7 +633,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -666,7 +689,7 @@
     public static pb::MessageParser<TestMessageMap> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -687,6 +710,7 @@
       return new TestMessageMap(this);
     }
 
+    /// <summary>Field number for the "map_int32_message" field.</summary>
     public const int MapInt32MessageFieldNumber = 1;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes>.Codec _map_mapInt32Message_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.TestAllTypes>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.TestAllTypes.Parser), 10);
@@ -717,7 +741,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -754,13 +778,16 @@
 
   }
 
+  /// <summary>
+  ///  Two map fields share the same entry default instance.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestSameTypeMap : pb::IMessage<TestSameTypeMap> {
     private static readonly pb::MessageParser<TestSameTypeMap> _parser = new pb::MessageParser<TestSameTypeMap>(() => new TestSameTypeMap());
     public static pb::MessageParser<TestSameTypeMap> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -782,6 +809,7 @@
       return new TestSameTypeMap(this);
     }
 
+    /// <summary>Field number for the "map1" field.</summary>
     public const int Map1FieldNumber = 1;
     private static readonly pbc::MapField<int, int>.Codec _map_map1_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
@@ -790,6 +818,7 @@
       get { return map1_; }
     }
 
+    /// <summary>Field number for the "map2" field.</summary>
     public const int Map2FieldNumber = 2;
     private static readonly pbc::MapField<int, int>.Codec _map_map2_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 18);
@@ -822,7 +851,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -872,7 +901,7 @@
     public static pb::MessageParser<TestArenaMap> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[4]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -907,6 +936,7 @@
       return new TestArenaMap(this);
     }
 
+    /// <summary>Field number for the "map_int32_int32" field.</summary>
     public const int MapInt32Int32FieldNumber = 1;
     private static readonly pbc::MapField<int, int>.Codec _map_mapInt32Int32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
@@ -915,6 +945,7 @@
       get { return mapInt32Int32_; }
     }
 
+    /// <summary>Field number for the "map_int64_int64" field.</summary>
     public const int MapInt64Int64FieldNumber = 2;
     private static readonly pbc::MapField<long, long>.Codec _map_mapInt64Int64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForInt64(8), pb::FieldCodec.ForInt64(16), 18);
@@ -923,6 +954,7 @@
       get { return mapInt64Int64_; }
     }
 
+    /// <summary>Field number for the "map_uint32_uint32" field.</summary>
     public const int MapUint32Uint32FieldNumber = 3;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapUint32Uint32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForUInt32(8), pb::FieldCodec.ForUInt32(16), 26);
@@ -931,6 +963,7 @@
       get { return mapUint32Uint32_; }
     }
 
+    /// <summary>Field number for the "map_uint64_uint64" field.</summary>
     public const int MapUint64Uint64FieldNumber = 4;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapUint64Uint64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForUInt64(8), pb::FieldCodec.ForUInt64(16), 34);
@@ -939,6 +972,7 @@
       get { return mapUint64Uint64_; }
     }
 
+    /// <summary>Field number for the "map_sint32_sint32" field.</summary>
     public const int MapSint32Sint32FieldNumber = 5;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSint32Sint32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSInt32(8), pb::FieldCodec.ForSInt32(16), 42);
@@ -947,6 +981,7 @@
       get { return mapSint32Sint32_; }
     }
 
+    /// <summary>Field number for the "map_sint64_sint64" field.</summary>
     public const int MapSint64Sint64FieldNumber = 6;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSint64Sint64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSInt64(8), pb::FieldCodec.ForSInt64(16), 50);
@@ -955,6 +990,7 @@
       get { return mapSint64Sint64_; }
     }
 
+    /// <summary>Field number for the "map_fixed32_fixed32" field.</summary>
     public const int MapFixed32Fixed32FieldNumber = 7;
     private static readonly pbc::MapField<uint, uint>.Codec _map_mapFixed32Fixed32_codec
         = new pbc::MapField<uint, uint>.Codec(pb::FieldCodec.ForFixed32(13), pb::FieldCodec.ForFixed32(21), 58);
@@ -963,6 +999,7 @@
       get { return mapFixed32Fixed32_; }
     }
 
+    /// <summary>Field number for the "map_fixed64_fixed64" field.</summary>
     public const int MapFixed64Fixed64FieldNumber = 8;
     private static readonly pbc::MapField<ulong, ulong>.Codec _map_mapFixed64Fixed64_codec
         = new pbc::MapField<ulong, ulong>.Codec(pb::FieldCodec.ForFixed64(9), pb::FieldCodec.ForFixed64(17), 66);
@@ -971,6 +1008,7 @@
       get { return mapFixed64Fixed64_; }
     }
 
+    /// <summary>Field number for the "map_sfixed32_sfixed32" field.</summary>
     public const int MapSfixed32Sfixed32FieldNumber = 9;
     private static readonly pbc::MapField<int, int>.Codec _map_mapSfixed32Sfixed32_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForSFixed32(13), pb::FieldCodec.ForSFixed32(21), 74);
@@ -979,6 +1017,7 @@
       get { return mapSfixed32Sfixed32_; }
     }
 
+    /// <summary>Field number for the "map_sfixed64_sfixed64" field.</summary>
     public const int MapSfixed64Sfixed64FieldNumber = 10;
     private static readonly pbc::MapField<long, long>.Codec _map_mapSfixed64Sfixed64_codec
         = new pbc::MapField<long, long>.Codec(pb::FieldCodec.ForSFixed64(9), pb::FieldCodec.ForSFixed64(17), 82);
@@ -987,6 +1026,7 @@
       get { return mapSfixed64Sfixed64_; }
     }
 
+    /// <summary>Field number for the "map_int32_float" field.</summary>
     public const int MapInt32FloatFieldNumber = 11;
     private static readonly pbc::MapField<int, float>.Codec _map_mapInt32Float_codec
         = new pbc::MapField<int, float>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForFloat(21), 90);
@@ -995,6 +1035,7 @@
       get { return mapInt32Float_; }
     }
 
+    /// <summary>Field number for the "map_int32_double" field.</summary>
     public const int MapInt32DoubleFieldNumber = 12;
     private static readonly pbc::MapField<int, double>.Codec _map_mapInt32Double_codec
         = new pbc::MapField<int, double>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForDouble(17), 98);
@@ -1003,6 +1044,7 @@
       get { return mapInt32Double_; }
     }
 
+    /// <summary>Field number for the "map_bool_bool" field.</summary>
     public const int MapBoolBoolFieldNumber = 13;
     private static readonly pbc::MapField<bool, bool>.Codec _map_mapBoolBool_codec
         = new pbc::MapField<bool, bool>.Codec(pb::FieldCodec.ForBool(8), pb::FieldCodec.ForBool(16), 106);
@@ -1011,6 +1053,7 @@
       get { return mapBoolBool_; }
     }
 
+    /// <summary>Field number for the "map_int32_enum" field.</summary>
     public const int MapInt32EnumFieldNumber = 14;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec _map_mapInt32Enum_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MapEnum>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::Google.Protobuf.TestProtos.MapEnum) x), 114);
@@ -1019,6 +1062,7 @@
       get { return mapInt32Enum_; }
     }
 
+    /// <summary>Field number for the "map_int32_foreign_message" field.</summary>
     public const int MapInt32ForeignMessageFieldNumber = 15;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec _map_mapInt32ForeignMessage_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.ForeignMessage>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.ForeignMessage.Parser), 122);
@@ -1077,7 +1121,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1212,13 +1256,17 @@
 
   }
 
+  /// <summary>
+  ///  Previously, message containing enum called Type cannot be used as value of
+  ///  map field.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class MessageContainingEnumCalledType : pb::IMessage<MessageContainingEnumCalledType> {
     private static readonly pb::MessageParser<MessageContainingEnumCalledType> _parser = new pb::MessageParser<MessageContainingEnumCalledType>(() => new MessageContainingEnumCalledType());
     public static pb::MessageParser<MessageContainingEnumCalledType> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[5]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1239,6 +1287,7 @@
       return new MessageContainingEnumCalledType(this);
     }
 
+    /// <summary>Field number for the "type" field.</summary>
     public const int TypeFieldNumber = 1;
     private static readonly pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType>.Codec _map_type_codec
         = new pbc::MapField<int, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.TestProtos.MessageContainingEnumCalledType.Parser), 10);
@@ -1269,7 +1318,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1305,6 +1354,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the MessageContainingEnumCalledType message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       public enum Type {
@@ -1316,13 +1366,16 @@
 
   }
 
+  /// <summary>
+  ///  Previously, message cannot contain map field called "entry".
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class MessageContainingMapCalledEntry : pb::IMessage<MessageContainingMapCalledEntry> {
     private static readonly pb::MessageParser<MessageContainingMapCalledEntry> _parser = new pb::MessageParser<MessageContainingMapCalledEntry>(() => new MessageContainingMapCalledEntry());
     public static pb::MessageParser<MessageContainingMapCalledEntry> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3.Descriptor.MessageTypes[6]; }
+      get { return global::Google.Protobuf.TestProtos.MapUnittestProto3Reflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1343,6 +1396,7 @@
       return new MessageContainingMapCalledEntry(this);
     }
 
+    /// <summary>Field number for the "entry" field.</summary>
     public const int EntryFieldNumber = 1;
     private static readonly pbc::MapField<int, int>.Codec _map_entry_codec
         = new pbc::MapField<int, int>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForInt32(16), 10);
@@ -1373,7 +1427,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
index bf527ac..7b824dc 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
@@ -9,30 +9,32 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.TestProtos {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_import_proto3.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class UnittestImportProto3 {
+  public static partial class UnittestImportProto3Reflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_import_proto3.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static UnittestImportProto3() {
+    static UnittestImportProto3Reflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "Cixnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3Byb3RvMy5wcm90", 
-            "bxIYcHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0GjNnb29nbGUvcHJvdG9idWYv", 
-            "dW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90bzMucHJvdG8iGgoNSW1wb3J0", 
-            "TWVzc2FnZRIJCgFkGAEgASgFKlkKCkltcG9ydEVudW0SGwoXSU1QT1JUX0VO", 
-            "VU1fVU5TUEVDSUZJRUQQABIOCgpJTVBPUlRfRk9PEAcSDgoKSU1QT1JUX0JB", 
-            "UhAIEg4KCklNUE9SVF9CQVoQCUI8Chhjb20uZ29vZ2xlLnByb3RvYnVmLnRl", 
-            "c3RIAfgBAaoCGkdvb2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zUABiBnByb3Rv", 
+            "Cixnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3Byb3RvMy5wcm90",
+            "bxIYcHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0GjNnb29nbGUvcHJvdG9idWYv",
+            "dW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90bzMucHJvdG8iGgoNSW1wb3J0",
+            "TWVzc2FnZRIJCgFkGAEgASgFKlkKCkltcG9ydEVudW0SGwoXSU1QT1JUX0VO",
+            "VU1fVU5TUEVDSUZJRUQQABIOCgpJTVBPUlRfRk9PEAcSDgoKSU1QT1JUX0JB",
+            "UhAIEg4KCklNUE9SVF9CQVoQCUI8Chhjb20uZ29vZ2xlLnByb3RvYnVmLnRl",
+            "c3RIAfgBAaoCGkdvb2dsZS5Qcm90b2J1Zi5UZXN0UHJvdG9zUABiBnByb3Rv",
             "Mw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.Descriptor, },
-          new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ImportEnum), }, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.ImportMessage), new[]{ "D" }, null, null, null)
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportPublicProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ImportEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.ImportMessage), global::Google.Protobuf.TestProtos.ImportMessage.Parser, new[]{ "D" }, null, null, null)
           }));
     }
     #endregion
@@ -55,7 +57,7 @@
     public static pb::MessageParser<ImportMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestImportProto3.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -76,6 +78,7 @@
       return new ImportMessage(this);
     }
 
+    /// <summary>Field number for the "d" field.</summary>
     public const int DFieldNumber = 1;
     private int d_;
     public int D {
@@ -107,7 +110,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
index ec46090..b471a8c 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
@@ -9,26 +9,28 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.TestProtos {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_import_public_proto3.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class UnittestImportPublicProto3 {
+  public static partial class UnittestImportPublicProto3Reflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_import_public_proto3.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static UnittestImportPublicProto3() {
+    static UnittestImportPublicProto3Reflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "CjNnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90", 
-            "bzMucHJvdG8SGHByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydCIgChNQdWJsaWNJ", 
-            "bXBvcnRNZXNzYWdlEgkKAWUYASABKAVCNwoYY29tLmdvb2dsZS5wcm90b2J1", 
+            "CjNnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfaW1wb3J0X3B1YmxpY19wcm90",
+            "bzMucHJvdG8SGHByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydCIgChNQdWJsaWNJ",
+            "bXBvcnRNZXNzYWdlEgkKAWUYASABKAVCNwoYY29tLmdvb2dsZS5wcm90b2J1",
             "Zi50ZXN0qgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.PublicImportMessage), new[]{ "E" }, null, null, null)
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.PublicImportMessage), global::Google.Protobuf.TestProtos.PublicImportMessage.Parser, new[]{ "E" }, null, null, null)
           }));
     }
     #endregion
@@ -41,7 +43,7 @@
     public static pb::MessageParser<PublicImportMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestImportPublicProto3Reflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -62,6 +64,7 @@
       return new PublicImportMessage(this);
     }
 
+    /// <summary>Field number for the "e" field.</summary>
     public const int EFieldNumber = 1;
     private int e_;
     public int E {
@@ -93,7 +96,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
index 63119a3..16176a3 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
@@ -9,51 +9,53 @@
 using scg = global::System.Collections.Generic;
 namespace UnitTest.Issues.TestProtos {
 
+  /// <summary>Holder for reflection information generated from unittest_issues.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class UnittestIssues {
+  public static partial class UnittestIssuesReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for unittest_issues.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static UnittestIssues() {
+    static UnittestIssuesReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "ChV1bml0dGVzdF9pc3N1ZXMucHJvdG8SD3VuaXR0ZXN0X2lzc3VlcyInCghJ", 
-            "c3N1ZTMwNxobCgpOZXN0ZWRPbmNlGg0KC05lc3RlZFR3aWNlIrABChNOZWdh", 
-            "dGl2ZUVudW1NZXNzYWdlEiwKBXZhbHVlGAEgASgOMh0udW5pdHRlc3RfaXNz", 
-            "dWVzLk5lZ2F0aXZlRW51bRIxCgZ2YWx1ZXMYAiADKA4yHS51bml0dGVzdF9p", 
-            "c3N1ZXMuTmVnYXRpdmVFbnVtQgIQABI4Cg1wYWNrZWRfdmFsdWVzGAMgAygO", 
-            "Mh0udW5pdHRlc3RfaXNzdWVzLk5lZ2F0aXZlRW51bUICEAEiEQoPRGVwcmVj", 
-            "YXRlZENoaWxkIrkCChdEZXByZWNhdGVkRmllbGRzTWVzc2FnZRIaCg5Qcmlt", 
-            "aXRpdmVWYWx1ZRgBIAEoBUICGAESGgoOUHJpbWl0aXZlQXJyYXkYAiADKAVC", 
-            "AhgBEjoKDE1lc3NhZ2VWYWx1ZRgDIAEoCzIgLnVuaXR0ZXN0X2lzc3Vlcy5E", 
-            "ZXByZWNhdGVkQ2hpbGRCAhgBEjoKDE1lc3NhZ2VBcnJheRgEIAMoCzIgLnVu", 
-            "aXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkQ2hpbGRCAhgBEjYKCUVudW1WYWx1", 
-            "ZRgFIAEoDjIfLnVuaXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkRW51bUICGAES", 
-            "NgoJRW51bUFycmF5GAYgAygOMh8udW5pdHRlc3RfaXNzdWVzLkRlcHJlY2F0", 
-            "ZWRFbnVtQgIYASIZCglJdGVtRmllbGQSDAoEaXRlbRgBIAEoBSJECg1SZXNl", 
-            "cnZlZE5hbWVzEg0KBXR5cGVzGAEgASgFEhIKCmRlc2NyaXB0b3IYAiABKAUa", 
-            "EAoOU29tZU5lc3RlZFR5cGUioAEKFVRlc3RKc29uRmllbGRPcmRlcmluZxIT", 
-            "CgtwbGFpbl9pbnQzMhgEIAEoBRITCglvMV9zdHJpbmcYAiABKAlIABISCghv", 
-            "MV9pbnQzMhgFIAEoBUgAEhQKDHBsYWluX3N0cmluZxgBIAEoCRISCghvMl9p", 
-            "bnQzMhgGIAEoBUgBEhMKCW8yX3N0cmluZxgDIAEoCUgBQgQKAm8xQgQKAm8y", 
-            "KlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8QABIWCglG", 
-            "aXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD///////////8BKi4K", 
-            "DkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcKA29uZRAB", 
+            "ChV1bml0dGVzdF9pc3N1ZXMucHJvdG8SD3VuaXR0ZXN0X2lzc3VlcyInCghJ",
+            "c3N1ZTMwNxobCgpOZXN0ZWRPbmNlGg0KC05lc3RlZFR3aWNlIrABChNOZWdh",
+            "dGl2ZUVudW1NZXNzYWdlEiwKBXZhbHVlGAEgASgOMh0udW5pdHRlc3RfaXNz",
+            "dWVzLk5lZ2F0aXZlRW51bRIxCgZ2YWx1ZXMYAiADKA4yHS51bml0dGVzdF9p",
+            "c3N1ZXMuTmVnYXRpdmVFbnVtQgIQABI4Cg1wYWNrZWRfdmFsdWVzGAMgAygO",
+            "Mh0udW5pdHRlc3RfaXNzdWVzLk5lZ2F0aXZlRW51bUICEAEiEQoPRGVwcmVj",
+            "YXRlZENoaWxkIrkCChdEZXByZWNhdGVkRmllbGRzTWVzc2FnZRIaCg5Qcmlt",
+            "aXRpdmVWYWx1ZRgBIAEoBUICGAESGgoOUHJpbWl0aXZlQXJyYXkYAiADKAVC",
+            "AhgBEjoKDE1lc3NhZ2VWYWx1ZRgDIAEoCzIgLnVuaXR0ZXN0X2lzc3Vlcy5E",
+            "ZXByZWNhdGVkQ2hpbGRCAhgBEjoKDE1lc3NhZ2VBcnJheRgEIAMoCzIgLnVu",
+            "aXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkQ2hpbGRCAhgBEjYKCUVudW1WYWx1",
+            "ZRgFIAEoDjIfLnVuaXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkRW51bUICGAES",
+            "NgoJRW51bUFycmF5GAYgAygOMh8udW5pdHRlc3RfaXNzdWVzLkRlcHJlY2F0",
+            "ZWRFbnVtQgIYASIZCglJdGVtRmllbGQSDAoEaXRlbRgBIAEoBSJECg1SZXNl",
+            "cnZlZE5hbWVzEg0KBXR5cGVzGAEgASgFEhIKCmRlc2NyaXB0b3IYAiABKAUa",
+            "EAoOU29tZU5lc3RlZFR5cGUioAEKFVRlc3RKc29uRmllbGRPcmRlcmluZxIT",
+            "CgtwbGFpbl9pbnQzMhgEIAEoBRITCglvMV9zdHJpbmcYAiABKAlIABISCghv",
+            "MV9pbnQzMhgFIAEoBUgAEhQKDHBsYWluX3N0cmluZxgBIAEoCRISCghvMl9p",
+            "bnQzMhgGIAEoBUgBEhMKCW8yX3N0cmluZxgDIAEoCUgBQgQKAm8xQgQKAm8y",
+            "KlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8QABIWCglG",
+            "aXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD///////////8BKi4K",
+            "DkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcKA29uZRAB",
             "Qh9IAaoCGlVuaXRUZXN0Lklzc3Vlcy5UZXN0UHJvdG9zYgZwcm90bzM="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307), null, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce), null, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice), null, null, null, null)})}),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.NegativeEnumMessage), new[]{ "Value", "Values", "PackedValues" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedChild), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage), new[]{ "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.ItemField), new[]{ "Item" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames), new[]{ "Types_", "Descriptor_" }, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType), null, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering), new[]{ "PlainInt32", "O1String", "O1Int32", "PlainString", "O2Int32", "O2String" }, new[]{ "O1", "O2" }, null, null)
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307), global::UnitTest.Issues.TestProtos.Issue307.Parser, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Parser, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice), global::UnitTest.Issues.TestProtos.Issue307.Types.NestedOnce.Types.NestedTwice.Parser, null, null, null, null)})}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NegativeEnumMessage), global::UnitTest.Issues.TestProtos.NegativeEnumMessage.Parser, new[]{ "Value", "Values", "PackedValues" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedChild), global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage), global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage.Parser, new[]{ "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ItemField), global::UnitTest.Issues.TestProtos.ItemField.Parser, new[]{ "Item" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames), global::UnitTest.Issues.TestProtos.ReservedNames.Parser, new[]{ "Types_", "Descriptor_" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType), global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType.Parser, null, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering), global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering.Parser, new[]{ "PlainInt32", "O1String", "O1Int32", "PlainString", "O2Int32", "O2String" }, new[]{ "O1", "O2" }, null, null)
           }));
     }
     #endregion
@@ -74,13 +76,17 @@
   #endregion
 
   #region Messages
+  /// <summary>
+  ///  Issue 307: when generating doubly-nested types, any references
+  ///  should be of the form A.Types.B.Types.C.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Issue307 : pb::IMessage<Issue307> {
     private static readonly pb::MessageParser<Issue307> _parser = new pb::MessageParser<Issue307>(() => new Issue307());
     public static pb::MessageParser<Issue307> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[0]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -120,7 +126,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -149,6 +155,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the Issue307 message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -197,7 +204,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -226,6 +233,7 @@
         }
 
         #region Nested types
+        /// <summary>Container for nested types declared in the NestedOnce message type.</summary>
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         public static partial class Types {
           [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -274,7 +282,7 @@
             }
 
             public override string ToString() {
-              return pb::JsonFormatter.Default.Format(this);
+              return pb::JsonFormatter.ToDiagnosticString(this);
             }
 
             public void WriteTo(pb::CodedOutputStream output) {
@@ -320,7 +328,7 @@
     public static pb::MessageParser<NegativeEnumMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[1]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -343,6 +351,7 @@
       return new NegativeEnumMessage(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private global::UnitTest.Issues.TestProtos.NegativeEnum value_ = global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO;
     public global::UnitTest.Issues.TestProtos.NegativeEnum Value {
@@ -352,6 +361,7 @@
       }
     }
 
+    /// <summary>Field number for the "values" field.</summary>
     public const int ValuesFieldNumber = 2;
     private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.NegativeEnum> _repeated_values_codec
         = pb::FieldCodec.ForEnum(16, x => (int) x, x => (global::UnitTest.Issues.TestProtos.NegativeEnum) x);
@@ -360,6 +370,7 @@
       get { return values_; }
     }
 
+    /// <summary>Field number for the "packed_values" field.</summary>
     public const int PackedValuesFieldNumber = 3;
     private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.NegativeEnum> _repeated_packedValues_codec
         = pb::FieldCodec.ForEnum(26, x => (int) x, x => (global::UnitTest.Issues.TestProtos.NegativeEnum) x);
@@ -394,7 +405,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -460,7 +471,7 @@
     public static pb::MessageParser<DeprecatedChild> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[2]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -500,7 +511,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -536,7 +547,7 @@
     public static pb::MessageParser<DeprecatedFieldsMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[3]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -562,6 +573,7 @@
       return new DeprecatedFieldsMessage(this);
     }
 
+    /// <summary>Field number for the "PrimitiveValue" field.</summary>
     public const int PrimitiveValueFieldNumber = 1;
     private int primitiveValue_;
     [global::System.ObsoleteAttribute()]
@@ -572,6 +584,7 @@
       }
     }
 
+    /// <summary>Field number for the "PrimitiveArray" field.</summary>
     public const int PrimitiveArrayFieldNumber = 2;
     private static readonly pb::FieldCodec<int> _repeated_primitiveArray_codec
         = pb::FieldCodec.ForInt32(18);
@@ -581,6 +594,7 @@
       get { return primitiveArray_; }
     }
 
+    /// <summary>Field number for the "MessageValue" field.</summary>
     public const int MessageValueFieldNumber = 3;
     private global::UnitTest.Issues.TestProtos.DeprecatedChild messageValue_;
     [global::System.ObsoleteAttribute()]
@@ -591,6 +605,7 @@
       }
     }
 
+    /// <summary>Field number for the "MessageArray" field.</summary>
     public const int MessageArrayFieldNumber = 4;
     private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.DeprecatedChild> _repeated_messageArray_codec
         = pb::FieldCodec.ForMessage(34, global::UnitTest.Issues.TestProtos.DeprecatedChild.Parser);
@@ -600,6 +615,7 @@
       get { return messageArray_; }
     }
 
+    /// <summary>Field number for the "EnumValue" field.</summary>
     public const int EnumValueFieldNumber = 5;
     private global::UnitTest.Issues.TestProtos.DeprecatedEnum enumValue_ = global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO;
     [global::System.ObsoleteAttribute()]
@@ -610,6 +626,7 @@
       }
     }
 
+    /// <summary>Field number for the "EnumArray" field.</summary>
     public const int EnumArrayFieldNumber = 6;
     private static readonly pb::FieldCodec<global::UnitTest.Issues.TestProtos.DeprecatedEnum> _repeated_enumArray_codec
         = pb::FieldCodec.ForEnum(50, x => (int) x, x => (global::UnitTest.Issues.TestProtos.DeprecatedEnum) x);
@@ -651,7 +668,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -752,13 +769,16 @@
 
   }
 
+  /// <summary>
+  ///  Issue 45: http://code.google.com/p/protobuf-csharp-port/issues/detail?id=45
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class ItemField : pb::IMessage<ItemField> {
     private static readonly pb::MessageParser<ItemField> _parser = new pb::MessageParser<ItemField>(() => new ItemField());
     public static pb::MessageParser<ItemField> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[4]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -779,6 +799,7 @@
       return new ItemField(this);
     }
 
+    /// <summary>Field number for the "item" field.</summary>
     public const int ItemFieldNumber = 1;
     private int item_;
     public int Item {
@@ -810,7 +831,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -860,7 +881,7 @@
     public static pb::MessageParser<ReservedNames> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[5]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -882,6 +903,7 @@
       return new ReservedNames(this);
     }
 
+    /// <summary>Field number for the "types" field.</summary>
     public const int Types_FieldNumber = 1;
     private int types_;
     public int Types_ {
@@ -891,6 +913,7 @@
       }
     }
 
+    /// <summary>Field number for the "descriptor" field.</summary>
     public const int Descriptor_FieldNumber = 2;
     private int descriptor_;
     public int Descriptor_ {
@@ -924,7 +947,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -981,8 +1004,12 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the ReservedNames message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
+      /// <summary>
+      ///  Force a nested type called Types
+      /// </summary>
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
       public sealed partial class SomeNestedType : pb::IMessage<SomeNestedType> {
         private static readonly pb::MessageParser<SomeNestedType> _parser = new pb::MessageParser<SomeNestedType>(() => new SomeNestedType());
@@ -1029,7 +1056,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1064,13 +1091,25 @@
 
   }
 
+  /// <summary>
+  ///  These fields are deliberately not declared in numeric
+  ///  order, and the oneof fields aren't contiguous either.
+  ///  This allows for reasonably robust tests of JSON output
+  ///  ordering.
+  ///  TestFieldOrderings in unittest_proto3.proto is similar,
+  ///  but doesn't include oneofs.
+  ///  TODO: Consider adding oneofs to TestFieldOrderings, although
+  ///  that will require fixing other tests in multiple platforms.
+  ///  Alternatively, consider just adding this to
+  ///  unittest_proto3.proto if multiple platforms want it.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestJsonFieldOrdering : pb::IMessage<TestJsonFieldOrdering> {
     private static readonly pb::MessageParser<TestJsonFieldOrdering> _parser = new pb::MessageParser<TestJsonFieldOrdering>(() => new TestJsonFieldOrdering());
     public static pb::MessageParser<TestJsonFieldOrdering> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::UnitTest.Issues.TestProtos.UnittestIssues.Descriptor.MessageTypes[6]; }
+      get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1110,6 +1149,7 @@
       return new TestJsonFieldOrdering(this);
     }
 
+    /// <summary>Field number for the "plain_int32" field.</summary>
     public const int PlainInt32FieldNumber = 4;
     private int plainInt32_;
     public int PlainInt32 {
@@ -1119,15 +1159,17 @@
       }
     }
 
+    /// <summary>Field number for the "o1_string" field.</summary>
     public const int O1StringFieldNumber = 2;
     public string O1String {
       get { return o1Case_ == O1OneofCase.O1String ? (string) o1_ : ""; }
       set {
-        o1_ = pb::Preconditions.CheckNotNull(value, "value");
+        o1_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         o1Case_ = O1OneofCase.O1String;
       }
     }
 
+    /// <summary>Field number for the "o1_int32" field.</summary>
     public const int O1Int32FieldNumber = 5;
     public int O1Int32 {
       get { return o1Case_ == O1OneofCase.O1Int32 ? (int) o1_ : 0; }
@@ -1137,15 +1179,17 @@
       }
     }
 
+    /// <summary>Field number for the "plain_string" field.</summary>
     public const int PlainStringFieldNumber = 1;
     private string plainString_ = "";
     public string PlainString {
       get { return plainString_; }
       set {
-        plainString_ = pb::Preconditions.CheckNotNull(value, "value");
+        plainString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "o2_int32" field.</summary>
     public const int O2Int32FieldNumber = 6;
     public int O2Int32 {
       get { return o2Case_ == O2OneofCase.O2Int32 ? (int) o2_ : 0; }
@@ -1155,16 +1199,18 @@
       }
     }
 
+    /// <summary>Field number for the "o2_string" field.</summary>
     public const int O2StringFieldNumber = 3;
     public string O2String {
       get { return o2Case_ == O2OneofCase.O2String ? (string) o2_ : ""; }
       set {
-        o2_ = pb::Preconditions.CheckNotNull(value, "value");
+        o2_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         o2Case_ = O2OneofCase.O2String;
       }
     }
 
     private object o1_;
+    /// <summary>Enum of possible cases for the "o1" oneof.</summary>
     public enum O1OneofCase {
       None = 0,
       O1String = 2,
@@ -1181,6 +1227,7 @@
     }
 
     private object o2_;
+    /// <summary>Enum of possible cases for the "o2" oneof.</summary>
     public enum O2OneofCase {
       None = 0,
       O2Int32 = 6,
@@ -1213,6 +1260,8 @@
       if (PlainString != other.PlainString) return false;
       if (O2Int32 != other.O2Int32) return false;
       if (O2String != other.O2String) return false;
+      if (O1Case != other.O1Case) return false;
+      if (O2Case != other.O2Case) return false;
       return true;
     }
 
@@ -1224,11 +1273,13 @@
       if (PlainString.Length != 0) hash ^= PlainString.GetHashCode();
       if (o2Case_ == O2OneofCase.O2Int32) hash ^= O2Int32.GetHashCode();
       if (o2Case_ == O2OneofCase.O2String) hash ^= O2String.GetHashCode();
+      hash ^= (int) o1Case_;
+      hash ^= (int) o2Case_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
index bf4590a..d846544 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
@@ -9,181 +9,183 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.TestProtos {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_proto3.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class UnittestProto3 {
+  public static partial class UnittestProto3Reflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_proto3.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static UnittestProto3() {
+    static UnittestProto3Reflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "CiVnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfcHJvdG8zLnByb3RvEhFwcm90", 
-            "b2J1Zl91bml0dGVzdBosZ29vZ2xlL3Byb3RvYnVmL3VuaXR0ZXN0X2ltcG9y", 
-            "dF9wcm90bzMucHJvdG8i8A8KDFRlc3RBbGxUeXBlcxIUCgxzaW5nbGVfaW50", 
-            "MzIYASABKAUSFAoMc2luZ2xlX2ludDY0GAIgASgDEhUKDXNpbmdsZV91aW50", 
-            "MzIYAyABKA0SFQoNc2luZ2xlX3VpbnQ2NBgEIAEoBBIVCg1zaW5nbGVfc2lu", 
-            "dDMyGAUgASgREhUKDXNpbmdsZV9zaW50NjQYBiABKBISFgoOc2luZ2xlX2Zp", 
-            "eGVkMzIYByABKAcSFgoOc2luZ2xlX2ZpeGVkNjQYCCABKAYSFwoPc2luZ2xl", 
-            "X3NmaXhlZDMyGAkgASgPEhcKD3NpbmdsZV9zZml4ZWQ2NBgKIAEoEBIUCgxz", 
-            "aW5nbGVfZmxvYXQYCyABKAISFQoNc2luZ2xlX2RvdWJsZRgMIAEoARITCgtz", 
-            "aW5nbGVfYm9vbBgNIAEoCBIVCg1zaW5nbGVfc3RyaW5nGA4gASgJEhQKDHNp", 
-            "bmdsZV9ieXRlcxgPIAEoDBJMChVzaW5nbGVfbmVzdGVkX21lc3NhZ2UYEiAB", 
-            "KAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVz", 
-            "c2FnZRJBChZzaW5nbGVfZm9yZWlnbl9tZXNzYWdlGBMgASgLMiEucHJvdG9i", 
-            "dWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USRgoVc2luZ2xlX2ltcG9ydF9t", 
-            "ZXNzYWdlGBQgASgLMicucHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9y", 
-            "dE1lc3NhZ2USRgoSc2luZ2xlX25lc3RlZF9lbnVtGBUgASgOMioucHJvdG9i", 
-            "dWZfdW5pdHRlc3QuVGVzdEFsbFR5cGVzLk5lc3RlZEVudW0SOwoTc2luZ2xl", 
-            "X2ZvcmVpZ25fZW51bRgWIAEoDjIeLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVp", 
-            "Z25FbnVtEkAKEnNpbmdsZV9pbXBvcnRfZW51bRgXIAEoDjIkLnByb3RvYnVm", 
-            "X3VuaXR0ZXN0X2ltcG9ydC5JbXBvcnRFbnVtElMKHHNpbmdsZV9wdWJsaWNf", 
-            "aW1wb3J0X21lc3NhZ2UYGiABKAsyLS5wcm90b2J1Zl91bml0dGVzdF9pbXBv", 
-            "cnQuUHVibGljSW1wb3J0TWVzc2FnZRIWCg5yZXBlYXRlZF9pbnQzMhgfIAMo", 
-            "BRIWCg5yZXBlYXRlZF9pbnQ2NBggIAMoAxIXCg9yZXBlYXRlZF91aW50MzIY", 
-            "ISADKA0SFwoPcmVwZWF0ZWRfdWludDY0GCIgAygEEhcKD3JlcGVhdGVkX3Np", 
-            "bnQzMhgjIAMoERIXCg9yZXBlYXRlZF9zaW50NjQYJCADKBISGAoQcmVwZWF0", 
-            "ZWRfZml4ZWQzMhglIAMoBxIYChByZXBlYXRlZF9maXhlZDY0GCYgAygGEhkK", 
-            "EXJlcGVhdGVkX3NmaXhlZDMyGCcgAygPEhkKEXJlcGVhdGVkX3NmaXhlZDY0", 
-            "GCggAygQEhYKDnJlcGVhdGVkX2Zsb2F0GCkgAygCEhcKD3JlcGVhdGVkX2Rv", 
-            "dWJsZRgqIAMoARIVCg1yZXBlYXRlZF9ib29sGCsgAygIEhcKD3JlcGVhdGVk", 
-            "X3N0cmluZxgsIAMoCRIWCg5yZXBlYXRlZF9ieXRlcxgtIAMoDBJOChdyZXBl", 
-            "YXRlZF9uZXN0ZWRfbWVzc2FnZRgwIAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0", 
-            "LlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlEkMKGHJlcGVhdGVkX2ZvcmVp", 
-            "Z25fbWVzc2FnZRgxIAMoCzIhLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVpZ25N", 
-            "ZXNzYWdlEkgKF3JlcGVhdGVkX2ltcG9ydF9tZXNzYWdlGDIgAygLMicucHJv", 
-            "dG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9ydE1lc3NhZ2USSAoUcmVwZWF0", 
-            "ZWRfbmVzdGVkX2VudW0YMyADKA4yKi5wcm90b2J1Zl91bml0dGVzdC5UZXN0", 
-            "QWxsVHlwZXMuTmVzdGVkRW51bRI9ChVyZXBlYXRlZF9mb3JlaWduX2VudW0Y", 
-            "NCADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bRJCChRyZXBl", 
-            "YXRlZF9pbXBvcnRfZW51bRg1IAMoDjIkLnByb3RvYnVmX3VuaXR0ZXN0X2lt", 
-            "cG9ydC5JbXBvcnRFbnVtElUKHnJlcGVhdGVkX3B1YmxpY19pbXBvcnRfbWVz", 
-            "c2FnZRg2IAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5QdWJsaWNJ", 
-            "bXBvcnRNZXNzYWdlEhYKDG9uZW9mX3VpbnQzMhhvIAEoDUgAEk0KFG9uZW9m", 
-            "X25lc3RlZF9tZXNzYWdlGHAgASgLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVz", 
-            "dEFsbFR5cGVzLk5lc3RlZE1lc3NhZ2VIABIWCgxvbmVvZl9zdHJpbmcYcSAB", 
-            "KAlIABIVCgtvbmVvZl9ieXRlcxhyIAEoDEgAGhsKDU5lc3RlZE1lc3NhZ2US", 
-            "CgoCYmIYASABKAUiVgoKTmVzdGVkRW51bRIbChdORVNURURfRU5VTV9VTlNQ", 
-            "RUNJRklFRBAAEgcKA0ZPTxABEgcKA0JBUhACEgcKA0JBWhADEhAKA05FRxD/", 
-            "//////////8BQg0KC29uZW9mX2ZpZWxkIrsBChJOZXN0ZWRUZXN0QWxsVHlw", 
-            "ZXMSNAoFY2hpbGQYASABKAsyJS5wcm90b2J1Zl91bml0dGVzdC5OZXN0ZWRU", 
-            "ZXN0QWxsVHlwZXMSMAoHcGF5bG9hZBgCIAEoCzIfLnByb3RvYnVmX3VuaXR0", 
-            "ZXN0LlRlc3RBbGxUeXBlcxI9Cg5yZXBlYXRlZF9jaGlsZBgDIAMoCzIlLnBy", 
-            "b3RvYnVmX3VuaXR0ZXN0Lk5lc3RlZFRlc3RBbGxUeXBlcyI0ChRUZXN0RGVw", 
-            "cmVjYXRlZEZpZWxkcxIcChBkZXByZWNhdGVkX2ludDMyGAEgASgFQgIYASIb", 
-            "Cg5Gb3JlaWduTWVzc2FnZRIJCgFjGAEgASgFIjAKElRlc3RSZXNlcnZlZEZp", 
-            "ZWxkc0oECAIQA0oECA8QEEoECAkQDFIDYmFyUgNiYXoiWgoRVGVzdEZvcmVp", 
-            "Z25OZXN0ZWQSRQoOZm9yZWlnbl9uZXN0ZWQYASABKAsyLS5wcm90b2J1Zl91", 
-            "bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZSI0ChhUZXN0UmVh", 
-            "bGx5TGFyZ2VUYWdOdW1iZXISCQoBYRgBIAEoBRINCgJiYhj///9/IAEoBSJV", 
-            "ChRUZXN0UmVjdXJzaXZlTWVzc2FnZRIyCgFhGAEgASgLMicucHJvdG9idWZf", 
-            "dW5pdHRlc3QuVGVzdFJlY3Vyc2l2ZU1lc3NhZ2USCQoBaRgCIAEoBSJLChRU", 
-            "ZXN0TXV0dWFsUmVjdXJzaW9uQRIzCgJiYhgBIAEoCzInLnByb3RvYnVmX3Vu", 
-            "aXR0ZXN0LlRlc3RNdXR1YWxSZWN1cnNpb25CImIKFFRlc3RNdXR1YWxSZWN1", 
-            "cnNpb25CEjIKAWEYASABKAsyJy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TXV0", 
-            "dWFsUmVjdXJzaW9uQRIWCg5vcHRpb25hbF9pbnQzMhgCIAEoBSLrAgoXVGVz", 
-            "dENhbWVsQ2FzZUZpZWxkTmFtZXMSFgoOUHJpbWl0aXZlRmllbGQYASABKAUS", 
-            "EwoLU3RyaW5nRmllbGQYAiABKAkSMQoJRW51bUZpZWxkGAMgASgOMh4ucHJv", 
-            "dG9idWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SNwoMTWVzc2FnZUZpZWxkGAQg", 
-            "ASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USHgoWUmVw", 
-            "ZWF0ZWRQcmltaXRpdmVGaWVsZBgHIAMoBRIbChNSZXBlYXRlZFN0cmluZ0Zp", 
-            "ZWxkGAggAygJEjkKEVJlcGVhdGVkRW51bUZpZWxkGAkgAygOMh4ucHJvdG9i", 
-            "dWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SPwoUUmVwZWF0ZWRNZXNzYWdlRmll", 
-            "bGQYCiADKAsyIS5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZSLH", 
-            "AQoSVGVzdEZpZWxkT3JkZXJpbmdzEhEKCW15X3N0cmluZxgLIAEoCRIOCgZt", 
-            "eV9pbnQYASABKAMSEAoIbXlfZmxvYXQYZSABKAISUwoVc2luZ2xlX25lc3Rl", 
-            "ZF9tZXNzYWdlGMgBIAEoCzIzLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RGaWVs", 
-            "ZE9yZGVyaW5ncy5OZXN0ZWRNZXNzYWdlGicKDU5lc3RlZE1lc3NhZ2USCgoC", 
-            "b28YAiABKAMSCgoCYmIYASABKAUiSwoRU3BhcnNlRW51bU1lc3NhZ2USNgoL", 
-            "c3BhcnNlX2VudW0YASABKA4yIS5wcm90b2J1Zl91bml0dGVzdC5UZXN0U3Bh", 
-            "cnNlRW51bSIZCglPbmVTdHJpbmcSDAoEZGF0YRgBIAEoCSIaCgpNb3JlU3Ry", 
-            "aW5nEgwKBGRhdGEYASADKAkiGAoIT25lQnl0ZXMSDAoEZGF0YRgBIAEoDCIZ", 
-            "CglNb3JlQnl0ZXMSDAoEZGF0YRgBIAEoDCIcCgxJbnQzMk1lc3NhZ2USDAoE", 
-            "ZGF0YRgBIAEoBSIdCg1VaW50MzJNZXNzYWdlEgwKBGRhdGEYASABKA0iHAoM", 
-            "SW50NjRNZXNzYWdlEgwKBGRhdGEYASABKAMiHQoNVWludDY0TWVzc2FnZRIM", 
-            "CgRkYXRhGAEgASgEIhsKC0Jvb2xNZXNzYWdlEgwKBGRhdGEYASABKAgicwoJ", 
-            "VGVzdE9uZW9mEhEKB2Zvb19pbnQYASABKAVIABIUCgpmb29fc3RyaW5nGAIg", 
-            "ASgJSAASNgoLZm9vX21lc3NhZ2UYAyABKAsyHy5wcm90b2J1Zl91bml0dGVz", 
-            "dC5UZXN0QWxsVHlwZXNIAEIFCgNmb28iqgMKD1Rlc3RQYWNrZWRUeXBlcxIY", 
-            "CgxwYWNrZWRfaW50MzIYWiADKAVCAhABEhgKDHBhY2tlZF9pbnQ2NBhbIAMo", 
-            "A0ICEAESGQoNcGFja2VkX3VpbnQzMhhcIAMoDUICEAESGQoNcGFja2VkX3Vp", 
-            "bnQ2NBhdIAMoBEICEAESGQoNcGFja2VkX3NpbnQzMhheIAMoEUICEAESGQoN", 
-            "cGFja2VkX3NpbnQ2NBhfIAMoEkICEAESGgoOcGFja2VkX2ZpeGVkMzIYYCAD", 
-            "KAdCAhABEhoKDnBhY2tlZF9maXhlZDY0GGEgAygGQgIQARIbCg9wYWNrZWRf", 
-            "c2ZpeGVkMzIYYiADKA9CAhABEhsKD3BhY2tlZF9zZml4ZWQ2NBhjIAMoEEIC", 
-            "EAESGAoMcGFja2VkX2Zsb2F0GGQgAygCQgIQARIZCg1wYWNrZWRfZG91Ymxl", 
-            "GGUgAygBQgIQARIXCgtwYWNrZWRfYm9vbBhmIAMoCEICEAESNwoLcGFja2Vk", 
-            "X2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bUIC", 
-            "EAEiyAMKEVRlc3RVbnBhY2tlZFR5cGVzEhoKDnVucGFja2VkX2ludDMyGFog", 
-            "AygFQgIQABIaCg51bnBhY2tlZF9pbnQ2NBhbIAMoA0ICEAASGwoPdW5wYWNr", 
-            "ZWRfdWludDMyGFwgAygNQgIQABIbCg91bnBhY2tlZF91aW50NjQYXSADKARC", 
-            "AhAAEhsKD3VucGFja2VkX3NpbnQzMhheIAMoEUICEAASGwoPdW5wYWNrZWRf", 
-            "c2ludDY0GF8gAygSQgIQABIcChB1bnBhY2tlZF9maXhlZDMyGGAgAygHQgIQ", 
-            "ABIcChB1bnBhY2tlZF9maXhlZDY0GGEgAygGQgIQABIdChF1bnBhY2tlZF9z", 
-            "Zml4ZWQzMhhiIAMoD0ICEAASHQoRdW5wYWNrZWRfc2ZpeGVkNjQYYyADKBBC", 
-            "AhAAEhoKDnVucGFja2VkX2Zsb2F0GGQgAygCQgIQABIbCg91bnBhY2tlZF9k", 
-            "b3VibGUYZSADKAFCAhAAEhkKDXVucGFja2VkX2Jvb2wYZiADKAhCAhAAEjkK", 
-            "DXVucGFja2VkX2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3Jl", 
-            "aWduRW51bUICEAAiwAEKI1Rlc3RSZXBlYXRlZFNjYWxhckRpZmZlcmVudFRh", 
-            "Z1NpemVzEhgKEHJlcGVhdGVkX2ZpeGVkMzIYDCADKAcSFgoOcmVwZWF0ZWRf", 
-            "aW50MzIYDSADKAUSGQoQcmVwZWF0ZWRfZml4ZWQ2NBj+DyADKAYSFwoOcmVw", 
-            "ZWF0ZWRfaW50NjQY/w8gAygDEhgKDnJlcGVhdGVkX2Zsb2F0GP7/DyADKAIS", 
-            "GQoPcmVwZWF0ZWRfdWludDY0GP//DyADKAQiKAobVGVzdENvbW1lbnRJbmpl", 
-            "Y3Rpb25NZXNzYWdlEgkKAWEYASABKAkiDAoKRm9vUmVxdWVzdCINCgtGb29S", 
-            "ZXNwb25zZSISChBGb29DbGllbnRNZXNzYWdlIhIKEEZvb1NlcnZlck1lc3Nh", 
-            "Z2UiDAoKQmFyUmVxdWVzdCINCgtCYXJSZXNwb25zZSpZCgtGb3JlaWduRW51", 
-            "bRIXChNGT1JFSUdOX1VOU1BFQ0lGSUVEEAASDwoLRk9SRUlHTl9GT08QBBIP", 
-            "CgtGT1JFSUdOX0JBUhAFEg8KC0ZPUkVJR05fQkFaEAYqdQoUVGVzdEVudW1X", 
-            "aXRoRHVwVmFsdWUSKAokVEVTVF9FTlVNX1dJVEhfRFVQX1ZBTFVFX1VOU1BF", 
-            "Q0lGSUVEEAASCAoERk9PMRABEggKBEJBUjEQAhIHCgNCQVoQAxIICgRGT08y", 
-            "EAESCAoEQkFSMhACGgIQASqdAQoOVGVzdFNwYXJzZUVudW0SIAocVEVTVF9T", 
-            "UEFSU0VfRU5VTV9VTlNQRUNJRklFRBAAEgwKCFNQQVJTRV9BEHsSDgoIU1BB", 
-            "UlNFX0IQpucDEg8KCFNQQVJTRV9DELKxgAYSFQoIU1BBUlNFX0QQ8f//////", 
-            "////ARIVCghTUEFSU0VfRRC03vz///////8BEgwKCFNQQVJTRV9HEAIymQEK", 
-            "C1Rlc3RTZXJ2aWNlEkQKA0ZvbxIdLnByb3RvYnVmX3VuaXR0ZXN0LkZvb1Jl", 
-            "cXVlc3QaHi5wcm90b2J1Zl91bml0dGVzdC5Gb29SZXNwb25zZRJECgNCYXIS", 
-            "HS5wcm90b2J1Zl91bml0dGVzdC5CYXJSZXF1ZXN0Gh4ucHJvdG9idWZfdW5p", 
-            "dHRlc3QuQmFyUmVzcG9uc2VCOkINVW5pdHRlc3RQcm90b0gBgAEBiAEBkAEB", 
+            "CiVnb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfcHJvdG8zLnByb3RvEhFwcm90",
+            "b2J1Zl91bml0dGVzdBosZ29vZ2xlL3Byb3RvYnVmL3VuaXR0ZXN0X2ltcG9y",
+            "dF9wcm90bzMucHJvdG8i8A8KDFRlc3RBbGxUeXBlcxIUCgxzaW5nbGVfaW50",
+            "MzIYASABKAUSFAoMc2luZ2xlX2ludDY0GAIgASgDEhUKDXNpbmdsZV91aW50",
+            "MzIYAyABKA0SFQoNc2luZ2xlX3VpbnQ2NBgEIAEoBBIVCg1zaW5nbGVfc2lu",
+            "dDMyGAUgASgREhUKDXNpbmdsZV9zaW50NjQYBiABKBISFgoOc2luZ2xlX2Zp",
+            "eGVkMzIYByABKAcSFgoOc2luZ2xlX2ZpeGVkNjQYCCABKAYSFwoPc2luZ2xl",
+            "X3NmaXhlZDMyGAkgASgPEhcKD3NpbmdsZV9zZml4ZWQ2NBgKIAEoEBIUCgxz",
+            "aW5nbGVfZmxvYXQYCyABKAISFQoNc2luZ2xlX2RvdWJsZRgMIAEoARITCgtz",
+            "aW5nbGVfYm9vbBgNIAEoCBIVCg1zaW5nbGVfc3RyaW5nGA4gASgJEhQKDHNp",
+            "bmdsZV9ieXRlcxgPIAEoDBJMChVzaW5nbGVfbmVzdGVkX21lc3NhZ2UYEiAB",
+            "KAsyLS5wcm90b2J1Zl91bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVz",
+            "c2FnZRJBChZzaW5nbGVfZm9yZWlnbl9tZXNzYWdlGBMgASgLMiEucHJvdG9i",
+            "dWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USRgoVc2luZ2xlX2ltcG9ydF9t",
+            "ZXNzYWdlGBQgASgLMicucHJvdG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9y",
+            "dE1lc3NhZ2USRgoSc2luZ2xlX25lc3RlZF9lbnVtGBUgASgOMioucHJvdG9i",
+            "dWZfdW5pdHRlc3QuVGVzdEFsbFR5cGVzLk5lc3RlZEVudW0SOwoTc2luZ2xl",
+            "X2ZvcmVpZ25fZW51bRgWIAEoDjIeLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVp",
+            "Z25FbnVtEkAKEnNpbmdsZV9pbXBvcnRfZW51bRgXIAEoDjIkLnByb3RvYnVm",
+            "X3VuaXR0ZXN0X2ltcG9ydC5JbXBvcnRFbnVtElMKHHNpbmdsZV9wdWJsaWNf",
+            "aW1wb3J0X21lc3NhZ2UYGiABKAsyLS5wcm90b2J1Zl91bml0dGVzdF9pbXBv",
+            "cnQuUHVibGljSW1wb3J0TWVzc2FnZRIWCg5yZXBlYXRlZF9pbnQzMhgfIAMo",
+            "BRIWCg5yZXBlYXRlZF9pbnQ2NBggIAMoAxIXCg9yZXBlYXRlZF91aW50MzIY",
+            "ISADKA0SFwoPcmVwZWF0ZWRfdWludDY0GCIgAygEEhcKD3JlcGVhdGVkX3Np",
+            "bnQzMhgjIAMoERIXCg9yZXBlYXRlZF9zaW50NjQYJCADKBISGAoQcmVwZWF0",
+            "ZWRfZml4ZWQzMhglIAMoBxIYChByZXBlYXRlZF9maXhlZDY0GCYgAygGEhkK",
+            "EXJlcGVhdGVkX3NmaXhlZDMyGCcgAygPEhkKEXJlcGVhdGVkX3NmaXhlZDY0",
+            "GCggAygQEhYKDnJlcGVhdGVkX2Zsb2F0GCkgAygCEhcKD3JlcGVhdGVkX2Rv",
+            "dWJsZRgqIAMoARIVCg1yZXBlYXRlZF9ib29sGCsgAygIEhcKD3JlcGVhdGVk",
+            "X3N0cmluZxgsIAMoCRIWCg5yZXBlYXRlZF9ieXRlcxgtIAMoDBJOChdyZXBl",
+            "YXRlZF9uZXN0ZWRfbWVzc2FnZRgwIAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0",
+            "LlRlc3RBbGxUeXBlcy5OZXN0ZWRNZXNzYWdlEkMKGHJlcGVhdGVkX2ZvcmVp",
+            "Z25fbWVzc2FnZRgxIAMoCzIhLnByb3RvYnVmX3VuaXR0ZXN0LkZvcmVpZ25N",
+            "ZXNzYWdlEkgKF3JlcGVhdGVkX2ltcG9ydF9tZXNzYWdlGDIgAygLMicucHJv",
+            "dG9idWZfdW5pdHRlc3RfaW1wb3J0LkltcG9ydE1lc3NhZ2USSAoUcmVwZWF0",
+            "ZWRfbmVzdGVkX2VudW0YMyADKA4yKi5wcm90b2J1Zl91bml0dGVzdC5UZXN0",
+            "QWxsVHlwZXMuTmVzdGVkRW51bRI9ChVyZXBlYXRlZF9mb3JlaWduX2VudW0Y",
+            "NCADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bRJCChRyZXBl",
+            "YXRlZF9pbXBvcnRfZW51bRg1IAMoDjIkLnByb3RvYnVmX3VuaXR0ZXN0X2lt",
+            "cG9ydC5JbXBvcnRFbnVtElUKHnJlcGVhdGVkX3B1YmxpY19pbXBvcnRfbWVz",
+            "c2FnZRg2IAMoCzItLnByb3RvYnVmX3VuaXR0ZXN0X2ltcG9ydC5QdWJsaWNJ",
+            "bXBvcnRNZXNzYWdlEhYKDG9uZW9mX3VpbnQzMhhvIAEoDUgAEk0KFG9uZW9m",
+            "X25lc3RlZF9tZXNzYWdlGHAgASgLMi0ucHJvdG9idWZfdW5pdHRlc3QuVGVz",
+            "dEFsbFR5cGVzLk5lc3RlZE1lc3NhZ2VIABIWCgxvbmVvZl9zdHJpbmcYcSAB",
+            "KAlIABIVCgtvbmVvZl9ieXRlcxhyIAEoDEgAGhsKDU5lc3RlZE1lc3NhZ2US",
+            "CgoCYmIYASABKAUiVgoKTmVzdGVkRW51bRIbChdORVNURURfRU5VTV9VTlNQ",
+            "RUNJRklFRBAAEgcKA0ZPTxABEgcKA0JBUhACEgcKA0JBWhADEhAKA05FRxD/",
+            "//////////8BQg0KC29uZW9mX2ZpZWxkIrsBChJOZXN0ZWRUZXN0QWxsVHlw",
+            "ZXMSNAoFY2hpbGQYASABKAsyJS5wcm90b2J1Zl91bml0dGVzdC5OZXN0ZWRU",
+            "ZXN0QWxsVHlwZXMSMAoHcGF5bG9hZBgCIAEoCzIfLnByb3RvYnVmX3VuaXR0",
+            "ZXN0LlRlc3RBbGxUeXBlcxI9Cg5yZXBlYXRlZF9jaGlsZBgDIAMoCzIlLnBy",
+            "b3RvYnVmX3VuaXR0ZXN0Lk5lc3RlZFRlc3RBbGxUeXBlcyI0ChRUZXN0RGVw",
+            "cmVjYXRlZEZpZWxkcxIcChBkZXByZWNhdGVkX2ludDMyGAEgASgFQgIYASIb",
+            "Cg5Gb3JlaWduTWVzc2FnZRIJCgFjGAEgASgFIjAKElRlc3RSZXNlcnZlZEZp",
+            "ZWxkc0oECAIQA0oECA8QEEoECAkQDFIDYmFyUgNiYXoiWgoRVGVzdEZvcmVp",
+            "Z25OZXN0ZWQSRQoOZm9yZWlnbl9uZXN0ZWQYASABKAsyLS5wcm90b2J1Zl91",
+            "bml0dGVzdC5UZXN0QWxsVHlwZXMuTmVzdGVkTWVzc2FnZSI0ChhUZXN0UmVh",
+            "bGx5TGFyZ2VUYWdOdW1iZXISCQoBYRgBIAEoBRINCgJiYhj///9/IAEoBSJV",
+            "ChRUZXN0UmVjdXJzaXZlTWVzc2FnZRIyCgFhGAEgASgLMicucHJvdG9idWZf",
+            "dW5pdHRlc3QuVGVzdFJlY3Vyc2l2ZU1lc3NhZ2USCQoBaRgCIAEoBSJLChRU",
+            "ZXN0TXV0dWFsUmVjdXJzaW9uQRIzCgJiYhgBIAEoCzInLnByb3RvYnVmX3Vu",
+            "aXR0ZXN0LlRlc3RNdXR1YWxSZWN1cnNpb25CImIKFFRlc3RNdXR1YWxSZWN1",
+            "cnNpb25CEjIKAWEYASABKAsyJy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TXV0",
+            "dWFsUmVjdXJzaW9uQRIWCg5vcHRpb25hbF9pbnQzMhgCIAEoBSLrAgoXVGVz",
+            "dENhbWVsQ2FzZUZpZWxkTmFtZXMSFgoOUHJpbWl0aXZlRmllbGQYASABKAUS",
+            "EwoLU3RyaW5nRmllbGQYAiABKAkSMQoJRW51bUZpZWxkGAMgASgOMh4ucHJv",
+            "dG9idWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SNwoMTWVzc2FnZUZpZWxkGAQg",
+            "ASgLMiEucHJvdG9idWZfdW5pdHRlc3QuRm9yZWlnbk1lc3NhZ2USHgoWUmVw",
+            "ZWF0ZWRQcmltaXRpdmVGaWVsZBgHIAMoBRIbChNSZXBlYXRlZFN0cmluZ0Zp",
+            "ZWxkGAggAygJEjkKEVJlcGVhdGVkRW51bUZpZWxkGAkgAygOMh4ucHJvdG9i",
+            "dWZfdW5pdHRlc3QuRm9yZWlnbkVudW0SPwoUUmVwZWF0ZWRNZXNzYWdlRmll",
+            "bGQYCiADKAsyIS5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduTWVzc2FnZSLH",
+            "AQoSVGVzdEZpZWxkT3JkZXJpbmdzEhEKCW15X3N0cmluZxgLIAEoCRIOCgZt",
+            "eV9pbnQYASABKAMSEAoIbXlfZmxvYXQYZSABKAISUwoVc2luZ2xlX25lc3Rl",
+            "ZF9tZXNzYWdlGMgBIAEoCzIzLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RGaWVs",
+            "ZE9yZGVyaW5ncy5OZXN0ZWRNZXNzYWdlGicKDU5lc3RlZE1lc3NhZ2USCgoC",
+            "b28YAiABKAMSCgoCYmIYASABKAUiSwoRU3BhcnNlRW51bU1lc3NhZ2USNgoL",
+            "c3BhcnNlX2VudW0YASABKA4yIS5wcm90b2J1Zl91bml0dGVzdC5UZXN0U3Bh",
+            "cnNlRW51bSIZCglPbmVTdHJpbmcSDAoEZGF0YRgBIAEoCSIaCgpNb3JlU3Ry",
+            "aW5nEgwKBGRhdGEYASADKAkiGAoIT25lQnl0ZXMSDAoEZGF0YRgBIAEoDCIZ",
+            "CglNb3JlQnl0ZXMSDAoEZGF0YRgBIAEoDCIcCgxJbnQzMk1lc3NhZ2USDAoE",
+            "ZGF0YRgBIAEoBSIdCg1VaW50MzJNZXNzYWdlEgwKBGRhdGEYASABKA0iHAoM",
+            "SW50NjRNZXNzYWdlEgwKBGRhdGEYASABKAMiHQoNVWludDY0TWVzc2FnZRIM",
+            "CgRkYXRhGAEgASgEIhsKC0Jvb2xNZXNzYWdlEgwKBGRhdGEYASABKAgicwoJ",
+            "VGVzdE9uZW9mEhEKB2Zvb19pbnQYASABKAVIABIUCgpmb29fc3RyaW5nGAIg",
+            "ASgJSAASNgoLZm9vX21lc3NhZ2UYAyABKAsyHy5wcm90b2J1Zl91bml0dGVz",
+            "dC5UZXN0QWxsVHlwZXNIAEIFCgNmb28iqgMKD1Rlc3RQYWNrZWRUeXBlcxIY",
+            "CgxwYWNrZWRfaW50MzIYWiADKAVCAhABEhgKDHBhY2tlZF9pbnQ2NBhbIAMo",
+            "A0ICEAESGQoNcGFja2VkX3VpbnQzMhhcIAMoDUICEAESGQoNcGFja2VkX3Vp",
+            "bnQ2NBhdIAMoBEICEAESGQoNcGFja2VkX3NpbnQzMhheIAMoEUICEAESGQoN",
+            "cGFja2VkX3NpbnQ2NBhfIAMoEkICEAESGgoOcGFja2VkX2ZpeGVkMzIYYCAD",
+            "KAdCAhABEhoKDnBhY2tlZF9maXhlZDY0GGEgAygGQgIQARIbCg9wYWNrZWRf",
+            "c2ZpeGVkMzIYYiADKA9CAhABEhsKD3BhY2tlZF9zZml4ZWQ2NBhjIAMoEEIC",
+            "EAESGAoMcGFja2VkX2Zsb2F0GGQgAygCQgIQARIZCg1wYWNrZWRfZG91Ymxl",
+            "GGUgAygBQgIQARIXCgtwYWNrZWRfYm9vbBhmIAMoCEICEAESNwoLcGFja2Vk",
+            "X2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3JlaWduRW51bUIC",
+            "EAEiyAMKEVRlc3RVbnBhY2tlZFR5cGVzEhoKDnVucGFja2VkX2ludDMyGFog",
+            "AygFQgIQABIaCg51bnBhY2tlZF9pbnQ2NBhbIAMoA0ICEAASGwoPdW5wYWNr",
+            "ZWRfdWludDMyGFwgAygNQgIQABIbCg91bnBhY2tlZF91aW50NjQYXSADKARC",
+            "AhAAEhsKD3VucGFja2VkX3NpbnQzMhheIAMoEUICEAASGwoPdW5wYWNrZWRf",
+            "c2ludDY0GF8gAygSQgIQABIcChB1bnBhY2tlZF9maXhlZDMyGGAgAygHQgIQ",
+            "ABIcChB1bnBhY2tlZF9maXhlZDY0GGEgAygGQgIQABIdChF1bnBhY2tlZF9z",
+            "Zml4ZWQzMhhiIAMoD0ICEAASHQoRdW5wYWNrZWRfc2ZpeGVkNjQYYyADKBBC",
+            "AhAAEhoKDnVucGFja2VkX2Zsb2F0GGQgAygCQgIQABIbCg91bnBhY2tlZF9k",
+            "b3VibGUYZSADKAFCAhAAEhkKDXVucGFja2VkX2Jvb2wYZiADKAhCAhAAEjkK",
+            "DXVucGFja2VkX2VudW0YZyADKA4yHi5wcm90b2J1Zl91bml0dGVzdC5Gb3Jl",
+            "aWduRW51bUICEAAiwAEKI1Rlc3RSZXBlYXRlZFNjYWxhckRpZmZlcmVudFRh",
+            "Z1NpemVzEhgKEHJlcGVhdGVkX2ZpeGVkMzIYDCADKAcSFgoOcmVwZWF0ZWRf",
+            "aW50MzIYDSADKAUSGQoQcmVwZWF0ZWRfZml4ZWQ2NBj+DyADKAYSFwoOcmVw",
+            "ZWF0ZWRfaW50NjQY/w8gAygDEhgKDnJlcGVhdGVkX2Zsb2F0GP7/DyADKAIS",
+            "GQoPcmVwZWF0ZWRfdWludDY0GP//DyADKAQiKAobVGVzdENvbW1lbnRJbmpl",
+            "Y3Rpb25NZXNzYWdlEgkKAWEYASABKAkiDAoKRm9vUmVxdWVzdCINCgtGb29S",
+            "ZXNwb25zZSISChBGb29DbGllbnRNZXNzYWdlIhIKEEZvb1NlcnZlck1lc3Nh",
+            "Z2UiDAoKQmFyUmVxdWVzdCINCgtCYXJSZXNwb25zZSpZCgtGb3JlaWduRW51",
+            "bRIXChNGT1JFSUdOX1VOU1BFQ0lGSUVEEAASDwoLRk9SRUlHTl9GT08QBBIP",
+            "CgtGT1JFSUdOX0JBUhAFEg8KC0ZPUkVJR05fQkFaEAYqdQoUVGVzdEVudW1X",
+            "aXRoRHVwVmFsdWUSKAokVEVTVF9FTlVNX1dJVEhfRFVQX1ZBTFVFX1VOU1BF",
+            "Q0lGSUVEEAASCAoERk9PMRABEggKBEJBUjEQAhIHCgNCQVoQAxIICgRGT08y",
+            "EAESCAoEQkFSMhACGgIQASqdAQoOVGVzdFNwYXJzZUVudW0SIAocVEVTVF9T",
+            "UEFSU0VfRU5VTV9VTlNQRUNJRklFRBAAEgwKCFNQQVJTRV9BEHsSDgoIU1BB",
+            "UlNFX0IQpucDEg8KCFNQQVJTRV9DELKxgAYSFQoIU1BBUlNFX0QQ8f//////",
+            "////ARIVCghTUEFSU0VfRRC03vz///////8BEgwKCFNQQVJTRV9HEAIymQEK",
+            "C1Rlc3RTZXJ2aWNlEkQKA0ZvbxIdLnByb3RvYnVmX3VuaXR0ZXN0LkZvb1Jl",
+            "cXVlc3QaHi5wcm90b2J1Zl91bml0dGVzdC5Gb29SZXNwb25zZRJECgNCYXIS",
+            "HS5wcm90b2J1Zl91bml0dGVzdC5CYXJSZXF1ZXN0Gh4ucHJvdG9idWZfdW5p",
+            "dHRlc3QuQmFyUmVzcG9uc2VCOkINVW5pdHRlc3RQcm90b0gBgAEBiAEBkAEB",
             "+AEBqgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportProto3.Descriptor, },
-          new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), }, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes), new[]{ "SingleInt32", "SingleInt64", "SingleUint32", "SingleUint64", "SingleSint32", "SingleSint64", "SingleFixed32", "SingleFixed64", "SingleSfixed32", "SingleSfixed64", "SingleFloat", "SingleDouble", "SingleBool", "SingleString", "SingleBytes", "SingleNestedMessage", "SingleForeignMessage", "SingleImportMessage", "SingleNestedEnum", "SingleForeignEnum", "SingleImportEnum", "SinglePublicImportMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedImportMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedImportEnum", "RepeatedPublicImportMessage", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes" }, new[]{ "OneofField" }, new[]{ typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage), new[]{ "Bb" }, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.NestedTestAllTypes), new[]{ "Child", "Payload", "RepeatedChild" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestDeprecatedFields), new[]{ "DeprecatedInt32" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.ForeignMessage), new[]{ "C" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestReservedFields), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestForeignNested), new[]{ "ForeignNested" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestReallyLargeTagNumber), new[]{ "A", "Bb" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestRecursiveMessage), new[]{ "A", "I" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionA), new[]{ "Bb" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionB), new[]{ "A", "OptionalInt32" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestCamelCaseFieldNames), new[]{ "PrimitiveField", "StringField", "EnumField", "MessageField", "RepeatedPrimitiveField", "RepeatedStringField", "RepeatedEnumField", "RepeatedMessageField" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings), new[]{ "MyString", "MyInt", "MyFloat", "SingleNestedMessage" }, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage), new[]{ "Oo", "Bb" }, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.SparseEnumMessage), new[]{ "SparseEnum" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.OneString), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.MoreString), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.OneBytes), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.MoreBytes), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.Int32Message), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.Uint32Message), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.Int64Message), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.Uint64Message), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.BoolMessage), new[]{ "Data" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestOneof), new[]{ "FooInt", "FooString", "FooMessage" }, new[]{ "Foo" }, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestPackedTypes), new[]{ "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedEnum" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestUnpackedTypes), new[]{ "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedEnum" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestRepeatedScalarDifferentTagSizes), new[]{ "RepeatedFixed32", "RepeatedInt32", "RepeatedFixed64", "RepeatedInt64", "RepeatedFloat", "RepeatedUint64" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestCommentInjectionMessage), new[]{ "A" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.FooRequest), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.FooResponse), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.FooClientMessage), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.FooServerMessage), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.BarRequest), null, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.BarResponse), null, null, null, null)
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes), global::Google.Protobuf.TestProtos.TestAllTypes.Parser, new[]{ "SingleInt32", "SingleInt64", "SingleUint32", "SingleUint64", "SingleSint32", "SingleSint64", "SingleFixed32", "SingleFixed64", "SingleSfixed32", "SingleSfixed64", "SingleFloat", "SingleDouble", "SingleBool", "SingleString", "SingleBytes", "SingleNestedMessage", "SingleForeignMessage", "SingleImportMessage", "SingleNestedEnum", "SingleForeignEnum", "SingleImportEnum", "SinglePublicImportMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedImportMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedImportEnum", "RepeatedPublicImportMessage", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes" }, new[]{ "OneofField" }, new[]{ typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser, new[]{ "Bb" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.NestedTestAllTypes), global::Google.Protobuf.TestProtos.NestedTestAllTypes.Parser, new[]{ "Child", "Payload", "RepeatedChild" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestDeprecatedFields), global::Google.Protobuf.TestProtos.TestDeprecatedFields.Parser, new[]{ "DeprecatedInt32" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.ForeignMessage), global::Google.Protobuf.TestProtos.ForeignMessage.Parser, new[]{ "C" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestReservedFields), global::Google.Protobuf.TestProtos.TestReservedFields.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestForeignNested), global::Google.Protobuf.TestProtos.TestForeignNested.Parser, new[]{ "ForeignNested" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestReallyLargeTagNumber), global::Google.Protobuf.TestProtos.TestReallyLargeTagNumber.Parser, new[]{ "A", "Bb" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestRecursiveMessage), global::Google.Protobuf.TestProtos.TestRecursiveMessage.Parser, new[]{ "A", "I" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionA), global::Google.Protobuf.TestProtos.TestMutualRecursionA.Parser, new[]{ "Bb" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestMutualRecursionB), global::Google.Protobuf.TestProtos.TestMutualRecursionB.Parser, new[]{ "A", "OptionalInt32" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestCamelCaseFieldNames), global::Google.Protobuf.TestProtos.TestCamelCaseFieldNames.Parser, new[]{ "PrimitiveField", "StringField", "EnumField", "MessageField", "RepeatedPrimitiveField", "RepeatedStringField", "RepeatedEnumField", "RepeatedMessageField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings), global::Google.Protobuf.TestProtos.TestFieldOrderings.Parser, new[]{ "MyString", "MyInt", "MyFloat", "SingleNestedMessage" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage.Parser, new[]{ "Oo", "Bb" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.SparseEnumMessage), global::Google.Protobuf.TestProtos.SparseEnumMessage.Parser, new[]{ "SparseEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneString), global::Google.Protobuf.TestProtos.OneString.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MoreString), global::Google.Protobuf.TestProtos.MoreString.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneBytes), global::Google.Protobuf.TestProtos.OneBytes.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MoreBytes), global::Google.Protobuf.TestProtos.MoreBytes.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Int32Message), global::Google.Protobuf.TestProtos.Int32Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Uint32Message), global::Google.Protobuf.TestProtos.Uint32Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Int64Message), global::Google.Protobuf.TestProtos.Int64Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.Uint64Message), global::Google.Protobuf.TestProtos.Uint64Message.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BoolMessage), global::Google.Protobuf.TestProtos.BoolMessage.Parser, new[]{ "Data" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestOneof), global::Google.Protobuf.TestProtos.TestOneof.Parser, new[]{ "FooInt", "FooString", "FooMessage" }, new[]{ "Foo" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestPackedTypes), global::Google.Protobuf.TestProtos.TestPackedTypes.Parser, new[]{ "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestUnpackedTypes), global::Google.Protobuf.TestProtos.TestUnpackedTypes.Parser, new[]{ "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedEnum" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestRepeatedScalarDifferentTagSizes), global::Google.Protobuf.TestProtos.TestRepeatedScalarDifferentTagSizes.Parser, new[]{ "RepeatedFixed32", "RepeatedInt32", "RepeatedFixed64", "RepeatedInt64", "RepeatedFloat", "RepeatedUint64" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestCommentInjectionMessage), global::Google.Protobuf.TestProtos.TestCommentInjectionMessage.Parser, new[]{ "A" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooRequest), global::Google.Protobuf.TestProtos.FooRequest.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooResponse), global::Google.Protobuf.TestProtos.FooResponse.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooClientMessage), global::Google.Protobuf.TestProtos.FooClientMessage.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooServerMessage), global::Google.Protobuf.TestProtos.FooServerMessage.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarRequest), global::Google.Protobuf.TestProtos.BarRequest.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarResponse), global::Google.Protobuf.TestProtos.BarResponse.Parser, null, null, null, null)
           }));
     }
     #endregion
@@ -197,6 +199,9 @@
     FOREIGN_BAZ = 6,
   }
 
+  /// <summary>
+  ///  Test an enum that has multiple values with the same number.
+  /// </summary>
   public enum TestEnumWithDupValue {
     TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED = 0,
     FOO1 = 1,
@@ -206,6 +211,9 @@
     BAR2 = 2,
   }
 
+  /// <summary>
+  ///  Test an enum with large, unordered values.
+  /// </summary>
   public enum TestSparseEnum {
     TEST_SPARSE_ENUM_UNSPECIFIED = 0,
     SPARSE_A = 123,
@@ -213,19 +221,27 @@
     SPARSE_C = 12589234,
     SPARSE_D = -15,
     SPARSE_E = -53452,
+    /// <summary>
+    ///  In proto3, value 0 must be the first one specified
+    ///  SPARSE_F = 0;
+    /// </summary>
     SPARSE_G = 2,
   }
 
   #endregion
 
   #region Messages
+  /// <summary>
+  ///  This proto includes every type of field in both singular and repeated
+  ///  forms.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestAllTypes : pb::IMessage<TestAllTypes> {
     private static readonly pb::MessageParser<TestAllTypes> _parser = new pb::MessageParser<TestAllTypes>(() => new TestAllTypes());
     public static pb::MessageParser<TestAllTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -304,8 +320,12 @@
       return new TestAllTypes(this);
     }
 
+    /// <summary>Field number for the "single_int32" field.</summary>
     public const int SingleInt32FieldNumber = 1;
     private int singleInt32_;
+    /// <summary>
+    ///  Singular
+    /// </summary>
     public int SingleInt32 {
       get { return singleInt32_; }
       set {
@@ -313,6 +333,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_int64" field.</summary>
     public const int SingleInt64FieldNumber = 2;
     private long singleInt64_;
     public long SingleInt64 {
@@ -322,6 +343,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_uint32" field.</summary>
     public const int SingleUint32FieldNumber = 3;
     private uint singleUint32_;
     public uint SingleUint32 {
@@ -331,6 +353,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_uint64" field.</summary>
     public const int SingleUint64FieldNumber = 4;
     private ulong singleUint64_;
     public ulong SingleUint64 {
@@ -340,6 +363,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_sint32" field.</summary>
     public const int SingleSint32FieldNumber = 5;
     private int singleSint32_;
     public int SingleSint32 {
@@ -349,6 +373,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_sint64" field.</summary>
     public const int SingleSint64FieldNumber = 6;
     private long singleSint64_;
     public long SingleSint64 {
@@ -358,6 +383,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_fixed32" field.</summary>
     public const int SingleFixed32FieldNumber = 7;
     private uint singleFixed32_;
     public uint SingleFixed32 {
@@ -367,6 +393,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_fixed64" field.</summary>
     public const int SingleFixed64FieldNumber = 8;
     private ulong singleFixed64_;
     public ulong SingleFixed64 {
@@ -376,6 +403,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_sfixed32" field.</summary>
     public const int SingleSfixed32FieldNumber = 9;
     private int singleSfixed32_;
     public int SingleSfixed32 {
@@ -385,6 +413,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_sfixed64" field.</summary>
     public const int SingleSfixed64FieldNumber = 10;
     private long singleSfixed64_;
     public long SingleSfixed64 {
@@ -394,6 +423,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_float" field.</summary>
     public const int SingleFloatFieldNumber = 11;
     private float singleFloat_;
     public float SingleFloat {
@@ -403,6 +433,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_double" field.</summary>
     public const int SingleDoubleFieldNumber = 12;
     private double singleDouble_;
     public double SingleDouble {
@@ -412,6 +443,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_bool" field.</summary>
     public const int SingleBoolFieldNumber = 13;
     private bool singleBool_;
     public bool SingleBool {
@@ -421,24 +453,27 @@
       }
     }
 
+    /// <summary>Field number for the "single_string" field.</summary>
     public const int SingleStringFieldNumber = 14;
     private string singleString_ = "";
     public string SingleString {
       get { return singleString_; }
       set {
-        singleString_ = pb::Preconditions.CheckNotNull(value, "value");
+        singleString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "single_bytes" field.</summary>
     public const int SingleBytesFieldNumber = 15;
     private pb::ByteString singleBytes_ = pb::ByteString.Empty;
     public pb::ByteString SingleBytes {
       get { return singleBytes_; }
       set {
-        singleBytes_ = pb::Preconditions.CheckNotNull(value, "value");
+        singleBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "single_nested_message" field.</summary>
     public const int SingleNestedMessageFieldNumber = 18;
     private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage singleNestedMessage_;
     public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage SingleNestedMessage {
@@ -448,6 +483,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_foreign_message" field.</summary>
     public const int SingleForeignMessageFieldNumber = 19;
     private global::Google.Protobuf.TestProtos.ForeignMessage singleForeignMessage_;
     public global::Google.Protobuf.TestProtos.ForeignMessage SingleForeignMessage {
@@ -457,6 +493,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_import_message" field.</summary>
     public const int SingleImportMessageFieldNumber = 20;
     private global::Google.Protobuf.TestProtos.ImportMessage singleImportMessage_;
     public global::Google.Protobuf.TestProtos.ImportMessage SingleImportMessage {
@@ -466,6 +503,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_nested_enum" field.</summary>
     public const int SingleNestedEnumFieldNumber = 21;
     private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum singleNestedEnum_ = global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED;
     public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum SingleNestedEnum {
@@ -475,6 +513,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_foreign_enum" field.</summary>
     public const int SingleForeignEnumFieldNumber = 22;
     private global::Google.Protobuf.TestProtos.ForeignEnum singleForeignEnum_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED;
     public global::Google.Protobuf.TestProtos.ForeignEnum SingleForeignEnum {
@@ -484,6 +523,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_import_enum" field.</summary>
     public const int SingleImportEnumFieldNumber = 23;
     private global::Google.Protobuf.TestProtos.ImportEnum singleImportEnum_ = global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED;
     public global::Google.Protobuf.TestProtos.ImportEnum SingleImportEnum {
@@ -493,8 +533,12 @@
       }
     }
 
+    /// <summary>Field number for the "single_public_import_message" field.</summary>
     public const int SinglePublicImportMessageFieldNumber = 26;
     private global::Google.Protobuf.TestProtos.PublicImportMessage singlePublicImportMessage_;
+    /// <summary>
+    ///  Defined in unittest_import_public.proto
+    /// </summary>
     public global::Google.Protobuf.TestProtos.PublicImportMessage SinglePublicImportMessage {
       get { return singlePublicImportMessage_; }
       set {
@@ -502,14 +546,19 @@
       }
     }
 
+    /// <summary>Field number for the "repeated_int32" field.</summary>
     public const int RepeatedInt32FieldNumber = 31;
     private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
         = pb::FieldCodec.ForInt32(250);
     private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Repeated
+    /// </summary>
     public pbc::RepeatedField<int> RepeatedInt32 {
       get { return repeatedInt32_; }
     }
 
+    /// <summary>Field number for the "repeated_int64" field.</summary>
     public const int RepeatedInt64FieldNumber = 32;
     private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
         = pb::FieldCodec.ForInt64(258);
@@ -518,6 +567,7 @@
       get { return repeatedInt64_; }
     }
 
+    /// <summary>Field number for the "repeated_uint32" field.</summary>
     public const int RepeatedUint32FieldNumber = 33;
     private static readonly pb::FieldCodec<uint> _repeated_repeatedUint32_codec
         = pb::FieldCodec.ForUInt32(266);
@@ -526,6 +576,7 @@
       get { return repeatedUint32_; }
     }
 
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
     public const int RepeatedUint64FieldNumber = 34;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
         = pb::FieldCodec.ForUInt64(274);
@@ -534,6 +585,7 @@
       get { return repeatedUint64_; }
     }
 
+    /// <summary>Field number for the "repeated_sint32" field.</summary>
     public const int RepeatedSint32FieldNumber = 35;
     private static readonly pb::FieldCodec<int> _repeated_repeatedSint32_codec
         = pb::FieldCodec.ForSInt32(282);
@@ -542,6 +594,7 @@
       get { return repeatedSint32_; }
     }
 
+    /// <summary>Field number for the "repeated_sint64" field.</summary>
     public const int RepeatedSint64FieldNumber = 36;
     private static readonly pb::FieldCodec<long> _repeated_repeatedSint64_codec
         = pb::FieldCodec.ForSInt64(290);
@@ -550,6 +603,7 @@
       get { return repeatedSint64_; }
     }
 
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
     public const int RepeatedFixed32FieldNumber = 37;
     private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
         = pb::FieldCodec.ForFixed32(298);
@@ -558,6 +612,7 @@
       get { return repeatedFixed32_; }
     }
 
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
     public const int RepeatedFixed64FieldNumber = 38;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
         = pb::FieldCodec.ForFixed64(306);
@@ -566,6 +621,7 @@
       get { return repeatedFixed64_; }
     }
 
+    /// <summary>Field number for the "repeated_sfixed32" field.</summary>
     public const int RepeatedSfixed32FieldNumber = 39;
     private static readonly pb::FieldCodec<int> _repeated_repeatedSfixed32_codec
         = pb::FieldCodec.ForSFixed32(314);
@@ -574,6 +630,7 @@
       get { return repeatedSfixed32_; }
     }
 
+    /// <summary>Field number for the "repeated_sfixed64" field.</summary>
     public const int RepeatedSfixed64FieldNumber = 40;
     private static readonly pb::FieldCodec<long> _repeated_repeatedSfixed64_codec
         = pb::FieldCodec.ForSFixed64(322);
@@ -582,6 +639,7 @@
       get { return repeatedSfixed64_; }
     }
 
+    /// <summary>Field number for the "repeated_float" field.</summary>
     public const int RepeatedFloatFieldNumber = 41;
     private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
         = pb::FieldCodec.ForFloat(330);
@@ -590,6 +648,7 @@
       get { return repeatedFloat_; }
     }
 
+    /// <summary>Field number for the "repeated_double" field.</summary>
     public const int RepeatedDoubleFieldNumber = 42;
     private static readonly pb::FieldCodec<double> _repeated_repeatedDouble_codec
         = pb::FieldCodec.ForDouble(338);
@@ -598,6 +657,7 @@
       get { return repeatedDouble_; }
     }
 
+    /// <summary>Field number for the "repeated_bool" field.</summary>
     public const int RepeatedBoolFieldNumber = 43;
     private static readonly pb::FieldCodec<bool> _repeated_repeatedBool_codec
         = pb::FieldCodec.ForBool(346);
@@ -606,6 +666,7 @@
       get { return repeatedBool_; }
     }
 
+    /// <summary>Field number for the "repeated_string" field.</summary>
     public const int RepeatedStringFieldNumber = 44;
     private static readonly pb::FieldCodec<string> _repeated_repeatedString_codec
         = pb::FieldCodec.ForString(354);
@@ -614,6 +675,7 @@
       get { return repeatedString_; }
     }
 
+    /// <summary>Field number for the "repeated_bytes" field.</summary>
     public const int RepeatedBytesFieldNumber = 45;
     private static readonly pb::FieldCodec<pb::ByteString> _repeated_repeatedBytes_codec
         = pb::FieldCodec.ForBytes(362);
@@ -622,6 +684,7 @@
       get { return repeatedBytes_; }
     }
 
+    /// <summary>Field number for the "repeated_nested_message" field.</summary>
     public const int RepeatedNestedMessageFieldNumber = 48;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage> _repeated_repeatedNestedMessage_codec
         = pb::FieldCodec.ForMessage(386, global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser);
@@ -630,6 +693,7 @@
       get { return repeatedNestedMessage_; }
     }
 
+    /// <summary>Field number for the "repeated_foreign_message" field.</summary>
     public const int RepeatedForeignMessageFieldNumber = 49;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignMessage> _repeated_repeatedForeignMessage_codec
         = pb::FieldCodec.ForMessage(394, global::Google.Protobuf.TestProtos.ForeignMessage.Parser);
@@ -638,6 +702,7 @@
       get { return repeatedForeignMessage_; }
     }
 
+    /// <summary>Field number for the "repeated_import_message" field.</summary>
     public const int RepeatedImportMessageFieldNumber = 50;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ImportMessage> _repeated_repeatedImportMessage_codec
         = pb::FieldCodec.ForMessage(402, global::Google.Protobuf.TestProtos.ImportMessage.Parser);
@@ -646,6 +711,7 @@
       get { return repeatedImportMessage_; }
     }
 
+    /// <summary>Field number for the "repeated_nested_enum" field.</summary>
     public const int RepeatedNestedEnumFieldNumber = 51;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum> _repeated_repeatedNestedEnum_codec
         = pb::FieldCodec.ForEnum(410, x => (int) x, x => (global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) x);
@@ -654,6 +720,7 @@
       get { return repeatedNestedEnum_; }
     }
 
+    /// <summary>Field number for the "repeated_foreign_enum" field.</summary>
     public const int RepeatedForeignEnumFieldNumber = 52;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_repeatedForeignEnum_codec
         = pb::FieldCodec.ForEnum(418, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
@@ -662,6 +729,7 @@
       get { return repeatedForeignEnum_; }
     }
 
+    /// <summary>Field number for the "repeated_import_enum" field.</summary>
     public const int RepeatedImportEnumFieldNumber = 53;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ImportEnum> _repeated_repeatedImportEnum_codec
         = pb::FieldCodec.ForEnum(426, x => (int) x, x => (global::Google.Protobuf.TestProtos.ImportEnum) x);
@@ -670,14 +738,19 @@
       get { return repeatedImportEnum_; }
     }
 
+    /// <summary>Field number for the "repeated_public_import_message" field.</summary>
     public const int RepeatedPublicImportMessageFieldNumber = 54;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.PublicImportMessage> _repeated_repeatedPublicImportMessage_codec
         = pb::FieldCodec.ForMessage(434, global::Google.Protobuf.TestProtos.PublicImportMessage.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage> repeatedPublicImportMessage_ = new pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage>();
+    /// <summary>
+    ///  Defined in unittest_import_public.proto
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.TestProtos.PublicImportMessage> RepeatedPublicImportMessage {
       get { return repeatedPublicImportMessage_; }
     }
 
+    /// <summary>Field number for the "oneof_uint32" field.</summary>
     public const int OneofUint32FieldNumber = 111;
     public uint OneofUint32 {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
@@ -687,6 +760,7 @@
       }
     }
 
+    /// <summary>Field number for the "oneof_nested_message" field.</summary>
     public const int OneofNestedMessageFieldNumber = 112;
     public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage OneofNestedMessage {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage ? (global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage) oneofField_ : null; }
@@ -696,25 +770,28 @@
       }
     }
 
+    /// <summary>Field number for the "oneof_string" field.</summary>
     public const int OneofStringFieldNumber = 113;
     public string OneofString {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
       set {
-        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofString;
       }
     }
 
+    /// <summary>Field number for the "oneof_bytes" field.</summary>
     public const int OneofBytesFieldNumber = 114;
     public pb::ByteString OneofBytes {
       get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
       set {
-        oneofField_ = pb::Preconditions.CheckNotNull(value, "value");
+        oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
       }
     }
 
     private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
     public enum OneofFieldOneofCase {
       None = 0,
       OneofUint32 = 111,
@@ -791,6 +868,7 @@
       if (!object.Equals(OneofNestedMessage, other.OneofNestedMessage)) return false;
       if (OneofString != other.OneofString) return false;
       if (OneofBytes != other.OneofBytes) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
       return true;
     }
 
@@ -844,11 +922,12 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1443,6 +1522,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the TestAllTypes message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       public enum NestedEnum {
@@ -1450,6 +1530,9 @@
         FOO = 1,
         BAR = 2,
         BAZ = 3,
+        /// <summary>
+        ///  Intentionally negative.
+        /// </summary>
         NEG = -1,
       }
 
@@ -1480,8 +1563,14 @@
           return new NestedMessage(this);
         }
 
+        /// <summary>Field number for the "bb" field.</summary>
         public const int BbFieldNumber = 1;
         private int bb_;
+        /// <summary>
+        ///  The field name "b" fails to compile in proto1 because it conflicts with
+        ///  a local variable named "b" in one of the generated methods.  Doh.
+        ///  This file needs to compile in proto1 to test backwards-compatibility.
+        /// </summary>
         public int Bb {
           get { return bb_; }
           set {
@@ -1511,7 +1600,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1560,13 +1649,16 @@
 
   }
 
+  /// <summary>
+  ///  This proto includes a recusively nested message.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class NestedTestAllTypes : pb::IMessage<NestedTestAllTypes> {
     private static readonly pb::MessageParser<NestedTestAllTypes> _parser = new pb::MessageParser<NestedTestAllTypes>(() => new NestedTestAllTypes());
     public static pb::MessageParser<NestedTestAllTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1589,6 +1681,7 @@
       return new NestedTestAllTypes(this);
     }
 
+    /// <summary>Field number for the "child" field.</summary>
     public const int ChildFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.NestedTestAllTypes child_;
     public global::Google.Protobuf.TestProtos.NestedTestAllTypes Child {
@@ -1598,6 +1691,7 @@
       }
     }
 
+    /// <summary>Field number for the "payload" field.</summary>
     public const int PayloadFieldNumber = 2;
     private global::Google.Protobuf.TestProtos.TestAllTypes payload_;
     public global::Google.Protobuf.TestProtos.TestAllTypes Payload {
@@ -1607,6 +1701,7 @@
       }
     }
 
+    /// <summary>Field number for the "repeated_child" field.</summary>
     public const int RepeatedChildFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.NestedTestAllTypes> _repeated_repeatedChild_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.TestProtos.NestedTestAllTypes.Parser);
@@ -1641,7 +1736,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1724,7 +1819,7 @@
     public static pb::MessageParser<TestDeprecatedFields> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1745,6 +1840,7 @@
       return new TestDeprecatedFields(this);
     }
 
+    /// <summary>Field number for the "deprecated_int32" field.</summary>
     public const int DeprecatedInt32FieldNumber = 1;
     private int deprecatedInt32_;
     [global::System.ObsoleteAttribute()]
@@ -1777,7 +1873,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1821,13 +1917,17 @@
 
   }
 
+  /// <summary>
+  ///  Define these after TestAllTypes to make sure the compiler can handle
+  ///  that.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class ForeignMessage : pb::IMessage<ForeignMessage> {
     private static readonly pb::MessageParser<ForeignMessage> _parser = new pb::MessageParser<ForeignMessage>(() => new ForeignMessage());
     public static pb::MessageParser<ForeignMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1848,6 +1948,7 @@
       return new ForeignMessage(this);
     }
 
+    /// <summary>Field number for the "c" field.</summary>
     public const int CFieldNumber = 1;
     private int c_;
     public int C {
@@ -1879,7 +1980,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1929,7 +2030,7 @@
     public static pb::MessageParser<TestReservedFields> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[4]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1969,7 +2070,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1999,13 +2100,16 @@
 
   }
 
+  /// <summary>
+  ///  Test that we can use NestedMessage from outside TestAllTypes.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestForeignNested : pb::IMessage<TestForeignNested> {
     private static readonly pb::MessageParser<TestForeignNested> _parser = new pb::MessageParser<TestForeignNested>(() => new TestForeignNested());
     public static pb::MessageParser<TestForeignNested> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[5]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2026,6 +2130,7 @@
       return new TestForeignNested(this);
     }
 
+    /// <summary>Field number for the "foreign_nested" field.</summary>
     public const int ForeignNestedFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage foreignNested_;
     public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage ForeignNested {
@@ -2057,7 +2162,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2107,13 +2212,16 @@
 
   }
 
+  /// <summary>
+  ///  Test that really large tag numbers don't break anything.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestReallyLargeTagNumber : pb::IMessage<TestReallyLargeTagNumber> {
     private static readonly pb::MessageParser<TestReallyLargeTagNumber> _parser = new pb::MessageParser<TestReallyLargeTagNumber>(() => new TestReallyLargeTagNumber());
     public static pb::MessageParser<TestReallyLargeTagNumber> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[6]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2135,8 +2243,13 @@
       return new TestReallyLargeTagNumber(this);
     }
 
+    /// <summary>Field number for the "a" field.</summary>
     public const int AFieldNumber = 1;
     private int a_;
+    /// <summary>
+    ///  The largest possible tag number is 2^28 - 1, since the wire format uses
+    ///  three bits to communicate wire type.
+    /// </summary>
     public int A {
       get { return a_; }
       set {
@@ -2144,6 +2257,7 @@
       }
     }
 
+    /// <summary>Field number for the "bb" field.</summary>
     public const int BbFieldNumber = 268435455;
     private int bb_;
     public int Bb {
@@ -2177,7 +2291,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2241,7 +2355,7 @@
     public static pb::MessageParser<TestRecursiveMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[7]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[7]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2263,6 +2377,7 @@
       return new TestRecursiveMessage(this);
     }
 
+    /// <summary>Field number for the "a" field.</summary>
     public const int AFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestRecursiveMessage a_;
     public global::Google.Protobuf.TestProtos.TestRecursiveMessage A {
@@ -2272,6 +2387,7 @@
       }
     }
 
+    /// <summary>Field number for the "i" field.</summary>
     public const int IFieldNumber = 2;
     private int i_;
     public int I {
@@ -2305,7 +2421,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2369,13 +2485,16 @@
 
   }
 
+  /// <summary>
+  ///  Test that mutual recursion works.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestMutualRecursionA : pb::IMessage<TestMutualRecursionA> {
     private static readonly pb::MessageParser<TestMutualRecursionA> _parser = new pb::MessageParser<TestMutualRecursionA>(() => new TestMutualRecursionA());
     public static pb::MessageParser<TestMutualRecursionA> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[8]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[8]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2396,6 +2515,7 @@
       return new TestMutualRecursionA(this);
     }
 
+    /// <summary>Field number for the "bb" field.</summary>
     public const int BbFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestMutualRecursionB bb_;
     public global::Google.Protobuf.TestProtos.TestMutualRecursionB Bb {
@@ -2427,7 +2547,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2483,7 +2603,7 @@
     public static pb::MessageParser<TestMutualRecursionB> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[9]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[9]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2505,6 +2625,7 @@
       return new TestMutualRecursionB(this);
     }
 
+    /// <summary>Field number for the "a" field.</summary>
     public const int AFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestMutualRecursionA a_;
     public global::Google.Protobuf.TestProtos.TestMutualRecursionA A {
@@ -2514,6 +2635,7 @@
       }
     }
 
+    /// <summary>Field number for the "optional_int32" field.</summary>
     public const int OptionalInt32FieldNumber = 2;
     private int optionalInt32_;
     public int OptionalInt32 {
@@ -2547,7 +2669,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2611,13 +2733,17 @@
 
   }
 
+  /// <summary>
+  ///  Test message with CamelCase field names.  This violates Protocol Buffer
+  ///  standard style.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestCamelCaseFieldNames : pb::IMessage<TestCamelCaseFieldNames> {
     private static readonly pb::MessageParser<TestCamelCaseFieldNames> _parser = new pb::MessageParser<TestCamelCaseFieldNames>(() => new TestCamelCaseFieldNames());
     public static pb::MessageParser<TestCamelCaseFieldNames> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[10]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[10]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2645,6 +2771,7 @@
       return new TestCamelCaseFieldNames(this);
     }
 
+    /// <summary>Field number for the "PrimitiveField" field.</summary>
     public const int PrimitiveFieldFieldNumber = 1;
     private int primitiveField_;
     public int PrimitiveField {
@@ -2654,15 +2781,17 @@
       }
     }
 
+    /// <summary>Field number for the "StringField" field.</summary>
     public const int StringFieldFieldNumber = 2;
     private string stringField_ = "";
     public string StringField {
       get { return stringField_; }
       set {
-        stringField_ = pb::Preconditions.CheckNotNull(value, "value");
+        stringField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "EnumField" field.</summary>
     public const int EnumFieldFieldNumber = 3;
     private global::Google.Protobuf.TestProtos.ForeignEnum enumField_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED;
     public global::Google.Protobuf.TestProtos.ForeignEnum EnumField {
@@ -2672,6 +2801,7 @@
       }
     }
 
+    /// <summary>Field number for the "MessageField" field.</summary>
     public const int MessageFieldFieldNumber = 4;
     private global::Google.Protobuf.TestProtos.ForeignMessage messageField_;
     public global::Google.Protobuf.TestProtos.ForeignMessage MessageField {
@@ -2681,6 +2811,7 @@
       }
     }
 
+    /// <summary>Field number for the "RepeatedPrimitiveField" field.</summary>
     public const int RepeatedPrimitiveFieldFieldNumber = 7;
     private static readonly pb::FieldCodec<int> _repeated_repeatedPrimitiveField_codec
         = pb::FieldCodec.ForInt32(58);
@@ -2689,6 +2820,7 @@
       get { return repeatedPrimitiveField_; }
     }
 
+    /// <summary>Field number for the "RepeatedStringField" field.</summary>
     public const int RepeatedStringFieldFieldNumber = 8;
     private static readonly pb::FieldCodec<string> _repeated_repeatedStringField_codec
         = pb::FieldCodec.ForString(66);
@@ -2697,6 +2829,7 @@
       get { return repeatedStringField_; }
     }
 
+    /// <summary>Field number for the "RepeatedEnumField" field.</summary>
     public const int RepeatedEnumFieldFieldNumber = 9;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_repeatedEnumField_codec
         = pb::FieldCodec.ForEnum(74, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
@@ -2705,6 +2838,7 @@
       get { return repeatedEnumField_; }
     }
 
+    /// <summary>Field number for the "RepeatedMessageField" field.</summary>
     public const int RepeatedMessageFieldFieldNumber = 10;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignMessage> _repeated_repeatedMessageField_codec
         = pb::FieldCodec.ForMessage(82, global::Google.Protobuf.TestProtos.ForeignMessage.Parser);
@@ -2749,7 +2883,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2871,13 +3005,17 @@
 
   }
 
+  /// <summary>
+  ///  We list fields out of order, to ensure that we're using field number and not
+  ///  field index to determine serialization order.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestFieldOrderings : pb::IMessage<TestFieldOrderings> {
     private static readonly pb::MessageParser<TestFieldOrderings> _parser = new pb::MessageParser<TestFieldOrderings>(() => new TestFieldOrderings());
     public static pb::MessageParser<TestFieldOrderings> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[11]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[11]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2901,15 +3039,17 @@
       return new TestFieldOrderings(this);
     }
 
+    /// <summary>Field number for the "my_string" field.</summary>
     public const int MyStringFieldNumber = 11;
     private string myString_ = "";
     public string MyString {
       get { return myString_; }
       set {
-        myString_ = pb::Preconditions.CheckNotNull(value, "value");
+        myString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "my_int" field.</summary>
     public const int MyIntFieldNumber = 1;
     private long myInt_;
     public long MyInt {
@@ -2919,6 +3059,7 @@
       }
     }
 
+    /// <summary>Field number for the "my_float" field.</summary>
     public const int MyFloatFieldNumber = 101;
     private float myFloat_;
     public float MyFloat {
@@ -2928,6 +3069,7 @@
       }
     }
 
+    /// <summary>Field number for the "single_nested_message" field.</summary>
     public const int SingleNestedMessageFieldNumber = 200;
     private global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage singleNestedMessage_;
     public global::Google.Protobuf.TestProtos.TestFieldOrderings.Types.NestedMessage SingleNestedMessage {
@@ -2965,7 +3107,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3056,6 +3198,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the TestFieldOrderings message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -3086,6 +3229,7 @@
           return new NestedMessage(this);
         }
 
+        /// <summary>Field number for the "oo" field.</summary>
         public const int OoFieldNumber = 2;
         private long oo_;
         public long Oo {
@@ -3095,8 +3239,14 @@
           }
         }
 
+        /// <summary>Field number for the "bb" field.</summary>
         public const int BbFieldNumber = 1;
         private int bb_;
+        /// <summary>
+        ///  The field name "b" fails to compile in proto1 because it conflicts with
+        ///  a local variable named "b" in one of the generated methods.  Doh.
+        ///  This file needs to compile in proto1 to test backwards-compatibility.
+        /// </summary>
         public int Bb {
           get { return bb_; }
           set {
@@ -3128,7 +3278,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -3197,7 +3347,7 @@
     public static pb::MessageParser<SparseEnumMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[12]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[12]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3218,6 +3368,7 @@
       return new SparseEnumMessage(this);
     }
 
+    /// <summary>Field number for the "sparse_enum" field.</summary>
     public const int SparseEnumFieldNumber = 1;
     private global::Google.Protobuf.TestProtos.TestSparseEnum sparseEnum_ = global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED;
     public global::Google.Protobuf.TestProtos.TestSparseEnum SparseEnum {
@@ -3249,7 +3400,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3293,13 +3444,16 @@
 
   }
 
+  /// <summary>
+  ///  Test String and Bytes: string is for valid UTF-8 strings
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class OneString : pb::IMessage<OneString> {
     private static readonly pb::MessageParser<OneString> _parser = new pb::MessageParser<OneString>(() => new OneString());
     public static pb::MessageParser<OneString> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[13]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[13]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3320,12 +3474,13 @@
       return new OneString(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private string data_ = "";
     public string Data {
       get { return data_; }
       set {
-        data_ = pb::Preconditions.CheckNotNull(value, "value");
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -3351,7 +3506,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3401,7 +3556,7 @@
     public static pb::MessageParser<MoreString> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[14]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[14]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3422,6 +3577,7 @@
       return new MoreString(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private static readonly pb::FieldCodec<string> _repeated_data_codec
         = pb::FieldCodec.ForString(10);
@@ -3452,7 +3608,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3495,7 +3651,7 @@
     public static pb::MessageParser<OneBytes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[15]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[15]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3516,12 +3672,13 @@
       return new OneBytes(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private pb::ByteString data_ = pb::ByteString.Empty;
     public pb::ByteString Data {
       get { return data_; }
       set {
-        data_ = pb::Preconditions.CheckNotNull(value, "value");
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -3547,7 +3704,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3597,7 +3754,7 @@
     public static pb::MessageParser<MoreBytes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[16]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[16]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3618,12 +3775,13 @@
       return new MoreBytes(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private pb::ByteString data_ = pb::ByteString.Empty;
     public pb::ByteString Data {
       get { return data_; }
       set {
-        data_ = pb::Preconditions.CheckNotNull(value, "value");
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -3649,7 +3807,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3693,13 +3851,16 @@
 
   }
 
+  /// <summary>
+  ///  Test int32, uint32, int64, uint64, and bool are all compatible
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Int32Message : pb::IMessage<Int32Message> {
     private static readonly pb::MessageParser<Int32Message> _parser = new pb::MessageParser<Int32Message>(() => new Int32Message());
     public static pb::MessageParser<Int32Message> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[17]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[17]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3720,6 +3881,7 @@
       return new Int32Message(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private int data_;
     public int Data {
@@ -3751,7 +3913,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3801,7 +3963,7 @@
     public static pb::MessageParser<Uint32Message> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[18]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[18]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3822,6 +3984,7 @@
       return new Uint32Message(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private uint data_;
     public uint Data {
@@ -3853,7 +4016,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3903,7 +4066,7 @@
     public static pb::MessageParser<Int64Message> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[19]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[19]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3924,6 +4087,7 @@
       return new Int64Message(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private long data_;
     public long Data {
@@ -3955,7 +4119,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4005,7 +4169,7 @@
     public static pb::MessageParser<Uint64Message> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[20]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[20]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4026,6 +4190,7 @@
       return new Uint64Message(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private ulong data_;
     public ulong Data {
@@ -4057,7 +4222,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4107,7 +4272,7 @@
     public static pb::MessageParser<BoolMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[21]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[21]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4128,6 +4293,7 @@
       return new BoolMessage(this);
     }
 
+    /// <summary>Field number for the "data" field.</summary>
     public const int DataFieldNumber = 1;
     private bool data_;
     public bool Data {
@@ -4159,7 +4325,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4203,13 +4369,16 @@
 
   }
 
+  /// <summary>
+  ///  Test oneofs.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestOneof : pb::IMessage<TestOneof> {
     private static readonly pb::MessageParser<TestOneof> _parser = new pb::MessageParser<TestOneof>(() => new TestOneof());
     public static pb::MessageParser<TestOneof> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[22]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[22]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4241,6 +4410,7 @@
       return new TestOneof(this);
     }
 
+    /// <summary>Field number for the "foo_int" field.</summary>
     public const int FooIntFieldNumber = 1;
     public int FooInt {
       get { return fooCase_ == FooOneofCase.FooInt ? (int) foo_ : 0; }
@@ -4250,15 +4420,17 @@
       }
     }
 
+    /// <summary>Field number for the "foo_string" field.</summary>
     public const int FooStringFieldNumber = 2;
     public string FooString {
       get { return fooCase_ == FooOneofCase.FooString ? (string) foo_ : ""; }
       set {
-        foo_ = pb::Preconditions.CheckNotNull(value, "value");
+        foo_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         fooCase_ = FooOneofCase.FooString;
       }
     }
 
+    /// <summary>Field number for the "foo_message" field.</summary>
     public const int FooMessageFieldNumber = 3;
     public global::Google.Protobuf.TestProtos.TestAllTypes FooMessage {
       get { return fooCase_ == FooOneofCase.FooMessage ? (global::Google.Protobuf.TestProtos.TestAllTypes) foo_ : null; }
@@ -4269,6 +4441,7 @@
     }
 
     private object foo_;
+    /// <summary>Enum of possible cases for the "foo" oneof.</summary>
     public enum FooOneofCase {
       None = 0,
       FooInt = 1,
@@ -4299,6 +4472,7 @@
       if (FooInt != other.FooInt) return false;
       if (FooString != other.FooString) return false;
       if (!object.Equals(FooMessage, other.FooMessage)) return false;
+      if (FooCase != other.FooCase) return false;
       return true;
     }
 
@@ -4307,11 +4481,12 @@
       if (fooCase_ == FooOneofCase.FooInt) hash ^= FooInt.GetHashCode();
       if (fooCase_ == FooOneofCase.FooString) hash ^= FooString.GetHashCode();
       if (fooCase_ == FooOneofCase.FooMessage) hash ^= FooMessage.GetHashCode();
+      hash ^= (int) fooCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4397,7 +4572,7 @@
     public static pb::MessageParser<TestPackedTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[23]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[23]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4431,6 +4606,7 @@
       return new TestPackedTypes(this);
     }
 
+    /// <summary>Field number for the "packed_int32" field.</summary>
     public const int PackedInt32FieldNumber = 90;
     private static readonly pb::FieldCodec<int> _repeated_packedInt32_codec
         = pb::FieldCodec.ForInt32(722);
@@ -4439,6 +4615,7 @@
       get { return packedInt32_; }
     }
 
+    /// <summary>Field number for the "packed_int64" field.</summary>
     public const int PackedInt64FieldNumber = 91;
     private static readonly pb::FieldCodec<long> _repeated_packedInt64_codec
         = pb::FieldCodec.ForInt64(730);
@@ -4447,6 +4624,7 @@
       get { return packedInt64_; }
     }
 
+    /// <summary>Field number for the "packed_uint32" field.</summary>
     public const int PackedUint32FieldNumber = 92;
     private static readonly pb::FieldCodec<uint> _repeated_packedUint32_codec
         = pb::FieldCodec.ForUInt32(738);
@@ -4455,6 +4633,7 @@
       get { return packedUint32_; }
     }
 
+    /// <summary>Field number for the "packed_uint64" field.</summary>
     public const int PackedUint64FieldNumber = 93;
     private static readonly pb::FieldCodec<ulong> _repeated_packedUint64_codec
         = pb::FieldCodec.ForUInt64(746);
@@ -4463,6 +4642,7 @@
       get { return packedUint64_; }
     }
 
+    /// <summary>Field number for the "packed_sint32" field.</summary>
     public const int PackedSint32FieldNumber = 94;
     private static readonly pb::FieldCodec<int> _repeated_packedSint32_codec
         = pb::FieldCodec.ForSInt32(754);
@@ -4471,6 +4651,7 @@
       get { return packedSint32_; }
     }
 
+    /// <summary>Field number for the "packed_sint64" field.</summary>
     public const int PackedSint64FieldNumber = 95;
     private static readonly pb::FieldCodec<long> _repeated_packedSint64_codec
         = pb::FieldCodec.ForSInt64(762);
@@ -4479,6 +4660,7 @@
       get { return packedSint64_; }
     }
 
+    /// <summary>Field number for the "packed_fixed32" field.</summary>
     public const int PackedFixed32FieldNumber = 96;
     private static readonly pb::FieldCodec<uint> _repeated_packedFixed32_codec
         = pb::FieldCodec.ForFixed32(770);
@@ -4487,6 +4669,7 @@
       get { return packedFixed32_; }
     }
 
+    /// <summary>Field number for the "packed_fixed64" field.</summary>
     public const int PackedFixed64FieldNumber = 97;
     private static readonly pb::FieldCodec<ulong> _repeated_packedFixed64_codec
         = pb::FieldCodec.ForFixed64(778);
@@ -4495,6 +4678,7 @@
       get { return packedFixed64_; }
     }
 
+    /// <summary>Field number for the "packed_sfixed32" field.</summary>
     public const int PackedSfixed32FieldNumber = 98;
     private static readonly pb::FieldCodec<int> _repeated_packedSfixed32_codec
         = pb::FieldCodec.ForSFixed32(786);
@@ -4503,6 +4687,7 @@
       get { return packedSfixed32_; }
     }
 
+    /// <summary>Field number for the "packed_sfixed64" field.</summary>
     public const int PackedSfixed64FieldNumber = 99;
     private static readonly pb::FieldCodec<long> _repeated_packedSfixed64_codec
         = pb::FieldCodec.ForSFixed64(794);
@@ -4511,6 +4696,7 @@
       get { return packedSfixed64_; }
     }
 
+    /// <summary>Field number for the "packed_float" field.</summary>
     public const int PackedFloatFieldNumber = 100;
     private static readonly pb::FieldCodec<float> _repeated_packedFloat_codec
         = pb::FieldCodec.ForFloat(802);
@@ -4519,6 +4705,7 @@
       get { return packedFloat_; }
     }
 
+    /// <summary>Field number for the "packed_double" field.</summary>
     public const int PackedDoubleFieldNumber = 101;
     private static readonly pb::FieldCodec<double> _repeated_packedDouble_codec
         = pb::FieldCodec.ForDouble(810);
@@ -4527,6 +4714,7 @@
       get { return packedDouble_; }
     }
 
+    /// <summary>Field number for the "packed_bool" field.</summary>
     public const int PackedBoolFieldNumber = 102;
     private static readonly pb::FieldCodec<bool> _repeated_packedBool_codec
         = pb::FieldCodec.ForBool(818);
@@ -4535,6 +4723,7 @@
       get { return packedBool_; }
     }
 
+    /// <summary>Field number for the "packed_enum" field.</summary>
     public const int PackedEnumFieldNumber = 103;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_packedEnum_codec
         = pb::FieldCodec.ForEnum(826, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
@@ -4591,7 +4780,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4733,13 +4922,17 @@
 
   }
 
+  /// <summary>
+  ///  A message with the same fields as TestPackedTypes, but without packing. Used
+  ///  to test packed &lt;-> unpacked wire compatibility.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestUnpackedTypes : pb::IMessage<TestUnpackedTypes> {
     private static readonly pb::MessageParser<TestUnpackedTypes> _parser = new pb::MessageParser<TestUnpackedTypes>(() => new TestUnpackedTypes());
     public static pb::MessageParser<TestUnpackedTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[24]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[24]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4773,6 +4966,7 @@
       return new TestUnpackedTypes(this);
     }
 
+    /// <summary>Field number for the "unpacked_int32" field.</summary>
     public const int UnpackedInt32FieldNumber = 90;
     private static readonly pb::FieldCodec<int> _repeated_unpackedInt32_codec
         = pb::FieldCodec.ForInt32(720);
@@ -4781,6 +4975,7 @@
       get { return unpackedInt32_; }
     }
 
+    /// <summary>Field number for the "unpacked_int64" field.</summary>
     public const int UnpackedInt64FieldNumber = 91;
     private static readonly pb::FieldCodec<long> _repeated_unpackedInt64_codec
         = pb::FieldCodec.ForInt64(728);
@@ -4789,6 +4984,7 @@
       get { return unpackedInt64_; }
     }
 
+    /// <summary>Field number for the "unpacked_uint32" field.</summary>
     public const int UnpackedUint32FieldNumber = 92;
     private static readonly pb::FieldCodec<uint> _repeated_unpackedUint32_codec
         = pb::FieldCodec.ForUInt32(736);
@@ -4797,6 +4993,7 @@
       get { return unpackedUint32_; }
     }
 
+    /// <summary>Field number for the "unpacked_uint64" field.</summary>
     public const int UnpackedUint64FieldNumber = 93;
     private static readonly pb::FieldCodec<ulong> _repeated_unpackedUint64_codec
         = pb::FieldCodec.ForUInt64(744);
@@ -4805,6 +5002,7 @@
       get { return unpackedUint64_; }
     }
 
+    /// <summary>Field number for the "unpacked_sint32" field.</summary>
     public const int UnpackedSint32FieldNumber = 94;
     private static readonly pb::FieldCodec<int> _repeated_unpackedSint32_codec
         = pb::FieldCodec.ForSInt32(752);
@@ -4813,6 +5011,7 @@
       get { return unpackedSint32_; }
     }
 
+    /// <summary>Field number for the "unpacked_sint64" field.</summary>
     public const int UnpackedSint64FieldNumber = 95;
     private static readonly pb::FieldCodec<long> _repeated_unpackedSint64_codec
         = pb::FieldCodec.ForSInt64(760);
@@ -4821,6 +5020,7 @@
       get { return unpackedSint64_; }
     }
 
+    /// <summary>Field number for the "unpacked_fixed32" field.</summary>
     public const int UnpackedFixed32FieldNumber = 96;
     private static readonly pb::FieldCodec<uint> _repeated_unpackedFixed32_codec
         = pb::FieldCodec.ForFixed32(773);
@@ -4829,6 +5029,7 @@
       get { return unpackedFixed32_; }
     }
 
+    /// <summary>Field number for the "unpacked_fixed64" field.</summary>
     public const int UnpackedFixed64FieldNumber = 97;
     private static readonly pb::FieldCodec<ulong> _repeated_unpackedFixed64_codec
         = pb::FieldCodec.ForFixed64(777);
@@ -4837,6 +5038,7 @@
       get { return unpackedFixed64_; }
     }
 
+    /// <summary>Field number for the "unpacked_sfixed32" field.</summary>
     public const int UnpackedSfixed32FieldNumber = 98;
     private static readonly pb::FieldCodec<int> _repeated_unpackedSfixed32_codec
         = pb::FieldCodec.ForSFixed32(789);
@@ -4845,6 +5047,7 @@
       get { return unpackedSfixed32_; }
     }
 
+    /// <summary>Field number for the "unpacked_sfixed64" field.</summary>
     public const int UnpackedSfixed64FieldNumber = 99;
     private static readonly pb::FieldCodec<long> _repeated_unpackedSfixed64_codec
         = pb::FieldCodec.ForSFixed64(793);
@@ -4853,6 +5056,7 @@
       get { return unpackedSfixed64_; }
     }
 
+    /// <summary>Field number for the "unpacked_float" field.</summary>
     public const int UnpackedFloatFieldNumber = 100;
     private static readonly pb::FieldCodec<float> _repeated_unpackedFloat_codec
         = pb::FieldCodec.ForFloat(805);
@@ -4861,6 +5065,7 @@
       get { return unpackedFloat_; }
     }
 
+    /// <summary>Field number for the "unpacked_double" field.</summary>
     public const int UnpackedDoubleFieldNumber = 101;
     private static readonly pb::FieldCodec<double> _repeated_unpackedDouble_codec
         = pb::FieldCodec.ForDouble(809);
@@ -4869,6 +5074,7 @@
       get { return unpackedDouble_; }
     }
 
+    /// <summary>Field number for the "unpacked_bool" field.</summary>
     public const int UnpackedBoolFieldNumber = 102;
     private static readonly pb::FieldCodec<bool> _repeated_unpackedBool_codec
         = pb::FieldCodec.ForBool(816);
@@ -4877,6 +5083,7 @@
       get { return unpackedBool_; }
     }
 
+    /// <summary>Field number for the "unpacked_enum" field.</summary>
     public const int UnpackedEnumFieldNumber = 103;
     private static readonly pb::FieldCodec<global::Google.Protobuf.TestProtos.ForeignEnum> _repeated_unpackedEnum_codec
         = pb::FieldCodec.ForEnum(824, x => (int) x, x => (global::Google.Protobuf.TestProtos.ForeignEnum) x);
@@ -4933,7 +5140,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5081,7 +5288,7 @@
     public static pb::MessageParser<TestRepeatedScalarDifferentTagSizes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[25]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[25]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5107,30 +5314,45 @@
       return new TestRepeatedScalarDifferentTagSizes(this);
     }
 
+    /// <summary>Field number for the "repeated_fixed32" field.</summary>
     public const int RepeatedFixed32FieldNumber = 12;
     private static readonly pb::FieldCodec<uint> _repeated_repeatedFixed32_codec
         = pb::FieldCodec.ForFixed32(98);
     private readonly pbc::RepeatedField<uint> repeatedFixed32_ = new pbc::RepeatedField<uint>();
+    /// <summary>
+    ///  Parsing repeated fixed size values used to fail. This message needs to be
+    ///  used in order to get a tag of the right size; all of the repeated fields
+    ///  in TestAllTypes didn't trigger the check.
+    /// </summary>
     public pbc::RepeatedField<uint> RepeatedFixed32 {
       get { return repeatedFixed32_; }
     }
 
+    /// <summary>Field number for the "repeated_int32" field.</summary>
     public const int RepeatedInt32FieldNumber = 13;
     private static readonly pb::FieldCodec<int> _repeated_repeatedInt32_codec
         = pb::FieldCodec.ForInt32(106);
     private readonly pbc::RepeatedField<int> repeatedInt32_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Check for a varint type, just for good measure.
+    /// </summary>
     public pbc::RepeatedField<int> RepeatedInt32 {
       get { return repeatedInt32_; }
     }
 
+    /// <summary>Field number for the "repeated_fixed64" field.</summary>
     public const int RepeatedFixed64FieldNumber = 2046;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedFixed64_codec
         = pb::FieldCodec.ForFixed64(16370);
     private readonly pbc::RepeatedField<ulong> repeatedFixed64_ = new pbc::RepeatedField<ulong>();
+    /// <summary>
+    ///  These have two-byte tags.
+    /// </summary>
     public pbc::RepeatedField<ulong> RepeatedFixed64 {
       get { return repeatedFixed64_; }
     }
 
+    /// <summary>Field number for the "repeated_int64" field.</summary>
     public const int RepeatedInt64FieldNumber = 2047;
     private static readonly pb::FieldCodec<long> _repeated_repeatedInt64_codec
         = pb::FieldCodec.ForInt64(16378);
@@ -5139,14 +5361,19 @@
       get { return repeatedInt64_; }
     }
 
+    /// <summary>Field number for the "repeated_float" field.</summary>
     public const int RepeatedFloatFieldNumber = 262142;
     private static readonly pb::FieldCodec<float> _repeated_repeatedFloat_codec
         = pb::FieldCodec.ForFloat(2097138);
     private readonly pbc::RepeatedField<float> repeatedFloat_ = new pbc::RepeatedField<float>();
+    /// <summary>
+    ///  Three byte tags.
+    /// </summary>
     public pbc::RepeatedField<float> RepeatedFloat {
       get { return repeatedFloat_; }
     }
 
+    /// <summary>Field number for the "repeated_uint64" field.</summary>
     public const int RepeatedUint64FieldNumber = 262143;
     private static readonly pb::FieldCodec<ulong> _repeated_repeatedUint64_codec
         = pb::FieldCodec.ForUInt64(2097146);
@@ -5187,7 +5414,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5271,7 +5498,7 @@
     public static pb::MessageParser<TestCommentInjectionMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[26]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[26]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5292,12 +5519,16 @@
       return new TestCommentInjectionMessage(this);
     }
 
+    /// <summary>Field number for the "a" field.</summary>
     public const int AFieldNumber = 1;
     private string a_ = "";
+    /// <summary>
+    ///  */ &lt;- This should not close the generated doc comment
+    /// </summary>
     public string A {
       get { return a_; }
       set {
-        a_ = pb::Preconditions.CheckNotNull(value, "value");
+        a_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -5323,7 +5554,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5367,13 +5598,16 @@
 
   }
 
+  /// <summary>
+  ///  Test that RPC services work.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class FooRequest : pb::IMessage<FooRequest> {
     private static readonly pb::MessageParser<FooRequest> _parser = new pb::MessageParser<FooRequest>(() => new FooRequest());
     public static pb::MessageParser<FooRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[27]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[27]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5413,7 +5647,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5449,7 +5683,7 @@
     public static pb::MessageParser<FooResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[28]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[28]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5489,7 +5723,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5525,7 +5759,7 @@
     public static pb::MessageParser<FooClientMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[29]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[29]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5565,7 +5799,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5601,7 +5835,7 @@
     public static pb::MessageParser<FooServerMessage> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[30]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[30]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5641,7 +5875,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5677,7 +5911,7 @@
     public static pb::MessageParser<BarRequest> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[31]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[31]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5717,7 +5951,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -5753,7 +5987,7 @@
     public static pb::MessageParser<BarResponse> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestProto3.Descriptor.MessageTypes[32]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[32]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -5793,7 +6027,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
index 16634e0..ae12f4a 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
@@ -9,174 +9,182 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.TestProtos {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/unittest_well_known_types.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class UnittestWellKnownTypes {
+  public static partial class UnittestWellKnownTypesReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/unittest_well_known_types.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static UnittestWellKnownTypes() {
+    static UnittestWellKnownTypesReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "Ci9nb29nbGUvcHJvdG9idWYvdW5pdHRlc3Rfd2VsbF9rbm93bl90eXBlcy5w", 
-            "cm90bxIRcHJvdG9idWZfdW5pdHRlc3QaGWdvb2dsZS9wcm90b2J1Zi9hbnku", 
-            "cHJvdG8aGWdvb2dsZS9wcm90b2J1Zi9hcGkucHJvdG8aHmdvb2dsZS9wcm90", 
-            "b2J1Zi9kdXJhdGlvbi5wcm90bxobZ29vZ2xlL3Byb3RvYnVmL2VtcHR5LnBy", 
-            "b3RvGiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxokZ29vZ2xl", 
-            "L3Byb3RvYnVmL3NvdXJjZV9jb250ZXh0LnByb3RvGhxnb29nbGUvcHJvdG9i", 
-            "dWYvc3RydWN0LnByb3RvGh9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnBy", 
-            "b3RvGhpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxoeZ29vZ2xlL3Byb3Rv", 
-            "YnVmL3dyYXBwZXJzLnByb3RvIpEHChJUZXN0V2VsbEtub3duVHlwZXMSJwoJ", 
-            "YW55X2ZpZWxkGAEgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueRInCglhcGlf", 
-            "ZmllbGQYAiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpEjEKDmR1cmF0aW9u", 
-            "X2ZpZWxkGAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uEisKC2Vt", 
-            "cHR5X2ZpZWxkGAQgASgLMhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5EjQKEGZp", 
-            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN", 
-            "YXNrEjwKFHNvdXJjZV9jb250ZXh0X2ZpZWxkGAYgASgLMh4uZ29vZ2xlLnBy", 
-            "b3RvYnVmLlNvdXJjZUNvbnRleHQSLQoMc3RydWN0X2ZpZWxkGAcgASgLMhcu", 
-            "Z29vZ2xlLnByb3RvYnVmLlN0cnVjdBIzCg90aW1lc3RhbXBfZmllbGQYCCAB", 
-            "KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEikKCnR5cGVfZmllbGQY", 
-            "CSABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZRIyCgxkb3VibGVfZmllbGQY", 
-            "CiABKAsyHC5nb29nbGUucHJvdG9idWYuRG91YmxlVmFsdWUSMAoLZmxvYXRf", 
-            "ZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxvYXRWYWx1ZRIwCgtp", 
-            "bnQ2NF9maWVsZBgMIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl", 
-            "EjIKDHVpbnQ2NF9maWVsZBgNIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50", 
-            "NjRWYWx1ZRIwCgtpbnQzMl9maWVsZBgOIAEoCzIbLmdvb2dsZS5wcm90b2J1", 
-            "Zi5JbnQzMlZhbHVlEjIKDHVpbnQzMl9maWVsZBgPIAEoCzIcLmdvb2dsZS5w", 
-            "cm90b2J1Zi5VSW50MzJWYWx1ZRIuCgpib29sX2ZpZWxkGBAgASgLMhouZ29v", 
-            "Z2xlLnByb3RvYnVmLkJvb2xWYWx1ZRIyCgxzdHJpbmdfZmllbGQYESABKAsy", 
-            "HC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSMAoLYnl0ZXNfZmllbGQY", 
-            "EiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZSKVBwoWUmVwZWF0", 
-            "ZWRXZWxsS25vd25UeXBlcxInCglhbnlfZmllbGQYASADKAsyFC5nb29nbGUu", 
-            "cHJvdG9idWYuQW55EicKCWFwaV9maWVsZBgCIAMoCzIULmdvb2dsZS5wcm90", 
-            "b2J1Zi5BcGkSMQoOZHVyYXRpb25fZmllbGQYAyADKAsyGS5nb29nbGUucHJv", 
-            "dG9idWYuRHVyYXRpb24SKwoLZW1wdHlfZmllbGQYBCADKAsyFi5nb29nbGUu", 
-            "cHJvdG9idWYuRW1wdHkSNAoQZmllbGRfbWFza19maWVsZBgFIAMoCzIaLmdv", 
-            "b2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sSPAoUc291cmNlX2NvbnRleHRfZmll", 
-            "bGQYBiADKAsyHi5nb29nbGUucHJvdG9idWYuU291cmNlQ29udGV4dBItCgxz", 
-            "dHJ1Y3RfZmllbGQYByADKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EjMK", 
-            "D3RpbWVzdGFtcF9maWVsZBgIIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1l", 
-            "c3RhbXASKQoKdHlwZV9maWVsZBgJIAMoCzIVLmdvb2dsZS5wcm90b2J1Zi5U", 
-            "eXBlEjIKDGRvdWJsZV9maWVsZBgKIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5E", 
-            "b3VibGVWYWx1ZRIwCgtmbG9hdF9maWVsZBgLIAMoCzIbLmdvb2dsZS5wcm90", 
-            "b2J1Zi5GbG9hdFZhbHVlEjAKC2ludDY0X2ZpZWxkGAwgAygLMhsuZ29vZ2xl", 
-            "LnByb3RvYnVmLkludDY0VmFsdWUSMgoMdWludDY0X2ZpZWxkGA0gAygLMhwu", 
-            "Z29vZ2xlLnByb3RvYnVmLlVJbnQ2NFZhbHVlEjAKC2ludDMyX2ZpZWxkGA4g", 
-            "AygLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSMgoMdWludDMyX2Zp", 
-            "ZWxkGA8gAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEi4KCmJv", 
-            "b2xfZmllbGQYECADKAsyGi5nb29nbGUucHJvdG9idWYuQm9vbFZhbHVlEjIK", 
-            "DHN0cmluZ19maWVsZBgRIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5TdHJpbmdW", 
-            "YWx1ZRIwCgtieXRlc19maWVsZBgSIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5C", 
-            "eXRlc1ZhbHVlIsUHChNPbmVvZldlbGxLbm93blR5cGVzEikKCWFueV9maWVs", 
-            "ZBgBIAEoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlIABIpCglhcGlfZmllbGQY", 
-            "AiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpSAASMwoOZHVyYXRpb25fZmll", 
-            "bGQYAyABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25IABItCgtlbXB0", 
-            "eV9maWVsZBgEIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eUgAEjYKEGZp", 
-            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN", 
-            "YXNrSAASPgoUc291cmNlX2NvbnRleHRfZmllbGQYBiABKAsyHi5nb29nbGUu", 
-            "cHJvdG9idWYuU291cmNlQ29udGV4dEgAEi8KDHN0cnVjdF9maWVsZBgHIAEo", 
-            "CzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIABI1Cg90aW1lc3RhbXBfZmll", 
-            "bGQYCCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAASKwoKdHlw", 
-            "ZV9maWVsZBgJIAEoCzIVLmdvb2dsZS5wcm90b2J1Zi5UeXBlSAASNAoMZG91", 
-            "YmxlX2ZpZWxkGAogASgLMhwuZ29vZ2xlLnByb3RvYnVmLkRvdWJsZVZhbHVl", 
-            "SAASMgoLZmxvYXRfZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxv", 
-            "YXRWYWx1ZUgAEjIKC2ludDY0X2ZpZWxkGAwgASgLMhsuZ29vZ2xlLnByb3Rv", 
-            "YnVmLkludDY0VmFsdWVIABI0Cgx1aW50NjRfZmllbGQYDSABKAsyHC5nb29n", 
-            "bGUucHJvdG9idWYuVUludDY0VmFsdWVIABIyCgtpbnQzMl9maWVsZBgOIAEo", 
-            "CzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlSAASNAoMdWludDMyX2Zp", 
-            "ZWxkGA8gASgLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlSAASMAoK", 
-            "Ym9vbF9maWVsZBgQIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5Cb29sVmFsdWVI", 
-            "ABI0CgxzdHJpbmdfZmllbGQYESABKAsyHC5nb29nbGUucHJvdG9idWYuU3Ry", 
-            "aW5nVmFsdWVIABIyCgtieXRlc19maWVsZBgSIAEoCzIbLmdvb2dsZS5wcm90", 
-            "b2J1Zi5CeXRlc1ZhbHVlSABCDQoLb25lb2ZfZmllbGQilhYKEU1hcFdlbGxL", 
-            "bm93blR5cGVzEkUKCWFueV9maWVsZBgBIAMoCzIyLnByb3RvYnVmX3VuaXR0", 
-            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkFueUZpZWxkRW50cnkSRQoJYXBpX2Zp", 
-            "ZWxkGAIgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlw", 
-            "ZXMuQXBpRmllbGRFbnRyeRJPCg5kdXJhdGlvbl9maWVsZBgDIAMoCzI3LnBy", 
-            "b3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkR1cmF0aW9uRmll", 
-            "bGRFbnRyeRJJCgtlbXB0eV9maWVsZBgEIAMoCzI0LnByb3RvYnVmX3VuaXR0", 
-            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkVtcHR5RmllbGRFbnRyeRJSChBmaWVs", 
-            "ZF9tYXNrX2ZpZWxkGAUgAygLMjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs", 
-            "bEtub3duVHlwZXMuRmllbGRNYXNrRmllbGRFbnRyeRJaChRzb3VyY2VfY29u", 
-            "dGV4dF9maWVsZBgGIAMoCzI8LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxL", 
-            "bm93blR5cGVzLlNvdXJjZUNvbnRleHRGaWVsZEVudHJ5EksKDHN0cnVjdF9m", 
-            "aWVsZBgHIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5", 
-            "cGVzLlN0cnVjdEZpZWxkRW50cnkSUQoPdGltZXN0YW1wX2ZpZWxkGAggAygL", 
-            "MjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVGltZXN0", 
-            "YW1wRmllbGRFbnRyeRJHCgp0eXBlX2ZpZWxkGAkgAygLMjMucHJvdG9idWZf", 
-            "dW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVHlwZUZpZWxkRW50cnkSSwoM", 
-            "ZG91YmxlX2ZpZWxkGAogAygLMjUucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs", 
-            "bEtub3duVHlwZXMuRG91YmxlRmllbGRFbnRyeRJJCgtmbG9hdF9maWVsZBgL", 
-            "IAMoCzI0LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkZs", 
-            "b2F0RmllbGRFbnRyeRJJCgtpbnQ2NF9maWVsZBgMIAMoCzI0LnByb3RvYnVm", 
-            "X3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkludDY0RmllbGRFbnRyeRJL", 
-            "Cgx1aW50NjRfZmllbGQYDSADKAsyNS5wcm90b2J1Zl91bml0dGVzdC5NYXBX", 
-            "ZWxsS25vd25UeXBlcy5VaW50NjRGaWVsZEVudHJ5EkkKC2ludDMyX2ZpZWxk", 
-            "GA4gAygLMjQucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMu", 
-            "SW50MzJGaWVsZEVudHJ5EksKDHVpbnQzMl9maWVsZBgPIAMoCzI1LnByb3Rv", 
-            "YnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLlVpbnQzMkZpZWxkRW50", 
-            "cnkSRwoKYm9vbF9maWVsZBgQIAMoCzIzLnByb3RvYnVmX3VuaXR0ZXN0Lk1h", 
-            "cFdlbGxLbm93blR5cGVzLkJvb2xGaWVsZEVudHJ5EksKDHN0cmluZ19maWVs", 
-            "ZBgRIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVz", 
-            "LlN0cmluZ0ZpZWxkRW50cnkSSQoLYnl0ZXNfZmllbGQYEiADKAsyNC5wcm90", 
-            "b2J1Zl91bml0dGVzdC5NYXBXZWxsS25vd25UeXBlcy5CeXRlc0ZpZWxkRW50", 
-            "cnkaRQoNQW55RmllbGRFbnRyeRILCgNrZXkYASABKAUSIwoFdmFsdWUYAiAB", 
-            "KAsyFC5nb29nbGUucHJvdG9idWYuQW55OgI4ARpFCg1BcGlGaWVsZEVudHJ5", 
-            "EgsKA2tleRgBIAEoBRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5wcm90b2J1", 
-            "Zi5BcGk6AjgBGk8KEkR1cmF0aW9uRmllbGRFbnRyeRILCgNrZXkYASABKAUS", 
-            "KAoFdmFsdWUYAiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb246AjgB", 
-            "GkkKD0VtcHR5RmllbGRFbnRyeRILCgNrZXkYASABKAUSJQoFdmFsdWUYAiAB", 
-            "KAsyFi5nb29nbGUucHJvdG9idWYuRW1wdHk6AjgBGlEKE0ZpZWxkTWFza0Zp", 
-            "ZWxkRW50cnkSCwoDa2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xl", 
-            "LnByb3RvYnVmLkZpZWxkTWFzazoCOAEaWQoXU291cmNlQ29udGV4dEZpZWxk", 
-            "RW50cnkSCwoDa2V5GAEgASgFEi0KBXZhbHVlGAIgASgLMh4uZ29vZ2xlLnBy", 
-            "b3RvYnVmLlNvdXJjZUNvbnRleHQ6AjgBGksKEFN0cnVjdEZpZWxkRW50cnkS", 
-            "CwoDa2V5GAEgASgFEiYKBXZhbHVlGAIgASgLMhcuZ29vZ2xlLnByb3RvYnVm", 
-            "LlN0cnVjdDoCOAEaUQoTVGltZXN0YW1wRmllbGRFbnRyeRILCgNrZXkYASAB", 
-            "KAUSKQoFdmFsdWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w", 
-            "OgI4ARpHCg5UeXBlRmllbGRFbnRyeRILCgNrZXkYASABKAUSJAoFdmFsdWUY", 
-            "AiABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZToCOAEaUAoQRG91YmxlRmll", 
-            "bGRFbnRyeRILCgNrZXkYASABKAUSKwoFdmFsdWUYAiABKAsyHC5nb29nbGUu", 
-            "cHJvdG9idWYuRG91YmxlVmFsdWU6AjgBGk4KD0Zsb2F0RmllbGRFbnRyeRIL", 
-            "CgNrZXkYASABKAUSKgoFdmFsdWUYAiABKAsyGy5nb29nbGUucHJvdG9idWYu", 
-            "RmxvYXRWYWx1ZToCOAEaTgoPSW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEo", 
-            "BRIqCgV2YWx1ZRgCIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl", 
-            "OgI4ARpQChBVaW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1", 
-            "ZRgCIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZToCOAEaTgoP", 
-            "SW50MzJGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIqCgV2YWx1ZRgCIAEoCzIb", 
-            "Lmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlOgI4ARpQChBVaW50MzJGaWVs", 
-            "ZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1ZRgCIAEoCzIcLmdvb2dsZS5w", 
-            "cm90b2J1Zi5VSW50MzJWYWx1ZToCOAEaTAoOQm9vbEZpZWxkRW50cnkSCwoD", 
-            "a2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkJv", 
-            "b2xWYWx1ZToCOAEaUAoQU3RyaW5nRmllbGRFbnRyeRILCgNrZXkYASABKAUS", 
-            "KwoFdmFsdWUYAiABKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWU6", 
-            "AjgBGk4KD0J5dGVzRmllbGRFbnRyeRILCgNrZXkYASABKAUSKgoFdmFsdWUY", 
-            "AiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZToCOAFCOQoYY29t", 
-            "Lmdvb2dsZS5wcm90b2J1Zi50ZXN0UAGqAhpHb29nbGUuUHJvdG9idWYuVGVz", 
+            "Ci9nb29nbGUvcHJvdG9idWYvdW5pdHRlc3Rfd2VsbF9rbm93bl90eXBlcy5w",
+            "cm90bxIRcHJvdG9idWZfdW5pdHRlc3QaGWdvb2dsZS9wcm90b2J1Zi9hbnku",
+            "cHJvdG8aGWdvb2dsZS9wcm90b2J1Zi9hcGkucHJvdG8aHmdvb2dsZS9wcm90",
+            "b2J1Zi9kdXJhdGlvbi5wcm90bxobZ29vZ2xlL3Byb3RvYnVmL2VtcHR5LnBy",
+            "b3RvGiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxokZ29vZ2xl",
+            "L3Byb3RvYnVmL3NvdXJjZV9jb250ZXh0LnByb3RvGhxnb29nbGUvcHJvdG9i",
+            "dWYvc3RydWN0LnByb3RvGh9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnBy",
+            "b3RvGhpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxoeZ29vZ2xlL3Byb3Rv",
+            "YnVmL3dyYXBwZXJzLnByb3RvIr4HChJUZXN0V2VsbEtub3duVHlwZXMSJwoJ",
+            "YW55X2ZpZWxkGAEgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueRInCglhcGlf",
+            "ZmllbGQYAiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpEjEKDmR1cmF0aW9u",
+            "X2ZpZWxkGAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uEisKC2Vt",
+            "cHR5X2ZpZWxkGAQgASgLMhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5EjQKEGZp",
+            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN",
+            "YXNrEjwKFHNvdXJjZV9jb250ZXh0X2ZpZWxkGAYgASgLMh4uZ29vZ2xlLnBy",
+            "b3RvYnVmLlNvdXJjZUNvbnRleHQSLQoMc3RydWN0X2ZpZWxkGAcgASgLMhcu",
+            "Z29vZ2xlLnByb3RvYnVmLlN0cnVjdBIzCg90aW1lc3RhbXBfZmllbGQYCCAB",
+            "KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEikKCnR5cGVfZmllbGQY",
+            "CSABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZRIyCgxkb3VibGVfZmllbGQY",
+            "CiABKAsyHC5nb29nbGUucHJvdG9idWYuRG91YmxlVmFsdWUSMAoLZmxvYXRf",
+            "ZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxvYXRWYWx1ZRIwCgtp",
+            "bnQ2NF9maWVsZBgMIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl",
+            "EjIKDHVpbnQ2NF9maWVsZBgNIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50",
+            "NjRWYWx1ZRIwCgtpbnQzMl9maWVsZBgOIAEoCzIbLmdvb2dsZS5wcm90b2J1",
+            "Zi5JbnQzMlZhbHVlEjIKDHVpbnQzMl9maWVsZBgPIAEoCzIcLmdvb2dsZS5w",
+            "cm90b2J1Zi5VSW50MzJWYWx1ZRIuCgpib29sX2ZpZWxkGBAgASgLMhouZ29v",
+            "Z2xlLnByb3RvYnVmLkJvb2xWYWx1ZRIyCgxzdHJpbmdfZmllbGQYESABKAsy",
+            "HC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWUSMAoLYnl0ZXNfZmllbGQY",
+            "EiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZRIrCgt2YWx1ZV9m",
+            "aWVsZBgTIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSKVBwoWUmVwZWF0",
+            "ZWRXZWxsS25vd25UeXBlcxInCglhbnlfZmllbGQYASADKAsyFC5nb29nbGUu",
+            "cHJvdG9idWYuQW55EicKCWFwaV9maWVsZBgCIAMoCzIULmdvb2dsZS5wcm90",
+            "b2J1Zi5BcGkSMQoOZHVyYXRpb25fZmllbGQYAyADKAsyGS5nb29nbGUucHJv",
+            "dG9idWYuRHVyYXRpb24SKwoLZW1wdHlfZmllbGQYBCADKAsyFi5nb29nbGUu",
+            "cHJvdG9idWYuRW1wdHkSNAoQZmllbGRfbWFza19maWVsZBgFIAMoCzIaLmdv",
+            "b2dsZS5wcm90b2J1Zi5GaWVsZE1hc2sSPAoUc291cmNlX2NvbnRleHRfZmll",
+            "bGQYBiADKAsyHi5nb29nbGUucHJvdG9idWYuU291cmNlQ29udGV4dBItCgxz",
+            "dHJ1Y3RfZmllbGQYByADKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EjMK",
+            "D3RpbWVzdGFtcF9maWVsZBgIIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1l",
+            "c3RhbXASKQoKdHlwZV9maWVsZBgJIAMoCzIVLmdvb2dsZS5wcm90b2J1Zi5U",
+            "eXBlEjIKDGRvdWJsZV9maWVsZBgKIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5E",
+            "b3VibGVWYWx1ZRIwCgtmbG9hdF9maWVsZBgLIAMoCzIbLmdvb2dsZS5wcm90",
+            "b2J1Zi5GbG9hdFZhbHVlEjAKC2ludDY0X2ZpZWxkGAwgAygLMhsuZ29vZ2xl",
+            "LnByb3RvYnVmLkludDY0VmFsdWUSMgoMdWludDY0X2ZpZWxkGA0gAygLMhwu",
+            "Z29vZ2xlLnByb3RvYnVmLlVJbnQ2NFZhbHVlEjAKC2ludDMyX2ZpZWxkGA4g",
+            "AygLMhsuZ29vZ2xlLnByb3RvYnVmLkludDMyVmFsdWUSMgoMdWludDMyX2Zp",
+            "ZWxkGA8gAygLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlEi4KCmJv",
+            "b2xfZmllbGQYECADKAsyGi5nb29nbGUucHJvdG9idWYuQm9vbFZhbHVlEjIK",
+            "DHN0cmluZ19maWVsZBgRIAMoCzIcLmdvb2dsZS5wcm90b2J1Zi5TdHJpbmdW",
+            "YWx1ZRIwCgtieXRlc19maWVsZBgSIAMoCzIbLmdvb2dsZS5wcm90b2J1Zi5C",
+            "eXRlc1ZhbHVlIsUHChNPbmVvZldlbGxLbm93blR5cGVzEikKCWFueV9maWVs",
+            "ZBgBIAEoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlIABIpCglhcGlfZmllbGQY",
+            "AiABKAsyFC5nb29nbGUucHJvdG9idWYuQXBpSAASMwoOZHVyYXRpb25fZmll",
+            "bGQYAyABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25IABItCgtlbXB0",
+            "eV9maWVsZBgEIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5FbXB0eUgAEjYKEGZp",
+            "ZWxkX21hc2tfZmllbGQYBSABKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRN",
+            "YXNrSAASPgoUc291cmNlX2NvbnRleHRfZmllbGQYBiABKAsyHi5nb29nbGUu",
+            "cHJvdG9idWYuU291cmNlQ29udGV4dEgAEi8KDHN0cnVjdF9maWVsZBgHIAEo",
+            "CzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RIABI1Cg90aW1lc3RhbXBfZmll",
+            "bGQYCCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAASKwoKdHlw",
+            "ZV9maWVsZBgJIAEoCzIVLmdvb2dsZS5wcm90b2J1Zi5UeXBlSAASNAoMZG91",
+            "YmxlX2ZpZWxkGAogASgLMhwuZ29vZ2xlLnByb3RvYnVmLkRvdWJsZVZhbHVl",
+            "SAASMgoLZmxvYXRfZmllbGQYCyABKAsyGy5nb29nbGUucHJvdG9idWYuRmxv",
+            "YXRWYWx1ZUgAEjIKC2ludDY0X2ZpZWxkGAwgASgLMhsuZ29vZ2xlLnByb3Rv",
+            "YnVmLkludDY0VmFsdWVIABI0Cgx1aW50NjRfZmllbGQYDSABKAsyHC5nb29n",
+            "bGUucHJvdG9idWYuVUludDY0VmFsdWVIABIyCgtpbnQzMl9maWVsZBgOIAEo",
+            "CzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlSAASNAoMdWludDMyX2Zp",
+            "ZWxkGA8gASgLMhwuZ29vZ2xlLnByb3RvYnVmLlVJbnQzMlZhbHVlSAASMAoK",
+            "Ym9vbF9maWVsZBgQIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5Cb29sVmFsdWVI",
+            "ABI0CgxzdHJpbmdfZmllbGQYESABKAsyHC5nb29nbGUucHJvdG9idWYuU3Ry",
+            "aW5nVmFsdWVIABIyCgtieXRlc19maWVsZBgSIAEoCzIbLmdvb2dsZS5wcm90",
+            "b2J1Zi5CeXRlc1ZhbHVlSABCDQoLb25lb2ZfZmllbGQilhYKEU1hcFdlbGxL",
+            "bm93blR5cGVzEkUKCWFueV9maWVsZBgBIAMoCzIyLnByb3RvYnVmX3VuaXR0",
+            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkFueUZpZWxkRW50cnkSRQoJYXBpX2Zp",
+            "ZWxkGAIgAygLMjIucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlw",
+            "ZXMuQXBpRmllbGRFbnRyeRJPCg5kdXJhdGlvbl9maWVsZBgDIAMoCzI3LnBy",
+            "b3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkR1cmF0aW9uRmll",
+            "bGRFbnRyeRJJCgtlbXB0eV9maWVsZBgEIAMoCzI0LnByb3RvYnVmX3VuaXR0",
+            "ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkVtcHR5RmllbGRFbnRyeRJSChBmaWVs",
+            "ZF9tYXNrX2ZpZWxkGAUgAygLMjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs",
+            "bEtub3duVHlwZXMuRmllbGRNYXNrRmllbGRFbnRyeRJaChRzb3VyY2VfY29u",
+            "dGV4dF9maWVsZBgGIAMoCzI8LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxL",
+            "bm93blR5cGVzLlNvdXJjZUNvbnRleHRGaWVsZEVudHJ5EksKDHN0cnVjdF9m",
+            "aWVsZBgHIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5",
+            "cGVzLlN0cnVjdEZpZWxkRW50cnkSUQoPdGltZXN0YW1wX2ZpZWxkGAggAygL",
+            "MjgucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVGltZXN0",
+            "YW1wRmllbGRFbnRyeRJHCgp0eXBlX2ZpZWxkGAkgAygLMjMucHJvdG9idWZf",
+            "dW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMuVHlwZUZpZWxkRW50cnkSSwoM",
+            "ZG91YmxlX2ZpZWxkGAogAygLMjUucHJvdG9idWZfdW5pdHRlc3QuTWFwV2Vs",
+            "bEtub3duVHlwZXMuRG91YmxlRmllbGRFbnRyeRJJCgtmbG9hdF9maWVsZBgL",
+            "IAMoCzI0LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkZs",
+            "b2F0RmllbGRFbnRyeRJJCgtpbnQ2NF9maWVsZBgMIAMoCzI0LnByb3RvYnVm",
+            "X3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLkludDY0RmllbGRFbnRyeRJL",
+            "Cgx1aW50NjRfZmllbGQYDSADKAsyNS5wcm90b2J1Zl91bml0dGVzdC5NYXBX",
+            "ZWxsS25vd25UeXBlcy5VaW50NjRGaWVsZEVudHJ5EkkKC2ludDMyX2ZpZWxk",
+            "GA4gAygLMjQucHJvdG9idWZfdW5pdHRlc3QuTWFwV2VsbEtub3duVHlwZXMu",
+            "SW50MzJGaWVsZEVudHJ5EksKDHVpbnQzMl9maWVsZBgPIAMoCzI1LnByb3Rv",
+            "YnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVzLlVpbnQzMkZpZWxkRW50",
+            "cnkSRwoKYm9vbF9maWVsZBgQIAMoCzIzLnByb3RvYnVmX3VuaXR0ZXN0Lk1h",
+            "cFdlbGxLbm93blR5cGVzLkJvb2xGaWVsZEVudHJ5EksKDHN0cmluZ19maWVs",
+            "ZBgRIAMoCzI1LnByb3RvYnVmX3VuaXR0ZXN0Lk1hcFdlbGxLbm93blR5cGVz",
+            "LlN0cmluZ0ZpZWxkRW50cnkSSQoLYnl0ZXNfZmllbGQYEiADKAsyNC5wcm90",
+            "b2J1Zl91bml0dGVzdC5NYXBXZWxsS25vd25UeXBlcy5CeXRlc0ZpZWxkRW50",
+            "cnkaRQoNQW55RmllbGRFbnRyeRILCgNrZXkYASABKAUSIwoFdmFsdWUYAiAB",
+            "KAsyFC5nb29nbGUucHJvdG9idWYuQW55OgI4ARpFCg1BcGlGaWVsZEVudHJ5",
+            "EgsKA2tleRgBIAEoBRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5wcm90b2J1",
+            "Zi5BcGk6AjgBGk8KEkR1cmF0aW9uRmllbGRFbnRyeRILCgNrZXkYASABKAUS",
+            "KAoFdmFsdWUYAiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb246AjgB",
+            "GkkKD0VtcHR5RmllbGRFbnRyeRILCgNrZXkYASABKAUSJQoFdmFsdWUYAiAB",
+            "KAsyFi5nb29nbGUucHJvdG9idWYuRW1wdHk6AjgBGlEKE0ZpZWxkTWFza0Zp",
+            "ZWxkRW50cnkSCwoDa2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xl",
+            "LnByb3RvYnVmLkZpZWxkTWFzazoCOAEaWQoXU291cmNlQ29udGV4dEZpZWxk",
+            "RW50cnkSCwoDa2V5GAEgASgFEi0KBXZhbHVlGAIgASgLMh4uZ29vZ2xlLnBy",
+            "b3RvYnVmLlNvdXJjZUNvbnRleHQ6AjgBGksKEFN0cnVjdEZpZWxkRW50cnkS",
+            "CwoDa2V5GAEgASgFEiYKBXZhbHVlGAIgASgLMhcuZ29vZ2xlLnByb3RvYnVm",
+            "LlN0cnVjdDoCOAEaUQoTVGltZXN0YW1wRmllbGRFbnRyeRILCgNrZXkYASAB",
+            "KAUSKQoFdmFsdWUYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1w",
+            "OgI4ARpHCg5UeXBlRmllbGRFbnRyeRILCgNrZXkYASABKAUSJAoFdmFsdWUY",
+            "AiABKAsyFS5nb29nbGUucHJvdG9idWYuVHlwZToCOAEaUAoQRG91YmxlRmll",
+            "bGRFbnRyeRILCgNrZXkYASABKAUSKwoFdmFsdWUYAiABKAsyHC5nb29nbGUu",
+            "cHJvdG9idWYuRG91YmxlVmFsdWU6AjgBGk4KD0Zsb2F0RmllbGRFbnRyeRIL",
+            "CgNrZXkYASABKAUSKgoFdmFsdWUYAiABKAsyGy5nb29nbGUucHJvdG9idWYu",
+            "RmxvYXRWYWx1ZToCOAEaTgoPSW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEo",
+            "BRIqCgV2YWx1ZRgCIAEoCzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQ2NFZhbHVl",
+            "OgI4ARpQChBVaW50NjRGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1",
+            "ZRgCIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5VSW50NjRWYWx1ZToCOAEaTgoP",
+            "SW50MzJGaWVsZEVudHJ5EgsKA2tleRgBIAEoBRIqCgV2YWx1ZRgCIAEoCzIb",
+            "Lmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlOgI4ARpQChBVaW50MzJGaWVs",
+            "ZEVudHJ5EgsKA2tleRgBIAEoBRIrCgV2YWx1ZRgCIAEoCzIcLmdvb2dsZS5w",
+            "cm90b2J1Zi5VSW50MzJWYWx1ZToCOAEaTAoOQm9vbEZpZWxkRW50cnkSCwoD",
+            "a2V5GAEgASgFEikKBXZhbHVlGAIgASgLMhouZ29vZ2xlLnByb3RvYnVmLkJv",
+            "b2xWYWx1ZToCOAEaUAoQU3RyaW5nRmllbGRFbnRyeRILCgNrZXkYASABKAUS",
+            "KwoFdmFsdWUYAiABKAsyHC5nb29nbGUucHJvdG9idWYuU3RyaW5nVmFsdWU6",
+            "AjgBGk4KD0J5dGVzRmllbGRFbnRyeRILCgNrZXkYASABKAUSKgoFdmFsdWUY",
+            "AiABKAsyGy5nb29nbGUucHJvdG9idWYuQnl0ZXNWYWx1ZToCOAFCOQoYY29t",
+            "Lmdvb2dsZS5wcm90b2J1Zi50ZXN0UAGqAhpHb29nbGUuUHJvdG9idWYuVGVz",
             "dFByb3Rvc2IGcHJvdG8z"));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.Proto.Any.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Api.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Duration.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Empty.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.FieldMask.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.SourceContext.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Struct.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Timestamp.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor, global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor, },
-          new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.TestWellKnownTypes), new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.RepeatedWellKnownTypes), new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.OneofWellKnownTypes), new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, new[]{ "OneofField" }, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.TestProtos.MapWellKnownTypes), new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, new pbr::GeneratedCodeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, })
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestWellKnownTypes), global::Google.Protobuf.TestProtos.TestWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField", "ValueField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.RepeatedWellKnownTypes), global::Google.Protobuf.TestProtos.RepeatedWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.OneofWellKnownTypes), global::Google.Protobuf.TestProtos.OneofWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, new[]{ "OneofField" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.MapWellKnownTypes), global::Google.Protobuf.TestProtos.MapWellKnownTypes.Parser, new[]{ "AnyField", "ApiField", "DurationField", "EmptyField", "FieldMaskField", "SourceContextField", "StructField", "TimestampField", "TypeField", "DoubleField", "FloatField", "Int64Field", "Uint64Field", "Int32Field", "Uint32Field", "BoolField", "StringField", "BytesField" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, })
           }));
     }
     #endregion
 
   }
   #region Messages
+  /// <summary>
+  ///  Test that we can include all well-known types.
+  ///  Each wrapper type is included separately, as languages
+  ///  map handle different wrappers in different ways.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class TestWellKnownTypes : pb::IMessage<TestWellKnownTypes> {
     private static readonly pb::MessageParser<TestWellKnownTypes> _parser = new pb::MessageParser<TestWellKnownTypes>(() => new TestWellKnownTypes());
     public static pb::MessageParser<TestWellKnownTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypes.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -208,12 +216,14 @@
       BoolField = other.BoolField;
       StringField = other.StringField;
       BytesField = other.BytesField;
+      ValueField = other.valueField_ != null ? other.ValueField.Clone() : null;
     }
 
     public TestWellKnownTypes Clone() {
       return new TestWellKnownTypes(this);
     }
 
+    /// <summary>Field number for the "any_field" field.</summary>
     public const int AnyFieldFieldNumber = 1;
     private global::Google.Protobuf.WellKnownTypes.Any anyField_;
     public global::Google.Protobuf.WellKnownTypes.Any AnyField {
@@ -223,6 +233,7 @@
       }
     }
 
+    /// <summary>Field number for the "api_field" field.</summary>
     public const int ApiFieldFieldNumber = 2;
     private global::Google.Protobuf.WellKnownTypes.Api apiField_;
     public global::Google.Protobuf.WellKnownTypes.Api ApiField {
@@ -232,6 +243,7 @@
       }
     }
 
+    /// <summary>Field number for the "duration_field" field.</summary>
     public const int DurationFieldFieldNumber = 3;
     private global::Google.Protobuf.WellKnownTypes.Duration durationField_;
     public global::Google.Protobuf.WellKnownTypes.Duration DurationField {
@@ -241,6 +253,7 @@
       }
     }
 
+    /// <summary>Field number for the "empty_field" field.</summary>
     public const int EmptyFieldFieldNumber = 4;
     private global::Google.Protobuf.WellKnownTypes.Empty emptyField_;
     public global::Google.Protobuf.WellKnownTypes.Empty EmptyField {
@@ -250,6 +263,7 @@
       }
     }
 
+    /// <summary>Field number for the "field_mask_field" field.</summary>
     public const int FieldMaskFieldFieldNumber = 5;
     private global::Google.Protobuf.WellKnownTypes.FieldMask fieldMaskField_;
     public global::Google.Protobuf.WellKnownTypes.FieldMask FieldMaskField {
@@ -259,6 +273,7 @@
       }
     }
 
+    /// <summary>Field number for the "source_context_field" field.</summary>
     public const int SourceContextFieldFieldNumber = 6;
     private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContextField_;
     public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContextField {
@@ -268,6 +283,7 @@
       }
     }
 
+    /// <summary>Field number for the "struct_field" field.</summary>
     public const int StructFieldFieldNumber = 7;
     private global::Google.Protobuf.WellKnownTypes.Struct structField_;
     public global::Google.Protobuf.WellKnownTypes.Struct StructField {
@@ -277,6 +293,7 @@
       }
     }
 
+    /// <summary>Field number for the "timestamp_field" field.</summary>
     public const int TimestampFieldFieldNumber = 8;
     private global::Google.Protobuf.WellKnownTypes.Timestamp timestampField_;
     public global::Google.Protobuf.WellKnownTypes.Timestamp TimestampField {
@@ -286,6 +303,7 @@
       }
     }
 
+    /// <summary>Field number for the "type_field" field.</summary>
     public const int TypeFieldFieldNumber = 9;
     private global::Google.Protobuf.WellKnownTypes.Type typeField_;
     public global::Google.Protobuf.WellKnownTypes.Type TypeField {
@@ -295,6 +313,7 @@
       }
     }
 
+    /// <summary>Field number for the "double_field" field.</summary>
     public const int DoubleFieldFieldNumber = 10;
     private static readonly pb::FieldCodec<double?> _single_doubleField_codec = pb::FieldCodec.ForStructWrapper<double>(82);
     private double? doubleField_;
@@ -305,6 +324,7 @@
       }
     }
 
+    /// <summary>Field number for the "float_field" field.</summary>
     public const int FloatFieldFieldNumber = 11;
     private static readonly pb::FieldCodec<float?> _single_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90);
     private float? floatField_;
@@ -315,6 +335,7 @@
       }
     }
 
+    /// <summary>Field number for the "int64_field" field.</summary>
     public const int Int64FieldFieldNumber = 12;
     private static readonly pb::FieldCodec<long?> _single_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98);
     private long? int64Field_;
@@ -325,6 +346,7 @@
       }
     }
 
+    /// <summary>Field number for the "uint64_field" field.</summary>
     public const int Uint64FieldFieldNumber = 13;
     private static readonly pb::FieldCodec<ulong?> _single_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106);
     private ulong? uint64Field_;
@@ -335,6 +357,7 @@
       }
     }
 
+    /// <summary>Field number for the "int32_field" field.</summary>
     public const int Int32FieldFieldNumber = 14;
     private static readonly pb::FieldCodec<int?> _single_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114);
     private int? int32Field_;
@@ -345,6 +368,7 @@
       }
     }
 
+    /// <summary>Field number for the "uint32_field" field.</summary>
     public const int Uint32FieldFieldNumber = 15;
     private static readonly pb::FieldCodec<uint?> _single_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122);
     private uint? uint32Field_;
@@ -355,6 +379,7 @@
       }
     }
 
+    /// <summary>Field number for the "bool_field" field.</summary>
     public const int BoolFieldFieldNumber = 16;
     private static readonly pb::FieldCodec<bool?> _single_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130);
     private bool? boolField_;
@@ -365,6 +390,7 @@
       }
     }
 
+    /// <summary>Field number for the "string_field" field.</summary>
     public const int StringFieldFieldNumber = 17;
     private static readonly pb::FieldCodec<string> _single_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138);
     private string stringField_;
@@ -375,6 +401,7 @@
       }
     }
 
+    /// <summary>Field number for the "bytes_field" field.</summary>
     public const int BytesFieldFieldNumber = 18;
     private static readonly pb::FieldCodec<pb::ByteString> _single_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
     private pb::ByteString bytesField_;
@@ -385,6 +412,19 @@
       }
     }
 
+    /// <summary>Field number for the "value_field" field.</summary>
+    public const int ValueFieldFieldNumber = 19;
+    private global::Google.Protobuf.WellKnownTypes.Value valueField_;
+    /// <summary>
+    ///  Part of struct, but useful to be able to test separately
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Value ValueField {
+      get { return valueField_; }
+      set {
+        valueField_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as TestWellKnownTypes);
     }
@@ -414,6 +454,7 @@
       if (BoolField != other.BoolField) return false;
       if (StringField != other.StringField) return false;
       if (BytesField != other.BytesField) return false;
+      if (!object.Equals(ValueField, other.ValueField)) return false;
       return true;
     }
 
@@ -437,11 +478,12 @@
       if (boolField_ != null) hash ^= BoolField.GetHashCode();
       if (stringField_ != null) hash ^= StringField.GetHashCode();
       if (bytesField_ != null) hash ^= BytesField.GetHashCode();
+      if (valueField_ != null) hash ^= ValueField.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -508,6 +550,10 @@
       if (bytesField_ != null) {
         _single_bytesField_codec.WriteTagAndValue(output, BytesField);
       }
+      if (valueField_ != null) {
+        output.WriteRawTag(154, 1);
+        output.WriteMessage(ValueField);
+      }
     }
 
     public int CalculateSize() {
@@ -566,6 +612,9 @@
       if (bytesField_ != null) {
         size += _single_bytesField_codec.CalculateSizeWithTag(BytesField);
       }
+      if (valueField_ != null) {
+        size += 2 + pb::CodedOutputStream.ComputeMessageSize(ValueField);
+      }
       return size;
     }
 
@@ -672,6 +721,12 @@
           BytesField = other.BytesField;
         }
       }
+      if (other.valueField_ != null) {
+        if (valueField_ == null) {
+          valueField_ = new global::Google.Protobuf.WellKnownTypes.Value();
+        }
+        ValueField.MergeFrom(other.ValueField);
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -807,19 +862,29 @@
             }
             break;
           }
+          case 154: {
+            if (valueField_ == null) {
+              valueField_ = new global::Google.Protobuf.WellKnownTypes.Value();
+            }
+            input.ReadMessage(valueField_);
+            break;
+          }
         }
       }
     }
 
   }
 
+  /// <summary>
+  ///  A repeated field for each well-known type.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class RepeatedWellKnownTypes : pb::IMessage<RepeatedWellKnownTypes> {
     private static readonly pb::MessageParser<RepeatedWellKnownTypes> _parser = new pb::MessageParser<RepeatedWellKnownTypes>(() => new RepeatedWellKnownTypes());
     public static pb::MessageParser<RepeatedWellKnownTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypes.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -857,6 +922,7 @@
       return new RepeatedWellKnownTypes(this);
     }
 
+    /// <summary>Field number for the "any_field" field.</summary>
     public const int AnyFieldFieldNumber = 1;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Any> _repeated_anyField_codec
         = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Any.Parser);
@@ -865,6 +931,7 @@
       get { return anyField_; }
     }
 
+    /// <summary>Field number for the "api_field" field.</summary>
     public const int ApiFieldFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Api> _repeated_apiField_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Api.Parser);
@@ -873,6 +940,7 @@
       get { return apiField_; }
     }
 
+    /// <summary>Field number for the "duration_field" field.</summary>
     public const int DurationFieldFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Duration> _repeated_durationField_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Duration.Parser);
@@ -881,6 +949,7 @@
       get { return durationField_; }
     }
 
+    /// <summary>Field number for the "empty_field" field.</summary>
     public const int EmptyFieldFieldNumber = 4;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Empty> _repeated_emptyField_codec
         = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Empty.Parser);
@@ -889,6 +958,7 @@
       get { return emptyField_; }
     }
 
+    /// <summary>Field number for the "field_mask_field" field.</summary>
     public const int FieldMaskFieldFieldNumber = 5;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.FieldMask> _repeated_fieldMaskField_codec
         = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser);
@@ -897,6 +967,7 @@
       get { return fieldMaskField_; }
     }
 
+    /// <summary>Field number for the "source_context_field" field.</summary>
     public const int SourceContextFieldFieldNumber = 6;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.SourceContext> _repeated_sourceContextField_codec
         = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.SourceContext.Parser);
@@ -905,6 +976,7 @@
       get { return sourceContextField_; }
     }
 
+    /// <summary>Field number for the "struct_field" field.</summary>
     public const int StructFieldFieldNumber = 7;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Struct> _repeated_structField_codec
         = pb::FieldCodec.ForMessage(58, global::Google.Protobuf.WellKnownTypes.Struct.Parser);
@@ -913,6 +985,7 @@
       get { return structField_; }
     }
 
+    /// <summary>Field number for the "timestamp_field" field.</summary>
     public const int TimestampFieldFieldNumber = 8;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Timestamp> _repeated_timestampField_codec
         = pb::FieldCodec.ForMessage(66, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser);
@@ -921,6 +994,7 @@
       get { return timestampField_; }
     }
 
+    /// <summary>Field number for the "type_field" field.</summary>
     public const int TypeFieldFieldNumber = 9;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Type> _repeated_typeField_codec
         = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Type.Parser);
@@ -929,14 +1003,19 @@
       get { return typeField_; }
     }
 
+    /// <summary>Field number for the "double_field" field.</summary>
     public const int DoubleFieldFieldNumber = 10;
     private static readonly pb::FieldCodec<double?> _repeated_doubleField_codec
         = pb::FieldCodec.ForStructWrapper<double>(82);
     private readonly pbc::RepeatedField<double?> doubleField_ = new pbc::RepeatedField<double?>();
+    /// <summary>
+    ///  These don't actually make a lot of sense, but they're not prohibited...
+    /// </summary>
     public pbc::RepeatedField<double?> DoubleField {
       get { return doubleField_; }
     }
 
+    /// <summary>Field number for the "float_field" field.</summary>
     public const int FloatFieldFieldNumber = 11;
     private static readonly pb::FieldCodec<float?> _repeated_floatField_codec
         = pb::FieldCodec.ForStructWrapper<float>(90);
@@ -945,6 +1024,7 @@
       get { return floatField_; }
     }
 
+    /// <summary>Field number for the "int64_field" field.</summary>
     public const int Int64FieldFieldNumber = 12;
     private static readonly pb::FieldCodec<long?> _repeated_int64Field_codec
         = pb::FieldCodec.ForStructWrapper<long>(98);
@@ -953,6 +1033,7 @@
       get { return int64Field_; }
     }
 
+    /// <summary>Field number for the "uint64_field" field.</summary>
     public const int Uint64FieldFieldNumber = 13;
     private static readonly pb::FieldCodec<ulong?> _repeated_uint64Field_codec
         = pb::FieldCodec.ForStructWrapper<ulong>(106);
@@ -961,6 +1042,7 @@
       get { return uint64Field_; }
     }
 
+    /// <summary>Field number for the "int32_field" field.</summary>
     public const int Int32FieldFieldNumber = 14;
     private static readonly pb::FieldCodec<int?> _repeated_int32Field_codec
         = pb::FieldCodec.ForStructWrapper<int>(114);
@@ -969,6 +1051,7 @@
       get { return int32Field_; }
     }
 
+    /// <summary>Field number for the "uint32_field" field.</summary>
     public const int Uint32FieldFieldNumber = 15;
     private static readonly pb::FieldCodec<uint?> _repeated_uint32Field_codec
         = pb::FieldCodec.ForStructWrapper<uint>(122);
@@ -977,6 +1060,7 @@
       get { return uint32Field_; }
     }
 
+    /// <summary>Field number for the "bool_field" field.</summary>
     public const int BoolFieldFieldNumber = 16;
     private static readonly pb::FieldCodec<bool?> _repeated_boolField_codec
         = pb::FieldCodec.ForStructWrapper<bool>(130);
@@ -985,6 +1069,7 @@
       get { return boolField_; }
     }
 
+    /// <summary>Field number for the "string_field" field.</summary>
     public const int StringFieldFieldNumber = 17;
     private static readonly pb::FieldCodec<string> _repeated_stringField_codec
         = pb::FieldCodec.ForClassWrapper<string>(138);
@@ -993,6 +1078,7 @@
       get { return stringField_; }
     }
 
+    /// <summary>Field number for the "bytes_field" field.</summary>
     public const int BytesFieldFieldNumber = 18;
     private static readonly pb::FieldCodec<pb::ByteString> _repeated_bytesField_codec
         = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
@@ -1057,7 +1143,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1219,7 +1305,7 @@
     public static pb::MessageParser<OneofWellKnownTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypes.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1296,6 +1382,7 @@
       return new OneofWellKnownTypes(this);
     }
 
+    /// <summary>Field number for the "any_field" field.</summary>
     public const int AnyFieldFieldNumber = 1;
     public global::Google.Protobuf.WellKnownTypes.Any AnyField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.AnyField ? (global::Google.Protobuf.WellKnownTypes.Any) oneofField_ : null; }
@@ -1305,6 +1392,7 @@
       }
     }
 
+    /// <summary>Field number for the "api_field" field.</summary>
     public const int ApiFieldFieldNumber = 2;
     public global::Google.Protobuf.WellKnownTypes.Api ApiField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.ApiField ? (global::Google.Protobuf.WellKnownTypes.Api) oneofField_ : null; }
@@ -1314,6 +1402,7 @@
       }
     }
 
+    /// <summary>Field number for the "duration_field" field.</summary>
     public const int DurationFieldFieldNumber = 3;
     public global::Google.Protobuf.WellKnownTypes.Duration DurationField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.DurationField ? (global::Google.Protobuf.WellKnownTypes.Duration) oneofField_ : null; }
@@ -1323,6 +1412,7 @@
       }
     }
 
+    /// <summary>Field number for the "empty_field" field.</summary>
     public const int EmptyFieldFieldNumber = 4;
     public global::Google.Protobuf.WellKnownTypes.Empty EmptyField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.EmptyField ? (global::Google.Protobuf.WellKnownTypes.Empty) oneofField_ : null; }
@@ -1332,6 +1422,7 @@
       }
     }
 
+    /// <summary>Field number for the "field_mask_field" field.</summary>
     public const int FieldMaskFieldFieldNumber = 5;
     public global::Google.Protobuf.WellKnownTypes.FieldMask FieldMaskField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.FieldMaskField ? (global::Google.Protobuf.WellKnownTypes.FieldMask) oneofField_ : null; }
@@ -1341,6 +1432,7 @@
       }
     }
 
+    /// <summary>Field number for the "source_context_field" field.</summary>
     public const int SourceContextFieldFieldNumber = 6;
     public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContextField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.SourceContextField ? (global::Google.Protobuf.WellKnownTypes.SourceContext) oneofField_ : null; }
@@ -1350,6 +1442,7 @@
       }
     }
 
+    /// <summary>Field number for the "struct_field" field.</summary>
     public const int StructFieldFieldNumber = 7;
     public global::Google.Protobuf.WellKnownTypes.Struct StructField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.StructField ? (global::Google.Protobuf.WellKnownTypes.Struct) oneofField_ : null; }
@@ -1359,6 +1452,7 @@
       }
     }
 
+    /// <summary>Field number for the "timestamp_field" field.</summary>
     public const int TimestampFieldFieldNumber = 8;
     public global::Google.Protobuf.WellKnownTypes.Timestamp TimestampField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.TimestampField ? (global::Google.Protobuf.WellKnownTypes.Timestamp) oneofField_ : null; }
@@ -1368,6 +1462,7 @@
       }
     }
 
+    /// <summary>Field number for the "type_field" field.</summary>
     public const int TypeFieldFieldNumber = 9;
     public global::Google.Protobuf.WellKnownTypes.Type TypeField {
       get { return oneofFieldCase_ == OneofFieldOneofCase.TypeField ? (global::Google.Protobuf.WellKnownTypes.Type) oneofField_ : null; }
@@ -1377,6 +1472,7 @@
       }
     }
 
+    /// <summary>Field number for the "double_field" field.</summary>
     public const int DoubleFieldFieldNumber = 10;
     private static readonly pb::FieldCodec<double?> _oneof_doubleField_codec = pb::FieldCodec.ForStructWrapper<double>(82);
     public double? DoubleField {
@@ -1387,6 +1483,7 @@
       }
     }
 
+    /// <summary>Field number for the "float_field" field.</summary>
     public const int FloatFieldFieldNumber = 11;
     private static readonly pb::FieldCodec<float?> _oneof_floatField_codec = pb::FieldCodec.ForStructWrapper<float>(90);
     public float? FloatField {
@@ -1397,6 +1494,7 @@
       }
     }
 
+    /// <summary>Field number for the "int64_field" field.</summary>
     public const int Int64FieldFieldNumber = 12;
     private static readonly pb::FieldCodec<long?> _oneof_int64Field_codec = pb::FieldCodec.ForStructWrapper<long>(98);
     public long? Int64Field {
@@ -1407,6 +1505,7 @@
       }
     }
 
+    /// <summary>Field number for the "uint64_field" field.</summary>
     public const int Uint64FieldFieldNumber = 13;
     private static readonly pb::FieldCodec<ulong?> _oneof_uint64Field_codec = pb::FieldCodec.ForStructWrapper<ulong>(106);
     public ulong? Uint64Field {
@@ -1417,6 +1516,7 @@
       }
     }
 
+    /// <summary>Field number for the "int32_field" field.</summary>
     public const int Int32FieldFieldNumber = 14;
     private static readonly pb::FieldCodec<int?> _oneof_int32Field_codec = pb::FieldCodec.ForStructWrapper<int>(114);
     public int? Int32Field {
@@ -1427,6 +1527,7 @@
       }
     }
 
+    /// <summary>Field number for the "uint32_field" field.</summary>
     public const int Uint32FieldFieldNumber = 15;
     private static readonly pb::FieldCodec<uint?> _oneof_uint32Field_codec = pb::FieldCodec.ForStructWrapper<uint>(122);
     public uint? Uint32Field {
@@ -1437,6 +1538,7 @@
       }
     }
 
+    /// <summary>Field number for the "bool_field" field.</summary>
     public const int BoolFieldFieldNumber = 16;
     private static readonly pb::FieldCodec<bool?> _oneof_boolField_codec = pb::FieldCodec.ForStructWrapper<bool>(130);
     public bool? BoolField {
@@ -1447,6 +1549,7 @@
       }
     }
 
+    /// <summary>Field number for the "string_field" field.</summary>
     public const int StringFieldFieldNumber = 17;
     private static readonly pb::FieldCodec<string> _oneof_stringField_codec = pb::FieldCodec.ForClassWrapper<string>(138);
     public string StringField {
@@ -1457,6 +1560,7 @@
       }
     }
 
+    /// <summary>Field number for the "bytes_field" field.</summary>
     public const int BytesFieldFieldNumber = 18;
     private static readonly pb::FieldCodec<pb::ByteString> _oneof_bytesField_codec = pb::FieldCodec.ForClassWrapper<pb::ByteString>(146);
     public pb::ByteString BytesField {
@@ -1468,6 +1572,7 @@
     }
 
     private object oneofField_;
+    /// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
     public enum OneofFieldOneofCase {
       None = 0,
       AnyField = 1,
@@ -1528,6 +1633,7 @@
       if (BoolField != other.BoolField) return false;
       if (StringField != other.StringField) return false;
       if (BytesField != other.BytesField) return false;
+      if (OneofFieldCase != other.OneofFieldCase) return false;
       return true;
     }
 
@@ -1551,11 +1657,12 @@
       if (oneofFieldCase_ == OneofFieldOneofCase.BoolField) hash ^= BoolField.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.StringField) hash ^= StringField.GetHashCode();
       if (oneofFieldCase_ == OneofFieldOneofCase.BytesField) hash ^= BytesField.GetHashCode();
+      hash ^= (int) oneofFieldCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1876,13 +1983,18 @@
 
   }
 
+  /// <summary>
+  ///  A map field for each well-known type. We only
+  ///  need to worry about the value part of the map being the
+  ///  well-known types, as messages can't be map keys.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class MapWellKnownTypes : pb::IMessage<MapWellKnownTypes> {
     private static readonly pb::MessageParser<MapWellKnownTypes> _parser = new pb::MessageParser<MapWellKnownTypes>(() => new MapWellKnownTypes());
     public static pb::MessageParser<MapWellKnownTypes> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypes.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.TestProtos.UnittestWellKnownTypesReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1920,6 +2032,7 @@
       return new MapWellKnownTypes(this);
     }
 
+    /// <summary>Field number for the "any_field" field.</summary>
     public const int AnyFieldFieldNumber = 1;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any>.Codec _map_anyField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Any>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Any.Parser), 10);
@@ -1928,6 +2041,7 @@
       get { return anyField_; }
     }
 
+    /// <summary>Field number for the "api_field" field.</summary>
     public const int ApiFieldFieldNumber = 2;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api>.Codec _map_apiField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Api>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Api.Parser), 18);
@@ -1936,6 +2050,7 @@
       get { return apiField_; }
     }
 
+    /// <summary>Field number for the "duration_field" field.</summary>
     public const int DurationFieldFieldNumber = 3;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration>.Codec _map_durationField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Duration>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Duration.Parser), 26);
@@ -1944,6 +2059,7 @@
       get { return durationField_; }
     }
 
+    /// <summary>Field number for the "empty_field" field.</summary>
     public const int EmptyFieldFieldNumber = 4;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty>.Codec _map_emptyField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Empty>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Empty.Parser), 34);
@@ -1952,6 +2068,7 @@
       get { return emptyField_; }
     }
 
+    /// <summary>Field number for the "field_mask_field" field.</summary>
     public const int FieldMaskFieldFieldNumber = 5;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask>.Codec _map_fieldMaskField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.FieldMask>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.FieldMask.Parser), 42);
@@ -1960,6 +2077,7 @@
       get { return fieldMaskField_; }
     }
 
+    /// <summary>Field number for the "source_context_field" field.</summary>
     public const int SourceContextFieldFieldNumber = 6;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext>.Codec _map_sourceContextField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.SourceContext>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.SourceContext.Parser), 50);
@@ -1968,6 +2086,7 @@
       get { return sourceContextField_; }
     }
 
+    /// <summary>Field number for the "struct_field" field.</summary>
     public const int StructFieldFieldNumber = 7;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct>.Codec _map_structField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Struct>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Struct.Parser), 58);
@@ -1976,6 +2095,7 @@
       get { return structField_; }
     }
 
+    /// <summary>Field number for the "timestamp_field" field.</summary>
     public const int TimestampFieldFieldNumber = 8;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp>.Codec _map_timestampField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Timestamp>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Timestamp.Parser), 66);
@@ -1984,6 +2104,7 @@
       get { return timestampField_; }
     }
 
+    /// <summary>Field number for the "type_field" field.</summary>
     public const int TypeFieldFieldNumber = 9;
     private static readonly pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type>.Codec _map_typeField_codec
         = new pbc::MapField<int, global::Google.Protobuf.WellKnownTypes.Type>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Type.Parser), 74);
@@ -1992,74 +2113,83 @@
       get { return typeField_; }
     }
 
+    /// <summary>Field number for the "double_field" field.</summary>
     public const int DoubleFieldFieldNumber = 10;
     private static readonly pbc::MapField<int, double?>.Codec _map_doubleField_codec
         = new pbc::MapField<int, double?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<double>(18), 82);
-    private readonly pbc::MapField<int, double?> doubleField_ = new pbc::MapField<int, double?>(true);
+    private readonly pbc::MapField<int, double?> doubleField_ = new pbc::MapField<int, double?>();
     public pbc::MapField<int, double?> DoubleField {
       get { return doubleField_; }
     }
 
+    /// <summary>Field number for the "float_field" field.</summary>
     public const int FloatFieldFieldNumber = 11;
     private static readonly pbc::MapField<int, float?>.Codec _map_floatField_codec
         = new pbc::MapField<int, float?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<float>(18), 90);
-    private readonly pbc::MapField<int, float?> floatField_ = new pbc::MapField<int, float?>(true);
+    private readonly pbc::MapField<int, float?> floatField_ = new pbc::MapField<int, float?>();
     public pbc::MapField<int, float?> FloatField {
       get { return floatField_; }
     }
 
+    /// <summary>Field number for the "int64_field" field.</summary>
     public const int Int64FieldFieldNumber = 12;
     private static readonly pbc::MapField<int, long?>.Codec _map_int64Field_codec
         = new pbc::MapField<int, long?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<long>(18), 98);
-    private readonly pbc::MapField<int, long?> int64Field_ = new pbc::MapField<int, long?>(true);
+    private readonly pbc::MapField<int, long?> int64Field_ = new pbc::MapField<int, long?>();
     public pbc::MapField<int, long?> Int64Field {
       get { return int64Field_; }
     }
 
+    /// <summary>Field number for the "uint64_field" field.</summary>
     public const int Uint64FieldFieldNumber = 13;
     private static readonly pbc::MapField<int, ulong?>.Codec _map_uint64Field_codec
         = new pbc::MapField<int, ulong?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<ulong>(18), 106);
-    private readonly pbc::MapField<int, ulong?> uint64Field_ = new pbc::MapField<int, ulong?>(true);
+    private readonly pbc::MapField<int, ulong?> uint64Field_ = new pbc::MapField<int, ulong?>();
     public pbc::MapField<int, ulong?> Uint64Field {
       get { return uint64Field_; }
     }
 
+    /// <summary>Field number for the "int32_field" field.</summary>
     public const int Int32FieldFieldNumber = 14;
     private static readonly pbc::MapField<int, int?>.Codec _map_int32Field_codec
         = new pbc::MapField<int, int?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<int>(18), 114);
-    private readonly pbc::MapField<int, int?> int32Field_ = new pbc::MapField<int, int?>(true);
+    private readonly pbc::MapField<int, int?> int32Field_ = new pbc::MapField<int, int?>();
     public pbc::MapField<int, int?> Int32Field {
       get { return int32Field_; }
     }
 
+    /// <summary>Field number for the "uint32_field" field.</summary>
     public const int Uint32FieldFieldNumber = 15;
     private static readonly pbc::MapField<int, uint?>.Codec _map_uint32Field_codec
         = new pbc::MapField<int, uint?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<uint>(18), 122);
-    private readonly pbc::MapField<int, uint?> uint32Field_ = new pbc::MapField<int, uint?>(true);
+    private readonly pbc::MapField<int, uint?> uint32Field_ = new pbc::MapField<int, uint?>();
     public pbc::MapField<int, uint?> Uint32Field {
       get { return uint32Field_; }
     }
 
+    /// <summary>Field number for the "bool_field" field.</summary>
     public const int BoolFieldFieldNumber = 16;
     private static readonly pbc::MapField<int, bool?>.Codec _map_boolField_codec
         = new pbc::MapField<int, bool?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<bool>(18), 130);
-    private readonly pbc::MapField<int, bool?> boolField_ = new pbc::MapField<int, bool?>(true);
+    private readonly pbc::MapField<int, bool?> boolField_ = new pbc::MapField<int, bool?>();
     public pbc::MapField<int, bool?> BoolField {
       get { return boolField_; }
     }
 
+    /// <summary>Field number for the "string_field" field.</summary>
     public const int StringFieldFieldNumber = 17;
     private static readonly pbc::MapField<int, string>.Codec _map_stringField_codec
         = new pbc::MapField<int, string>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<string>(18), 138);
-    private readonly pbc::MapField<int, string> stringField_ = new pbc::MapField<int, string>(true);
+    private readonly pbc::MapField<int, string> stringField_ = new pbc::MapField<int, string>();
     public pbc::MapField<int, string> StringField {
       get { return stringField_; }
     }
 
+    /// <summary>Field number for the "bytes_field" field.</summary>
     public const int BytesFieldFieldNumber = 18;
     private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_bytesField_codec
         = new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<pb::ByteString>(18), 146);
-    private readonly pbc::MapField<int, pb::ByteString> bytesField_ = new pbc::MapField<int, pb::ByteString>(true);
+    private readonly pbc::MapField<int, pb::ByteString> bytesField_ = new pbc::MapField<int, pb::ByteString>();
     public pbc::MapField<int, pb::ByteString> BytesField {
       get { return bytesField_; }
     }
@@ -2120,7 +2250,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
index 0a2b8b3..f3593e5 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs
@@ -62,5 +62,28 @@
             var unpacked = any.Unpack<TestAllTypes>();
             Assert.AreEqual(message, unpacked);
         }
+
+        [Test]
+        public void ToString_WithValues()
+        {
+            var message = SampleMessages.CreateFullTestAllTypes();
+            var any = Any.Pack(message);
+            var text = any.ToString();
+            Assert.That(text, Is.StringContaining("\"@value\": \"" + message.ToByteString().ToBase64() + "\""));
+        }
+
+        [Test]
+        public void ToString_Empty()
+        {
+            var any = new Any();
+            Assert.AreEqual("{ \"@type\": \"\", \"@value\": \"\" }", any.ToString());
+        }
+
+        [Test]
+        public void ToString_MessageContainingAny()
+        {
+            var message = new TestWellKnownTypes { AnyField = new Any() };
+            Assert.AreEqual("{ \"anyField\": { \"@type\": \"\", \"@value\": \"\" } }", message.ToString());
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
index 36012e6..141faf8 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/DurationTest.cs
@@ -50,11 +50,6 @@
             // Rounding is towards 0
             Assert.AreEqual(TimeSpan.FromTicks(2), new Duration { Nanos = 250 }.ToTimeSpan());
             Assert.AreEqual(TimeSpan.FromTicks(-2), new Duration { Nanos = -250 }.ToTimeSpan());
-
-            // Non-normalized durations
-            Assert.AreEqual(TimeSpan.FromSeconds(3), new Duration { Seconds = 1, Nanos = 2 * Duration.NanosecondsPerSecond }.ToTimeSpan());
-            Assert.AreEqual(TimeSpan.FromSeconds(1), new Duration { Seconds = 3, Nanos = -2 * Duration.NanosecondsPerSecond }.ToTimeSpan());
-            Assert.AreEqual(TimeSpan.FromSeconds(-1), new Duration { Seconds = 1, Nanos = -2 * Duration.NanosecondsPerSecond }.ToTimeSpan());
         }
 
         [Test]
@@ -100,5 +95,38 @@
             Assert.AreEqual(new Duration { Seconds = 1 }, Duration.FromTimeSpan(TimeSpan.FromSeconds(1)));
             Assert.AreEqual(new Duration { Nanos = Duration.NanosecondsPerTick }, Duration.FromTimeSpan(TimeSpan.FromTicks(1)));
         }
+
+        [Test]
+        [TestCase(0, Duration.MaxNanoseconds + 1)]
+        [TestCase(0, Duration.MinNanoseconds - 1)]
+        [TestCase(Duration.MinSeconds - 1, 0)]
+        [TestCase(Duration.MaxSeconds + 1, 0)]
+        [TestCase(1, -1)]
+        [TestCase(-1, 1)]
+        public void ToTimeSpan_Invalid(long seconds, int nanoseconds)
+        {
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => duration.ToTimeSpan());
+        }
+
+        [Test]
+        [TestCase(0, Duration.MaxNanoseconds)]
+        [TestCase(0, Duration.MinNanoseconds)]
+        [TestCase(Duration.MinSeconds, Duration.MinNanoseconds)]
+        [TestCase(Duration.MaxSeconds, Duration.MaxNanoseconds)]
+        public void ToTimeSpan_Valid(long seconds, int nanoseconds)
+        {
+            // Only testing that these values don't throw, unlike their similar tests in ToTimeSpan_Invalid
+            var duration = new Duration { Seconds = seconds, Nanos = nanoseconds };
+            duration.ToTimeSpan();
+        }
+
+        [Test]
+        public void ToString_NonNormalized()
+        {
+            // Just a single example should be sufficient...
+            var duration = new Duration { Seconds = 1, Nanos = -1 };
+            Assert.AreEqual("{ \"@warning\": \"Invalid Duration\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
+        }
     }
 }
diff --git a/src/google/protobuf/proto_cast_test.cc b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
similarity index 61%
copy from src/google/protobuf/proto_cast_test.cc
copy to csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
index a8f43ae..89bc827 100644
--- a/src/google/protobuf/proto_cast_test.cc
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs
@@ -1,5 +1,6 @@
+#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2008 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
@@ -27,34 +28,35 @@
 // 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
 
-#include <google/protobuf/util/proto_cast.h>
 
-#include <google/protobuf/util/unknown_enum_test.pb.h>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
+using NUnit.Framework;
 
-namespace google {
-using google::protobuf::util::UpRevision;
-using google::protobuf::util::DownRevision;
+namespace Google.Protobuf.WellKnownTypes
+{
+    public class FieldMaskTest
+    {
+        [Test]
+        [TestCase("foo__bar")]
+        [TestCase("foo_3_ar")]
+        [TestCase("fooBar")]
+        public void ToString_Invalid(string input)
+        {
+            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));
+        }
 
-namespace {
-
-TEST(ProtoCastTest, V2KnownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NONDEFAULT_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
+        [Test]
+        public void ToString_Invalid_Precise()
+        {
+            var mask = new FieldMask { Paths = { "x", "foo__bar", @"x\y" } };
+            Assert.AreEqual(
+                "{ \"@warning\": \"Invalid FieldMask\", \"paths\": [ \"x\", \"foo__bar\", \"x\\\\y\" ] }",
+                mask.ToString());
+        }
+    }
 }
-
-TEST(ProtoCastTest, V2UnknownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NEW_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value());
-}
-
-}  // namespace
-}  // namespace google
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs
index 597539e..9ecd24c 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs
@@ -61,6 +61,29 @@
             Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 59).AddMilliseconds(1), t2.ToDateTime());
         }
 
+        [Test]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, Timestamp.MaxNanos)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)]
+        [TestCase(0, -1)]
+        [TestCase(0, Timestamp.MaxNanos + 1)]
+        public void ToDateTime_OutOfRange(long seconds, int nanoseconds)
+        {
+            var value = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            Assert.Throws<InvalidOperationException>(() => value.ToDateTime());
+        }
+
+        // 1ns larger or smaller than the above values
+        [Test]
+        [TestCase(Timestamp.UnixSecondsAtBclMinValue, 0)]
+        [TestCase(Timestamp.UnixSecondsAtBclMaxValue, Timestamp.MaxNanos)]
+        [TestCase(0, 0)]
+        [TestCase(0, Timestamp.MaxNanos)]
+        public void ToDateTime_ValidBoundaries(long seconds, int nanoseconds)
+        {
+            var value = new Timestamp { Seconds = seconds, Nanos = nanoseconds };
+            value.ToDateTime();
+        }
+
         private static void AssertRoundtrip(Timestamp timestamp, DateTime dateTime)
         {
             Assert.AreEqual(timestamp, Timestamp.FromDateTime(dateTime));
@@ -80,5 +103,13 @@
             Assert.AreEqual(t1, t2 + difference);
             Assert.AreEqual(t2, t1 - difference);
         }
+
+        [Test]
+        public void ToString_NonNormalized()
+        {
+            // Just a single example should be sufficient...
+            var duration = new Timestamp { Seconds = 1, Nanos = -1 };
+            Assert.AreEqual("{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
index fbc0ff0..5b7185d 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
@@ -149,8 +149,34 @@
         }
 
         [Test]
+        public void RepeatedWrappersBinaryFormat()
+        {
+            // At one point we accidentally used a packed format for repeated wrappers, which is wrong (and weird).
+            // This test is just to prove that we use the right format.
+
+            var rawOutput = new MemoryStream();
+            var output = new CodedOutputStream(rawOutput);
+            // Write a value of 5
+            output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            output.WriteLength(2);
+            output.WriteTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint);
+            output.WriteInt32(5);
+            // Write a value of 0 (empty message)
+            output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+            output.WriteLength(0);
+            output.Flush();
+            var expectedBytes = rawOutput.ToArray();
+
+            var message = new RepeatedWellKnownTypes { Int32Field = { 5, 0 } };
+            var actualBytes = message.ToByteArray();
+            Assert.AreEqual(expectedBytes, actualBytes);
+        }
+
+        [Test]
         public void MapWrappersSerializeDeserialize()
         {
+            // Note: no null values here, as they are prohibited in map fields
+            // (despite being representable).
             var message = new MapWellKnownTypes
             {
                 BoolField = { { 10, false }, { 20, true } },
@@ -158,13 +184,12 @@
                     { -1, ByteString.CopyFrom(1, 2, 3) },
                     { 10, ByteString.CopyFrom(4, 5, 6) },
                     { 1000, ByteString.Empty },
-                    { 10000, null }
                 },
                 DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } },
                 FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } },
                 Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } },
                 Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } },
-                StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" }, { 14, null } },
+                StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" } },
                 Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } },
                 Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } },
             };
@@ -224,13 +249,11 @@
         [Test]
         public void Reflection_MapFields()
         {
-            // Just a single example... note that we can't have a null value here
-            var message = new MapWellKnownTypes { Int32Field = { { 1, 2 }, { 3, null } } };
+            // Just a single example... note that we can't have a null value here despite the value type being int?
+            var message = new MapWellKnownTypes { Int32Field = { { 1, 2 } } };
             var fields = MapWellKnownTypes.Descriptor.Fields;
             var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
             Assert.AreEqual(2, dictionary[1]);
-            Assert.IsNull(dictionary[3]);
-            Assert.IsTrue(dictionary.Contains(3));
         }
 
         [Test]
@@ -296,9 +319,10 @@
 
         // Merging is odd with wrapper types, due to the way that default values aren't emitted in
         // the binary stream. In fact we cheat a little bit - a message with an explicitly present default
-        // value will have that default value ignored.
+        // value will have that default value ignored. See issue 615. Fixing this would require significant upheaval to
+        // the FieldCodec side of things.
         [Test]
-        public void MergingCornerCase()
+        public void MergingStreamExplicitValue()
         {
             var message = new TestWellKnownTypes { Int32Field = 5 };
 
@@ -320,10 +344,48 @@
 
             message.MergeFrom(bytes);
             // A normal implementation would have 0 now, as the explicit default would have been overwritten the 5.
+            // With the FieldCodec for Nullable<int>, we can't tell the difference between an implicit 0 and an explicit 0.
             Assert.AreEqual(5, message.Int32Field);
         }
 
         [Test]
+        public void MergingStreamNoValue()
+        {
+            var message = new TestWellKnownTypes { Int32Field = 5 };
+
+            // Create a byte array which an Int32 field, but with no value.
+            var bytes = new TestWellKnownTypes { Int32Field = 0 }.ToByteArray();
+            Assert.AreEqual(2, bytes.Length); // The tag for Int32Field is a single byte, then a byte indicating a 0-length message.
+            message.MergeFrom(bytes);
+
+            // The "implicit" 0 did *not* overwrite the value.
+            // (This is the correct behaviour.)
+            Assert.AreEqual(5, message.Int32Field);
+        }
+
+        // All permutations of origin/merging value being null, zero (default) or non-default.
+        // As this is the in-memory version, we don't need to worry about the difference between implicit and explicit 0.
+        [Test]
+        [TestCase(null, null, null)]
+        [TestCase(null, 0, 0)]
+        [TestCase(null, 5, 5)]
+        [TestCase(0, null, 0)]
+        [TestCase(0, 0, 0)]
+        [TestCase(0, 5, 5)]
+        [TestCase(5, null, 5)]
+        [TestCase(5, 0, 5)]
+        [TestCase(5, 10, 10)]
+        public void MergingMessageWithZero(int? originValue, int? mergingValue, int? expectedResult)
+        {
+            // This differs from the MergingStreamCornerCase because when we merge message *objects*,
+            // we ignore default values from the "source".
+            var message1 = new TestWellKnownTypes { Int32Field = originValue };
+            var message2 = new TestWellKnownTypes { Int32Field = mergingValue };
+            message1.MergeFrom(message2);
+            Assert.AreEqual(expectedResult, message1.Int32Field);
+        }
+
+        [Test]
         public void UnknownFieldInWrapper()
         {
             var stream = new MemoryStream();
@@ -345,5 +407,15 @@
             var message = TestWellKnownTypes.Parser.ParseFrom(stream);
             Assert.AreEqual(6, message.Int32Field);
         }
+
+        [Test]
+        public void ClearWithReflection()
+        {
+            // String and Bytes are the tricky ones here, as the CLR type of the property
+            // is the same between the wrapper and non-wrapper types.
+            var message = new TestWellKnownTypes { StringField = "foo" };
+            TestWellKnownTypes.Descriptor.Fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.Clear(message);
+            Assert.IsNull(message.StringField);
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs
index 3d55f02..dd7f22d 100644
--- a/csharp/src/Google.Protobuf/ByteString.cs
+++ b/csharp/src/Google.Protobuf/ByteString.cs
@@ -50,13 +50,13 @@
         /// <summary>

         /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.

         /// </summary>

-        public static class Unsafe

+        internal static class Unsafe

         {

             /// <summary>

             /// Constructs a new ByteString from the given byte array. The array is

             /// *not* copied, and must not be modified after this constructor is called.

             /// </summary>

-            public static ByteString FromBytes(byte[] bytes)

+            internal static ByteString FromBytes(byte[] bytes)

             {

                 return new ByteString(bytes);

             }

@@ -65,7 +65,7 @@
             /// Provides direct, unrestricted access to the bytes contained in this instance.

             /// You must not modify or resize the byte array returned by this method.

             /// </summary>

-            public static byte[] GetBuffer(ByteString bytes)

+            internal static byte[] GetBuffer(ByteString bytes)

             {

                 return bytes.bytes;

             }

diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index 82c6cea..1c02d95 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -38,7 +38,7 @@
 namespace Google.Protobuf

 {

     /// <summary>

-    /// Readings and decodes protocol message fields.

+    /// Reads and decodes protocol message fields.

     /// </summary>

     /// <remarks>

     /// <para>

@@ -115,7 +115,7 @@
         /// <summary>

         /// Creates a new CodedInputStream reading data from the given byte array.

         /// </summary>

-        public CodedInputStream(byte[] buffer) : this(null, Preconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)

+        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)

         {            

         }

 

@@ -123,7 +123,7 @@
         /// Creates a new CodedInputStream that reads from the given byte array slice.

         /// </summary>

         public CodedInputStream(byte[] buffer, int offset, int length)

-            : this(null, Preconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)

+            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)

         {            

             if (offset < 0 || offset > buffer.Length)

             {

@@ -140,7 +140,7 @@
         /// </summary>

         public CodedInputStream(Stream input) : this(input, new byte[BufferSize], 0, 0)

         {

-            Preconditions.CheckNotNull(input, "input");

+            ProtoPreconditions.CheckNotNull(input, "input");

         }

 

         /// <summary>

@@ -349,6 +349,14 @@
         /// This should be called directly after <see cref="ReadTag"/>, when

         /// the caller wishes to skip an unknown field.

         /// </summary>

+        /// <remarks>

+        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.

+        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the

+        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly

+        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.

+        /// </remarks>

+        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>

+        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>

         public void SkipLastField()

         {

             if (lastTag == 0)

@@ -358,11 +366,11 @@
             switch (WireFormat.GetTagWireType(lastTag))

             {

                 case WireFormat.WireType.StartGroup:

-                    SkipGroup();

+                    SkipGroup(lastTag);

                     break;

                 case WireFormat.WireType.EndGroup:

-                    // Just ignore; there's no data following the tag.

-                    break;

+                    throw new InvalidProtocolBufferException(

+                        "SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");

                 case WireFormat.WireType.Fixed32:

                     ReadFixed32();

                     break;

@@ -379,7 +387,7 @@
             }

         }

 

-        private void SkipGroup()

+        private void SkipGroup(uint startGroupTag)

         {

             // Note: Currently we expect this to be the way that groups are read. We could put the recursion

             // depth changes into the ReadTag method instead, potentially...

@@ -389,16 +397,28 @@
                 throw InvalidProtocolBufferException.RecursionLimitExceeded();

             }

             uint tag;

-            do

+            while (true)

             {

                 tag = ReadTag();

                 if (tag == 0)

                 {

                     throw InvalidProtocolBufferException.TruncatedMessage();

                 }

+                // Can't call SkipLastField for this case- that would throw.

+                if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)

+                {

+                    break;

+                }

                 // This recursion will allow us to handle nested groups.

                 SkipLastField();

-            } while (WireFormat.GetTagWireType(tag) != WireFormat.WireType.EndGroup);

+            }

+            int startField = WireFormat.GetTagFieldNumber(startGroupTag);

+            int endField = WireFormat.GetTagFieldNumber(tag);

+            if (startField != endField)

+            {

+                throw new InvalidProtocolBufferException(

+                    $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}");

+            }

             recursionDepth--;

         }

 

diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 0fa63be..90a5ff1 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -35,6 +35,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 using Google.Protobuf.Compatibility;
 
 namespace Google.Protobuf.Collections
@@ -45,43 +46,33 @@
     /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
     /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
     /// <remarks>
+    /// <para>
     /// This implementation preserves insertion order for simplicity of testing
     /// code using maps fields. Overwriting an existing entry does not change the
     /// position of that entry within the map. Equality is not order-sensitive.
     /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
+    /// </para>
+    /// <para>
+    /// Null values are not permitted in the map, either for wrapper types or regular messages.
+    /// If a map is deserialized from a data stream and the value is missing from an entry, a default value
+    /// is created instead. For primitive types, that is the regular default value (0, the empty string and so
+    /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
+    /// encoded value for the field.
+    /// </para>
+    /// <para>
+    /// This implementation does not generally prohibit the use of key/value types which are not
+    /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
+    /// that all operations will work in such cases.
+    /// </para>
     /// </remarks>
     public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
     {
         // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
-        private readonly bool allowNullValues;
         private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
             new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
         private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
 
         /// <summary>
-        /// Constructs a new map field, defaulting the value nullability to only allow null values for message types
-        /// and non-nullable value types.
-        /// </summary>
-        public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue)) || Nullable.GetUnderlyingType(typeof(TValue)) != null)
-        {
-        }
-
-        /// <summary>
-        /// Constructs a new map field, overriding the choice of whether null values are permitted in the map.
-        /// This is used by wrapper types, where maps with string and bytes wrappers as the value types
-        /// support null values.
-        /// </summary>
-        /// <param name="allowNullValues">Whether null values are permitted in the map or not.</param>
-        public MapField(bool allowNullValues)
-        {
-            if (allowNullValues && typeof(TValue).IsValueType() && Nullable.GetUnderlyingType(typeof(TValue)) == null)
-            {
-                throw new ArgumentException("allowNullValues", "Non-nullable value types do not support null values");
-            }
-            this.allowNullValues = allowNullValues;
-        }
-
-        /// <summary>
         /// Creates a deep clone of this object.
         /// </summary>
         /// <returns>
@@ -89,13 +80,13 @@
         /// </returns>
         public MapField<TKey, TValue> Clone()
         {
-            var clone = new MapField<TKey, TValue>(allowNullValues);
+            var clone = new MapField<TKey, TValue>();
             // Keys are never cloneable. Values might be.
             if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
             {
                 foreach (var pair in list)
                 {
-                    clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDeepCloneable<TValue>)pair.Value).Clone());
+                    clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
                 }
             }
             else
@@ -132,7 +123,7 @@
         /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
         public bool ContainsKey(TKey key)
         {
-            Preconditions.CheckNotNullUnconstrained(key, "key");
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
             return map.ContainsKey(key);
         }
 
@@ -149,7 +140,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)
         {
-            Preconditions.CheckNotNullUnconstrained(key, "key");
+            ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
             LinkedListNode<KeyValuePair<TKey, TValue>> node;
             if (map.TryGetValue(key, out node))
             {
@@ -197,7 +188,7 @@
         {
             get
             {
-                Preconditions.CheckNotNullUnconstrained(key, "key");
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
                 TValue value;
                 if (TryGetValue(key, out value))
                 {
@@ -207,11 +198,11 @@
             }
             set
             {
-                Preconditions.CheckNotNullUnconstrained(key, "key");
+                ProtoPreconditions.CheckNotNullUnconstrained(key, "key");
                 // value == null check here is redundant, but avoids boxing.
-                if (value == null && !allowNullValues)
+                if (value == null)
                 {
-                    Preconditions.CheckNotNullUnconstrained(value, "value");
+                    ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
                 }
                 LinkedListNode<KeyValuePair<TKey, TValue>> node;
                 var pair = new KeyValuePair<TKey, TValue>(key, value);
@@ -238,12 +229,12 @@
         public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
 
         /// <summary>
-        /// Adds the specified entries to the map.
+        /// Adds the specified entries to the map. The keys and values are not automatically cloned.
         /// </summary>
         /// <param name="entries">The entries to add to the map.</param>
         public void Add(IDictionary<TKey, TValue> entries)
         {
-            Preconditions.CheckNotNull(entries, "entries");
+            ProtoPreconditions.CheckNotNull(entries, "entries");
             foreach (var pair in entries)
             {
                 Add(pair.Key, pair.Value);
@@ -339,11 +330,6 @@
         }
 
         /// <summary>
-        /// Returns whether or not this map allows values to be null.
-        /// </summary>
-        public bool AllowsNullValues { get { return allowNullValues; } }
-
-        /// <summary>
         /// Gets the number of elements contained in the map.
         /// </summary>
         public int Count { get { return list.Count; } }
@@ -482,6 +468,17 @@
             return size;
         }
 
+        /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var builder = new StringBuilder();
+            JsonFormatter.Default.WriteDictionary(builder, this);
+            return builder.ToString();
+        }
+
         #region IDictionary explicit interface implementation
         void IDictionary.Add(object key, object value)
         {
@@ -504,7 +501,7 @@
 
         void IDictionary.Remove(object key)
         {
-            Preconditions.CheckNotNull(key, "key");
+            ProtoPreconditions.CheckNotNull(key, "key");
             if (!(key is TKey))
             {
                 return;
@@ -533,7 +530,7 @@
         {
             get
             {
-                Preconditions.CheckNotNull(key, "key");
+                ProtoPreconditions.CheckNotNull(key, "key");
                 if (!(key is TKey))
                 {
                     return null;
@@ -613,6 +610,8 @@
             /// </summary>
             internal class MessageAdapter : IMessage
             {
+                private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
+
                 private readonly Codec codec;
                 internal TKey Key { get; set; }
                 internal TValue Value { get; set; }
@@ -646,6 +645,13 @@
                             input.SkipLastField();
                         }
                     }
+
+                    // Corner case: a map entry with a key but no value, where the value type is a message.
+                    // Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
+                    if (Value == null)
+                    {
+                        Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
+                    }
                 }
 
                 public void WriteTo(CodedOutputStream output)
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index d9ced6e..1cde03b 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -33,7 +33,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using Google.Protobuf.Compatibility;
+using System.Text;
 
 namespace Google.Protobuf.Collections
 {
@@ -41,6 +41,10 @@
     /// The contents of a repeated field: essentially, a collection with some extra
     /// restrictions (no null values) and capabilities (deep cloning).
     /// </summary>
+    /// <remarks>
+    /// This implementation does not generally prohibit the use of types which are not
+    /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
+    /// </remarks>
     /// <typeparam name="T">The element type of the repeated field.</typeparam>
     public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
     {
@@ -91,8 +95,8 @@
             // iteration.
             uint tag = input.LastTag;
             var reader = codec.ValueReader;
-            // Value types can be packed or not.
-            if (typeof(T).IsValueType() && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited)
+            // Non-nullable value types can be packed or not.
+            if (FieldCodec<T>.IsPackedRepeatedField(tag))
             {
                 int length = input.ReadLength();
                 if (length > 0)
@@ -129,7 +133,7 @@
                 return 0;
             }
             uint tag = codec.Tag;
-            if (typeof(T).IsValueType() && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited)
+            if (codec.PackedRepeatedField)
             {
                 int dataSize = CalculatePackedDataSize(codec);
                 return CodedOutputStream.ComputeRawVarint32Size(tag) +
@@ -181,7 +185,7 @@
             }
             var writer = codec.ValueWriter;
             var tag = codec.Tag;
-            if (typeof(T).IsValueType() && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited)
+            if (codec.PackedRepeatedField)
             {
                 // Packed primitive type
                 uint size = (uint)CalculatePackedDataSize(codec);
@@ -465,6 +469,17 @@
         }
 
         /// <summary>
+        /// Returns a string representation of this repeated field, in the same
+        /// way as it would be represented by the default JSON formatter.
+        /// </summary>
+        public override string ToString()
+        {
+            var builder = new StringBuilder();
+            JsonFormatter.Default.WriteList(builder, this);
+            return builder.ToString();
+        }
+
+        /// <summary>
         /// Gets or sets the item at the specified index.
         /// </summary>
         /// <value>
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
index 20a1f43..9831308 100644
--- a/csharp/src/Google.Protobuf/FieldCodec.cs
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -30,6 +30,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 
+using Google.Protobuf.Compatibility;
+using Google.Protobuf.WellKnownTypes;
 using System;
 using System.Collections.Generic;
 
@@ -261,20 +263,17 @@
         /// </remarks>
         private static class WrapperCodecs
         {
-            // All the field numbers are the same (1).
-            private const int WrapperValueFieldNumber = Google.Protobuf.WellKnownTypes.Int32Value.ValueFieldNumber;
-
-            private static readonly Dictionary<Type, object> Codecs = new Dictionary<Type, object>
+            private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
             {
-                { typeof(bool), ForBool(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
-                { typeof(int), ForInt32(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
-                { typeof(long), ForInt64(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
-                { typeof(uint), ForUInt32(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
-                { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
-                { typeof(float), ForFloat(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
-                { typeof(double), ForDouble(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
-                { typeof(string), ForString(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
-                { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
+                { typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
+                { typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
+                { typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
+                { typeof(string), ForString(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
+                { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
             };
 
             /// <summary>
@@ -331,17 +330,24 @@
     }
 
     /// <summary>
+    /// <para>
     /// An encode/decode pair for a single field. This effectively encapsulates
     /// all the information needed to read or write the field value from/to a coded
     /// stream.
+    /// </para>
+    /// <para>
+    /// This class is public and has to be as it is used by generated code, but its public
+    /// API is very limited - just what the generated code needs to call directly.
+    /// </para>
     /// </summary>
     /// <remarks>
-    /// This never writes default values to the stream, and is not currently designed
-    /// to play well with packed arrays.
+    /// This never writes default values to the stream, and does not address "packedness"
+    /// in repeated fields itself, other than to know whether or not the field *should* be packed.
     /// </remarks>
     public sealed class FieldCodec<T>
     {
         private static readonly T DefaultDefault;
+        private static readonly bool TypeSupportsPacking = typeof(T).IsValueType() && Nullable.GetUnderlyingType(typeof(T)) == null;
 
         static FieldCodec()
         {
@@ -356,21 +362,60 @@
             // Otherwise it's the default value of the CLR type
         }
 
-        private static Func<T, bool> CreateDefaultValueCheck<TTmp>(Func<TTmp, bool> check)
-        {
-            return (Func<T, bool>)(object)check;
-        }
+        internal static bool IsPackedRepeatedField(uint tag) =>
+            TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
 
-        private readonly Func<CodedInputStream, T> reader;
-        private readonly Action<CodedOutputStream, T> writer;
-        private readonly Func<T, int> sizeCalculator;
-        private readonly uint tag;
+        internal bool PackedRepeatedField { get; }
+
+        /// <summary>
+        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
+        /// </summary>
+        internal Action<CodedOutputStream, T> ValueWriter { get; }
+
+        /// <summary>
+        /// Returns the size calculator for just a value.
+        /// </summary>
+        internal Func<T, int> ValueSizeCalculator { get; }
+
+        /// <summary>
+        /// Returns a delegate to read a value from a coded input stream. It is assumed that
+        /// the stream is already positioned on the appropriate tag.
+        /// </summary>
+        internal Func<CodedInputStream, T> ValueReader { get; }
+
+        /// <summary>
+        /// Returns the fixed size for an entry, or 0 if sizes vary.
+        /// </summary>
+        internal int FixedSize { get; }
+
+        /// <summary>
+        /// Gets the tag of the codec.
+        /// </summary>
+        /// <value>
+        /// The tag of the codec.
+        /// </value>
+        internal uint Tag { get; }
+
+        /// <summary>
+        /// Default value for this codec. Usually the same for every instance of the same type, but
+        /// for string/ByteString wrapper fields the codec's default value is null, whereas for
+        /// other string/ByteString fields it's "" or ByteString.Empty.
+        /// </summary>
+        /// <value>
+        /// The default value of the codec's type.
+        /// </value>
+        internal T DefaultValue { get; }
+
         private readonly int tagSize;
-        private readonly int fixedSize;
-        // Default value for this codec. Usually the same for every instance of the same type, but
-        // for string/ByteString wrapper fields the codec's default value is null, whereas for
-        // other string/ByteString fields it's "" or ByteString.Empty.
-        private readonly T defaultValue;
+        
+        internal FieldCodec(
+                Func<CodedInputStream, T> reader,
+                Action<CodedOutputStream, T> writer,
+                int fixedSize,
+                uint tag) : this(reader, writer, _ => fixedSize, tag)
+        {
+            FixedSize = fixedSize;
+        }
 
         internal FieldCodec(
             Func<CodedInputStream, T> reader,
@@ -387,66 +432,17 @@
             uint tag,
             T defaultValue)
         {
-            this.reader = reader;
-            this.writer = writer;
-            this.sizeCalculator = sizeCalculator;
-            this.fixedSize = 0;
-            this.tag = tag;
-            this.defaultValue = defaultValue;
+            ValueReader = reader;
+            ValueWriter = writer;
+            ValueSizeCalculator = sizeCalculator;
+            FixedSize = 0;
+            Tag = tag;
+            DefaultValue = defaultValue;
             tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
+            // Detect packed-ness once, so we can check for it within RepeatedField<T>.
+            PackedRepeatedField = IsPackedRepeatedField(tag);
         }
 
-        internal FieldCodec(
-            Func<CodedInputStream, T> reader,
-            Action<CodedOutputStream, T> writer,
-            int fixedSize,
-            uint tag)
-        {
-            this.reader = reader;
-            this.writer = writer;
-            this.sizeCalculator = _ => fixedSize;
-            this.fixedSize = fixedSize;
-            this.tag = tag;
-            tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
-        }
-
-        /// <summary>
-        /// Returns the size calculator for just a value.
-        /// </summary>
-        internal Func<T, int> ValueSizeCalculator { get { return sizeCalculator; } }
-
-        /// <summary>
-        /// Returns a delegate to write a value (unconditionally) to a coded output stream.
-        /// </summary>
-        internal Action<CodedOutputStream, T> ValueWriter { get { return writer; } }
-
-        /// <summary>
-        /// Returns a delegate to read a value from a coded input stream. It is assumed that
-        /// the stream is already positioned on the appropriate tag.
-        /// </summary>
-        internal Func<CodedInputStream, T> ValueReader { get { return reader; } }
-
-        /// <summary>
-        /// Returns the fixed size for an entry, or 0 if sizes vary.
-        /// </summary>
-        internal int FixedSize { get { return fixedSize; } }
-
-        /// <summary>
-        /// Gets the tag of the codec.
-        /// </summary>
-        /// <value>
-        /// The tag of the codec.
-        /// </value>
-        public uint Tag { get { return tag; } }
-
-        /// <summary>
-        /// Gets the default value of the codec's type.
-        /// </summary>
-        /// <value>
-        /// The default value of the codec's type.
-        /// </value>
-        public T DefaultValue { get { return defaultValue; } }
-
         /// <summary>
         /// Write a tag and the given value, *if* the value is not the default.
         /// </summary>
@@ -454,8 +450,8 @@
         {
             if (!IsDefault(value))
             {
-                output.WriteTag(tag);
-                writer(output, value);
+                output.WriteTag(Tag);
+                ValueWriter(output, value);
             }
         }
 
@@ -464,23 +460,14 @@
         /// </summary>
         /// <param name="input">The input stream to read from.</param>
         /// <returns>The value read from the stream.</returns>
-        public T Read(CodedInputStream input)
-        {
-            return reader(input);
-        }
+        public T Read(CodedInputStream input) => ValueReader(input);
 
         /// <summary>
         /// Calculates the size required to write the given value, with a tag,
         /// if the value is not the default.
         /// </summary>
-        public int CalculateSizeWithTag(T value)
-        {
-            return IsDefault(value) ? 0 : sizeCalculator(value) + tagSize;
-        }
+        public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
 
-        private bool IsDefault(T value)
-        {
-            return EqualityComparer<T>.Default.Equals(value, defaultValue);
-        }
+        private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(value, DefaultValue);
     }
 }
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index 8c680d4..ef524ba 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -16,6 +16,8 @@
     <FileAlignment>512</FileAlignment>

     <OldToolsVersion>3.5</OldToolsVersion>

     <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>

+    <NuGetPackageImportStamp>

+    </NuGetPackageImportStamp>

   </PropertyGroup>

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

     <DebugSymbols>true</DebugSymbols>

@@ -62,7 +64,7 @@
     <NoStdLib>true</NoStdLib>

     <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>

     <SignAssembly>True</SignAssembly>

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

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

     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

   </PropertyGroup>

   <ItemGroup>

@@ -83,17 +85,22 @@
     <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\DescriptorProtoFile.cs" />

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

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

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

@@ -102,7 +109,7 @@
     <Compile Include="Reflection\FieldDescriptor.cs" />

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

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

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

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

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

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

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

@@ -116,7 +123,8 @@
     <Compile Include="Reflection\RepeatedFieldAccessor.cs" />

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

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

-    <Compile Include="Preconditions.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" />

@@ -124,20 +132,31 @@
     <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">

diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
index 9542138..d530254 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?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-alpha4</version>
+    <version>3.0.0-beta2</version>
     <authors>Google Inc.</authors>
     <owners>protobuf-packages</owners>
     <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
@@ -14,24 +14,53 @@
     <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.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" />
+      </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="**\*.cs" target="src" />
-	<file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
-	<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
-	<file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
+    <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" />
+    <file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
+    <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
   </files>
-</package>
+</package>
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
new file mode 100644
index 0000000..a009056
--- /dev/null
+++ b/csharp/src/Google.Protobuf/ICustomDiagnosticMessage.cs
@@ -0,0 +1,69 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// A message type that has a custom string format for diagnostic purposes.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Calling <see cref="object.ToString"/> on a generated message type normally
+    /// returns the JSON representation. If a message type implements this interface,
+    /// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
+    /// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
+    /// or on another message which contains it. This does not affect the normal JSON formatting of
+    /// the message.
+    /// </para>
+    /// <para>
+    /// For example, if you create a proto message representing a GUID, the internal
+    /// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
+    /// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
+    /// </para>
+    /// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
+    /// on types other than messages, where it would not be used by anything in the framework.</para>
+    /// </remarks>
+    public interface ICustomDiagnosticMessage : IMessage
+    {
+        /// <summary>
+        /// Returns a string representation of this object, for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
+        /// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
+        /// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
+        /// that the result is valid JSON, this is never assumed by the Protobuf library.
+        /// </remarks>
+        /// <returns>A string representation of this object, for diagnostic purposes.</returns>
+        string ToDiagnosticString();
+    }
+}
diff --git a/src/google/protobuf/proto_cast_test.cc b/csharp/src/Google.Protobuf/InvalidJsonException.cs
similarity index 62%
copy from src/google/protobuf/proto_cast_test.cc
copy to csharp/src/Google.Protobuf/InvalidJsonException.cs
index a8f43ae..b543420 100644
--- a/src/google/protobuf/proto_cast_test.cc
+++ b/csharp/src/Google.Protobuf/InvalidJsonException.cs
@@ -1,5 +1,6 @@
+#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
+// Copyright 2015 Google Inc.  All rights reserved.
 // https://developers.google.com/protocol-buffers/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,34 +28,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
 
-#include <google/protobuf/util/proto_cast.h>
+using System.IO;
 
-#include <google/protobuf/util/unknown_enum_test.pb.h>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
-
-namespace google {
-using google::protobuf::util::UpRevision;
-using google::protobuf::util::DownRevision;
-
-namespace {
-
-TEST(ProtoCastTest, V2KnownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NONDEFAULT_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
-}
-
-TEST(ProtoCastTest, V2UnknownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NEW_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value());
-}
-
-}  // namespace
-}  // namespace google
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Thrown when an attempt is made to parse invalid JSON, e.g. using
+    /// a non-string property key, or including a redundant comma. Parsing a protocol buffer
+    /// message represented in JSON using <see cref="JsonParser"/> can throw both this
+    /// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
+    /// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
+    /// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
+    /// message.
+    /// </summary>
+    public sealed class InvalidJsonException : IOException
+    {
+        internal InvalidJsonException(string message)
+            : base(message)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
index 01d5539..eeb0f13 100644
--- a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
+++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
@@ -30,6 +30,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 #endregion

 

+using System;

 using System.IO;

 

 namespace Google.Protobuf

@@ -45,6 +46,11 @@
         {

         }

 

+        internal InvalidProtocolBufferException(string message, Exception innerException)

+            : base(message, innerException)

+        {

+        }

+

         internal static InvalidProtocolBufferException MoreDataAvailable()

         {

             return new InvalidProtocolBufferException(

@@ -82,6 +88,11 @@
                 "Protocol message contained an invalid tag (zero).");

         }

 

+        internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)

+        {

+            return new InvalidProtocolBufferException("Invalid base64 data", innerException);

+        }

+

         internal static InvalidProtocolBufferException InvalidEndTag()

         {

             return new InvalidProtocolBufferException(

@@ -95,6 +106,13 @@
                 "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");

         }

 

+        internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()

+        {

+            return new InvalidProtocolBufferException(

+                "Protocol message had too many levels of nesting.  May be malicious.  " +

+                "Use JsonParser.Settings to increase the depth limit.");

+        }

+

         internal static InvalidProtocolBufferException SizeLimitExceeded()

         {

             return new InvalidProtocolBufferException(

diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index 12bbdfd..60f61fc 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -37,6 +37,7 @@
 using Google.Protobuf.Reflection;
 using Google.Protobuf.WellKnownTypes;
 using System.Linq;
+using System.Collections.Generic;
 
 namespace Google.Protobuf
 {
@@ -55,12 +56,20 @@
     /// </remarks>
     public sealed class JsonFormatter
     {
-        private static JsonFormatter defaultInstance = new JsonFormatter(Settings.Default);
+        internal const string AnyTypeUrlField = "@type";
+        internal const string AnyDiagnosticValueField = "@value";
+        internal const string AnyWellKnownTypeValueField = "value";
+        private const string TypeUrlPrefix = "type.googleapis.com";
+        private const string NameValueSeparator = ": ";
+        private const string PropertySeparator = ", ";
 
         /// <summary>
         /// Returns a formatter using the default settings.
         /// </summary>
-        public static JsonFormatter Default { get { return defaultInstance; } }
+        public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
+
+        // A JSON formatter which *only* exists 
+        private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
 
         /// <summary>
         /// The JSON representation of the first 160 characters of Unicode.
@@ -114,6 +123,8 @@
 
         private readonly Settings settings;
 
+        private bool DiagnosticOnly => ReferenceEquals(this, diagnosticFormatter);
+
         /// <summary>
         /// Creates a new formatted with the given settings.
         /// </summary>
@@ -130,11 +141,11 @@
         /// <returns>The formatted message.</returns>
         public string Format(IMessage message)
         {
-            Preconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
             StringBuilder builder = new StringBuilder();
             if (message.Descriptor.IsWellKnownType)
             {
-                WriteWellKnownTypeValue(builder, message.Descriptor, message, false);
+                WriteWellKnownTypeValue(builder, message.Descriptor, message);
             }
             else
             {
@@ -143,6 +154,29 @@
             return builder.ToString();
         }
 
+        /// <summary>
+        /// Converts a message to JSON for diagnostic purposes with no extra context.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
+        /// formatter in its handling of <see cref="Any"/>. As no type registry is available
+        /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
+        /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
+        /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
+        /// </para>
+        /// <para>The value returned by this method is only designed to be used for diagnostic
+        /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
+        /// by other Protocol Buffer implementations.</para>
+        /// </remarks>
+        /// <param name="message">The message to format for diagnostic purposes.</param>
+        /// <returns>The diagnostic-only JSON representation of the message</returns>
+        public static string ToDiagnosticString(IMessage message)
+        {
+            ProtoPreconditions.CheckNotNull(message, nameof(message));
+            return diagnosticFormatter.Format(message);
+        }
+
         private void WriteMessage(StringBuilder builder, IMessage message)
         {
             if (message == null)
@@ -150,14 +184,28 @@
                 WriteNull(builder);
                 return;
             }
+            if (DiagnosticOnly)
+            {
+                ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
+                if (customDiagnosticMessage != null)
+                {
+                    builder.Append(customDiagnosticMessage.ToDiagnosticString());
+                    return;
+                }
+            }
             builder.Append("{ ");
+            bool writtenFields = WriteMessageFields(builder, message, false);
+            builder.Append(writtenFields ? " }" : "}");
+        }
+
+        private bool WriteMessageFields(StringBuilder builder, IMessage message, bool assumeFirstFieldWritten)
+        {
             var fields = message.Descriptor.Fields;
-            bool first = true;
+            bool first = !assumeFirstFieldWritten;
             // First non-oneof fields
             foreach (var field in fields.InFieldNumberOrder())
             {
                 var accessor = field.Accessor;
-                // Oneofs are written later
                 if (field.ContainingOneof != null && field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) != field)
                 {
                     continue;
@@ -169,26 +217,47 @@
                 {
                     continue;
                 }
-                // Omit awkward (single) values such as unknown enum values
-                if (!field.IsRepeated && !field.IsMap && !CanWriteSingleValue(accessor.Descriptor, value))
-                {
-                    continue;
-                }
 
                 // Okay, all tests complete: let's write the field value...
                 if (!first)
                 {
-                    builder.Append(", ");
+                    builder.Append(PropertySeparator);
                 }
                 WriteString(builder, ToCamelCase(accessor.Descriptor.Name));
-                builder.Append(": ");
-                WriteValue(builder, accessor, value);
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, value);
                 first = false;
             }            
-            builder.Append(first ? "}" : " }");
+            return !first;
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static string ToCamelCaseForFieldMask(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
+                    }
+                }
+            }
+            return ToCamelCase(input);
         }
 
         // 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;
@@ -291,93 +360,88 @@
                     throw new ArgumentException("Invalid field type");
             }
         }
-
-        private void WriteValue(StringBuilder builder, IFieldAccessor accessor, object value)
+        
+        private void WriteValue(StringBuilder builder, object value)
         {
-            if (accessor.Descriptor.IsMap)
+            if (value == null)
             {
-                WriteDictionary(builder, accessor, (IDictionary) value);
+                WriteNull(builder);
             }
-            else if (accessor.Descriptor.IsRepeated)
+            else if (value is bool)
             {
-                WriteList(builder, accessor, (IList) value);
+                builder.Append((bool) value ? "true" : "false");
+            }
+            else if (value is ByteString)
+            {
+                // Nothing in Base64 needs escaping
+                builder.Append('"');
+                builder.Append(((ByteString) value).ToBase64());
+                builder.Append('"');
+            }
+            else if (value is string)
+            {
+                WriteString(builder, (string) value);
+            }
+            else if (value is IDictionary)
+            {
+                WriteDictionary(builder, (IDictionary) value);
+            }
+            else if (value is IList)
+            {
+                WriteList(builder, (IList) value);
+            }
+            else if (value is int || value is uint)
+            {
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+            }
+            else if (value is long || value is ulong)
+            {
+                builder.Append('"');
+                IFormattable formattable = (IFormattable) value;
+                builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
+                builder.Append('"');
+            }
+            else if (value is System.Enum)
+            {
+                if (System.Enum.IsDefined(value.GetType(), value))
+                {
+                    WriteString(builder, value.ToString());
+                }
+                else
+                {
+                    WriteValue(builder, (int) value);
+                }
+            }
+            else if (value is float || value is double)
+            {
+                string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
+                if (text == "NaN" || text == "Infinity" || text == "-Infinity")
+                {
+                    builder.Append('"');
+                    builder.Append(text);
+                    builder.Append('"');
+                }
+                else
+                {
+                    builder.Append(text);
+                }
+            }
+            else if (value is IMessage)
+            {
+                IMessage message = (IMessage) value;
+                if (message.Descriptor.IsWellKnownType)
+                {
+                    WriteWellKnownTypeValue(builder, message.Descriptor, value);
+                }
+                else
+                {
+                    WriteMessage(builder, (IMessage) value);
+                }
             }
             else
             {
-                WriteSingleValue(builder, accessor.Descriptor, value);
-            }
-        }
-
-        private void WriteSingleValue(StringBuilder builder, FieldDescriptor descriptor, object value)
-        {
-            switch (descriptor.FieldType)
-            {
-                case FieldType.Bool:
-                    builder.Append((bool) value ? "true" : "false");
-                    break;
-                case FieldType.Bytes:
-                    // Nothing in Base64 needs escaping
-                    builder.Append('"');
-                    builder.Append(((ByteString) value).ToBase64());
-                    builder.Append('"');
-                    break;
-                case FieldType.String:
-                    WriteString(builder, (string) value);
-                    break;
-                case FieldType.Fixed32:
-                case FieldType.UInt32:
-                case FieldType.SInt32:
-                case FieldType.Int32:
-                case FieldType.SFixed32:
-                    {
-                        IFormattable formattable = (IFormattable) value;
-                        builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
-                        break;
-                    }
-                case FieldType.Enum:
-                    EnumValueDescriptor enumValue = descriptor.EnumType.FindValueByNumber((int) value);
-                    // We will already have validated that this is a known value.
-                    WriteString(builder, enumValue.Name);
-                    break;
-                case FieldType.Fixed64:
-                case FieldType.UInt64:
-                case FieldType.SFixed64:
-                case FieldType.Int64:
-                case FieldType.SInt64:
-                    {
-                        builder.Append('"');
-                        IFormattable formattable = (IFormattable) value;
-                        builder.Append(formattable.ToString("d", CultureInfo.InvariantCulture));
-                        builder.Append('"');
-                        break;
-                    }
-                case FieldType.Double:
-                case FieldType.Float:
-                    string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
-                    if (text == "NaN" || text == "Infinity" || text == "-Infinity")
-                    {
-                        builder.Append('"');
-                        builder.Append(text);
-                        builder.Append('"');
-                    }
-                    else
-                    {
-                        builder.Append(text);
-                    }
-                    break;
-                case FieldType.Message:
-                case FieldType.Group: // Never expect to get this, but...
-                    if (descriptor.MessageType.IsWellKnownType)
-                    {
-                        WriteWellKnownTypeValue(builder, descriptor.MessageType, value, true);
-                    }
-                    else
-                    {
-                        WriteMessage(builder, (IMessage) value);
-                    }
-                    break;
-                default:
-                    throw new ArgumentException("Invalid field type: " + descriptor.FieldType);
+                throw new ArgumentException("Unable to format value of type " + value.GetType());
             }
         }
 
@@ -387,33 +451,43 @@
         /// values are using the embedded well-known types, in order to allow for dynamic messages
         /// in the future.
         /// </summary>
-        private void WriteWellKnownTypeValue(StringBuilder builder, MessageDescriptor descriptor, object value, bool inField)
+        private void WriteWellKnownTypeValue(StringBuilder builder, MessageDescriptor descriptor, object value)
         {
+            // Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
+            // this would do the right thing.
             if (value == null)
             {
                 WriteNull(builder);
                 return;
             }
-            // For wrapper types, the value will be the (possibly boxed) "native" value,
-            // so we can write it as if we were unconditionally writing the Value field for the wrapper type.
-            if (descriptor.File == Int32Value.Descriptor.File)
+            // For wrapper types, the value will either be the (possibly boxed) "native" value,
+            // or the message itself if we're formatting it at the top level (e.g. just calling ToString on the object itself).
+            // If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
+            // and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
+            // WriteValue will do the right thing.)
+            if (descriptor.IsWrapperType)
             {
-                WriteSingleValue(builder, descriptor.FindFieldByNumber(1), value);
+                if (value is IMessage)
+                {
+                    var message = (IMessage) value;
+                    value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message);
+                }
+                WriteValue(builder, value);
                 return;
             }
             if (descriptor.FullName == Timestamp.Descriptor.FullName)
             {
-                MaybeWrapInString(builder, value, WriteTimestamp, inField);
+                WriteTimestamp(builder, (IMessage) value);
                 return;
             }
             if (descriptor.FullName == Duration.Descriptor.FullName)
             {
-                MaybeWrapInString(builder, value, WriteDuration, inField);
+                WriteDuration(builder, (IMessage) value);
                 return;
             }
             if (descriptor.FullName == FieldMask.Descriptor.FullName)
             {
-                MaybeWrapInString(builder, value, WriteFieldMask, inField);
+                WriteFieldMask(builder, (IMessage) value);
                 return;
             }
             if (descriptor.FullName == Struct.Descriptor.FullName)
@@ -424,7 +498,7 @@
             if (descriptor.FullName == ListValue.Descriptor.FullName)
             {
                 var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
-                WriteList(builder, fieldAccessor, (IList) fieldAccessor.GetValue((IMessage) value));
+                WriteList(builder, (IList) fieldAccessor.GetValue((IMessage) value));
                 return;
             }
             if (descriptor.FullName == Value.Descriptor.FullName)
@@ -432,27 +506,14 @@
                 WriteStructFieldValue(builder, (IMessage) value);
                 return;
             }
+            if (descriptor.FullName == Any.Descriptor.FullName)
+            {
+                WriteAny(builder, (IMessage) value);
+                return;
+            }
             WriteMessage(builder, (IMessage) value);
         }
 
-        /// <summary>
-        /// Some well-known types end up as string values... so they need wrapping in quotes, but only
-        /// when they're being used as fields within another message.
-        /// </summary>
-        private void MaybeWrapInString(StringBuilder builder, object value, Action<StringBuilder, IMessage> action, bool inField)
-        {
-            if (inField)
-            {
-                builder.Append('"');
-                action(builder, (IMessage) value);
-                builder.Append('"');
-            }
-            else
-            {
-                action(builder, (IMessage) value);
-            }
-        }
-
         private void WriteTimestamp(StringBuilder builder, IMessage value)
         {
             // TODO: In the common case where this *is* using the built-in Timestamp type, we could
@@ -461,15 +522,7 @@
             // it still works in that case.
             int nanos = (int) value.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.GetValue(value);
             long seconds = (long) value.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.GetValue(value);
-
-            // Even if the original message isn't using the built-in classes, we can still build one... and then
-            // rely on it being normalized.
-            Timestamp normalized = Timestamp.Normalize(seconds, nanos);
-            // Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
-            DateTime dateTime = normalized.ToDateTime();
-            builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture));
-            AppendNanoseconds(builder, Math.Abs(normalized.Nanos));
-            builder.Append('Z');
+            builder.Append(Timestamp.ToJson(seconds, nanos, DiagnosticOnly));
         }
 
         private void WriteDuration(StringBuilder builder, IMessage value)
@@ -477,51 +530,76 @@
             // TODO: Same as for WriteTimestamp
             int nanos = (int) value.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.GetValue(value);
             long seconds = (long) value.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.GetValue(value);
-
-            // Even if the original message isn't using the built-in classes, we can still build one... and then
-            // rely on it being normalized.
-            Duration normalized = Duration.Normalize(seconds, nanos);
-
-            // The seconds part will normally provide the minus sign if we need it, but not if it's 0...
-            if (normalized.Seconds == 0 && normalized.Nanos < 0)
-            {
-                builder.Append('-');
-            }
-
-            builder.Append(normalized.Seconds.ToString("d", CultureInfo.InvariantCulture));
-            AppendNanoseconds(builder, Math.Abs(normalized.Nanos));
-            builder.Append('s');
+            builder.Append(Duration.ToJson(seconds, nanos, DiagnosticOnly));
         }
 
         private void WriteFieldMask(StringBuilder builder, IMessage value)
         {
-            IList paths = (IList) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
-            AppendEscapedString(builder, string.Join(",", paths.Cast<string>().Select(ToCamelCase)));
+            var paths = (IList<string>) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
+            builder.Append(FieldMask.ToJson(paths, DiagnosticOnly));
         }
 
-        /// <summary>
-        /// Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
-        /// case no "." is appended), or 3 6 or 9 digits.
-        /// </summary>
-        private static void AppendNanoseconds(StringBuilder builder, int nanos)
+        private void WriteAny(StringBuilder builder, IMessage value)
         {
-            if (nanos != 0)
+            if (DiagnosticOnly)
             {
-                builder.Append('.');
-                // Output to 3, 6 or 9 digits.
-                if (nanos % 1000000 == 0)
-                {
-                    builder.Append((nanos / 1000000).ToString("d", CultureInfo.InvariantCulture));
-                }
-                else if (nanos % 1000 == 0)
-                {
-                    builder.Append((nanos / 1000).ToString("d", CultureInfo.InvariantCulture));
-                }
-                else
-                {
-                    builder.Append(nanos.ToString("d", CultureInfo.InvariantCulture));
-                }
+                WriteDiagnosticOnlyAny(builder, value);
+                return;
             }
+
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            string typeName = GetTypeName(typeUrl);
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+            IMessage message = descriptor.Parser.ParseFrom(data);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+
+            if (descriptor.IsWellKnownType)
+            {
+                builder.Append(PropertySeparator);
+                WriteString(builder, AnyWellKnownTypeValueField);
+                builder.Append(NameValueSeparator);
+                WriteWellKnownTypeValue(builder, descriptor, message);
+            }
+            else
+            {
+                WriteMessageFields(builder, message, true);
+            }
+            builder.Append(" }");
+        }
+
+        private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value)
+        {
+            string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
+            ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
+            builder.Append("{ ");
+            WriteString(builder, AnyTypeUrlField);
+            builder.Append(NameValueSeparator);
+            WriteString(builder, typeUrl);
+            builder.Append(PropertySeparator);
+            WriteString(builder, AnyDiagnosticValueField);
+            builder.Append(NameValueSeparator);
+            builder.Append('"');
+            builder.Append(data.ToBase64());
+            builder.Append('"');
+            builder.Append(" }");
+        }
+
+        internal static string GetTypeName(String typeUrl)
+        {
+            string[] parts = typeUrl.Split('/');
+            if (parts.Length != 2 || parts[0] != TypeUrlPrefix)
+            {
+                throw new InvalidProtocolBufferException($"Invalid type url: {typeUrl}");
+            }
+            return parts[1];
         }
 
         private void WriteStruct(StringBuilder builder, IMessage message)
@@ -540,10 +618,10 @@
 
                 if (!first)
                 {
-                    builder.Append(", ");
+                    builder.Append(PropertySeparator);
                 }
                 WriteString(builder, key);
-                builder.Append(": ");
+                builder.Append(NameValueSeparator);
                 WriteStructFieldValue(builder, value);
                 first = false;
             }
@@ -565,13 +643,13 @@
                 case Value.BoolValueFieldNumber:
                 case Value.StringValueFieldNumber:
                 case Value.NumberValueFieldNumber:
-                    WriteSingleValue(builder, specifiedField, value);
+                    WriteValue(builder, value);
                     return;
                 case Value.StructValueFieldNumber:
                 case Value.ListValueFieldNumber:
                     // Structs and ListValues are nested messages, and already well-known types.
                     var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
-                    WriteWellKnownTypeValue(builder, nestedMessage.Descriptor, nestedMessage, true);
+                    WriteWellKnownTypeValue(builder, nestedMessage.Descriptor, nestedMessage);
                     return;
                 case Value.NullValueFieldNumber:
                     WriteNull(builder);
@@ -581,70 +659,57 @@
             }
         }
 
-        private void WriteList(StringBuilder builder, IFieldAccessor accessor, IList list)
+        internal void WriteList(StringBuilder builder, IList list)
         {
             builder.Append("[ ");
             bool first = true;
             foreach (var value in list)
             {
-                if (!CanWriteSingleValue(accessor.Descriptor, value))
-                {
-                    continue;
-                }
                 if (!first)
                 {
-                    builder.Append(", ");
+                    builder.Append(PropertySeparator);
                 }
-                WriteSingleValue(builder, accessor.Descriptor, value);
+                WriteValue(builder, value);
                 first = false;
             }
             builder.Append(first ? "]" : " ]");
         }
 
-        private void WriteDictionary(StringBuilder builder, IFieldAccessor accessor, IDictionary dictionary)
+        internal void WriteDictionary(StringBuilder builder, IDictionary dictionary)
         {
             builder.Append("{ ");
             bool first = true;
-            FieldDescriptor keyType = accessor.Descriptor.MessageType.FindFieldByNumber(1);
-            FieldDescriptor valueType = accessor.Descriptor.MessageType.FindFieldByNumber(2);
             // This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
             foreach (DictionaryEntry pair in dictionary)
             {
-                if (!CanWriteSingleValue(valueType, pair.Value))
-                {
-                    continue;
-                }
                 if (!first)
                 {
-                    builder.Append(", ");
+                    builder.Append(PropertySeparator);
                 }
                 string keyText;
-                switch (keyType.FieldType)
+                if (pair.Key is string)
                 {
-                    case FieldType.String:
-                        keyText = (string) pair.Key;
-                        break;
-                    case FieldType.Bool:
-                        keyText = (bool) pair.Key ? "true" : "false";
-                        break;
-                    case FieldType.Fixed32:
-                    case FieldType.Fixed64:
-                    case FieldType.SFixed32:
-                    case FieldType.SFixed64:
-                    case FieldType.Int32:
-                    case FieldType.Int64:
-                    case FieldType.SInt32:
-                    case FieldType.SInt64:
-                    case FieldType.UInt32:
-                    case FieldType.UInt64:
-                        keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
-                        break;
-                    default:
-                        throw new ArgumentException("Invalid key type: " + keyType.FieldType);
+                    keyText = (string) pair.Key;
+                }
+                else if (pair.Key is bool)
+                {
+                    keyText = (bool) pair.Key ? "true" : "false";
+                }
+                else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
+                {
+                    keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
+                }
+                else
+                {
+                    if (pair.Key == null)
+                    {
+                        throw new ArgumentException("Dictionary has entry with null key");
+                    }
+                    throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
                 }
                 WriteString(builder, keyText);
-                builder.Append(": ");
-                WriteSingleValue(builder, valueType, pair.Value);
+                builder.Append(NameValueSeparator);
+                WriteValue(builder, pair.Value);
                 first = false;
             }
             builder.Append(first ? "}" : " }");
@@ -655,12 +720,11 @@
         /// Currently only relevant for enums, where unknown values can't be represented.
         /// For repeated/map fields, this always returns true.
         /// </summary>
-        private bool CanWriteSingleValue(FieldDescriptor descriptor, object value)
+        private bool CanWriteSingleValue(object value)
         {
-            if (descriptor.FieldType == FieldType.Enum)
+            if (value is System.Enum)
             {
-                EnumValueDescriptor enumValue = descriptor.EnumType.FindValueByNumber((int) value);
-                return enumValue != null;
+                return System.Enum.IsDefined(value.GetType(), value);
             }
             return true;
         }
@@ -671,18 +735,9 @@
         /// <remarks>
         /// Other than surrogate pair handling, this code is mostly taken from src/google/protobuf/util/internal/json_escaping.cc.
         /// </remarks>
-        private void WriteString(StringBuilder builder, string text)
+        internal static void WriteString(StringBuilder builder, string text)
         {
             builder.Append('"');
-            AppendEscapedString(builder, text);
-            builder.Append('"');
-        }
-
-        /// <summary>
-        /// Appends the given text to the string builder, escaping as required.
-        /// </summary>
-        private void AppendEscapedString(StringBuilder builder, string text)
-        {
             for (int i = 0; i < text.Length; i++)
             {
                 char c = text[i];
@@ -742,6 +797,7 @@
                         break;
                 }
             }
+            builder.Append('"');
         }
 
         private const string Hex = "0123456789abcdef";
@@ -759,29 +815,50 @@
         /// </summary>
         public sealed class Settings
         {
-            private static readonly Settings defaultInstance = new Settings(false);
-
             /// <summary>
             /// Default settings, as used by <see cref="JsonFormatter.Default"/>
             /// </summary>
-            public static Settings Default { get { return defaultInstance; } }
+            public static Settings Default { get; }
 
-            private readonly bool formatDefaultValues;
-
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(false);
+            }
 
             /// <summary>
             /// Whether fields whose values are the default for the field type (e.g. 0 for integers)
             /// should be formatted (true) or omitted (false).
             /// </summary>
-            public bool FormatDefaultValues { get { return formatDefaultValues; } }
+            public bool FormatDefaultValues { get; }
 
             /// <summary>
-            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values.
+            /// The type registry used to format <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            // TODO: Work out how we're going to scale this to multiple settings. "WithXyz" methods?
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and an empty type registry.
             /// </summary>
             /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
-            public Settings(bool formatDefaultValues)
+            public Settings(bool formatDefaultValues) : this(formatDefaultValues, TypeRegistry.Empty)
             {
-                this.formatDefaultValues = formatDefaultValues;
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified formatting of default values
+            /// and type registry.
+            /// </summary>
+            /// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
+            /// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
+            public Settings(bool formatDefaultValues, TypeRegistry typeRegistry)
+            {
+                FormatDefaultValues = formatDefaultValues;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
             }
         }
     }
diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs
new file mode 100644
index 0000000..80d3013
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonParser.cs
@@ -0,0 +1,1018 @@
+#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/
+//
+// 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.
+#endregion
+
+using Google.Protobuf.Reflection;
+using Google.Protobuf.WellKnownTypes;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Reflection-based converter from JSON to messages.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Instances of this class are thread-safe, with no mutable state.
+    /// </para>
+    /// <para>
+    /// This is a simple start to get JSON parsing working. As it's reflection-based,
+    /// it's not as quick as baking calls into generated messages - but is a simpler implementation.
+    /// (This code is generally not heavily optimized.)
+    /// </para>
+    /// </remarks>
+    public sealed class JsonParser
+    {
+        // Note: using 0-9 instead of \d to ensure no non-ASCII digits.
+        // This regex isn't a complete validator, but will remove *most* invalid input. We rely on parsing to do the rest.
+        private static readonly Regex TimestampRegex = new Regex(@"^(?<datetime>[0-9]{4}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9])(?<subseconds>\.[0-9]{1,9})?(?<offset>(Z|[+-][0-1][0-9]:[0-5][0-9]))$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly Regex DurationRegex = new Regex(@"^(?<sign>-)?(?<int>[0-9]{1,12})(?<subseconds>\.[0-9]{1,9})?s$", FrameworkPortability.CompiledRegexWhereAvailable);
+        private static readonly int[] SubsecondScalingFactors = { 0, 100000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
+        private static readonly char[] FieldMaskPathSeparators = new[] { ',' };
+
+        private static readonly JsonParser defaultInstance = new JsonParser(Settings.Default);
+
+        // TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers
+        // and the signatures of various methods.
+        private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+            WellKnownTypeHandlers = new Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
+        {
+            { Timestamp.Descriptor.FullName, (parser, message, tokenizer) => MergeTimestamp(message, tokenizer.Next()) },
+            { Duration.Descriptor.FullName, (parser, message, tokenizer) => MergeDuration(message, tokenizer.Next()) },
+            { Value.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStructValue(message, tokenizer) },
+            { ListValue.Descriptor.FullName, (parser, message, tokenizer) =>
+                parser.MergeRepeatedField(message, message.Descriptor.Fields[ListValue.ValuesFieldNumber], tokenizer) },
+            { Struct.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeStruct(message, tokenizer) },
+            { Any.Descriptor.FullName, (parser, message, tokenizer) => parser.MergeAny(message, tokenizer) },
+            { FieldMask.Descriptor.FullName, (parser, message, tokenizer) => MergeFieldMask(message, tokenizer.Next()) },
+            { Int32Value.Descriptor.FullName, MergeWrapperField },
+            { Int64Value.Descriptor.FullName, MergeWrapperField },
+            { UInt32Value.Descriptor.FullName, MergeWrapperField },
+            { UInt64Value.Descriptor.FullName, MergeWrapperField },
+            { FloatValue.Descriptor.FullName, MergeWrapperField },
+            { DoubleValue.Descriptor.FullName, MergeWrapperField },
+            { BytesValue.Descriptor.FullName, MergeWrapperField },
+            { StringValue.Descriptor.FullName, MergeWrapperField }
+        };
+
+        // Convenience method to avoid having to repeat the same code multiple times in the above
+        // dictionary initialization.
+        private static void MergeWrapperField(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
+        {
+            parser.MergeField(message, message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber], tokenizer);
+        }
+
+        /// <summary>
+        /// Returns a formatter using the default settings.
+        /// </summary>
+        public static JsonParser Default { get { return defaultInstance; } }
+
+        private readonly Settings settings;
+
+        /// <summary>
+        /// Creates a new formatted with the given settings.
+        /// </summary>
+        /// <param name="settings">The settings.</param>
+        public JsonParser(Settings settings)
+        {
+            this.settings = settings;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="json">The JSON to parse.</param>
+        internal void Merge(IMessage message, string json)
+        {
+            Merge(message, new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> and merges the information into the given message.
+        /// </summary>
+        /// <param name="message">The message to merge the JSON information into.</param>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        internal void Merge(IMessage message, TextReader jsonReader)
+        {
+            var tokenizer = JsonTokenizer.FromTextReader(jsonReader);
+            Merge(message, tokenizer);
+            var lastToken = tokenizer.Next();
+            if (lastToken != JsonToken.EndDocument)
+            {
+                throw new InvalidProtocolBufferException("Expected end of JSON after object");
+            }
+        }
+
+        /// <summary>
+        /// Merges the given message using data from the given tokenizer. In most cases, the next
+        /// token should be a "start object" token, but wrapper types and nullity can invalidate
+        /// that assumption. This is implemented as an LL(1) recursive descent parser over the stream
+        /// of tokens provided by the tokenizer. This token stream is assumed to be valid JSON, with the
+        /// tokenizer performing that validation - but not every token stream is valid "protobuf JSON".
+        /// </summary>
+        private void Merge(IMessage message, JsonTokenizer tokenizer)
+        {
+            if (tokenizer.ObjectDepth > settings.RecursionLimit)
+            {
+                throw InvalidProtocolBufferException.JsonRecursionLimitExceeded();
+            }
+            if (message.Descriptor.IsWellKnownType)
+            {
+                Action<JsonParser, IMessage, JsonTokenizer> handler;
+                if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out handler))
+                {
+                    handler(this, message, tokenizer);
+                    return;
+                }
+                // Well-known types with no special handling continue in the normal way.
+            }
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object");
+            }
+            var descriptor = message.Descriptor;
+            var jsonFieldMap = descriptor.Fields.ByJsonName();
+            // All the oneof fields we've already accounted for - we can only see each of them once.
+            // The set is created lazily to avoid the overhead of creating a set for every message
+            // we parsed, when oneofs are relatively rare.
+            HashSet<OneofDescriptor> seenOneofs = null;
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                if (token.Type != JsonToken.TokenType.Name)
+                {
+                    throw new InvalidOperationException("Unexpected token type " + token.Type);
+                }
+                string name = token.StringValue;
+                FieldDescriptor field;
+                if (jsonFieldMap.TryGetValue(name, out field))
+                {
+                    if (field.ContainingOneof != null)
+                    {
+                        if (seenOneofs == null)
+                        {
+                            seenOneofs = new HashSet<OneofDescriptor>();
+                        }
+                        if (!seenOneofs.Add(field.ContainingOneof))
+                        {
+                            throw new InvalidProtocolBufferException($"Multiple values specified for oneof {field.ContainingOneof.Name}");
+                        }
+                    }
+                    MergeField(message, field, tokenizer);
+                }
+                else
+                {
+                    // TODO: Is this what we want to do? If not, we'll need to skip the value,
+                    // which may be an object or array. (We might want to put code in the tokenizer
+                    // to do that.)
+                    throw new InvalidProtocolBufferException("Unknown field: " + name);
+                }
+            }
+        }
+
+        private void MergeField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // Clear the field if we see a null token, unless it's for a singular field of type
+                // google.protobuf.Value.
+                // Note: different from Java API, which just ignores it.
+                // TODO: Bring it more in line? Discuss...
+                if (field.IsMap || field.IsRepeated || !IsGoogleProtobufValueField(field))
+                {
+                    field.Accessor.Clear(message);
+                    return;
+                }
+            }
+            tokenizer.PushBack(token);
+
+            if (field.IsMap)
+            {
+                MergeMapField(message, field, tokenizer);
+            }
+            else if (field.IsRepeated)
+            {
+                MergeRepeatedField(message, field, tokenizer);
+            }
+            else
+            {
+                var value = ParseSingleValue(field, tokenizer);
+                field.Accessor.SetValue(message, value);
+            }
+        }
+
+        private void MergeRepeatedField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartArray)
+            {
+                throw new InvalidProtocolBufferException("Repeated field value was not an array. Token type: " + token.Type);
+            }
+
+            IList list = (IList) field.Accessor.GetValue(message);
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndArray)
+                {
+                    return;
+                }
+                tokenizer.PushBack(token);
+                if (token.Type == JsonToken.TokenType.Null)
+                {
+                    throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
+                }
+                list.Add(ParseSingleValue(field, tokenizer));
+            }
+        }
+
+        private void MergeMapField(IMessage message, FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected an object to populate a map");
+            }
+
+            var type = field.MessageType;
+            var keyField = type.FindFieldByNumber(1);
+            var valueField = type.FindFieldByNumber(2);
+            if (keyField == null || valueField == null)
+            {
+                throw new InvalidProtocolBufferException("Invalid map field: " + field.FullName);
+            }
+            IDictionary dictionary = (IDictionary) field.Accessor.GetValue(message);
+
+            while (true)
+            {
+                token = tokenizer.Next();
+                if (token.Type == JsonToken.TokenType.EndObject)
+                {
+                    return;
+                }
+                object key = ParseMapKey(keyField, token.StringValue);
+                object value = ParseSingleValue(valueField, tokenizer);
+                if (value == null)
+                {
+                    throw new InvalidProtocolBufferException("Map values must not be null");
+                }
+                dictionary[key] = value;
+            }
+        }
+
+        private static bool IsGoogleProtobufValueField(FieldDescriptor field)
+        {
+            return field.FieldType == FieldType.Message &&
+                field.MessageType.FullName == Value.Descriptor.FullName;
+        }
+
+        private object ParseSingleValue(FieldDescriptor field, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type == JsonToken.TokenType.Null)
+            {
+                // TODO: In order to support dynamic messages, we should really build this up
+                // dynamically.
+                if (IsGoogleProtobufValueField(field))
+                {
+                    return Value.ForNull();
+                }
+                return null;
+            }
+
+            var fieldType = field.FieldType;
+            if (fieldType == FieldType.Message)
+            {
+                // Parse wrapper types as their constituent types.
+                // TODO: What does this mean for null?
+                if (field.MessageType.IsWrapperType)
+                {
+                    field = field.MessageType.Fields[WrappersReflection.WrapperValueFieldNumber];
+                    fieldType = field.FieldType;
+                }
+                else
+                {
+                    // TODO: Merge the current value in message? (Public API currently doesn't make this relevant as we don't expose merging.)
+                    tokenizer.PushBack(token);
+                    IMessage subMessage = NewMessageForField(field);
+                    Merge(subMessage, tokenizer);
+                    return subMessage;
+                }
+            }
+
+            switch (token.Type)
+            {
+                case JsonToken.TokenType.True:
+                case JsonToken.TokenType.False:
+                    if (fieldType == FieldType.Bool)
+                    {
+                        return token.Type == JsonToken.TokenType.True;
+                    }
+                    // Fall through to "we don't support this type for this case"; could duplicate the behaviour of the default
+                    // case instead, but this way we'd only need to change one place.
+                    goto default;
+                case JsonToken.TokenType.StringValue:
+                    return ParseSingleStringValue(field, token.StringValue);
+                // Note: not passing the number value itself here, as we may end up storing the string value in the token too.
+                case JsonToken.TokenType.Number:
+                    return ParseSingleNumberValue(field, token);
+                case JsonToken.TokenType.Null:
+                    throw new NotImplementedException("Haven't worked out what to do for null yet");
+                default:
+                    throw new InvalidProtocolBufferException("Unsupported JSON token type " + token.Type + " for field type " + fieldType);
+            }
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="json">The JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(string json) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            return Parse<T>(new StringReader(json));
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <typeparam name="T">The type of message to create.</typeparam>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public T Parse<T>(TextReader jsonReader) where T : IMessage, new()
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            T message = new T();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses <paramref name="json"/> into a new message.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(string json, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(json, nameof(json));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            return Parse(new StringReader(json), descriptor);
+        }
+
+        /// <summary>
+        /// Parses JSON read from <paramref name="jsonReader"/> into a new message.
+        /// </summary>
+        /// <param name="jsonReader">Reader providing the JSON to parse.</param>
+        /// <param name="descriptor">Descriptor of message type to parse.</param>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage Parse(TextReader jsonReader, MessageDescriptor descriptor)
+        {
+            ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
+            ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
+            IMessage message = descriptor.Parser.CreateTemplate();
+            Merge(message, jsonReader);
+            return message;
+        }
+
+        private void MergeStructValue(IMessage message, JsonTokenizer tokenizer)
+        {
+            var firstToken = tokenizer.Next();
+            var fields = message.Descriptor.Fields;
+            switch (firstToken.Type)
+            {
+                case JsonToken.TokenType.Null:
+                    fields[Value.NullValueFieldNumber].Accessor.SetValue(message, 0);
+                    return;
+                case JsonToken.TokenType.StringValue:
+                    fields[Value.StringValueFieldNumber].Accessor.SetValue(message, firstToken.StringValue);
+                    return;
+                case JsonToken.TokenType.Number:
+                    fields[Value.NumberValueFieldNumber].Accessor.SetValue(message, firstToken.NumberValue);
+                    return;
+                case JsonToken.TokenType.False:
+                case JsonToken.TokenType.True:
+                    fields[Value.BoolValueFieldNumber].Accessor.SetValue(message, firstToken.Type == JsonToken.TokenType.True);
+                    return;
+                case JsonToken.TokenType.StartObject:
+                    {
+                        var field = fields[Value.StructValueFieldNumber];
+                        var structMessage = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(structMessage, tokenizer);
+                        field.Accessor.SetValue(message, structMessage);
+                        return;
+                    }
+                case JsonToken.TokenType.StartArray:
+                    {
+                        var field = fields[Value.ListValueFieldNumber];
+                        var list = NewMessageForField(field);
+                        tokenizer.PushBack(firstToken);
+                        Merge(list, tokenizer);
+                        field.Accessor.SetValue(message, list);
+                        return;
+                    }
+                default:
+                    throw new InvalidOperationException("Unexpected token type: " + firstToken.Type);
+            }
+        }
+
+        private void MergeStruct(IMessage message, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Struct");
+            }
+            tokenizer.PushBack(token);
+
+            var field = message.Descriptor.Fields[Struct.FieldsFieldNumber];
+            MergeMapField(message, field, tokenizer);
+        }
+
+        private void MergeAny(IMessage message, JsonTokenizer tokenizer)
+        {
+            // Record the token stream until we see the @type property. At that point, we can take the value, consult
+            // the type registry for the relevant message, and replay the stream, omitting the @type property.
+            var tokens = new List<JsonToken>();
+
+            var token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StartObject)
+            {
+                throw new InvalidProtocolBufferException("Expected object value for Any");
+            }
+            int typeUrlObjectDepth = tokenizer.ObjectDepth;
+
+            // The check for the property depth protects us from nested Any values which occur before the type URL
+            // for *this* Any.
+            while (token.Type != JsonToken.TokenType.Name ||
+                token.StringValue != JsonFormatter.AnyTypeUrlField ||
+                tokenizer.ObjectDepth != typeUrlObjectDepth)
+            {
+                tokens.Add(token);
+                token = tokenizer.Next();
+
+                if (tokenizer.ObjectDepth < typeUrlObjectDepth)
+                {
+                    throw new InvalidProtocolBufferException("Any message with no @type");
+                }
+            }
+
+            // Don't add the @type property or its value to the recorded token list
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Any.@type");
+            }
+            string typeUrl = token.StringValue;
+            string typeName = JsonFormatter.GetTypeName(typeUrl);
+
+            MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
+            if (descriptor == null)
+            {
+                throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
+            }
+
+            // Now replay the token stream we've already read and anything that remains of the object, just parsing it
+            // as normal. Our original tokenizer should end up at the end of the object.
+            var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer);
+            var body = descriptor.Parser.CreateTemplate();
+            if (descriptor.IsWellKnownType)
+            {
+                MergeWellKnownTypeAnyBody(body, replay);
+            }
+            else
+            {
+                Merge(body, replay);
+            }
+            var data = body.ToByteString();
+
+            // Now that we have the message data, we can pack it into an Any (the message received as a parameter).
+            message.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.SetValue(message, typeUrl);
+            message.Descriptor.Fields[Any.ValueFieldNumber].Accessor.SetValue(message, data);
+        }
+
+        // Well-known types end up in a property called "value" in the JSON. As there's no longer a @type property
+        // in the given JSON token stream, we should *only* have tokens of start-object, name("value"), the value
+        // itself, and then end-object.
+        private void MergeWellKnownTypeAnyBody(IMessage body, JsonTokenizer tokenizer)
+        {
+            var token = tokenizer.Next(); // Definitely start-object; checked in previous method
+            token = tokenizer.Next();
+            // TODO: What about an absent Int32Value, for example?
+            if (token.Type != JsonToken.TokenType.Name || token.StringValue != JsonFormatter.AnyWellKnownTypeValueField)
+            {
+                throw new InvalidProtocolBufferException($"Expected '{JsonFormatter.AnyWellKnownTypeValueField}' property for well-known type Any body");
+            }
+            Merge(body, tokenizer);
+            token = tokenizer.Next();
+            if (token.Type != JsonToken.TokenType.EndObject)
+            {
+                throw new InvalidProtocolBufferException($"Expected end-object token after @type/value for well-known type");
+            }
+        }
+
+        #region Utility methods which don't depend on the state (or settings) of the parser.
+        private static object ParseMapKey(FieldDescriptor field, string keyText)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.Bool:
+                    if (keyText == "true")
+                    {
+                        return true;
+                    }
+                    if (keyText == "false")
+                    {
+                        return false;
+                    }
+                    throw new InvalidProtocolBufferException("Invalid string for bool map key: " + keyText);
+                case FieldType.String:
+                    return keyText;
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(keyText, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(keyText, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(keyText, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(keyText, ulong.Parse);
+                default:
+                    throw new InvalidProtocolBufferException("Invalid field type for map: " + field.FieldType);
+            }
+        }
+
+        private static object ParseSingleNumberValue(FieldDescriptor field, JsonToken token)
+        {
+            double value = token.NumberValue;
+            checked
+            {
+                try
+                {
+                    switch (field.FieldType)
+                    {
+                        case FieldType.Int32:
+                        case FieldType.SInt32:
+                        case FieldType.SFixed32:
+                            CheckInteger(value);
+                            return (int) value;
+                        case FieldType.UInt32:
+                        case FieldType.Fixed32:
+                            CheckInteger(value);
+                            return (uint) value;
+                        case FieldType.Int64:
+                        case FieldType.SInt64:
+                        case FieldType.SFixed64:
+                            CheckInteger(value);
+                            return (long) value;
+                        case FieldType.UInt64:
+                        case FieldType.Fixed64:
+                            CheckInteger(value);
+                            return (ulong) value;
+                        case FieldType.Double:
+                            return value;
+                        case FieldType.Float:
+                            if (double.IsNaN(value))
+                            {
+                                return float.NaN;
+                            }
+                            if (value > float.MaxValue || value < float.MinValue)
+                            {
+                                if (double.IsPositiveInfinity(value))
+                                {
+                                    return float.PositiveInfinity;
+                                }
+                                if (double.IsNegativeInfinity(value))
+                                {
+                                    return float.NegativeInfinity;
+                                }
+                                throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                            }
+                            return (float) value;
+                        case FieldType.Enum:
+                            CheckInteger(value);
+                            // Just return it as an int, and let the CLR convert it.
+                            // Note that we deliberately don't check that it's a known value.
+                            return (int) value;
+                        default:
+                            throw new InvalidProtocolBufferException($"Unsupported conversion from JSON number for field type {field.FieldType}");
+                    }
+                }
+                catch (OverflowException)
+                {
+                    throw new InvalidProtocolBufferException($"Value out of range: {value}");
+                }
+            }
+        }
+
+        private static void CheckInteger(double value)
+        {
+            if (double.IsInfinity(value) || double.IsNaN(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }
+            if (value != Math.Floor(value))
+            {
+                throw new InvalidProtocolBufferException($"Value not an integer: {value}");
+            }            
+        }
+
+        private static object ParseSingleStringValue(FieldDescriptor field, string text)
+        {
+            switch (field.FieldType)
+            {
+                case FieldType.String:
+                    return text;
+                case FieldType.Bytes:
+                    try
+                    {
+                        return ByteString.FromBase64(text);
+                    }
+                    catch (FormatException e)
+                    {
+                        throw InvalidProtocolBufferException.InvalidBase64(e);
+                    }
+                case FieldType.Int32:
+                case FieldType.SInt32:
+                case FieldType.SFixed32:
+                    return ParseNumericString(text, int.Parse);
+                case FieldType.UInt32:
+                case FieldType.Fixed32:
+                    return ParseNumericString(text, uint.Parse);
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                case FieldType.SFixed64:
+                    return ParseNumericString(text, long.Parse);
+                case FieldType.UInt64:
+                case FieldType.Fixed64:
+                    return ParseNumericString(text, ulong.Parse);
+                case FieldType.Double:
+                    double d = ParseNumericString(text, double.Parse);
+                    ValidateInfinityAndNan(text, double.IsPositiveInfinity(d), double.IsNegativeInfinity(d), double.IsNaN(d));
+                    return d;
+                case FieldType.Float:
+                    float f = ParseNumericString(text, float.Parse);
+                    ValidateInfinityAndNan(text, float.IsPositiveInfinity(f), float.IsNegativeInfinity(f), float.IsNaN(f));
+                    return f;
+                case FieldType.Enum:
+                    var enumValue = field.EnumType.FindValueByName(text);
+                    if (enumValue == null)
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid enum value: {text} for enum type: {field.EnumType.FullName}");
+                    }
+                    // Just return it as an int, and let the CLR convert it.
+                    return enumValue.Number;
+                default:
+                    throw new InvalidProtocolBufferException($"Unsupported conversion from JSON string for field type {field.FieldType}");
+            }
+        }
+
+        /// <summary>
+        /// Creates a new instance of the message type for the given field.
+        /// </summary>
+        private static IMessage NewMessageForField(FieldDescriptor field)
+        {
+            return field.MessageType.Parser.CreateTemplate();
+        }
+
+        private static T ParseNumericString<T>(string text, Func<string, NumberStyles, IFormatProvider, T> parser)
+        {
+            // Can't prohibit this with NumberStyles.
+            if (text.StartsWith("+"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+            if (text.StartsWith("0") && text.Length > 1)
+            {
+                if (text[1] >= '0' && text[1] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            else if (text.StartsWith("-0") && text.Length > 2)
+            {
+                if (text[2] >= '0' && text[2] <= '9')
+                {
+                    throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+                }
+            }
+            try
+            {
+                return parser(text, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value for type: {text}");
+            }
+            catch (OverflowException)
+            {
+                throw new InvalidProtocolBufferException($"Value out of range: {text}");
+            }
+        }
+
+        /// <summary>
+        /// Checks that any infinite/NaN values originated from the correct text.
+        /// This corrects the lenient whitespace handling of double.Parse/float.Parse, as well as the
+        /// way that Mono parses out-of-range values as infinity.
+        /// </summary>
+        private static void ValidateInfinityAndNan(string text, bool isPositiveInfinity, bool isNegativeInfinity, bool isNaN)
+        {
+            if ((isPositiveInfinity && text != "Infinity") ||
+                (isNegativeInfinity && text != "-Infinity") ||
+                (isNaN && text != "NaN"))
+            {
+                throw new InvalidProtocolBufferException($"Invalid numeric value: {text}");
+            }
+        }
+
+        private static void MergeTimestamp(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Timestamp");
+            }
+            var match = TimestampRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Timestamp value: {token.StringValue}");
+            }
+            var dateTime = match.Groups["datetime"].Value;
+            var subseconds = match.Groups["subseconds"].Value;
+            var offset = match.Groups["offset"].Value;
+
+            try
+            {
+                DateTime parsed = DateTime.ParseExact(
+                    dateTime,
+                    "yyyy-MM-dd'T'HH:mm:ss",
+                    CultureInfo.InvariantCulture,
+                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
+                // TODO: It would be nice not to have to create all these objects... easy to optimize later though.
+                Timestamp timestamp = Timestamp.FromDateTime(parsed);
+                int nanosToAdd = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1), CultureInfo.InvariantCulture);
+                    nanosToAdd = parsedFraction * SubsecondScalingFactors[subseconds.Length];
+                }
+                int secondsToAdd = 0;
+                if (offset != "Z")
+                {
+                    // This is the amount we need to *subtract* from the local time to get to UTC - hence - => +1 and vice versa.
+                    int sign = offset[0] == '-' ? 1 : -1;
+                    int hours = int.Parse(offset.Substring(1, 2), CultureInfo.InvariantCulture);
+                    int minutes = int.Parse(offset.Substring(4, 2));
+                    int totalMinutes = hours * 60 + minutes;
+                    if (totalMinutes > 18 * 60)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    if (totalMinutes == 0 && sign == 1)
+                    {
+                        // This is an offset of -00:00, which means "unknown local offset". It makes no sense for a timestamp.
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                    // We need to *subtract* the offset from local time to get UTC.
+                    secondsToAdd = sign * totalMinutes * 60;
+                }
+                // Ensure we've got the right signs. Currently unnecessary, but easy to do.
+                if (secondsToAdd < 0 && nanosToAdd > 0)
+                {
+                    secondsToAdd++;
+                    nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond;
+                }
+                if (secondsToAdd != 0 || nanosToAdd != 0)
+                {
+                    timestamp += new Duration { Nanos = nanosToAdd, Seconds = secondsToAdd };
+                    // The resulting timestamp after offset change would be out of our expected range. Currently the Timestamp message doesn't validate this
+                    // anywhere, but we shouldn't parse it.
+                    if (timestamp.Seconds < Timestamp.UnixSecondsAtBclMinValue || timestamp.Seconds > Timestamp.UnixSecondsAtBclMaxValue)
+                    {
+                        throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+                    }
+                }
+                message.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.SetValue(message, timestamp.Seconds);
+                message.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.SetValue(message, timestamp.Nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException("Invalid Timestamp value: " + token.StringValue);
+            }
+        }
+
+        private static void MergeDuration(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for Duration");
+            }
+            var match = DurationRegex.Match(token.StringValue);
+            if (!match.Success)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var sign = match.Groups["sign"].Value;
+            var secondsText = match.Groups["int"].Value;
+            // Prohibit leading insignficant zeroes
+            if (secondsText[0] == '0' && secondsText.Length > 1)
+            {
+                throw new InvalidProtocolBufferException("Invalid Duration value: " + token.StringValue);
+            }
+            var subseconds = match.Groups["subseconds"].Value;
+            var multiplier = sign == "-" ? -1 : 1;
+
+            try
+            {
+                long seconds = long.Parse(secondsText, CultureInfo.InvariantCulture) * multiplier;
+                int nanos = 0;
+                if (subseconds != "")
+                {
+                    // This should always work, as we've got 1-9 digits.
+                    int parsedFraction = int.Parse(subseconds.Substring(1));
+                    nanos = parsedFraction * SubsecondScalingFactors[subseconds.Length] * multiplier;
+                }
+                if (!Duration.IsNormalized(seconds, nanos))
+                {
+                    throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+                }
+                message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.SetValue(message, seconds);
+                message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.SetValue(message, nanos);
+            }
+            catch (FormatException)
+            {
+                throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
+            }
+        }
+
+        private static void MergeFieldMask(IMessage message, JsonToken token)
+        {
+            if (token.Type != JsonToken.TokenType.StringValue)
+            {
+                throw new InvalidProtocolBufferException("Expected string value for FieldMask");
+            }
+            // TODO: Do we *want* to remove empty entries? Probably okay to treat "" as "no paths", but "foo,,bar"?
+            string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators, StringSplitOptions.RemoveEmptyEntries);
+            IList messagePaths = (IList) message.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(message);
+            foreach (var path in jsonPaths)
+            {
+                messagePaths.Add(ToSnakeCase(path));
+            }
+        }
+        
+        // Ported from src/google/protobuf/util/internal/utility.cc
+        private static string ToSnakeCase(string text)
+        {
+            var builder = new StringBuilder(text.Length * 2);
+            // Note: this is probably unnecessary now, but currently retained to be as close as possible to the
+            // C++, whilst still throwing an exception on underscores.
+            bool wasNotUnderscore = false;  // Initialize to false for case 1 (below)
+            bool wasNotCap = false;
+
+            for (int i = 0; i < text.Length; i++)
+            {
+                char c = text[i];
+                if (c >= 'A' && c <= 'Z') // ascii_isupper
+                {
+                    // Consider when the current character B is capitalized:
+                    // 1) At beginning of input:   "B..." => "b..."
+                    //    (e.g. "Biscuit" => "biscuit")
+                    // 2) Following a lowercase:   "...aB..." => "...a_b..."
+                    //    (e.g. "gBike" => "g_bike")
+                    // 3) At the end of input:     "...AB" => "...ab"
+                    //    (e.g. "GoogleLAB" => "google_lab")
+                    // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
+                    //    (e.g. "GBike" => "g_bike")
+                    if (wasNotUnderscore &&               //            case 1 out
+                        (wasNotCap ||                     // case 2 in, case 3 out
+                         (i + 1 < text.Length &&         //            case 3 out
+                          (text[i + 1] >= 'a' && text[i + 1] <= 'z')))) // ascii_islower(text[i + 1])
+                    {  // case 4 in
+                       // We add an underscore for case 2 and case 4.
+                        builder.Append('_');
+                    }
+                    // ascii_tolower, but we already know that c *is* an upper case ASCII character...
+                    builder.Append((char) (c + 'a' - 'A'));
+                    wasNotUnderscore = true;
+                    wasNotCap = false;
+                }
+                else
+                {
+                    builder.Append(c);
+                    if (c == '_')
+                    {
+                        throw new InvalidProtocolBufferException($"Invalid field mask: {text}");
+                    }
+                    wasNotUnderscore = true;
+                    wasNotCap = true;
+                }
+            }
+            return builder.ToString();
+        }
+        #endregion
+
+        /// <summary>
+        /// Settings controlling JSON parsing.
+        /// </summary>
+        public sealed class Settings
+        {
+            /// <summary>
+            /// Default settings, as used by <see cref="JsonParser.Default"/>. This has the same default
+            /// recursion limit as <see cref="CodedInputStream"/>, and an empty type registry.
+            /// </summary>
+            public static Settings Default { get; }
+
+            // Workaround for the Mono compiler complaining about XML comments not being on
+            // valid language elements.
+            static Settings()
+            {
+                Default = new Settings(CodedInputStream.DefaultRecursionLimit);
+            }
+
+            /// <summary>
+            /// The maximum depth of messages to parse. Note that this limit only applies to parsing
+            /// messages, not collections - so a message within a collection within a message only counts as
+            /// depth 2, not 3.
+            /// </summary>
+            public int RecursionLimit { get; }
+
+            /// <summary>
+            /// The type registry used to parse <see cref="Any"/> messages.
+            /// </summary>
+            public TypeRegistry TypeRegistry { get; }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            public Settings(int recursionLimit) : this(recursionLimit, TypeRegistry.Empty)
+            {
+            }
+
+            /// <summary>
+            /// Creates a new <see cref="Settings"/> object with the specified recursion limit and type registry.
+            /// </summary>
+            /// <param name="recursionLimit">The maximum depth of messages to parse</param>
+            /// <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param>
+            public Settings(int recursionLimit, TypeRegistry typeRegistry)
+            {
+                RecursionLimit = recursionLimit;
+                TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry));
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonToken.cs b/csharp/src/Google.Protobuf/JsonToken.cs
new file mode 100644
index 0000000..6c0138c
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonToken.cs
@@ -0,0 +1,166 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+
+namespace Google.Protobuf
+{
+    internal sealed class JsonToken : IEquatable<JsonToken>
+    {
+        // Tokens with no value can be reused.
+        private static readonly JsonToken _true = new JsonToken(TokenType.True);
+        private static readonly JsonToken _false = new JsonToken(TokenType.False);
+        private static readonly JsonToken _null = new JsonToken(TokenType.Null);
+        private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject);
+        private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject);
+        private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray);
+        private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray);
+        private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument);
+
+        internal static JsonToken Null { get { return _null; } }
+        internal static JsonToken False { get { return _false; } }
+        internal static JsonToken True { get { return _true; } }
+        internal static JsonToken StartObject{ get { return startObject; } }
+        internal static JsonToken EndObject { get { return endObject; } }
+        internal static JsonToken StartArray { get { return startArray; } }
+        internal static JsonToken EndArray { get { return endArray; } }
+        internal static JsonToken EndDocument { get { return endDocument; } }
+
+        internal static JsonToken Name(string name)
+        {
+            return new JsonToken(TokenType.Name, stringValue: name);
+        }
+
+        internal static JsonToken Value(string value)
+        {
+            return new JsonToken(TokenType.StringValue, stringValue: value);
+        }
+
+        internal static JsonToken Value(double value)
+        {
+            return new JsonToken(TokenType.Number, numberValue: value);
+        }
+
+        internal enum TokenType
+        {
+            Null,
+            False,
+            True,
+            StringValue,
+            Number,
+            Name,
+            StartObject,
+            EndObject,
+            StartArray,
+            EndArray,
+            EndDocument
+        }
+
+        // A value is a string, number, array, object, null, true or false
+        // Arrays and objects have start/end
+        // A document consists of a value
+        // Objects are name/value sequences.
+
+        private readonly TokenType type;
+        private readonly string stringValue;
+        private readonly double numberValue;
+
+        internal TokenType Type { get { return type; } }
+        internal string StringValue { get { return stringValue; } }
+        internal double NumberValue { get { return numberValue; } }
+
+        private JsonToken(TokenType type, string stringValue = null, double numberValue = 0)
+        {
+            this.type = type;
+            this.stringValue = stringValue;
+            this.numberValue = numberValue;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as JsonToken);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+                hash = hash * 31 + (int) type;
+                hash = hash * 31 + stringValue == null ? 0 : stringValue.GetHashCode();
+                hash = hash * 31 + numberValue.GetHashCode();
+                return hash;
+            }
+        }
+
+        public override string ToString()
+        {
+            switch (type)
+            {
+                case TokenType.Null:
+                    return "null";
+                case TokenType.True:
+                    return "true";
+                case TokenType.False:
+                    return "false";
+                case TokenType.Name:
+                    return "name (" + stringValue + ")";
+                case TokenType.StringValue:
+                    return "value (" + stringValue + ")";
+                case TokenType.Number:
+                    return "number (" + numberValue + ")";
+                case TokenType.StartObject:
+                    return "start-object";
+                case TokenType.EndObject:
+                    return "end-object";
+                case TokenType.StartArray:
+                    return "start-array";
+                case TokenType.EndArray:
+                    return "end-array";
+                case TokenType.EndDocument:
+                    return "end-document";
+                default:
+                    throw new InvalidOperationException("Token is of unknown type " + type);
+            }
+        }
+
+        public bool Equals(JsonToken other)
+        {
+            if (ReferenceEquals(other, null))
+            {
+                return false;
+            }
+            // Note use of other.numberValue.Equals rather than ==, so that NaN compares appropriately.
+            return other.type == type && other.stringValue == stringValue && other.numberValue.Equals(numberValue);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
new file mode 100644
index 0000000..09a6d43
--- /dev/null
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -0,0 +1,738 @@
+#region Copyright notice and license
+// 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.
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Simple but strict JSON tokenizer, rigidly following RFC 7159.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This tokenizer is stateful, and only returns "useful" tokens - names, values etc.
+    /// It does not create tokens for the separator between names and values, or for the comma
+    /// between values. It validates the token stream as it goes - so callers can assume that the
+    /// tokens it produces are appropriate. For example, it would never produce "start object, end array."
+    /// </para>
+    /// <para>Implementation details: the base class handles single token push-back and </para>
+    /// <para>Not thread-safe.</para>
+    /// </remarks>
+    internal abstract class JsonTokenizer
+    {
+        private JsonToken bufferedToken;
+
+        /// <summary>
+        ///  Creates a tokenizer that reads from the given text reader.
+        /// </summary>
+        internal static JsonTokenizer FromTextReader(TextReader reader)
+        {
+            return new JsonTextTokenizer(reader);
+        }
+
+        /// <summary>
+        /// Creates a tokenizer that first replays the given list of tokens, then continues reading
+        /// from another tokenizer. Note that if the returned tokenizer is "pushed back", that does not push back
+        /// on the continuation tokenizer, or vice versa. Care should be taken when using this method - it was
+        /// created for the sake of Any parsing.
+        /// </summary>
+        internal static JsonTokenizer FromReplayedTokens(IList<JsonToken> tokens, JsonTokenizer continuation)
+        {
+            return new JsonReplayTokenizer(tokens, continuation);
+        }
+
+        /// <summary>
+        /// Returns the depth of the stack, purely in objects (not collections).
+        /// Informally, this is the number of remaining unclosed '{' characters we have.
+        /// </summary>
+        internal int ObjectDepth { get; private set; }
+
+        // TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
+        // token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
+        internal void PushBack(JsonToken token)
+        {
+            if (bufferedToken != null)
+            {
+                throw new InvalidOperationException("Can't push back twice");
+            }
+            bufferedToken = token;
+            if (token.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth--;
+            }
+            else if (token.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth++;
+            }
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream. An EndDocument token is returned to indicate the end of the stream,
+        /// after which point <c>Next()</c> should not be called again.
+        /// </summary>
+        /// <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
+        /// <returns>The next token in the stream. This is never null.</returns>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        internal JsonToken Next()
+        {
+            JsonToken tokenToReturn;
+            if (bufferedToken != null)
+            {
+                tokenToReturn = bufferedToken;
+                bufferedToken = null;
+            }
+            else
+            {
+                tokenToReturn = NextImpl();
+            }
+            if (tokenToReturn.Type == JsonToken.TokenType.StartObject)
+            {
+                ObjectDepth++;
+            }
+            else if (tokenToReturn.Type == JsonToken.TokenType.EndObject)
+            {
+                ObjectDepth--;
+            }
+            return tokenToReturn;
+        }
+
+        /// <summary>
+        /// Returns the next JSON token in the stream, when requested by the base class. (The <see cref="Next"/> method delegates
+        /// to this if it doesn't have a buffered token.)
+        /// </summary>
+        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+        /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
+        protected abstract JsonToken NextImpl();
+
+        /// <summary>
+        /// Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
+        /// </summary>
+        private class JsonReplayTokenizer : JsonTokenizer
+        {
+            private readonly IList<JsonToken> tokens;
+            private readonly JsonTokenizer nextTokenizer;
+            private int nextTokenIndex;
+
+            internal JsonReplayTokenizer(IList<JsonToken> tokens, JsonTokenizer nextTokenizer)
+            {
+                this.tokens = tokens;
+                this.nextTokenizer = nextTokenizer;
+            }
+
+            // FIXME: Object depth not maintained...
+            protected override JsonToken NextImpl()
+            {
+                if (nextTokenIndex >= tokens.Count)
+                {
+                    return nextTokenizer.Next();
+                }
+                return tokens[nextTokenIndex++];
+            }
+        }
+
+        /// <summary>
+        /// Tokenizer which does all the *real* work of parsing JSON.
+        /// </summary>
+        private sealed class JsonTextTokenizer : JsonTokenizer
+        {
+            // The set of states in which a value is valid next token.
+            private static readonly State ValueStates = State.ArrayStart | State.ArrayAfterComma | State.ObjectAfterColon | State.StartOfDocument;
+
+            private readonly Stack<ContainerType> containerStack = new Stack<ContainerType>();
+            private readonly PushBackReader reader;
+            private State state;
+
+            internal JsonTextTokenizer(TextReader reader)
+            {
+                this.reader = new PushBackReader(reader);
+                state = State.StartOfDocument;
+                containerStack.Push(ContainerType.Document);
+            }
+
+            /// <remarks>
+            /// This method essentially just loops through characters skipping whitespace, validating and
+            /// changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
+            /// until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
+            /// it returns the token. Although the method is large, it would be relatively hard to break down further... most
+            /// of it is the large switch statement, which sometimes returns and sometimes doesn't.
+            /// </remarks>
+            protected override JsonToken NextImpl()
+            {
+                if (state == State.ReaderExhausted)
+                {
+                    throw new InvalidOperationException("Next() called after end of document");
+                }
+                while (true)
+                {
+                    var next = reader.Read();
+                    if (next == null)
+                    {
+                        ValidateState(State.ExpectedEndOfDocument, "Unexpected end of document in state: ");
+                        state = State.ReaderExhausted;
+                        return JsonToken.EndDocument;
+                    }
+                    switch (next.Value)
+                    {
+                        // Skip whitespace between tokens
+                        case ' ':
+                        case '\t':
+                        case '\r':
+                        case '\n':
+                            break;
+                        case ':':
+                            ValidateState(State.ObjectBeforeColon, "Invalid state to read a colon: ");
+                            state = State.ObjectAfterColon;
+                            break;
+                        case ',':
+                            ValidateState(State.ObjectAfterProperty | State.ArrayAfterValue, "Invalid state to read a colon: ");
+                            state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
+                            break;
+                        case '"':
+                            string stringValue = ReadString();
+                            if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
+                            {
+                                state = State.ObjectBeforeColon;
+                                return JsonToken.Name(stringValue);
+                            }
+                            else
+                            {
+                                ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
+                                return JsonToken.Value(stringValue);
+                            }
+                        case '{':
+                            ValidateState(ValueStates, "Invalid state to read an open brace: ");
+                            state = State.ObjectStart;
+                            containerStack.Push(ContainerType.Object);
+                            return JsonToken.StartObject;
+                        case '}':
+                            ValidateState(State.ObjectAfterProperty | State.ObjectStart, "Invalid state to read a close brace: ");
+                            PopContainer();
+                            return JsonToken.EndObject;
+                        case '[':
+                            ValidateState(ValueStates, "Invalid state to read an open square bracket: ");
+                            state = State.ArrayStart;
+                            containerStack.Push(ContainerType.Array);
+                            return JsonToken.StartArray;
+                        case ']':
+                            ValidateState(State.ArrayAfterValue | State.ArrayStart, "Invalid state to read a close square bracket: ");
+                            PopContainer();
+                            return JsonToken.EndArray;
+                        case 'n': // Start of null
+                            ConsumeLiteral("null");
+                            ValidateAndModifyStateForValue("Invalid state to read a null literal: ");
+                            return JsonToken.Null;
+                        case 't': // Start of true
+                            ConsumeLiteral("true");
+                            ValidateAndModifyStateForValue("Invalid state to read a true literal: ");
+                            return JsonToken.True;
+                        case 'f': // Start of false
+                            ConsumeLiteral("false");
+                            ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
+                            return JsonToken.False;
+                        case '-': // Start of a number
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
+                            double number = ReadNumber(next.Value);
+                            ValidateAndModifyStateForValue("Invalid state to read a number token: ");
+                            return JsonToken.Value(number);
+                        default:
+                            throw new InvalidJsonException("Invalid first character of token: " + next.Value);
+                    }
+                }
+            }
+
+            private void ValidateState(State validStates, string errorPrefix)
+            {
+                if ((validStates & state) == 0)
+                {
+                    throw reader.CreateException(errorPrefix + state);
+                }
+            }
+
+            /// <summary>
+            /// Reads a string token. It is assumed that the opening " has already been read.
+            /// </summary>
+            private string ReadString()
+            {
+                var value = new StringBuilder();
+                bool haveHighSurrogate = false;
+                while (true)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading string");
+                    if (c < ' ')
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
+                    }
+                    if (c == '"')
+                    {
+                        if (haveHighSurrogate)
+                        {
+                            throw reader.CreateException("Invalid use of surrogate pair code units");
+                        }
+                        return value.ToString();
+                    }
+                    if (c == '\\')
+                    {
+                        c = ReadEscapedCharacter();
+                    }
+                    // TODO: Consider only allowing surrogate pairs that are either both escaped,
+                    // or both not escaped. It would be a very odd text stream that contained a "lone" high surrogate
+                    // followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
+                    if (haveHighSurrogate != char.IsLowSurrogate(c))
+                    {
+                        throw reader.CreateException("Invalid use of surrogate pair code units");
+                    }
+                    haveHighSurrogate = char.IsHighSurrogate(c);
+                    value.Append(c);
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped character. It is assumed that the leading backslash has already been read.
+            /// </summary>
+            private char ReadEscapedCharacter()
+            {
+                char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence");
+                switch (c)
+                {
+                    case 'n':
+                        return '\n';
+                    case '\\':
+                        return '\\';
+                    case 'b':
+                        return '\b';
+                    case 'f':
+                        return '\f';
+                    case 'r':
+                        return '\r';
+                    case 't':
+                        return '\t';
+                    case '"':
+                        return '"';
+                    case '/':
+                        return '/';
+                    case 'u':
+                        return ReadUnicodeEscape();
+                    default:
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                }
+            }
+
+            /// <summary>
+            /// Reads an escaped Unicode 4-nybble hex sequence. It is assumed that the leading \u has already been read.
+            /// </summary>
+            private char ReadUnicodeEscape()
+            {
+                int result = 0;
+                for (int i = 0; i < 4; i++)
+                {
+                    char c = reader.ReadOrFail("Unexpected end of text while reading Unicode escape sequence");
+                    int nybble;
+                    if (c >= '0' && c <= '9')
+                    {
+                        nybble = c - '0';
+                    }
+                    else if (c >= 'a' && c <= 'f')
+                    {
+                        nybble = c - 'a' + 10;
+                    }
+                    else if (c >= 'A' && c <= 'F')
+                    {
+                        nybble = c - 'A' + 10;
+                    }
+                    else
+                    {
+                        throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+                    }
+                    result = (result << 4) + nybble;
+                }
+                return (char) result;
+            }
+
+            /// <summary>
+            /// Consumes a text-only literal, throwing an exception if the read text doesn't match it.
+            /// It is assumed that the first letter of the literal has already been read.
+            /// </summary>
+            private void ConsumeLiteral(string text)
+            {
+                for (int i = 1; i < text.Length; i++)
+                {
+                    char? next = reader.Read();
+                    if (next == null)
+                    {
+                        throw reader.CreateException("Unexpected end of text while reading literal token " + text);
+                    }
+                    if (next.Value != text[i])
+                    {
+                        throw reader.CreateException("Unexpected character while reading literal token " + text);
+                    }
+                }
+            }
+
+            private double ReadNumber(char initialCharacter)
+            {
+                StringBuilder builder = new StringBuilder();
+                if (initialCharacter == '-')
+                {
+                    builder.Append("-");
+                }
+                else
+                {
+                    reader.PushBack(initialCharacter);
+                }
+                // Each method returns the character it read that doesn't belong in that part,
+                // so we know what to do next, including pushing the character back at the end.
+                // null is returned for "end of text".
+                char? next = ReadInt(builder);
+                if (next == '.')
+                {
+                    next = ReadFrac(builder);
+                }
+                if (next == 'e' || next == 'E')
+                {
+                    next = ReadExp(builder);
+                }
+                // If we read a character which wasn't part of the number, push it back so we can read it again
+                // to parse the next token.
+                if (next != null)
+                {
+                    reader.PushBack(next.Value);
+                }
+
+                // TODO: What exception should we throw if the value can't be represented as a double?
+                try
+                {
+                    return double.Parse(builder.ToString(),
+                        NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
+                        CultureInfo.InvariantCulture);
+                }
+                catch (OverflowException)
+                {
+                    throw reader.CreateException("Numeric value out of range: " + builder);
+                }
+            }
+
+            private char? ReadInt(StringBuilder builder)
+            {
+                char first = reader.ReadOrFail("Invalid numeric literal");
+                if (first < '0' || first > '9')
+                {
+                    throw reader.CreateException("Invalid numeric literal");
+                }
+                builder.Append(first);
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (first == '0' && digitCount != 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
+                }
+                return next;
+            }
+
+            private char? ReadFrac(StringBuilder builder)
+            {
+                builder.Append('.'); // Already consumed this
+                int digitCount;
+                char? next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
+                }
+                return next;
+            }
+
+            private char? ReadExp(StringBuilder builder)
+            {
+                builder.Append('E'); // Already consumed this (or 'e')
+                char? next = reader.Read();
+                if (next == null)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits");
+                }
+                if (next == '-' || next == '+')
+                {
+                    builder.Append(next.Value);
+                }
+                else
+                {
+                    reader.PushBack(next.Value);
+                }
+                int digitCount;
+                next = ConsumeDigits(builder, out digitCount);
+                if (digitCount == 0)
+                {
+                    throw reader.CreateException("Invalid numeric literal: exponent without value");
+                }
+                return next;
+            }
+
+            private char? ConsumeDigits(StringBuilder builder, out int count)
+            {
+                count = 0;
+                while (true)
+                {
+                    char? next = reader.Read();
+                    if (next == null || next.Value < '0' || next.Value > '9')
+                    {
+                        return next;
+                    }
+                    count++;
+                    builder.Append(next.Value);
+                }
+            }
+
+            /// <summary>
+            /// Validates that we're in a valid state to read a value (using the given error prefix if necessary)
+            /// and changes the state to the appropriate one, e.g. ObjectAfterColon to ObjectAfterProperty.
+            /// </summary>
+            private void ValidateAndModifyStateForValue(string errorPrefix)
+            {
+                ValidateState(ValueStates, errorPrefix);
+                switch (state)
+                {
+                    case State.StartOfDocument:
+                        state = State.ExpectedEndOfDocument;
+                        return;
+                    case State.ObjectAfterColon:
+                        state = State.ObjectAfterProperty;
+                        return;
+                    case State.ArrayStart:
+                    case State.ArrayAfterComma:
+                        state = State.ArrayAfterValue;
+                        return;
+                    default:
+                        throw new InvalidOperationException("ValidateAndModifyStateForValue does not handle all value states (and should)");
+                }
+            }
+
+            /// <summary>
+            /// Pops the top-most container, and sets the state to the appropriate one for the end of a value
+            /// in the parent container.
+            /// </summary>
+            private void PopContainer()
+            {
+                containerStack.Pop();
+                var parent = containerStack.Peek();
+                switch (parent)
+                {
+                    case ContainerType.Object:
+                        state = State.ObjectAfterProperty;
+                        break;
+                    case ContainerType.Array:
+                        state = State.ArrayAfterValue;
+                        break;
+                    case ContainerType.Document:
+                        state = State.ExpectedEndOfDocument;
+                        break;
+                    default:
+                        throw new InvalidOperationException("Unexpected container type: " + parent);
+                }
+            }
+
+            private enum ContainerType
+            {
+                Document, Object, Array
+            }
+
+            /// <summary>
+            /// Possible states of the tokenizer.
+            /// </summary>
+            /// <remarks>
+            /// <para>This is a flags enum purely so we can simply and efficiently represent a set of valid states
+            /// for checking.</para>
+            /// <para>
+            /// Each is documented with an example,
+            /// where ^ represents the current position within the text stream. The examples all use string values,
+            /// but could be any value, including nested objects/arrays.
+            /// The complete state of the tokenizer also includes a stack to indicate the contexts (arrays/objects).
+            /// Any additional notional state of "AfterValue" indicates that a value has been completed, at which 
+            /// point there's an immediate transition to ExpectedEndOfDocument,  ObjectAfterProperty or ArrayAfterValue.
+            /// </para>
+            /// <para>
+            /// These states were derived manually by reading RFC 7159 carefully.
+            /// </para>
+            /// </remarks>
+            [Flags]
+            private enum State
+            {
+                /// <summary>
+                /// ^ { "foo": "bar" }
+                /// Before the value in a document. Next states: ObjectStart, ArrayStart, "AfterValue"
+                /// </summary>
+                StartOfDocument = 1 << 0,
+                /// <summary>
+                /// { "foo": "bar" } ^
+                /// After the value in a document. Next states: ReaderExhausted
+                /// </summary>
+                ExpectedEndOfDocument = 1 << 1,
+                /// <summary>
+                /// { "foo": "bar" } ^ (and already read to the end of the reader)
+                /// Terminal state.
+                /// </summary>
+                ReaderExhausted = 1 << 2,
+                /// <summary>
+                /// { ^ "foo": "bar" }
+                /// Before the *first* property in an object.
+                /// Next states:
+                /// "AfterValue" (empty object)
+                /// ObjectBeforeColon (read a name)
+                /// </summary>
+                ObjectStart = 1 << 3,
+                /// <summary>
+                /// { "foo" ^ : "bar", "x": "y" }
+                /// Next state: ObjectAfterColon
+                /// </summary>
+                ObjectBeforeColon = 1 << 4,
+                /// <summary>
+                /// { "foo" : ^ "bar", "x": "y" }
+                /// Before any property other than the first in an object.
+                /// (Equivalently: after any property in an object) 
+                /// Next states:
+                /// "AfterValue" (value is simple)
+                /// ObjectStart (value is object)
+                /// ArrayStart (value is array)
+                /// </summary>
+                ObjectAfterColon = 1 << 5,
+                /// <summary>
+                /// { "foo" : "bar" ^ , "x" : "y" }
+                /// At the end of a property, so expecting either a comma or end-of-object
+                /// Next states: ObjectAfterComma or "AfterValue"
+                /// </summary>
+                ObjectAfterProperty = 1 << 6,
+                /// <summary>
+                /// { "foo":"bar", ^ "x":"y" }
+                /// Read the comma after the previous property, so expecting another property.
+                /// This is like ObjectStart, but closing brace isn't valid here
+                /// Next state: ObjectBeforeColon.
+                /// </summary>
+                ObjectAfterComma = 1 << 7,
+                /// <summary>
+                /// [ ^ "foo", "bar" ]
+                /// Before the *first* value in an array.
+                /// Next states:
+                /// "AfterValue" (read a value)
+                /// "AfterValue" (end of array; will pop stack)
+                /// </summary>
+                ArrayStart = 1 << 8,
+                /// <summary>
+                /// [ "foo" ^ , "bar" ]
+                /// After any value in an array, so expecting either a comma or end-of-array
+                /// Next states: ArrayAfterComma or "AfterValue"
+                /// </summary>
+                ArrayAfterValue = 1 << 9,
+                /// <summary>
+                /// [ "foo", ^ "bar" ]
+                /// After a comma in an array, so there *must* be another value (simple or complex).
+                /// Next states: "AfterValue" (simple value), StartObject, StartArray
+                /// </summary>
+                ArrayAfterComma = 1 << 10
+            }
+
+            /// <summary>
+            /// Wrapper around a text reader allowing small amounts of buffering and location handling.
+            /// </summary>
+            private class PushBackReader
+            {
+                // TODO: Add locations for errors etc.
+
+                private readonly TextReader reader;
+
+                internal PushBackReader(TextReader reader)
+                {
+                    // TODO: Wrap the reader in a BufferedReader?
+                    this.reader = reader;
+                }
+
+                /// <summary>
+                /// The buffered next character, if we have one.
+                /// </summary>
+                private char? nextChar;
+
+                /// <summary>
+                /// Returns the next character in the stream, or null if we have reached the end.
+                /// </summary>
+                /// <returns></returns>
+                internal char? Read()
+                {
+                    if (nextChar != null)
+                    {
+                        char? tmp = nextChar;
+                        nextChar = null;
+                        return tmp;
+                    }
+                    int next = reader.Read();
+                    return next == -1 ? null : (char?) next;
+                }
+
+                internal char ReadOrFail(string messageOnFailure)
+                {
+                    char? next = Read();
+                    if (next == null)
+                    {
+                        throw CreateException(messageOnFailure);
+                    }
+                    return next.Value;
+                }
+
+                internal void PushBack(char c)
+                {
+                    if (nextChar != null)
+                    {
+                        throw new InvalidOperationException("Cannot push back when already buffering a character");
+                    }
+                    nextChar = c;
+                }
+
+                /// <summary>
+                /// Creates a new exception appropriate for the current state of the reader.
+                /// </summary>
+                internal InvalidJsonException CreateException(string message)
+                {
+                    // TODO: Keep track of and use the location.
+                    return new InvalidJsonException(message);
+                }
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
index d2d057c..047156c 100644
--- a/csharp/src/Google.Protobuf/MessageExtensions.cs
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -46,8 +46,8 @@
         /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
         public static void MergeFrom(this IMessage message, byte[] data)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(data, "data");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
             CodedInputStream input = new CodedInputStream(data);
             message.MergeFrom(input);
             input.CheckReadEndOfStreamTag();
@@ -60,8 +60,8 @@
         /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
         public static void MergeFrom(this IMessage message, ByteString data)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(data, "data");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(data, "data");
             CodedInputStream input = data.CreateCodedInput();
             message.MergeFrom(input);
             input.CheckReadEndOfStreamTag();
@@ -74,8 +74,8 @@
         /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
         public static void MergeFrom(this IMessage message, Stream input)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(input, "input");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
             CodedInputStream codedInput = new CodedInputStream(input);
             message.MergeFrom(codedInput);
             codedInput.CheckReadEndOfStreamTag();
@@ -92,8 +92,8 @@
         /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
         public static void MergeDelimitedFrom(this IMessage message, Stream input)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(input, "input");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(input, "input");
             int size = (int) CodedInputStream.ReadRawVarint32(input);
             Stream limitedStream = new LimitedInputStream(input, size);
             message.MergeFrom(limitedStream);
@@ -106,7 +106,7 @@
         /// <returns>The message data as a byte array.</returns>
         public static byte[] ToByteArray(this IMessage message)
         {
-            Preconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(message, "message");
             byte[] result = new byte[message.CalculateSize()];
             CodedOutputStream output = new CodedOutputStream(result);
             message.WriteTo(output);
@@ -121,8 +121,8 @@
         /// <param name="output">The stream to write to.</param>
         public static void WriteTo(this IMessage message, Stream output)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(output, "output");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
             CodedOutputStream codedOutput = new CodedOutputStream(output);
             message.WriteTo(codedOutput);
             codedOutput.Flush();
@@ -135,8 +135,8 @@
         /// <param name="output">The output stream to write to.</param>
         public static void WriteDelimitedTo(this IMessage message, Stream output)
         {
-            Preconditions.CheckNotNull(message, "message");
-            Preconditions.CheckNotNull(output, "output");
+            ProtoPreconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(output, "output");
             CodedOutputStream codedOutput = new CodedOutputStream(output);
             codedOutput.WriteRawVarint32((uint)message.CalculateSize());
             message.WriteTo(codedOutput);
@@ -150,7 +150,7 @@
         /// <returns>The message data as a byte string.</returns>
         public static ByteString ToByteString(this IMessage message)
         {
-            Preconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(message, "message");
             return ByteString.AttachBytes(message.ToByteArray());
         }        
     }
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
index 6a6f101..8889638 100644
--- a/csharp/src/Google.Protobuf/MessageParser.cs
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -36,6 +36,109 @@
 namespace Google.Protobuf
 {
     /// <summary>
+    /// A general message parser, typically used by reflection-based code as all the methods
+    /// return simple <see cref="IMessage"/>.
+    /// </summary>
+    public class MessageParser
+    {
+        private Func<IMessage> factory;
+
+        internal MessageParser(Func<IMessage> factory)
+        {
+            this.factory = factory;
+        }
+
+        /// <summary>
+        /// Creates a template instance ready for population.
+        /// </summary>
+        /// <returns>An empty message.</returns>
+        internal IMessage CreateTemplate()
+        {
+            return factory();
+        }
+
+        /// <summary>
+        /// Parses a message from a byte array.
+        /// </summary>
+        /// <param name="data">The byte array containing the message. Must not be null.</param>
+        /// <returns>The newly parsed message.</returns>
+        public IMessage ParseFrom(byte[] data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given byte string.
+        /// </summary>
+        /// <param name="data">The data to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(ByteString data)
+        {
+            ProtoPreconditions.CheckNotNull(data, "data");
+            IMessage message = factory();
+            message.MergeFrom(data);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a length-delimited message from the given stream.
+        /// </summary>
+        /// <remarks>
+        /// The stream is expected to contain a length and then the data. Only the amount of data
+        /// specified by the length will be consumed.
+        /// </remarks>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseDelimitedFrom(Stream input)
+        {
+            IMessage message = factory();
+            message.MergeDelimitedFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given coded input stream.
+        /// </summary>
+        /// <param name="input">The stream to parse.</param>
+        /// <returns>The parsed message.</returns>
+        public IMessage ParseFrom(CodedInputStream input)
+        {
+            IMessage message = factory();
+            message.MergeFrom(input);
+            return message;
+        }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public IMessage ParseJson(string json)
+        {
+            IMessage message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
+    }
+
+    /// <summary>
     /// A parser for a specific message type.
     /// </summary>
     /// <remarks>
@@ -51,8 +154,12 @@
     /// </p>
     /// </remarks>
     /// <typeparam name="T">The type of message to be parsed.</typeparam>
-    public sealed class MessageParser<T> where T : IMessage<T>
+    public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
     {
+        // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
+        // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
+        // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
+        // The API wouldn't change anyway - just the implementation - so this work can be deferred.
         private readonly Func<T> factory; 
 
         /// <summary>
@@ -63,7 +170,7 @@
         /// to require a parameterless constructor: delegates are significantly faster to execute.
         /// </remarks>
         /// <param name="factory">Function to invoke when a new, empty message is required.</param>
-        public MessageParser(Func<T> factory)
+        public MessageParser(Func<T> factory) : base(() => factory())
         {
             this.factory = factory;
         }
@@ -72,7 +179,7 @@
         /// Creates a template instance ready for population.
         /// </summary>
         /// <returns>An empty message.</returns>
-        internal T CreateTemplate()
+        internal new T CreateTemplate()
         {
             return factory();
         }
@@ -82,9 +189,9 @@
         /// </summary>
         /// <param name="data">The byte array containing the message. Must not be null.</param>
         /// <returns>The newly parsed message.</returns>
-        public T ParseFrom(byte[] data)
+        public new T ParseFrom(byte[] data)
         {
-            Preconditions.CheckNotNull(data, "data");
+            ProtoPreconditions.CheckNotNull(data, "data");
             T message = factory();
             message.MergeFrom(data);
             return message;
@@ -95,9 +202,9 @@
         /// </summary>
         /// <param name="data">The data to parse.</param>
         /// <returns>The parsed message.</returns>
-        public T ParseFrom(ByteString data)
+        public new T ParseFrom(ByteString data)
         {
-            Preconditions.CheckNotNull(data, "data");
+            ProtoPreconditions.CheckNotNull(data, "data");
             T message = factory();
             message.MergeFrom(data);
             return message;
@@ -108,7 +215,7 @@
         /// </summary>
         /// <param name="input">The stream to parse.</param>
         /// <returns>The parsed message.</returns>
-        public T ParseFrom(Stream input)
+        public new T ParseFrom(Stream input)
         {
             T message = factory();
             message.MergeFrom(input);
@@ -124,7 +231,7 @@
         /// </remarks>
         /// <param name="input">The stream to parse.</param>
         /// <returns>The parsed message.</returns>
-        public T ParseDelimitedFrom(Stream input)
+        public new T ParseDelimitedFrom(Stream input)
         {
             T message = factory();
             message.MergeDelimitedFrom(input);
@@ -136,11 +243,25 @@
         /// </summary>
         /// <param name="input">The stream to parse.</param>
         /// <returns>The parsed message.</returns>
-        public T ParseFrom(CodedInputStream input)
+        public new T ParseFrom(CodedInputStream input)
         {
             T message = factory();
             message.MergeFrom(input);
             return message;
         }
+
+        /// <summary>
+        /// Parses a message from the given JSON.
+        /// </summary>
+        /// <param name="json">The JSON to parse.</param>
+        /// <returns>The parsed message.</returns>
+        /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+        /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
+        public new T ParseJson(string json)
+        {
+            T message = factory();
+            JsonParser.Default.Merge(message, json);
+            return message;
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
index 9a484ad..225ac0d 100644
--- a/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
+++ b/csharp/src/Google.Protobuf/Properties/AssemblyInfo.cs
@@ -46,7 +46,10 @@
 [assembly: AssemblyCopyright("Copyright ©  2015")]

 [assembly: AssemblyTrademark("")]

 [assembly: AssemblyCulture("")]

+

+#if !NCRUNCH

 [assembly: AllowPartiallyTrustedCallers]

+#endif

 

 #if SIGNED

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

diff --git a/csharp/src/Google.Protobuf/Preconditions.cs b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
similarity index 89%
rename from csharp/src/Google.Protobuf/Preconditions.cs
rename to csharp/src/Google.Protobuf/ProtoPreconditions.cs
index 2db35ff..abaeb9b 100644
--- a/csharp/src/Google.Protobuf/Preconditions.cs
+++ b/csharp/src/Google.Protobuf/ProtoPreconditions.cs
@@ -35,9 +35,14 @@
 namespace Google.Protobuf
 {
     /// <summary>
-    /// Helper methods for throwing exceptions
+    /// Helper methods for throwing exceptions when preconditions are not met.
     /// </summary>
-    public static class Preconditions
+    /// <remarks>
+    /// This class is used internally and by generated code; it is not particularly
+    /// expected to be used from application code, although nothing prevents it
+    /// from being used that way.
+    /// </remarks>
+    public static class ProtoPreconditions
     {
         /// <summary>
         /// Throws an ArgumentNullException if the given value is null, otherwise
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
similarity index 68%
rename from csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
rename to csharp/src/Google.Protobuf/Reflection/Descriptor.cs
index f9158ca..7de7b5f 100644
--- a/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -9,164 +9,176 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.Reflection {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/descriptor.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  internal static partial class DescriptorProtoFile {
+  internal static partial class DescriptorReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/descriptor.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static DescriptorProtoFile() {
+    static DescriptorReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "CiBnb29nbGUvcHJvdG9idWYvZGVzY3JpcHRvci5wcm90bxIPZ29vZ2xlLnBy", 
-            "b3RvYnVmIkcKEUZpbGVEZXNjcmlwdG9yU2V0EjIKBGZpbGUYASADKAsyJC5n", 
-            "b29nbGUucHJvdG9idWYuRmlsZURlc2NyaXB0b3JQcm90byLbAwoTRmlsZURl", 
-            "c2NyaXB0b3JQcm90bxIMCgRuYW1lGAEgASgJEg8KB3BhY2thZ2UYAiABKAkS", 
-            "EgoKZGVwZW5kZW5jeRgDIAMoCRIZChFwdWJsaWNfZGVwZW5kZW5jeRgKIAMo", 
-            "BRIXCg93ZWFrX2RlcGVuZGVuY3kYCyADKAUSNgoMbWVzc2FnZV90eXBlGAQg", 
-            "AygLMiAuZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90bxI3CgllbnVt", 
-            "X3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQ", 
-            "cm90bxI4CgdzZXJ2aWNlGAYgAygLMicuZ29vZ2xlLnByb3RvYnVmLlNlcnZp", 
-            "Y2VEZXNjcmlwdG9yUHJvdG8SOAoJZXh0ZW5zaW9uGAcgAygLMiUuZ29vZ2xl", 
-            "LnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvEi0KB29wdGlvbnMYCCAB", 
-            "KAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMSOQoQc291cmNlX2Nv", 
-            "ZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5m", 
-            "bxIOCgZzeW50YXgYDCABKAki8AQKD0Rlc2NyaXB0b3JQcm90bxIMCgRuYW1l", 
-            "GAEgASgJEjQKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxk", 
-            "RGVzY3JpcHRvclByb3RvEjgKCWV4dGVuc2lvbhgGIAMoCzIlLmdvb2dsZS5w", 
-            "cm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90bxI1CgtuZXN0ZWRfdHlwZRgD", 
-            "IAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8SNwoJZW51", 
-            "bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9y", 
-            "UHJvdG8SSAoPZXh0ZW5zaW9uX3JhbmdlGAUgAygLMi8uZ29vZ2xlLnByb3Rv", 
-            "YnVmLkRlc2NyaXB0b3JQcm90by5FeHRlbnNpb25SYW5nZRI5CgpvbmVvZl9k", 
-            "ZWNsGAggAygLMiUuZ29vZ2xlLnByb3RvYnVmLk9uZW9mRGVzY3JpcHRvclBy", 
-            "b3RvEjAKB29wdGlvbnMYByABKAsyHy5nb29nbGUucHJvdG9idWYuTWVzc2Fn", 
-            "ZU9wdGlvbnMSRgoOcmVzZXJ2ZWRfcmFuZ2UYCSADKAsyLi5nb29nbGUucHJv", 
-            "dG9idWYuRGVzY3JpcHRvclByb3RvLlJlc2VydmVkUmFuZ2USFQoNcmVzZXJ2", 
-            "ZWRfbmFtZRgKIAMoCRosCg5FeHRlbnNpb25SYW5nZRINCgVzdGFydBgBIAEo", 
-            "BRILCgNlbmQYAiABKAUaKwoNUmVzZXJ2ZWRSYW5nZRINCgVzdGFydBgBIAEo", 
-            "BRILCgNlbmQYAiABKAUiqQUKFEZpZWxkRGVzY3JpcHRvclByb3RvEgwKBG5h", 
-            "bWUYASABKAkSDgoGbnVtYmVyGAMgASgFEjoKBWxhYmVsGAQgASgOMisuZ29v", 
-            "Z2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsEjgKBHR5", 
-            "cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJv", 
-            "dG8uVHlwZRIRCgl0eXBlX25hbWUYBiABKAkSEAoIZXh0ZW5kZWUYAiABKAkS", 
-            "FQoNZGVmYXVsdF92YWx1ZRgHIAEoCRITCgtvbmVvZl9pbmRleBgJIAEoBRIu", 
-            "CgdvcHRpb25zGAggASgLMh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9u", 
-            "cyK2AgoEVHlwZRIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIO", 
-            "CgpUWVBFX0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMy", 
-            "EAUSEAoMVFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQ", 
-            "RV9CT09MEAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoM", 
-            "VFlQRV9NRVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMy", 
-            "EA0SDQoJVFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVf", 
-            "U0ZJWEVENjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIi", 
-            "QwoFTGFiZWwSEgoOTEFCRUxfT1BUSU9OQUwQARISCg5MQUJFTF9SRVFVSVJF", 
-            "RBACEhIKDkxBQkVMX1JFUEVBVEVEEAMiJAoUT25lb2ZEZXNjcmlwdG9yUHJv", 
-            "dG8SDAoEbmFtZRgBIAEoCSKMAQoTRW51bURlc2NyaXB0b3JQcm90bxIMCgRu", 
-            "YW1lGAEgASgJEjgKBXZhbHVlGAIgAygLMikuZ29vZ2xlLnByb3RvYnVmLkVu", 
-            "dW1WYWx1ZURlc2NyaXB0b3JQcm90bxItCgdvcHRpb25zGAMgASgLMhwuZ29v", 
-            "Z2xlLnByb3RvYnVmLkVudW1PcHRpb25zImwKGEVudW1WYWx1ZURlc2NyaXB0", 
-            "b3JQcm90bxIMCgRuYW1lGAEgASgJEg4KBm51bWJlchgCIAEoBRIyCgdvcHRp", 
-            "b25zGAMgASgLMiEuZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZU9wdGlvbnMi", 
-            "kAEKFlNlcnZpY2VEZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRI2CgZt", 
-            "ZXRob2QYAiADKAsyJi5nb29nbGUucHJvdG9idWYuTWV0aG9kRGVzY3JpcHRv", 
-            "clByb3RvEjAKB29wdGlvbnMYAyABKAsyHy5nb29nbGUucHJvdG9idWYuU2Vy", 
-            "dmljZU9wdGlvbnMiwQEKFU1ldGhvZERlc2NyaXB0b3JQcm90bxIMCgRuYW1l", 
-            "GAEgASgJEhIKCmlucHV0X3R5cGUYAiABKAkSEwoLb3V0cHV0X3R5cGUYAyAB", 
-            "KAkSLwoHb3B0aW9ucxgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RP", 
-            "cHRpb25zEh8KEGNsaWVudF9zdHJlYW1pbmcYBSABKAg6BWZhbHNlEh8KEHNl", 
-            "cnZlcl9zdHJlYW1pbmcYBiABKAg6BWZhbHNlIqoFCgtGaWxlT3B0aW9ucxIU", 
-            "CgxqYXZhX3BhY2thZ2UYASABKAkSHAoUamF2YV9vdXRlcl9jbGFzc25hbWUY", 
-            "CCABKAkSIgoTamF2YV9tdWx0aXBsZV9maWxlcxgKIAEoCDoFZmFsc2USLAod", 
-            "amF2YV9nZW5lcmF0ZV9lcXVhbHNfYW5kX2hhc2gYFCABKAg6BWZhbHNlEiUK", 
-            "FmphdmFfc3RyaW5nX2NoZWNrX3V0ZjgYGyABKAg6BWZhbHNlEkYKDG9wdGlt", 
-            "aXplX2ZvchgJIAEoDjIpLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucy5P", 
-            "cHRpbWl6ZU1vZGU6BVNQRUVEEhIKCmdvX3BhY2thZ2UYCyABKAkSIgoTY2Nf", 
-            "Z2VuZXJpY19zZXJ2aWNlcxgQIAEoCDoFZmFsc2USJAoVamF2YV9nZW5lcmlj", 
-            "X3NlcnZpY2VzGBEgASgIOgVmYWxzZRIiChNweV9nZW5lcmljX3NlcnZpY2Vz", 
-            "GBIgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGBcgASgIOgVmYWxzZRIfChBj", 
-            "Y19lbmFibGVfYXJlbmFzGB8gASgIOgVmYWxzZRIZChFvYmpjX2NsYXNzX3By", 
-            "ZWZpeBgkIAEoCRIYChBjc2hhcnBfbmFtZXNwYWNlGCUgASgJEicKH2phdmFu", 
-            "YW5vX3VzZV9kZXByZWNhdGVkX3BhY2thZ2UYJiABKAgSQwoUdW5pbnRlcnBy", 
-            "ZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJw", 
-            "cmV0ZWRPcHRpb24iOgoMT3B0aW1pemVNb2RlEgkKBVNQRUVEEAESDQoJQ09E", 
-            "RV9TSVpFEAISEAoMTElURV9SVU5USU1FEAMqCQjoBxCAgICAAiLmAQoOTWVz", 
-            "c2FnZU9wdGlvbnMSJgoXbWVzc2FnZV9zZXRfd2lyZV9mb3JtYXQYASABKAg6", 
-            "BWZhbHNlEi4KH25vX3N0YW5kYXJkX2Rlc2NyaXB0b3JfYWNjZXNzb3IYAiAB", 
-            "KAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlEhEKCW1hcF9l", 
-            "bnRyeRgHIAEoCBJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n", 
-            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIAC", 
-            "IpgDCgxGaWVsZE9wdGlvbnMSOgoFY3R5cGUYASABKA4yIy5nb29nbGUucHJv", 
-            "dG9idWYuRmllbGRPcHRpb25zLkNUeXBlOgZTVFJJTkcSDgoGcGFja2VkGAIg", 
-            "ASgIEj8KBmpzdHlwZRgGIAEoDjIkLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9w", 
-            "dGlvbnMuSlNUeXBlOglKU19OT1JNQUwSEwoEbGF6eRgFIAEoCDoFZmFsc2US", 
-            "GQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USEwoEd2VhaxgKIAEoCDoFZmFs", 
-            "c2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnBy", 
-            "b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24iLwoFQ1R5cGUSCgoGU1RSSU5H", 
-            "EAASCAoEQ09SRBABEhAKDFNUUklOR19QSUVDRRACIjUKBkpTVHlwZRINCglK", 
-            "U19OT1JNQUwQABINCglKU19TVFJJTkcQARINCglKU19OVU1CRVIQAioJCOgH", 
-            "EICAgIACIo0BCgtFbnVtT3B0aW9ucxITCgthbGxvd19hbGlhcxgCIAEoCBIZ", 
-            "CgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w", 
-            "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w", 
-            "dGlvbioJCOgHEICAgIACIn0KEEVudW1WYWx1ZU9wdGlvbnMSGQoKZGVwcmVj", 
-            "YXRlZBgBIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcg", 
-            "AygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjo", 
-            "BxCAgICAAiJ7Cg5TZXJ2aWNlT3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgI", 
-            "OgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29n", 
-            "bGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInoK", 
-            "DU1ldGhvZE9wdGlvbnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2USQwoU", 
-            "dW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVm", 
-            "LlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKeAgoTVW5pbnRlcnBy", 
-            "ZXRlZE9wdGlvbhI7CgRuYW1lGAIgAygLMi0uZ29vZ2xlLnByb3RvYnVmLlVu", 
-            "aW50ZXJwcmV0ZWRPcHRpb24uTmFtZVBhcnQSGAoQaWRlbnRpZmllcl92YWx1", 
-            "ZRgDIAEoCRIaChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKAQSGgoSbmVnYXRp", 
-            "dmVfaW50X3ZhbHVlGAUgASgDEhQKDGRvdWJsZV92YWx1ZRgGIAEoARIUCgxz", 
-            "dHJpbmdfdmFsdWUYByABKAwSFwoPYWdncmVnYXRlX3ZhbHVlGAggASgJGjMK", 
-            "CE5hbWVQYXJ0EhEKCW5hbWVfcGFydBgBIAIoCRIUCgxpc19leHRlbnNpb24Y", 
-            "AiACKAgi1QEKDlNvdXJjZUNvZGVJbmZvEjoKCGxvY2F0aW9uGAEgAygLMigu", 
-            "Z29vZ2xlLnByb3RvYnVmLlNvdXJjZUNvZGVJbmZvLkxvY2F0aW9uGoYBCghM", 
-            "b2NhdGlvbhIQCgRwYXRoGAEgAygFQgIQARIQCgRzcGFuGAIgAygFQgIQARIY", 
-            "ChBsZWFkaW5nX2NvbW1lbnRzGAMgASgJEhkKEXRyYWlsaW5nX2NvbW1lbnRz", 
-            "GAQgASgJEiEKGWxlYWRpbmdfZGV0YWNoZWRfY29tbWVudHMYBiADKAlCWwoT", 
-            "Y29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRvclByb3Rvc0gBWgpkZXNj", 
-            "cmlwdG9yogIDR1BCqgIaR29vZ2xlLlByb3RvYnVmLlJlZmxlY3Rpb26wAgE="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            "CiBnb29nbGUvcHJvdG9idWYvZGVzY3JpcHRvci5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIkcKEUZpbGVEZXNjcmlwdG9yU2V0EjIKBGZpbGUYASADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuRmlsZURlc2NyaXB0b3JQcm90byLbAwoTRmlsZURl",
+            "c2NyaXB0b3JQcm90bxIMCgRuYW1lGAEgASgJEg8KB3BhY2thZ2UYAiABKAkS",
+            "EgoKZGVwZW5kZW5jeRgDIAMoCRIZChFwdWJsaWNfZGVwZW5kZW5jeRgKIAMo",
+            "BRIXCg93ZWFrX2RlcGVuZGVuY3kYCyADKAUSNgoMbWVzc2FnZV90eXBlGAQg",
+            "AygLMiAuZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90bxI3CgllbnVt",
+            "X3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQ",
+            "cm90bxI4CgdzZXJ2aWNlGAYgAygLMicuZ29vZ2xlLnByb3RvYnVmLlNlcnZp",
+            "Y2VEZXNjcmlwdG9yUHJvdG8SOAoJZXh0ZW5zaW9uGAcgAygLMiUuZ29vZ2xl",
+            "LnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvEi0KB29wdGlvbnMYCCAB",
+            "KAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMSOQoQc291cmNlX2Nv",
+            "ZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5m",
+            "bxIOCgZzeW50YXgYDCABKAki8AQKD0Rlc2NyaXB0b3JQcm90bxIMCgRuYW1l",
+            "GAEgASgJEjQKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxk",
+            "RGVzY3JpcHRvclByb3RvEjgKCWV4dGVuc2lvbhgGIAMoCzIlLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90bxI1CgtuZXN0ZWRfdHlwZRgD",
+            "IAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8SNwoJZW51",
+            "bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9y",
+            "UHJvdG8SSAoPZXh0ZW5zaW9uX3JhbmdlGAUgAygLMi8uZ29vZ2xlLnByb3Rv",
+            "YnVmLkRlc2NyaXB0b3JQcm90by5FeHRlbnNpb25SYW5nZRI5CgpvbmVvZl9k",
+            "ZWNsGAggAygLMiUuZ29vZ2xlLnByb3RvYnVmLk9uZW9mRGVzY3JpcHRvclBy",
+            "b3RvEjAKB29wdGlvbnMYByABKAsyHy5nb29nbGUucHJvdG9idWYuTWVzc2Fn",
+            "ZU9wdGlvbnMSRgoOcmVzZXJ2ZWRfcmFuZ2UYCSADKAsyLi5nb29nbGUucHJv",
+            "dG9idWYuRGVzY3JpcHRvclByb3RvLlJlc2VydmVkUmFuZ2USFQoNcmVzZXJ2",
+            "ZWRfbmFtZRgKIAMoCRosCg5FeHRlbnNpb25SYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUaKwoNUmVzZXJ2ZWRSYW5nZRINCgVzdGFydBgBIAEo",
+            "BRILCgNlbmQYAiABKAUivAUKFEZpZWxkRGVzY3JpcHRvclByb3RvEgwKBG5h",
+            "bWUYASABKAkSDgoGbnVtYmVyGAMgASgFEjoKBWxhYmVsGAQgASgOMisuZ29v",
+            "Z2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLkxhYmVsEjgKBHR5",
+            "cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJv",
+            "dG8uVHlwZRIRCgl0eXBlX25hbWUYBiABKAkSEAoIZXh0ZW5kZWUYAiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgHIAEoCRITCgtvbmVvZl9pbmRleBgJIAEoBRIR",
+            "Cglqc29uX25hbWUYCiABKAkSLgoHb3B0aW9ucxgIIAEoCzIdLmdvb2dsZS5w",
+            "cm90b2J1Zi5GaWVsZE9wdGlvbnMitgIKBFR5cGUSDwoLVFlQRV9ET1VCTEUQ",
+            "ARIOCgpUWVBFX0ZMT0FUEAISDgoKVFlQRV9JTlQ2NBADEg8KC1RZUEVfVUlO",
+            "VDY0EAQSDgoKVFlQRV9JTlQzMhAFEhAKDFRZUEVfRklYRUQ2NBAGEhAKDFRZ",
+            "UEVfRklYRUQzMhAHEg0KCVRZUEVfQk9PTBAIEg8KC1RZUEVfU1RSSU5HEAkS",
+            "DgoKVFlQRV9HUk9VUBAKEhAKDFRZUEVfTUVTU0FHRRALEg4KClRZUEVfQllU",
+            "RVMQDBIPCgtUWVBFX1VJTlQzMhANEg0KCVRZUEVfRU5VTRAOEhEKDVRZUEVf",
+            "U0ZJWEVEMzIQDxIRCg1UWVBFX1NGSVhFRDY0EBASDwoLVFlQRV9TSU5UMzIQ",
+            "ERIPCgtUWVBFX1NJTlQ2NBASIkMKBUxhYmVsEhIKDkxBQkVMX09QVElPTkFM",
+            "EAESEgoOTEFCRUxfUkVRVUlSRUQQAhISCg5MQUJFTF9SRVBFQVRFRBADIiQK",
+            "FE9uZW9mRGVzY3JpcHRvclByb3RvEgwKBG5hbWUYASABKAkijAEKE0VudW1E",
+            "ZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRI4CgV2YWx1ZRgCIAMoCzIp",
+            "Lmdvb2dsZS5wcm90b2J1Zi5FbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SLQoH",
+            "b3B0aW9ucxgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9ucyJs",
+            "ChhFbnVtVmFsdWVEZXNjcmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRIOCgZu",
+            "dW1iZXIYAiABKAUSMgoHb3B0aW9ucxgDIAEoCzIhLmdvb2dsZS5wcm90b2J1",
+            "Zi5FbnVtVmFsdWVPcHRpb25zIpABChZTZXJ2aWNlRGVzY3JpcHRvclByb3Rv",
+            "EgwKBG5hbWUYASABKAkSNgoGbWV0aG9kGAIgAygLMiYuZ29vZ2xlLnByb3Rv",
+            "YnVmLk1ldGhvZERlc2NyaXB0b3JQcm90bxIwCgdvcHRpb25zGAMgASgLMh8u",
+            "Z29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zIsEBChVNZXRob2REZXNj",
+            "cmlwdG9yUHJvdG8SDAoEbmFtZRgBIAEoCRISCgppbnB1dF90eXBlGAIgASgJ",
+            "EhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5nb29n",
+            "bGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFtaW5n",
+            "GAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVmYWxz",
+            "ZSKuBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph",
+            "dmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVfZmls",
+            "ZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2FuZF9o",
+            "YXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
+            "ASgIOgVmYWxzZRJGCgxvcHRpbWl6ZV9mb3IYCSABKA4yKS5nb29nbGUucHJv",
+            "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
+            "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
+            "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
+            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
+            "cGFjZRglIAEoCRIrCh9qYXZhbmFub191c2VfZGVwcmVjYXRlZF9wYWNrYWdl",
+            "GCYgASgIQgIYARJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n",
+            "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6",
+            "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ",
+            "TUUQAyoJCOgHEICAgIACIuYBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdl",
+            "X3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3RhbmRhcmRf",
+            "ZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
+            "ZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVuaW50ZXJw",
+            "cmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy",
+            "cHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9ucxI6CgVj",
+            "dHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5",
+            "cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYgASgOMiQu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpTX05PUk1B",
+            "TBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVm",
+            "YWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w",
+            "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w",
+            "dGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5H",
+            "X1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklO",
+            "RxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1PcHRpb25z",
+            "EhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh",
+            "bHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w",
+            "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIifQoQRW51",
+            "bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1",
+            "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu",
+            "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRp",
+            "b25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0",
+            "ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl",
+            "dGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZCgpkZXBy",
+            "ZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn",
+            "ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ",
+            "COgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiAD",
+            "KAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1l",
+            "UGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2lu",
+            "dF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoM",
+            "ZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9h",
+            "Z2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0",
+            "GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUlu",
+            "Zm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNl",
+            "Q29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVC",
+            "AhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyAB",
+            "KAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRh",
+            "Y2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoK",
+            "YW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRD",
+            "b2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMo",
+            "BUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoD",
+            "ZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2NyaXB0b3JQ",
+            "cm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5S",
+            "ZWZsZWN0aW9u"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorSet), new[]{ "File" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorProto), new[]{ "Name", "Package", "Dependency", "PublicDependency", "WeakDependency", "MessageType", "EnumType", "Service", "Extension", "Options", "SourceCodeInfo", "Syntax" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto), new[]{ "Name", "Field", "Extension", "NestedType", "EnumType", "ExtensionRange", "OneofDecl", "Options", "ReservedRange", "ReservedName" }, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange), new[]{ "Start", "End" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange), new[]{ "Start", "End" }, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto), new[]{ "Name", "Number", "Label", "Type", "TypeName", "Extendee", "DefaultValue", "OneofIndex", "Options" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type), typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) }, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.OneofDescriptorProto), new[]{ "Name" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.EnumDescriptorProto), new[]{ "Name", "Value", "Options" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), new[]{ "Name", "Number", "Options" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), new[]{ "Name", "Method", "Options" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "JavananoUseDeprecatedPackage", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.ServiceOptions), new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption), new[]{ "Name", "IdentifierValue", "PositiveIntValue", "NegativeIntValue", "DoubleValue", "StringValue", "AggregateValue" }, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart), new[]{ "NamePart_", "IsExtension" }, null, null, null)}),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo), new[]{ "Location" }, null, null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location), new[]{ "Path", "Span", "LeadingComments", "TrailingComments", "LeadingDetachedComments" }, null, null, null)})
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorSet), global::Google.Protobuf.Reflection.FileDescriptorSet.Parser, new[]{ "File" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileDescriptorProto), global::Google.Protobuf.Reflection.FileDescriptorProto.Parser, new[]{ "Name", "Package", "Dependency", "PublicDependency", "WeakDependency", "MessageType", "EnumType", "Service", "Extension", "Options", "SourceCodeInfo", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto), global::Google.Protobuf.Reflection.DescriptorProto.Parser, new[]{ "Name", "Field", "Extension", "NestedType", "EnumType", "ExtensionRange", "OneofDecl", "Options", "ReservedRange", "ReservedName" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser, new[]{ "Start", "End" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange), global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser, new[]{ "Start", "End" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto), global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser, new[]{ "Name", "Number", "Label", "Type", "TypeName", "Extendee", "DefaultValue", "OneofIndex", "JsonName", "Options" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type), typeof(global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.OneofDescriptorProto), global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser, new[]{ "Name" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumDescriptorProto), global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser, new[]{ "Name", "Value", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser, new[]{ "Name", "Method", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser, new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "JavananoUseDeprecatedPackage", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), global::Google.Protobuf.Reflection.MessageOptions.Parser, new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), global::Google.Protobuf.Reflection.EnumValueOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceOptions), global::Google.Protobuf.Reflection.ServiceOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodOptions), global::Google.Protobuf.Reflection.MethodOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption), global::Google.Protobuf.Reflection.UninterpretedOption.Parser, new[]{ "Name", "IdentifierValue", "PositiveIntValue", "NegativeIntValue", "DoubleValue", "StringValue", "AggregateValue" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart), global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser, new[]{ "NamePart_", "IsExtension" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo), global::Google.Protobuf.Reflection.SourceCodeInfo.Parser, new[]{ "Location" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location), global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser, new[]{ "Path", "Span", "LeadingComments", "TrailingComments", "LeadingDetachedComments" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Parser, new[]{ "Annotation" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation), global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser, new[]{ "Path", "SourceFile", "Begin", "End" }, null, null, null)})
           }));
     }
     #endregion
 
   }
   #region Messages
+  /// <summary>
+  ///  The protocol compiler can output a FileDescriptorSet containing the .proto
+  ///  files it parses.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class FileDescriptorSet : pb::IMessage<FileDescriptorSet> {
     private static readonly pb::MessageParser<FileDescriptorSet> _parser = new pb::MessageParser<FileDescriptorSet>(() => new FileDescriptorSet());
     public static pb::MessageParser<FileDescriptorSet> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -187,6 +199,7 @@
       return new FileDescriptorSet(this);
     }
 
+    /// <summary>Field number for the "file" field.</summary>
     public const int FileFieldNumber = 1;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FileDescriptorProto> _repeated_file_codec
         = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.FileDescriptorProto.Parser);
@@ -217,7 +230,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -254,13 +267,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a complete .proto file.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class FileDescriptorProto : pb::IMessage<FileDescriptorProto> {
     private static readonly pb::MessageParser<FileDescriptorProto> _parser = new pb::MessageParser<FileDescriptorProto>(() => new FileDescriptorProto());
     public static pb::MessageParser<FileDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -292,56 +308,82 @@
       return new FileDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  file name, relative to root of source tree
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "package" field.</summary>
     public const int PackageFieldNumber = 2;
     private string package_ = "";
+    /// <summary>
+    ///  e.g. "foo", "foo.bar", etc.
+    /// </summary>
     public string Package {
       get { return package_; }
       set {
-        package_ = pb::Preconditions.CheckNotNull(value, "value");
+        package_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "dependency" field.</summary>
     public const int DependencyFieldNumber = 3;
     private static readonly pb::FieldCodec<string> _repeated_dependency_codec
         = pb::FieldCodec.ForString(26);
     private readonly pbc::RepeatedField<string> dependency_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Names of files imported by this file.
+    /// </summary>
     public pbc::RepeatedField<string> Dependency {
       get { return dependency_; }
     }
 
+    /// <summary>Field number for the "public_dependency" field.</summary>
     public const int PublicDependencyFieldNumber = 10;
     private static readonly pb::FieldCodec<int> _repeated_publicDependency_codec
         = pb::FieldCodec.ForInt32(80);
     private readonly pbc::RepeatedField<int> publicDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the public imported files in the dependency list above.
+    /// </summary>
     public pbc::RepeatedField<int> PublicDependency {
       get { return publicDependency_; }
     }
 
+    /// <summary>Field number for the "weak_dependency" field.</summary>
     public const int WeakDependencyFieldNumber = 11;
     private static readonly pb::FieldCodec<int> _repeated_weakDependency_codec
         = pb::FieldCodec.ForInt32(88);
     private readonly pbc::RepeatedField<int> weakDependency_ = new pbc::RepeatedField<int>();
+    /// <summary>
+    ///  Indexes of the weak imported files in the dependency list.
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
     public pbc::RepeatedField<int> WeakDependency {
       get { return weakDependency_; }
     }
 
+    /// <summary>Field number for the "message_type" field.</summary>
     public const int MessageTypeFieldNumber = 4;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_messageType_codec
         = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> messageType_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto>();
+    /// <summary>
+    ///  All top-level definitions in this file.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.DescriptorProto> MessageType {
       get { return messageType_; }
     }
 
+    /// <summary>Field number for the "enum_type" field.</summary>
     public const int EnumTypeFieldNumber = 5;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
         = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
@@ -350,6 +392,7 @@
       get { return enumType_; }
     }
 
+    /// <summary>Field number for the "service" field.</summary>
     public const int ServiceFieldNumber = 6;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.ServiceDescriptorProto> _repeated_service_codec
         = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser);
@@ -358,6 +401,7 @@
       get { return service_; }
     }
 
+    /// <summary>Field number for the "extension" field.</summary>
     public const int ExtensionFieldNumber = 7;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
         = pb::FieldCodec.ForMessage(58, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
@@ -366,6 +410,7 @@
       get { return extension_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 8;
     private global::Google.Protobuf.Reflection.FileOptions options_;
     public global::Google.Protobuf.Reflection.FileOptions Options {
@@ -375,8 +420,15 @@
       }
     }
 
+    /// <summary>Field number for the "source_code_info" field.</summary>
     public const int SourceCodeInfoFieldNumber = 9;
     private global::Google.Protobuf.Reflection.SourceCodeInfo sourceCodeInfo_;
+    /// <summary>
+    ///  This field contains optional information about the original source code.
+    ///  You may safely remove this entire field without harming runtime
+    ///  functionality of the descriptors -- the information is needed only by
+    ///  development tools.
+    /// </summary>
     public global::Google.Protobuf.Reflection.SourceCodeInfo SourceCodeInfo {
       get { return sourceCodeInfo_; }
       set {
@@ -384,12 +436,17 @@
       }
     }
 
+    /// <summary>Field number for the "syntax" field.</summary>
     public const int SyntaxFieldNumber = 12;
     private string syntax_ = "";
+    /// <summary>
+    ///  The syntax of the proto file.
+    ///  The supported values are "proto2" and "proto3".
+    /// </summary>
     public string Syntax {
       get { return syntax_; }
       set {
-        syntax_ = pb::Preconditions.CheckNotNull(value, "value");
+        syntax_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -437,7 +494,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -600,13 +657,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a message type.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class DescriptorProto : pb::IMessage<DescriptorProto> {
     private static readonly pb::MessageParser<DescriptorProto> _parser = new pb::MessageParser<DescriptorProto>(() => new DescriptorProto());
     public static pb::MessageParser<DescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -636,15 +696,17 @@
       return new DescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "field" field.</summary>
     public const int FieldFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_field_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
@@ -653,6 +715,7 @@
       get { return field_; }
     }
 
+    /// <summary>Field number for the "extension" field.</summary>
     public const int ExtensionFieldNumber = 6;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.FieldDescriptorProto> _repeated_extension_codec
         = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.Reflection.FieldDescriptorProto.Parser);
@@ -661,6 +724,7 @@
       get { return extension_; }
     }
 
+    /// <summary>Field number for the "nested_type" field.</summary>
     public const int NestedTypeFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto> _repeated_nestedType_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.Reflection.DescriptorProto.Parser);
@@ -669,6 +733,7 @@
       get { return nestedType_; }
     }
 
+    /// <summary>Field number for the "enum_type" field.</summary>
     public const int EnumTypeFieldNumber = 4;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumDescriptorProto> _repeated_enumType_codec
         = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.Reflection.EnumDescriptorProto.Parser);
@@ -677,6 +742,7 @@
       get { return enumType_; }
     }
 
+    /// <summary>Field number for the "extension_range" field.</summary>
     public const int ExtensionRangeFieldNumber = 5;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange> _repeated_extensionRange_codec
         = pb::FieldCodec.ForMessage(42, global::Google.Protobuf.Reflection.DescriptorProto.Types.ExtensionRange.Parser);
@@ -685,6 +751,7 @@
       get { return extensionRange_; }
     }
 
+    /// <summary>Field number for the "oneof_decl" field.</summary>
     public const int OneofDeclFieldNumber = 8;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.OneofDescriptorProto> _repeated_oneofDecl_codec
         = pb::FieldCodec.ForMessage(66, global::Google.Protobuf.Reflection.OneofDescriptorProto.Parser);
@@ -693,6 +760,7 @@
       get { return oneofDecl_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 7;
     private global::Google.Protobuf.Reflection.MessageOptions options_;
     public global::Google.Protobuf.Reflection.MessageOptions Options {
@@ -702,6 +770,7 @@
       }
     }
 
+    /// <summary>Field number for the "reserved_range" field.</summary>
     public const int ReservedRangeFieldNumber = 9;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange> _repeated_reservedRange_codec
         = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.Reflection.DescriptorProto.Types.ReservedRange.Parser);
@@ -710,10 +779,15 @@
       get { return reservedRange_; }
     }
 
+    /// <summary>Field number for the "reserved_name" field.</summary>
     public const int ReservedNameFieldNumber = 10;
     private static readonly pb::FieldCodec<string> _repeated_reservedName_codec
         = pb::FieldCodec.ForString(82);
     private readonly pbc::RepeatedField<string> reservedName_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  Reserved field names, which may not be used by fields in the same message.
+    ///  A given name may only be reserved once.
+    /// </summary>
     public pbc::RepeatedField<string> ReservedName {
       get { return reservedName_; }
     }
@@ -758,7 +832,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -877,6 +951,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the DescriptorProto message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -907,6 +982,7 @@
           return new ExtensionRange(this);
         }
 
+        /// <summary>Field number for the "start" field.</summary>
         public const int StartFieldNumber = 1;
         private int start_;
         public int Start {
@@ -916,6 +992,7 @@
           }
         }
 
+        /// <summary>Field number for the "end" field.</summary>
         public const int EndFieldNumber = 2;
         private int end_;
         public int End {
@@ -949,7 +1026,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1007,6 +1084,11 @@
 
       }
 
+      /// <summary>
+      ///  Range of reserved tag numbers. Reserved tag numbers may not be used by
+      ///  fields or extension ranges in the same message. Reserved ranges may
+      ///  not overlap.
+      /// </summary>
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
       internal sealed partial class ReservedRange : pb::IMessage<ReservedRange> {
         private static readonly pb::MessageParser<ReservedRange> _parser = new pb::MessageParser<ReservedRange>(() => new ReservedRange());
@@ -1035,8 +1117,12 @@
           return new ReservedRange(this);
         }
 
+        /// <summary>Field number for the "start" field.</summary>
         public const int StartFieldNumber = 1;
         private int start_;
+        /// <summary>
+        ///  Inclusive.
+        /// </summary>
         public int Start {
           get { return start_; }
           set {
@@ -1044,8 +1130,12 @@
           }
         }
 
+        /// <summary>Field number for the "end" field.</summary>
         public const int EndFieldNumber = 2;
         private int end_;
+        /// <summary>
+        ///  Exclusive.
+        /// </summary>
         public int End {
           get { return end_; }
           set {
@@ -1077,7 +1167,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -1140,13 +1230,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a field within a message.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class FieldDescriptorProto : pb::IMessage<FieldDescriptorProto> {
     private static readonly pb::MessageParser<FieldDescriptorProto> _parser = new pb::MessageParser<FieldDescriptorProto>(() => new FieldDescriptorProto());
     public static pb::MessageParser<FieldDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1168,6 +1261,7 @@
       extendee_ = other.extendee_;
       defaultValue_ = other.defaultValue_;
       oneofIndex_ = other.oneofIndex_;
+      jsonName_ = other.jsonName_;
       Options = other.options_ != null ? other.Options.Clone() : null;
     }
 
@@ -1175,15 +1269,17 @@
       return new FieldDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "number" field.</summary>
     public const int NumberFieldNumber = 3;
     private int number_;
     public int Number {
@@ -1193,6 +1289,7 @@
       }
     }
 
+    /// <summary>Field number for the "label" field.</summary>
     public const int LabelFieldNumber = 4;
     private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label label_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL;
     public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label Label {
@@ -1202,8 +1299,13 @@
       }
     }
 
+    /// <summary>Field number for the "type" field.</summary>
     public const int TypeFieldNumber = 5;
     private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type type_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE;
+    /// <summary>
+    ///  If type_name is set, this need not be set.  If both this and type_name
+    ///  are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
+    /// </summary>
     public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type Type {
       get { return type_; }
       set {
@@ -1211,35 +1313,61 @@
       }
     }
 
+    /// <summary>Field number for the "type_name" field.</summary>
     public const int TypeNameFieldNumber = 6;
     private string typeName_ = "";
+    /// <summary>
+    ///  For message and enum types, this is the name of the type.  If the name
+    ///  starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
+    ///  rules are used to find the type (i.e. first the nested types within this
+    ///  message are searched, then within the parent, on up to the root
+    ///  namespace).
+    /// </summary>
     public string TypeName {
       get { return typeName_; }
       set {
-        typeName_ = pb::Preconditions.CheckNotNull(value, "value");
+        typeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "extendee" field.</summary>
     public const int ExtendeeFieldNumber = 2;
     private string extendee_ = "";
+    /// <summary>
+    ///  For extensions, this is the name of the type being extended.  It is
+    ///  resolved in the same manner as type_name.
+    /// </summary>
     public string Extendee {
       get { return extendee_; }
       set {
-        extendee_ = pb::Preconditions.CheckNotNull(value, "value");
+        extendee_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "default_value" field.</summary>
     public const int DefaultValueFieldNumber = 7;
     private string defaultValue_ = "";
+    /// <summary>
+    ///  For numeric types, contains the original text representation of the value.
+    ///  For booleans, "true" or "false".
+    ///  For strings, contains the default text contents (not escaped in any way).
+    ///  For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
+    ///  TODO(kenton):  Base-64 encode?
+    /// </summary>
     public string DefaultValue {
       get { return defaultValue_; }
       set {
-        defaultValue_ = pb::Preconditions.CheckNotNull(value, "value");
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "oneof_index" field.</summary>
     public const int OneofIndexFieldNumber = 9;
     private int oneofIndex_;
+    /// <summary>
+    ///  If set, gives the index of a oneof in the containing type's oneof_decl
+    ///  list.  This field is a member of that oneof.
+    /// </summary>
     public int OneofIndex {
       get { return oneofIndex_; }
       set {
@@ -1247,6 +1375,23 @@
       }
     }
 
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  JSON name of this field. The value is set by protocol compiler. If the
+    ///  user has set a "json_name" option on this field, that option's value
+    ///  will be used. Otherwise, it's deduced from the field's name by converting
+    ///  it to camelCase.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 8;
     private global::Google.Protobuf.Reflection.FieldOptions options_;
     public global::Google.Protobuf.Reflection.FieldOptions Options {
@@ -1275,6 +1420,7 @@
       if (Extendee != other.Extendee) return false;
       if (DefaultValue != other.DefaultValue) return false;
       if (OneofIndex != other.OneofIndex) return false;
+      if (JsonName != other.JsonName) return false;
       if (!object.Equals(Options, other.Options)) return false;
       return true;
     }
@@ -1289,12 +1435,13 @@
       if (Extendee.Length != 0) hash ^= Extendee.GetHashCode();
       if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
       if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
       if (options_ != null) hash ^= Options.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1334,6 +1481,10 @@
         output.WriteRawTag(72);
         output.WriteInt32(OneofIndex);
       }
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
     }
 
     public int CalculateSize() {
@@ -1362,6 +1513,9 @@
       if (OneofIndex != 0) {
         size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofIndex);
       }
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
       if (options_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(Options);
       }
@@ -1396,6 +1550,9 @@
       if (other.OneofIndex != 0) {
         OneofIndex = other.OneofIndex;
       }
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
       if (other.options_ != null) {
         if (options_ == null) {
           options_ = new global::Google.Protobuf.Reflection.FieldOptions();
@@ -1450,37 +1607,75 @@
             OneofIndex = input.ReadInt32();
             break;
           }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
         }
       }
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the FieldDescriptorProto message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       internal enum Type {
+        /// <summary>
+        ///  0 is reserved for errors.
+        ///  Order is weird for historical reasons.
+        /// </summary>
         TYPE_DOUBLE = 1,
         TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if
+        ///  negative values are likely.
+        /// </summary>
         TYPE_INT64 = 3,
         TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if
+        ///  negative values are likely.
+        /// </summary>
         TYPE_INT32 = 5,
         TYPE_FIXED64 = 6,
         TYPE_FIXED32 = 7,
         TYPE_BOOL = 8,
         TYPE_STRING = 9,
+        /// <summary>
+        ///  Tag-delimited aggregate.
+        /// </summary>
         TYPE_GROUP = 10,
+        /// <summary>
+        ///  Length-delimited aggregate.
+        /// </summary>
         TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  New in version 2.
+        /// </summary>
         TYPE_BYTES = 12,
         TYPE_UINT32 = 13,
         TYPE_ENUM = 14,
         TYPE_SFIXED32 = 15,
         TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
         TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Uses ZigZag encoding.
+        /// </summary>
         TYPE_SINT64 = 18,
       }
 
       internal enum Label {
+        /// <summary>
+        ///  0 is reserved for errors
+        /// </summary>
         LABEL_OPTIONAL = 1,
         LABEL_REQUIRED = 2,
+        /// <summary>
+        ///  TODO(sanjay): Should we add LABEL_MAP?
+        /// </summary>
         LABEL_REPEATED = 3,
       }
 
@@ -1489,13 +1684,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a oneof.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class OneofDescriptorProto : pb::IMessage<OneofDescriptorProto> {
     private static readonly pb::MessageParser<OneofDescriptorProto> _parser = new pb::MessageParser<OneofDescriptorProto>(() => new OneofDescriptorProto());
     public static pb::MessageParser<OneofDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[4]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1516,12 +1714,13 @@
       return new OneofDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -1547,7 +1746,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1591,13 +1790,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes an enum type.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class EnumDescriptorProto : pb::IMessage<EnumDescriptorProto> {
     private static readonly pb::MessageParser<EnumDescriptorProto> _parser = new pb::MessageParser<EnumDescriptorProto>(() => new EnumDescriptorProto());
     public static pb::MessageParser<EnumDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[5]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1620,15 +1822,17 @@
       return new EnumDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.EnumValueDescriptorProto> _repeated_value_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser);
@@ -1637,6 +1841,7 @@
       get { return value_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private global::Google.Protobuf.Reflection.EnumOptions options_;
     public global::Google.Protobuf.Reflection.EnumOptions Options {
@@ -1672,7 +1877,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1743,13 +1948,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a value within an enum.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class EnumValueDescriptorProto : pb::IMessage<EnumValueDescriptorProto> {
     private static readonly pb::MessageParser<EnumValueDescriptorProto> _parser = new pb::MessageParser<EnumValueDescriptorProto>(() => new EnumValueDescriptorProto());
     public static pb::MessageParser<EnumValueDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[6]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1772,15 +1980,17 @@
       return new EnumValueDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "number" field.</summary>
     public const int NumberFieldNumber = 2;
     private int number_;
     public int Number {
@@ -1790,6 +2000,7 @@
       }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private global::Google.Protobuf.Reflection.EnumValueOptions options_;
     public global::Google.Protobuf.Reflection.EnumValueOptions Options {
@@ -1825,7 +2036,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -1903,13 +2114,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a service.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class ServiceDescriptorProto : pb::IMessage<ServiceDescriptorProto> {
     private static readonly pb::MessageParser<ServiceDescriptorProto> _parser = new pb::MessageParser<ServiceDescriptorProto>(() => new ServiceDescriptorProto());
     public static pb::MessageParser<ServiceDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[7]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[7]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1932,15 +2146,17 @@
       return new ServiceDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "method" field.</summary>
     public const int MethodFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.MethodDescriptorProto> _repeated_method_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser);
@@ -1949,6 +2165,7 @@
       get { return method_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private global::Google.Protobuf.Reflection.ServiceOptions options_;
     public global::Google.Protobuf.Reflection.ServiceOptions Options {
@@ -1984,7 +2201,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2055,13 +2272,16 @@
 
   }
 
+  /// <summary>
+  ///  Describes a method of a service.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class MethodDescriptorProto : pb::IMessage<MethodDescriptorProto> {
     private static readonly pb::MessageParser<MethodDescriptorProto> _parser = new pb::MessageParser<MethodDescriptorProto>(() => new MethodDescriptorProto());
     public static pb::MessageParser<MethodDescriptorProto> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[8]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[8]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2087,33 +2307,41 @@
       return new MethodDescriptorProto(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "input_type" field.</summary>
     public const int InputTypeFieldNumber = 2;
     private string inputType_ = "";
+    /// <summary>
+    ///  Input and output type names.  These are resolved in the same way as
+    ///  FieldDescriptorProto.type_name, but must refer to a message type.
+    /// </summary>
     public string InputType {
       get { return inputType_; }
       set {
-        inputType_ = pb::Preconditions.CheckNotNull(value, "value");
+        inputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "output_type" field.</summary>
     public const int OutputTypeFieldNumber = 3;
     private string outputType_ = "";
     public string OutputType {
       get { return outputType_; }
       set {
-        outputType_ = pb::Preconditions.CheckNotNull(value, "value");
+        outputType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 4;
     private global::Google.Protobuf.Reflection.MethodOptions options_;
     public global::Google.Protobuf.Reflection.MethodOptions Options {
@@ -2123,8 +2351,12 @@
       }
     }
 
+    /// <summary>Field number for the "client_streaming" field.</summary>
     public const int ClientStreamingFieldNumber = 5;
     private bool clientStreaming_;
+    /// <summary>
+    ///  Identifies if client streams multiple client messages
+    /// </summary>
     public bool ClientStreaming {
       get { return clientStreaming_; }
       set {
@@ -2132,8 +2364,12 @@
       }
     }
 
+    /// <summary>Field number for the "server_streaming" field.</summary>
     public const int ServerStreamingFieldNumber = 6;
     private bool serverStreaming_;
+    /// <summary>
+    ///  Identifies if server streams multiple server messages
+    /// </summary>
     public bool ServerStreaming {
       get { return serverStreaming_; }
       set {
@@ -2173,7 +2409,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2299,7 +2535,7 @@
     public static pb::MessageParser<FileOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[9]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[9]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2335,26 +2571,50 @@
       return new FileOptions(this);
     }
 
+    /// <summary>Field number for the "java_package" field.</summary>
     public const int JavaPackageFieldNumber = 1;
     private string javaPackage_ = "";
+    /// <summary>
+    ///  Sets the Java package where classes generated from this .proto will be
+    ///  placed.  By default, the proto package is used, but this is often
+    ///  inappropriate because proto packages do not normally start with backwards
+    ///  domain names.
+    /// </summary>
     public string JavaPackage {
       get { return javaPackage_; }
       set {
-        javaPackage_ = pb::Preconditions.CheckNotNull(value, "value");
+        javaPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "java_outer_classname" field.</summary>
     public const int JavaOuterClassnameFieldNumber = 8;
     private string javaOuterClassname_ = "";
+    /// <summary>
+    ///  If set, all the classes from the .proto file are wrapped in a single
+    ///  outer class with the given name.  This applies to both Proto1
+    ///  (equivalent to the old "--one_java_file" option) and Proto2 (where
+    ///  a .proto always translates to a single class, but you may want to
+    ///  explicitly choose the class name).
+    /// </summary>
     public string JavaOuterClassname {
       get { return javaOuterClassname_; }
       set {
-        javaOuterClassname_ = pb::Preconditions.CheckNotNull(value, "value");
+        javaOuterClassname_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "java_multiple_files" field.</summary>
     public const int JavaMultipleFilesFieldNumber = 10;
     private bool javaMultipleFiles_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate a separate .java
+    ///  file for each top-level message, enum, and service defined in the .proto
+    ///  file.  Thus, these types will *not* be nested inside the outer class
+    ///  named by java_outer_classname.  However, the outer class will still be
+    ///  generated to contain the file's getDescriptor() method as well as any
+    ///  top-level extensions defined in the file.
+    /// </summary>
     public bool JavaMultipleFiles {
       get { return javaMultipleFiles_; }
       set {
@@ -2362,8 +2622,23 @@
       }
     }
 
+    /// <summary>Field number for the "java_generate_equals_and_hash" field.</summary>
     public const int JavaGenerateEqualsAndHashFieldNumber = 20;
     private bool javaGenerateEqualsAndHash_;
+    /// <summary>
+    ///  If set true, then the Java code generator will generate equals() and
+    ///  hashCode() methods for all messages defined in the .proto file.
+    ///  This increases generated code size, potentially substantially for large
+    ///  protos, which may harm a memory-constrained application.
+    ///  - In the full runtime this is a speed optimization, as the
+    ///  AbstractMessage base class includes reflection-based implementations of
+    ///  these methods.
+    ///  - In the lite runtime, setting this option changes the semantics of
+    ///  equals() and hashCode() to more closely match those of the full runtime;
+    ///  the generated methods compute their results based on field values rather
+    ///  than object identity. (Implementations should not assume that hashcodes
+    ///  will be consistent across runtimes or versions of the protocol compiler.)
+    /// </summary>
     public bool JavaGenerateEqualsAndHash {
       get { return javaGenerateEqualsAndHash_; }
       set {
@@ -2371,8 +2646,17 @@
       }
     }
 
+    /// <summary>Field number for the "java_string_check_utf8" field.</summary>
     public const int JavaStringCheckUtf8FieldNumber = 27;
     private bool javaStringCheckUtf8_;
+    /// <summary>
+    ///  If set true, then the Java2 code generator will generate code that
+    ///  throws an exception whenever an attempt is made to assign a non-UTF-8
+    ///  byte sequence to a string field.
+    ///  Message reflection will do the same.
+    ///  However, an extension field still accepts non-UTF-8 byte sequences.
+    ///  This option has no effect on when used with the lite runtime.
+    /// </summary>
     public bool JavaStringCheckUtf8 {
       get { return javaStringCheckUtf8_; }
       set {
@@ -2380,6 +2664,7 @@
       }
     }
 
+    /// <summary>Field number for the "optimize_for" field.</summary>
     public const int OptimizeForFieldNumber = 9;
     private global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode optimizeFor_ = global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED;
     public global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode OptimizeFor {
@@ -2389,17 +2674,38 @@
       }
     }
 
+    /// <summary>Field number for the "go_package" field.</summary>
     public const int GoPackageFieldNumber = 11;
     private string goPackage_ = "";
+    /// <summary>
+    ///  Sets the Go package where structs generated from this .proto will be
+    ///  placed. If omitted, the Go package will be derived from the following:
+    ///    - The basename of the package import path, if provided.
+    ///    - Otherwise, the package statement in the .proto file, if present.
+    ///    - Otherwise, the basename of the .proto file, without extension.
+    /// </summary>
     public string GoPackage {
       get { return goPackage_; }
       set {
-        goPackage_ = pb::Preconditions.CheckNotNull(value, "value");
+        goPackage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "cc_generic_services" field.</summary>
     public const int CcGenericServicesFieldNumber = 16;
     private bool ccGenericServices_;
+    /// <summary>
+    ///  Should generic services be generated in each language?  "Generic" services
+    ///  are not specific to any particular RPC system.  They are generated by the
+    ///  main code generators in each language (without additional plugins).
+    ///  Generic services were the only kind of service generation supported by
+    ///  early versions of google.protobuf.
+    ///
+    ///  Generic services are now considered deprecated in favor of using plugins
+    ///  that generate code specific to your particular RPC system.  Therefore,
+    ///  these default to false.  Old code which depends on generic services should
+    ///  explicitly set them to true.
+    /// </summary>
     public bool CcGenericServices {
       get { return ccGenericServices_; }
       set {
@@ -2407,6 +2713,7 @@
       }
     }
 
+    /// <summary>Field number for the "java_generic_services" field.</summary>
     public const int JavaGenericServicesFieldNumber = 17;
     private bool javaGenericServices_;
     public bool JavaGenericServices {
@@ -2416,6 +2723,7 @@
       }
     }
 
+    /// <summary>Field number for the "py_generic_services" field.</summary>
     public const int PyGenericServicesFieldNumber = 18;
     private bool pyGenericServices_;
     public bool PyGenericServices {
@@ -2425,8 +2733,15 @@
       }
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 23;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this file deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for everything in the file, or it will be completely ignored; in the very
+    ///  least, this is a formalization for deprecating files.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -2434,8 +2749,13 @@
       }
     }
 
+    /// <summary>Field number for the "cc_enable_arenas" field.</summary>
     public const int CcEnableArenasFieldNumber = 31;
     private bool ccEnableArenas_;
+    /// <summary>
+    ///  Enables the use of arenas for the proto messages in this file. This applies
+    ///  only to generated classes for C++.
+    /// </summary>
     public bool CcEnableArenas {
       get { return ccEnableArenas_; }
       set {
@@ -2443,26 +2763,41 @@
       }
     }
 
+    /// <summary>Field number for the "objc_class_prefix" field.</summary>
     public const int ObjcClassPrefixFieldNumber = 36;
     private string objcClassPrefix_ = "";
+    /// <summary>
+    ///  Sets the objective c class prefix which is prepended to all objective c
+    ///  generated classes from this .proto. There is no default.
+    /// </summary>
     public string ObjcClassPrefix {
       get { return objcClassPrefix_; }
       set {
-        objcClassPrefix_ = pb::Preconditions.CheckNotNull(value, "value");
+        objcClassPrefix_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "csharp_namespace" field.</summary>
     public const int CsharpNamespaceFieldNumber = 37;
     private string csharpNamespace_ = "";
+    /// <summary>
+    ///  Namespace for generated classes; defaults to the package.
+    /// </summary>
     public string CsharpNamespace {
       get { return csharpNamespace_; }
       set {
-        csharpNamespace_ = pb::Preconditions.CheckNotNull(value, "value");
+        csharpNamespace_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "javanano_use_deprecated_package" field.</summary>
     public const int JavananoUseDeprecatedPackageFieldNumber = 38;
     private bool javananoUseDeprecatedPackage_;
+    /// <summary>
+    ///  Whether the nano proto compiler should generate in the deprecated non-nano
+    ///  suffixed package.
+    /// </summary>
+    [global::System.ObsoleteAttribute()]
     public bool JavananoUseDeprecatedPackage {
       get { return javananoUseDeprecatedPackage_; }
       set {
@@ -2470,10 +2805,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -2530,7 +2869,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2776,11 +3115,24 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the FileOptions message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
+      /// <summary>
+      ///  Generated classes can be optimized for speed or code size.
+      /// </summary>
       internal enum OptimizeMode {
+        /// <summary>
+        ///  Generate complete code for parsing, serialization,
+        /// </summary>
         SPEED = 1,
+        /// <summary>
+        ///  etc.
+        /// </summary>
         CODE_SIZE = 2,
+        /// <summary>
+        ///  Generate code using MessageLite and the lite runtime.
+        /// </summary>
         LITE_RUNTIME = 3,
       }
 
@@ -2795,7 +3147,7 @@
     public static pb::MessageParser<MessageOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[10]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[10]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -2820,8 +3172,29 @@
       return new MessageOptions(this);
     }
 
+    /// <summary>Field number for the "message_set_wire_format" field.</summary>
     public const int MessageSetWireFormatFieldNumber = 1;
     private bool messageSetWireFormat_;
+    /// <summary>
+    ///  Set true to use the old proto1 MessageSet wire format for extensions.
+    ///  This is provided for backwards-compatibility with the MessageSet wire
+    ///  format.  You should not use this for any other reason:  It's less
+    ///  efficient, has fewer features, and is more complicated.
+    ///
+    ///  The message must be defined exactly as follows:
+    ///    message Foo {
+    ///      option message_set_wire_format = true;
+    ///      extensions 4 to max;
+    ///    }
+    ///  Note that the message cannot have any defined fields; MessageSets only
+    ///  have extensions.
+    ///
+    ///  All extensions of your type must be singular messages; e.g. they cannot
+    ///  be int32s, enums, or repeated messages.
+    ///
+    ///  Because this is an option, the above two restrictions are not enforced by
+    ///  the protocol compiler.
+    /// </summary>
     public bool MessageSetWireFormat {
       get { return messageSetWireFormat_; }
       set {
@@ -2829,8 +3202,14 @@
       }
     }
 
+    /// <summary>Field number for the "no_standard_descriptor_accessor" field.</summary>
     public const int NoStandardDescriptorAccessorFieldNumber = 2;
     private bool noStandardDescriptorAccessor_;
+    /// <summary>
+    ///  Disables the generation of the standard "descriptor()" accessor, which can
+    ///  conflict with a field of the same name.  This is meant to make migration
+    ///  from proto1 easier; new code should avoid fields named "descriptor".
+    /// </summary>
     public bool NoStandardDescriptorAccessor {
       get { return noStandardDescriptorAccessor_; }
       set {
@@ -2838,8 +3217,15 @@
       }
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 3;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this message deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the message, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating messages.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -2847,8 +3233,32 @@
       }
     }
 
+    /// <summary>Field number for the "map_entry" field.</summary>
     public const int MapEntryFieldNumber = 7;
     private bool mapEntry_;
+    /// <summary>
+    ///  Whether the message is an automatically generated map entry type for the
+    ///  maps field.
+    ///
+    ///  For maps fields:
+    ///      map&lt;KeyType, ValueType> map_field = 1;
+    ///  The parsed descriptor looks like:
+    ///      message MapFieldEntry {
+    ///          option map_entry = true;
+    ///          optional KeyType key = 1;
+    ///          optional ValueType value = 2;
+    ///      }
+    ///      repeated MapFieldEntry map_field = 1;
+    ///
+    ///  Implementations may choose not to generate the map_entry=true message, but
+    ///  use a native map in the target language to hold the keys and values.
+    ///  The reflection APIs in such implementions still need to work as
+    ///  if the field is a repeated message field.
+    ///
+    ///  NOTE: Do not set the option in .proto files. Always use the maps syntax
+    ///  instead. The option should only be implicitly set by the proto compiler
+    ///  parser.
+    /// </summary>
     public bool MapEntry {
       get { return mapEntry_; }
       set {
@@ -2856,10 +3266,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -2894,7 +3308,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -2993,7 +3407,7 @@
     public static pb::MessageParser<FieldOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[11]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[11]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3020,8 +3434,15 @@
       return new FieldOptions(this);
     }
 
+    /// <summary>Field number for the "ctype" field.</summary>
     public const int CtypeFieldNumber = 1;
     private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING;
+    /// <summary>
+    ///  The ctype option instructs the C++ code generator to use a different
+    ///  representation of the field than it normally would.  See the specific
+    ///  options below.  This option is not yet implemented in the open source
+    ///  release -- sorry, we'll try to include it in a future version!
+    /// </summary>
     public global::Google.Protobuf.Reflection.FieldOptions.Types.CType Ctype {
       get { return ctype_; }
       set {
@@ -3029,8 +3450,16 @@
       }
     }
 
+    /// <summary>Field number for the "packed" field.</summary>
     public const int PackedFieldNumber = 2;
     private bool packed_;
+    /// <summary>
+    ///  The packed option can be enabled for repeated primitive fields to enable
+    ///  a more efficient representation on the wire. Rather than repeatedly
+    ///  writing the tag and type for each element, the entire array is encoded as
+    ///  a single length-delimited blob. In proto3, only explicit setting it to
+    ///  false will avoid using packed encoding.
+    /// </summary>
     public bool Packed {
       get { return packed_; }
       set {
@@ -3038,8 +3467,20 @@
       }
     }
 
+    /// <summary>Field number for the "jstype" field.</summary>
     public const int JstypeFieldNumber = 6;
     private global::Google.Protobuf.Reflection.FieldOptions.Types.JSType jstype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL;
+    /// <summary>
+    ///  The jstype option determines the JavaScript type used for values of the
+    ///  field.  The option is permitted only for 64 bit integral and fixed types
+    ///  (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+    ///  represented as JavaScript strings.  This avoids loss of precision that can
+    ///  happen when a large value is converted to a floating point JavaScript
+    ///  numbers.  Specifying JS_NUMBER for the jstype causes the generated
+    ///  JavaScript code to use the JavaScript "number" type instead of strings.
+    ///  This option is an enum to permit additional types to be added,
+    ///  e.g. goog.math.Integer.
+    /// </summary>
     public global::Google.Protobuf.Reflection.FieldOptions.Types.JSType Jstype {
       get { return jstype_; }
       set {
@@ -3047,8 +3488,38 @@
       }
     }
 
+    /// <summary>Field number for the "lazy" field.</summary>
     public const int LazyFieldNumber = 5;
     private bool lazy_;
+    /// <summary>
+    ///  Should this field be parsed lazily?  Lazy applies only to message-type
+    ///  fields.  It means that when the outer message is initially parsed, the
+    ///  inner message's contents will not be parsed but instead stored in encoded
+    ///  form.  The inner message will actually be parsed when it is first accessed.
+    ///
+    ///  This is only a hint.  Implementations are free to choose whether to use
+    ///  eager or lazy parsing regardless of the value of this option.  However,
+    ///  setting this option true suggests that the protocol author believes that
+    ///  using lazy parsing on this field is worth the additional bookkeeping
+    ///  overhead typically needed to implement it.
+    ///
+    ///  This option does not affect the public interface of any generated code;
+    ///  all method signatures remain the same.  Furthermore, thread-safety of the
+    ///  interface is not affected by this option; const methods remain safe to
+    ///  call from multiple threads concurrently, while non-const methods continue
+    ///  to require exclusive access.
+    ///
+    ///  Note that implementations may choose not to check required fields within
+    ///  a lazy sub-message.  That is, calling IsInitialized() on the outher message
+    ///  may return true even if the inner message has missing required fields.
+    ///  This is necessary because otherwise the inner message would have to be
+    ///  parsed in order to perform the check, defeating the purpose of lazy
+    ///  parsing.  An implementation which chooses not to check required fields
+    ///  must be consistent about it.  That is, for any particular sub-message, the
+    ///  implementation must either *always* check its required fields, or *never*
+    ///  check its required fields, regardless of whether or not the message has
+    ///  been parsed.
+    /// </summary>
     public bool Lazy {
       get { return lazy_; }
       set {
@@ -3056,8 +3527,15 @@
       }
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 3;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this field deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for accessors, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating fields.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -3065,8 +3543,12 @@
       }
     }
 
+    /// <summary>Field number for the "weak" field.</summary>
     public const int WeakFieldNumber = 10;
     private bool weak_;
+    /// <summary>
+    ///  For Google-internal migration only. Do not use.
+    /// </summary>
     public bool Weak {
       get { return weak_; }
       set {
@@ -3074,10 +3556,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -3116,7 +3602,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3236,17 +3722,30 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the FieldOptions message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       internal enum CType {
+        /// <summary>
+        ///  Default mode.
+        /// </summary>
         STRING = 0,
         CORD = 1,
         STRING_PIECE = 2,
       }
 
       internal enum JSType {
+        /// <summary>
+        ///  Use the default type.
+        /// </summary>
         JS_NORMAL = 0,
+        /// <summary>
+        ///  Use JavaScript strings.
+        /// </summary>
         JS_STRING = 1,
+        /// <summary>
+        ///  Use JavaScript numbers.
+        /// </summary>
         JS_NUMBER = 2,
       }
 
@@ -3261,7 +3760,7 @@
     public static pb::MessageParser<EnumOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[12]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[12]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3284,8 +3783,13 @@
       return new EnumOptions(this);
     }
 
+    /// <summary>Field number for the "allow_alias" field.</summary>
     public const int AllowAliasFieldNumber = 2;
     private bool allowAlias_;
+    /// <summary>
+    ///  Set this option to true to allow mapping different tag names to the same
+    ///  value.
+    /// </summary>
     public bool AllowAlias {
       get { return allowAlias_; }
       set {
@@ -3293,8 +3797,15 @@
       }
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 3;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this enum deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum, or it will be completely ignored; in the very least, this
+    ///  is a formalization for deprecating enums.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -3302,10 +3813,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -3336,7 +3851,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3407,7 +3922,7 @@
     public static pb::MessageParser<EnumValueOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[13]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[13]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3429,8 +3944,15 @@
       return new EnumValueOptions(this);
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 1;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this enum value deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the enum value, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating enum values.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -3438,10 +3960,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -3470,7 +3996,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3527,7 +4053,7 @@
     public static pb::MessageParser<ServiceOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[14]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[14]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3549,8 +4075,15 @@
       return new ServiceOptions(this);
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 33;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this service deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the service, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating services.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -3558,10 +4091,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -3590,7 +4127,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3647,7 +4184,7 @@
     public static pb::MessageParser<MethodOptions> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[15]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[15]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3669,8 +4206,15 @@
       return new MethodOptions(this);
     }
 
+    /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 33;
     private bool deprecated_;
+    /// <summary>
+    ///  Is this method deprecated?
+    ///  Depending on the target platform, this can emit Deprecated annotations
+    ///  for the method, or it will be completely ignored; in the very least,
+    ///  this is a formalization for deprecating methods.
+    /// </summary>
     public bool Deprecated {
       get { return deprecated_; }
       set {
@@ -3678,10 +4222,14 @@
       }
     }
 
+    /// <summary>Field number for the "uninterpreted_option" field.</summary>
     public const int UninterpretedOptionFieldNumber = 999;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _repeated_uninterpretedOption_codec
         = pb::FieldCodec.ForMessage(7994, global::Google.Protobuf.Reflection.UninterpretedOption.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> uninterpretedOption_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption>();
+    /// <summary>
+    ///  The parser stores options it doesn't recognize here. See above.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.UninterpretedOption> UninterpretedOption {
       get { return uninterpretedOption_; }
     }
@@ -3710,7 +4258,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -3761,13 +4309,21 @@
 
   }
 
+  /// <summary>
+  ///  A message representing a option the parser does not recognize. This only
+  ///  appears in options protos created by the compiler::Parser class.
+  ///  DescriptorPool resolves these when building Descriptor objects. Therefore,
+  ///  options protos in descriptor objects (e.g. returned by Descriptor::options(),
+  ///  or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+  ///  in them.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class UninterpretedOption : pb::IMessage<UninterpretedOption> {
     private static readonly pb::MessageParser<UninterpretedOption> _parser = new pb::MessageParser<UninterpretedOption>(() => new UninterpretedOption());
     public static pb::MessageParser<UninterpretedOption> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[16]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[16]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -3794,6 +4350,7 @@
       return new UninterpretedOption(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart> _repeated_name_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.Reflection.UninterpretedOption.Types.NamePart.Parser);
@@ -3802,15 +4359,21 @@
       get { return name_; }
     }
 
+    /// <summary>Field number for the "identifier_value" field.</summary>
     public const int IdentifierValueFieldNumber = 3;
     private string identifierValue_ = "";
+    /// <summary>
+    ///  The value of the uninterpreted option, in whatever type the tokenizer
+    ///  identified it as during parsing. Exactly one of these should be set.
+    /// </summary>
     public string IdentifierValue {
       get { return identifierValue_; }
       set {
-        identifierValue_ = pb::Preconditions.CheckNotNull(value, "value");
+        identifierValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "positive_int_value" field.</summary>
     public const int PositiveIntValueFieldNumber = 4;
     private ulong positiveIntValue_;
     public ulong PositiveIntValue {
@@ -3820,6 +4383,7 @@
       }
     }
 
+    /// <summary>Field number for the "negative_int_value" field.</summary>
     public const int NegativeIntValueFieldNumber = 5;
     private long negativeIntValue_;
     public long NegativeIntValue {
@@ -3829,6 +4393,7 @@
       }
     }
 
+    /// <summary>Field number for the "double_value" field.</summary>
     public const int DoubleValueFieldNumber = 6;
     private double doubleValue_;
     public double DoubleValue {
@@ -3838,21 +4403,23 @@
       }
     }
 
+    /// <summary>Field number for the "string_value" field.</summary>
     public const int StringValueFieldNumber = 7;
     private pb::ByteString stringValue_ = pb::ByteString.Empty;
     public pb::ByteString StringValue {
       get { return stringValue_; }
       set {
-        stringValue_ = pb::Preconditions.CheckNotNull(value, "value");
+        stringValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "aggregate_value" field.</summary>
     public const int AggregateValueFieldNumber = 8;
     private string aggregateValue_ = "";
     public string AggregateValue {
       get { return aggregateValue_; }
       set {
-        aggregateValue_ = pb::Preconditions.CheckNotNull(value, "value");
+        aggregateValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -3890,7 +4457,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4010,8 +4577,16 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the UninterpretedOption message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
+      /// <summary>
+      ///  The name of the uninterpreted option.  Each string represents a segment in
+      ///  a dot-separated name.  is_extension is true iff a segment represents an
+      ///  extension (denoted with parentheses in options specs in .proto files).
+      ///  E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
+      ///  "foo.(bar.baz).qux".
+      /// </summary>
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
       internal sealed partial class NamePart : pb::IMessage<NamePart> {
         private static readonly pb::MessageParser<NamePart> _parser = new pb::MessageParser<NamePart>(() => new NamePart());
@@ -4040,15 +4615,17 @@
           return new NamePart(this);
         }
 
+        /// <summary>Field number for the "name_part" field.</summary>
         public const int NamePart_FieldNumber = 1;
         private string namePart_ = "";
         public string NamePart_ {
           get { return namePart_; }
           set {
-            namePart_ = pb::Preconditions.CheckNotNull(value, "value");
+            namePart_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
           }
         }
 
+        /// <summary>Field number for the "is_extension" field.</summary>
         public const int IsExtensionFieldNumber = 2;
         private bool isExtension_;
         public bool IsExtension {
@@ -4082,7 +4659,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -4145,13 +4722,17 @@
 
   }
 
+  /// <summary>
+  ///  Encapsulates information about the original source file from which a
+  ///  FileDescriptorProto was generated.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   internal sealed partial class SourceCodeInfo : pb::IMessage<SourceCodeInfo> {
     private static readonly pb::MessageParser<SourceCodeInfo> _parser = new pb::MessageParser<SourceCodeInfo>(() => new SourceCodeInfo());
     public static pb::MessageParser<SourceCodeInfo> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.Reflection.DescriptorProtoFile.Descriptor.MessageTypes[17]; }
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[17]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -4172,10 +4753,56 @@
       return new SourceCodeInfo(this);
     }
 
+    /// <summary>Field number for the "location" field.</summary>
     public const int LocationFieldNumber = 1;
     private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> _repeated_location_codec
         = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> location_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location>();
+    /// <summary>
+    ///  A Location identifies a piece of source code in a .proto file which
+    ///  corresponds to a particular definition.  This information is intended
+    ///  to be useful to IDEs, code indexers, documentation generators, and similar
+    ///  tools.
+    ///
+    ///  For example, say we have a file like:
+    ///    message Foo {
+    ///      optional string foo = 1;
+    ///    }
+    ///  Let's look at just the field definition:
+    ///    optional string foo = 1;
+    ///    ^       ^^     ^^  ^  ^^^
+    ///    a       bc     de  f  ghi
+    ///  We have the following locations:
+    ///    span   path               represents
+    ///    [a,i)  [ 4, 0, 2, 0 ]     The whole field definition.
+    ///    [a,b)  [ 4, 0, 2, 0, 4 ]  The label (optional).
+    ///    [c,d)  [ 4, 0, 2, 0, 5 ]  The type (string).
+    ///    [e,f)  [ 4, 0, 2, 0, 1 ]  The name (foo).
+    ///    [g,h)  [ 4, 0, 2, 0, 3 ]  The number (1).
+    ///
+    ///  Notes:
+    ///  - A location may refer to a repeated field itself (i.e. not to any
+    ///    particular index within it).  This is used whenever a set of elements are
+    ///    logically enclosed in a single code segment.  For example, an entire
+    ///    extend block (possibly containing multiple extension definitions) will
+    ///    have an outer location whose path refers to the "extensions" repeated
+    ///    field without an index.
+    ///  - Multiple locations may have the same path.  This happens when a single
+    ///    logical declaration is spread out across multiple places.  The most
+    ///    obvious example is the "extend" block again -- there may be multiple
+    ///    extend blocks in the same scope, each of which will have the same path.
+    ///  - A location's span is not always a subset of its parent's span.  For
+    ///    example, the "extendee" of an extension declaration appears at the
+    ///    beginning of the "extend" block and is shared by all extensions within
+    ///    the block.
+    ///  - Just because a location's span is a subset of some other location's span
+    ///    does not mean that it is a descendent.  For example, a "group" defines
+    ///    both a type and a field in a single declaration.  Thus, the locations
+    ///    corresponding to the type and field and their components will overlap.
+    ///  - Code which tries to interpret locations should probably be designed to
+    ///    ignore those that it doesn't understand, as more types of locations could
+    ///    be recorded in the future.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.Reflection.SourceCodeInfo.Types.Location> Location {
       get { return location_; }
     }
@@ -4202,7 +4829,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -4238,6 +4865,7 @@
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the SourceCodeInfo message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
       [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -4271,40 +4899,126 @@
           return new Location(this);
         }
 
+        /// <summary>Field number for the "path" field.</summary>
         public const int PathFieldNumber = 1;
         private static readonly pb::FieldCodec<int> _repeated_path_codec
             = pb::FieldCodec.ForInt32(10);
         private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies which part of the FileDescriptorProto was defined at this
+        ///  location.
+        ///
+        ///  Each element is a field number or an index.  They form a path from
+        ///  the root FileDescriptorProto to the place where the definition.  For
+        ///  example, this path:
+        ///    [ 4, 3, 2, 7, 1 ]
+        ///  refers to:
+        ///    file.message_type(3)  // 4, 3
+        ///        .field(7)         // 2, 7
+        ///        .name()           // 1
+        ///  This is because FileDescriptorProto.message_type has field number 4:
+        ///    repeated DescriptorProto message_type = 4;
+        ///  and DescriptorProto.field has field number 2:
+        ///    repeated FieldDescriptorProto field = 2;
+        ///  and FieldDescriptorProto.name has field number 1:
+        ///    optional string name = 1;
+        ///
+        ///  Thus, the above path gives the location of a field name.  If we removed
+        ///  the last element:
+        ///    [ 4, 3, 2, 7 ]
+        ///  this path refers to the whole field declaration (from the beginning
+        ///  of the label to the terminating semicolon).
+        /// </summary>
         public pbc::RepeatedField<int> Path {
           get { return path_; }
         }
 
+        /// <summary>Field number for the "span" field.</summary>
         public const int SpanFieldNumber = 2;
         private static readonly pb::FieldCodec<int> _repeated_span_codec
             = pb::FieldCodec.ForInt32(18);
         private readonly pbc::RepeatedField<int> span_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Always has exactly three or four elements: start line, start column,
+        ///  end line (optional, otherwise assumed same as start line), end column.
+        ///  These are packed into a single field for efficiency.  Note that line
+        ///  and column numbers are zero-based -- typically you will want to add
+        ///  1 to each before displaying to a user.
+        /// </summary>
         public pbc::RepeatedField<int> Span {
           get { return span_; }
         }
 
+        /// <summary>Field number for the "leading_comments" field.</summary>
         public const int LeadingCommentsFieldNumber = 3;
         private string leadingComments_ = "";
+        /// <summary>
+        ///  If this SourceCodeInfo represents a complete declaration, these are any
+        ///  comments appearing before and after the declaration which appear to be
+        ///  attached to the declaration.
+        ///
+        ///  A series of line comments appearing on consecutive lines, with no other
+        ///  tokens appearing on those lines, will be treated as a single comment.
+        ///
+        ///  leading_detached_comments will keep paragraphs of comments that appear
+        ///  before (but not connected to) the current element. Each paragraph,
+        ///  separated by empty lines, will be one comment element in the repeated
+        ///  field.
+        ///
+        ///  Only the comment content is provided; comment markers (e.g. //) are
+        ///  stripped out.  For block comments, leading whitespace and an asterisk
+        ///  will be stripped from the beginning of each line other than the first.
+        ///  Newlines are included in the output.
+        ///
+        ///  Examples:
+        ///
+        ///    optional int32 foo = 1;  // Comment attached to foo.
+        ///    // Comment attached to bar.
+        ///    optional int32 bar = 2;
+        ///
+        ///    optional string baz = 3;
+        ///    // Comment attached to baz.
+        ///    // Another line attached to baz.
+        ///
+        ///    // Comment attached to qux.
+        ///    //
+        ///    // Another line attached to qux.
+        ///    optional double qux = 4;
+        ///
+        ///    // Detached comment for corge. This is not leading or trailing comments
+        ///    // to qux or corge because there are blank lines separating it from
+        ///    // both.
+        ///
+        ///    // Detached comment for corge paragraph 2.
+        ///
+        ///    optional string corge = 5;
+        ///    /* Block comment attached
+        ///     * to corge.  Leading asterisks
+        ///     * will be removed. */
+        ///    /* Block comment attached to
+        ///     * grault. */
+        ///    optional int32 grault = 6;
+        ///
+        ///    // ignored detached comments.
+        /// </summary>
         public string LeadingComments {
           get { return leadingComments_; }
           set {
-            leadingComments_ = pb::Preconditions.CheckNotNull(value, "value");
+            leadingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
           }
         }
 
+        /// <summary>Field number for the "trailing_comments" field.</summary>
         public const int TrailingCommentsFieldNumber = 4;
         private string trailingComments_ = "";
         public string TrailingComments {
           get { return trailingComments_; }
           set {
-            trailingComments_ = pb::Preconditions.CheckNotNull(value, "value");
+            trailingComments_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
           }
         }
 
+        /// <summary>Field number for the "leading_detached_comments" field.</summary>
         public const int LeadingDetachedCommentsFieldNumber = 6;
         private static readonly pb::FieldCodec<string> _repeated_leadingDetachedComments_codec
             = pb::FieldCodec.ForString(50);
@@ -4343,7 +5057,7 @@
         }
 
         public override string ToString() {
-          return pb::JsonFormatter.Default.Format(this);
+          return pb::JsonFormatter.ToDiagnosticString(this);
         }
 
         public void WriteTo(pb::CodedOutputStream output) {
@@ -4429,6 +5143,310 @@
 
   }
 
+  /// <summary>
+  ///  Describes the relationship between generated code and its original source
+  ///  file. A GeneratedCodeInfo message is associated with only one generated
+  ///  source file, but may contain references to different source .proto files.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  internal sealed partial class GeneratedCodeInfo : pb::IMessage<GeneratedCodeInfo> {
+    private static readonly pb::MessageParser<GeneratedCodeInfo> _parser = new pb::MessageParser<GeneratedCodeInfo>(() => new GeneratedCodeInfo());
+    public static pb::MessageParser<GeneratedCodeInfo> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.Reflection.DescriptorReflection.Descriptor.MessageTypes[18]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public GeneratedCodeInfo() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public GeneratedCodeInfo(GeneratedCodeInfo other) : this() {
+      annotation_ = other.annotation_.Clone();
+    }
+
+    public GeneratedCodeInfo Clone() {
+      return new GeneratedCodeInfo(this);
+    }
+
+    /// <summary>Field number for the "annotation" field.</summary>
+    public const int AnnotationFieldNumber = 1;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> _repeated_annotation_codec
+        = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> annotation_ = new pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation>();
+    /// <summary>
+    ///  An Annotation connects some span of text in generated code to an element
+    ///  of its generating .proto file.
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.Reflection.GeneratedCodeInfo.Types.Annotation> Annotation {
+      get { return annotation_; }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as GeneratedCodeInfo);
+    }
+
+    public bool Equals(GeneratedCodeInfo other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if(!annotation_.Equals(other.annotation_)) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      hash ^= annotation_.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      annotation_.WriteTo(output, _repeated_annotation_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      size += annotation_.CalculateSize(_repeated_annotation_codec);
+      return size;
+    }
+
+    public void MergeFrom(GeneratedCodeInfo other) {
+      if (other == null) {
+        return;
+      }
+      annotation_.Add(other.annotation_);
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            annotation_.AddEntriesFrom(input, _repeated_annotation_codec);
+            break;
+          }
+        }
+      }
+    }
+
+    #region Nested types
+    /// <summary>Container for nested types declared in the GeneratedCodeInfo message type.</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+      internal sealed partial class Annotation : pb::IMessage<Annotation> {
+        private static readonly pb::MessageParser<Annotation> _parser = new pb::MessageParser<Annotation>(() => new Annotation());
+        public static pb::MessageParser<Annotation> Parser { get { return _parser; } }
+
+        public static pbr::MessageDescriptor Descriptor {
+          get { return global::Google.Protobuf.Reflection.GeneratedCodeInfo.Descriptor.NestedTypes[0]; }
+        }
+
+        pbr::MessageDescriptor pb::IMessage.Descriptor {
+          get { return Descriptor; }
+        }
+
+        public Annotation() {
+          OnConstruction();
+        }
+
+        partial void OnConstruction();
+
+        public Annotation(Annotation other) : this() {
+          path_ = other.path_.Clone();
+          sourceFile_ = other.sourceFile_;
+          begin_ = other.begin_;
+          end_ = other.end_;
+        }
+
+        public Annotation Clone() {
+          return new Annotation(this);
+        }
+
+        /// <summary>Field number for the "path" field.</summary>
+        public const int PathFieldNumber = 1;
+        private static readonly pb::FieldCodec<int> _repeated_path_codec
+            = pb::FieldCodec.ForInt32(10);
+        private readonly pbc::RepeatedField<int> path_ = new pbc::RepeatedField<int>();
+        /// <summary>
+        ///  Identifies the element in the original source .proto file. This field
+        ///  is formatted the same as SourceCodeInfo.Location.path.
+        /// </summary>
+        public pbc::RepeatedField<int> Path {
+          get { return path_; }
+        }
+
+        /// <summary>Field number for the "source_file" field.</summary>
+        public const int SourceFileFieldNumber = 2;
+        private string sourceFile_ = "";
+        /// <summary>
+        ///  Identifies the filesystem path to the original source .proto.
+        /// </summary>
+        public string SourceFile {
+          get { return sourceFile_; }
+          set {
+            sourceFile_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+          }
+        }
+
+        /// <summary>Field number for the "begin" field.</summary>
+        public const int BeginFieldNumber = 3;
+        private int begin_;
+        /// <summary>
+        ///  Identifies the starting offset in bytes in the generated code
+        ///  that relates to the identified object.
+        /// </summary>
+        public int Begin {
+          get { return begin_; }
+          set {
+            begin_ = value;
+          }
+        }
+
+        /// <summary>Field number for the "end" field.</summary>
+        public const int EndFieldNumber = 4;
+        private int end_;
+        /// <summary>
+        ///  Identifies the ending offset in bytes in the generated code that
+        ///  relates to the identified offset. The end offset should be one past
+        ///  the last relevant byte (so the length of the text = end - begin).
+        /// </summary>
+        public int End {
+          get { return end_; }
+          set {
+            end_ = value;
+          }
+        }
+
+        public override bool Equals(object other) {
+          return Equals(other as Annotation);
+        }
+
+        public bool Equals(Annotation other) {
+          if (ReferenceEquals(other, null)) {
+            return false;
+          }
+          if (ReferenceEquals(other, this)) {
+            return true;
+          }
+          if(!path_.Equals(other.path_)) return false;
+          if (SourceFile != other.SourceFile) return false;
+          if (Begin != other.Begin) return false;
+          if (End != other.End) return false;
+          return true;
+        }
+
+        public override int GetHashCode() {
+          int hash = 1;
+          hash ^= path_.GetHashCode();
+          if (SourceFile.Length != 0) hash ^= SourceFile.GetHashCode();
+          if (Begin != 0) hash ^= Begin.GetHashCode();
+          if (End != 0) hash ^= End.GetHashCode();
+          return hash;
+        }
+
+        public override string ToString() {
+          return pb::JsonFormatter.ToDiagnosticString(this);
+        }
+
+        public void WriteTo(pb::CodedOutputStream output) {
+          path_.WriteTo(output, _repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            output.WriteRawTag(18);
+            output.WriteString(SourceFile);
+          }
+          if (Begin != 0) {
+            output.WriteRawTag(24);
+            output.WriteInt32(Begin);
+          }
+          if (End != 0) {
+            output.WriteRawTag(32);
+            output.WriteInt32(End);
+          }
+        }
+
+        public int CalculateSize() {
+          int size = 0;
+          size += path_.CalculateSize(_repeated_path_codec);
+          if (SourceFile.Length != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeStringSize(SourceFile);
+          }
+          if (Begin != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(Begin);
+          }
+          if (End != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(End);
+          }
+          return size;
+        }
+
+        public void MergeFrom(Annotation other) {
+          if (other == null) {
+            return;
+          }
+          path_.Add(other.path_);
+          if (other.SourceFile.Length != 0) {
+            SourceFile = other.SourceFile;
+          }
+          if (other.Begin != 0) {
+            Begin = other.Begin;
+          }
+          if (other.End != 0) {
+            End = other.End;
+          }
+        }
+
+        public void MergeFrom(pb::CodedInputStream input) {
+          uint tag;
+          while ((tag = input.ReadTag()) != 0) {
+            switch(tag) {
+              default:
+                input.SkipLastField();
+                break;
+              case 10:
+              case 8: {
+                path_.AddEntriesFrom(input, _repeated_path_codec);
+                break;
+              }
+              case 18: {
+                SourceFile = input.ReadString();
+                break;
+              }
+              case 24: {
+                Begin = input.ReadInt32();
+                break;
+              }
+              case 32: {
+                End = input.ReadInt32();
+                break;
+              }
+            }
+          }
+        }
+
+      }
+
+    }
+    #endregion
+
+  }
+
   #endregion
 
 }
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
index 285f26f..c732c93 100644
--- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
@@ -43,13 +43,13 @@
         private readonly EnumDescriptorProto proto;
         private readonly MessageDescriptor containingType;
         private readonly IList<EnumValueDescriptor> values;
-        private readonly Type generatedType;
+        private readonly Type clrType;
 
-        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type generatedType)
+        internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
             this.proto = proto;
-            this.generatedType = generatedType;
+            this.clrType = clrType;
             containingType = parent;
 
             if (proto.Value.Count == 0)
@@ -73,9 +73,9 @@
         public override string Name { get { return proto.Name; } }
 
         /// <summary>
-        /// The generated type for this enum, or <c>null</c> if the descriptor does not represent a generated type.
+        /// The CLR type for this enum. For generated code, this will be a CLR enum type.
         /// </summary>
-        public Type GeneratedType { get { return generatedType; } }
+        public Type ClrType { get { return clrType; } }
 
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
index 901cbf4..c6caaec 100644
--- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -62,8 +62,7 @@
 
             if (FieldNumber <= 0)
             {
-                throw new DescriptorValidationException(this,
-                                                        "Field numbers must be positive integers.");
+                throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
             }
             containingType = parent;
             // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
@@ -72,7 +71,7 @@
                 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
                 {
                     throw new DescriptorValidationException(this,
-                        "FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
+                        $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
                 }
                 containingOneof = parent.Oneofs[proto.OneofIndex];
             }
@@ -94,13 +93,22 @@
         internal FieldDescriptorProto Proto { get { return proto; } }
 
         /// <summary>
-        /// Returns the accessor for this field, or <c>null</c> if this descriptor does
-        /// not support reflective access.
+        /// Returns the accessor for this field.
         /// </summary>
         /// <remarks>
+        /// <para>
         /// While a <see cref="FieldDescriptor"/> describes the field, it does not provide
         /// any way of obtaining or changing the value of the field within a specific message;
         /// that is the responsibility of the accessor.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, and the value of the map field itself is represented by a dictionary in the
+        /// reflection API. There are never instances of those "hidden" messages, so no accessor is provided
+        /// and this property will return null.
+        /// </para>
         /// </remarks>
         public IFieldAccessor Accessor { get { return accessor; } }
         
@@ -197,7 +205,7 @@
         }
 
         /// <summary>
-        /// Returns  the type of the field.
+        /// Returns the type of the field.
         /// </summary>
         public FieldType FieldType
         {
@@ -252,7 +260,7 @@
             {
                 if (fieldType != FieldType.Message)
                 {
-                    throw new InvalidOperationException("MessageType is only valid for enum fields.");
+                    throw new InvalidOperationException("MessageType is only valid for message fields.");
                 }
                 return messageType;
             }
@@ -281,7 +289,7 @@
                     }
                     else
                     {
-                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not a type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a type.");
                     }
                 }
 
@@ -289,8 +297,7 @@
                 {
                     if (!(typeDescriptor is MessageDescriptor))
                     {
-                        throw new DescriptorValidationException(this,
-                                                                "\"" + Proto.TypeName + "\" is not a message type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
                     }
                     messageType = (MessageDescriptor) typeDescriptor;
 
@@ -303,7 +310,7 @@
                 {
                     if (!(typeDescriptor is EnumDescriptor))
                     {
-                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not an enum type.");
+                        throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type.");
                     }
                     enumType = (EnumDescriptor) typeDescriptor;
                 }
@@ -333,14 +340,16 @@
 
         private IFieldAccessor CreateAccessor(string propertyName)
         {
-            if (containingType.GeneratedType == null || propertyName == null)
+            // If we're given no property name, that's because we really don't want an accessor.
+            // (At the moment, that means it's a map entry message...)
+            if (propertyName == null)
             {
                 return null;
             }
-            var property = containingType.GeneratedType.GetProperty(propertyName);
+            var property = containingType.ClrType.GetProperty(propertyName);
             if (property == null)
             {
-                throw new DescriptorValidationException(this, "Property " + propertyName + " not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Property {propertyName} not found in {containingType.ClrType}");
             }
             return IsMap ? new MapFieldAccessor(property, this)
                 : IsRepeated ? new RepeatedFieldAccessor(property, this)
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index 45862af..ab7cd92 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -43,35 +43,26 @@
     /// </summary>
     public sealed class FileDescriptor : IDescriptor
     {
-        private readonly ByteString descriptorData;
-        private readonly FileDescriptorProto proto;
-        private readonly IList<MessageDescriptor> messageTypes;
-        private readonly IList<EnumDescriptor> enumTypes;
-        private readonly IList<ServiceDescriptor> services;
-        private readonly IList<FileDescriptor> dependencies;
-        private readonly IList<FileDescriptor> publicDependencies;
-        private readonly DescriptorPool pool;
-        
-        private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedCodeInfo generatedCodeInfo)
+        private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
         {
-            this.descriptorData = descriptorData;
-            this.pool = pool;
-            this.proto = proto;
-            this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
+            SerializedData = descriptorData;
+            DescriptorPool = pool;
+            Proto = proto;
+            Dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
 
-            publicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
+            PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
 
             pool.AddPackage(Package, this);
 
-            messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
+            MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
                                                                  (message, index) =>
-                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
+                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo.NestedTypes[index]));
 
-            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
                                                               (enumType, index) =>
-                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
+                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo.NestedEnums[index]));
 
-            services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
+            Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
                                                              (service, index) =>
                                                              new ServiceDescriptor(service, this, index));
         }
@@ -132,99 +123,63 @@
         /// <value>
         /// The descriptor in its protocol message representation.
         /// </value>
-        internal FileDescriptorProto Proto
-        {
-            get { return proto; }
-        }
+        internal FileDescriptorProto Proto { get; }
 
         /// <value>
         /// The file name.
         /// </value>
-        public string Name
-        {
-            get { return proto.Name; }
-        }
+        public string Name => Proto.Name;
 
         /// <summary>
         /// The package as declared in the .proto file. This may or may not
         /// be equivalent to the .NET namespace of the generated classes.
         /// </summary>
-        public string Package
-        {
-            get { return proto.Package; }
-        }
+        public string Package => Proto.Package;
 
         /// <value>
         /// Unmodifiable list of top-level message types declared in this file.
         /// </value>
-        public IList<MessageDescriptor> MessageTypes
-        {
-            get { return messageTypes; }
-        }
+        public IList<MessageDescriptor> MessageTypes { get; }
 
         /// <value>
         /// Unmodifiable list of top-level enum types declared in this file.
         /// </value>
-        public IList<EnumDescriptor> EnumTypes
-        {
-            get { return enumTypes; }
-        }
+        public IList<EnumDescriptor> EnumTypes { get; }
 
         /// <value>
         /// Unmodifiable list of top-level services declared in this file.
         /// </value>
-        public IList<ServiceDescriptor> Services
-        {
-            get { return services; }
-        }
+        public IList<ServiceDescriptor> Services { get; }
 
         /// <value>
         /// Unmodifiable list of this file's dependencies (imports).
         /// </value>
-        public IList<FileDescriptor> Dependencies
-        {
-            get { return dependencies; }
-        }
+        public IList<FileDescriptor> Dependencies { get; }
 
         /// <value>
         /// Unmodifiable list of this file's public dependencies (public imports).
         /// </value>
-        public IList<FileDescriptor> PublicDependencies
-        {
-            get { return publicDependencies; }
-        }
+        public IList<FileDescriptor> PublicDependencies { get; }
 
         /// <value>
         /// The original serialized binary form of this descriptor.
         /// </value>
-        public ByteString SerializedData
-        {
-            get { return descriptorData; }
-        }
+        public ByteString SerializedData { get; }
 
         /// <value>
         /// Implementation of IDescriptor.FullName - just returns the same as Name.
         /// </value>
-        string IDescriptor.FullName
-        {
-            get { return Name; }
-        }
+        string IDescriptor.FullName => Name;
 
         /// <value>
         /// Implementation of IDescriptor.File - just returns this descriptor.
         /// </value>
-        FileDescriptor IDescriptor.File
-        {
-            get { return this; }
-        }
+        FileDescriptor IDescriptor.File => this;
 
         /// <value>
         /// Pool containing symbol descriptors.
         /// </value>
-        internal DescriptorPool DescriptorPool
-        {
-            get { return pool; }
-        }
+        internal DescriptorPool DescriptorPool { get; }
 
         /// <summary>
         /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
@@ -245,7 +200,7 @@
             {
                 name = Package + "." + name;
             }
-            T result = pool.FindSymbol<T>(name);
+            T result = DescriptorPool.FindSymbol<T>(name);
             if (result != null && result.File == this)
             {
                 return result;
@@ -264,11 +219,11 @@
         /// file's dependencies, in the exact order listed in the .proto file. May be null,
         /// in which case it is treated as an empty array.</param>
         /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
-        /// <param name="generatedCodeInfo">Reflection information, if any. May be null, specifically for non-generated code.</param>
+        /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
         /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
         /// a valid descriptor. This can occur for a number of reasons, such as a field
         /// having an undefined type or because two messages were defined with the same name.</exception>
-        private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedCodeInfo generatedCodeInfo)
+        private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
         {
             // Building descriptors involves two steps: translating and linking.
             // In the translation step (implemented by FileDescriptor's
@@ -291,15 +246,17 @@
             // need.
             if (dependencies.Length != proto.Dependency.Count)
             {
-                throw new DescriptorValidationException(result,
-                                                        "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
-                                                        "those listed in the FileDescriptorProto.");
+                throw new DescriptorValidationException(
+                    result,
+                    "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,
+                    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);
@@ -312,28 +269,29 @@
 
         private void CrossLink()
         {
-            foreach (MessageDescriptor message in messageTypes)
+            foreach (MessageDescriptor message in MessageTypes)
             {
                 message.CrossLink();
             }
 
-            foreach (ServiceDescriptor service in services)
+            foreach (ServiceDescriptor service in Services)
             {
                 service.CrossLink();
             }
         }
 
         /// <summary>
-        /// Creates an instance for generated code.
+        /// Creates a descriptor for generated code.
         /// </summary>
         /// <remarks>
-        /// The <paramref name="generatedCodeInfo"/> parameter should be null for descriptors which don't correspond to
-        /// generated types. Otherwise, it should be a <see cref="GeneratedCodeInfo"/> with nested types and nested
-        /// enums corresponding to the types and enums contained within the file descriptor.
+        /// This method is only designed to be used by the results of generating code with protoc,
+        /// which creates the appropriate dependencies etc. It has to be public because the generated
+        /// code is "external", but should not be called directly by end users.
         /// </remarks>
-        public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
-                                                                    FileDescriptor[] dependencies,
-                                                                    GeneratedCodeInfo generatedCodeInfo)
+        public static FileDescriptor FromGeneratedCode(
+            byte[] descriptorData,
+            FileDescriptor[] dependencies,
+            GeneratedClrTypeInfo generatedCodeInfo)
         {
             FileDescriptorProto proto;
             try
@@ -345,8 +303,6 @@
                 throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
             }
 
-
-
             try
             {
                 // When building descriptors for generated code, we allow unknown
@@ -355,7 +311,7 @@
             }
             catch (DescriptorValidationException e)
             {
-                throw new ArgumentException("Invalid embedded descriptor for \"" + proto.Name + "\".", e);
+                throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e);
             }
         }
 
@@ -367,7 +323,7 @@
         /// </returns>
         public override string ToString()
         {
-            return "FileDescriptor for " + proto.Name;
+            return $"FileDescriptor for {Name}";
         }
 
         /// <summary>
@@ -383,6 +339,6 @@
         /// <value>
         /// The file descriptor for <c>descriptor.proto</c>.
         /// </value>
-        public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorProtoFile.Descriptor; } }
+        public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
new file mode 100644
index 0000000..fe5db65
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
@@ -0,0 +1,103 @@
+#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/
+//
+// 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.
+#endregion
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Extra information provided by generated code when initializing a message or file descriptor.
+    /// These are constructed as required, and are not long-lived. Hand-written code should
+    /// never need to use this type.
+    /// </summary>
+    public sealed class GeneratedClrTypeInfo
+    {
+        private static readonly string[] EmptyNames = new string[0];
+        private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
+        /// </summary>
+        public Type ClrType { get; private set; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the parser for message descriptors.
+        /// </summary>
+        public MessageParser Parser { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
+        /// for fields in the message for message descriptors.
+        /// </summary>
+        public string[] PropertyNames { get; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
+        /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
+        /// there will be a "FooCase" property and a "ClearFoo" method.
+        /// </summary>
+        public string[] OneofNames { get; }
+
+        /// <summary>
+        /// The reflection information for types within this file/message descriptor. Elements may be null
+        /// if there is no corresponding generated type, e.g. for map entry types.
+        /// </summary>
+        public GeneratedClrTypeInfo[] NestedTypes { get; }
+
+        /// <summary>
+        /// The CLR types for enums within this file/message descriptor.
+        /// </summary>
+        public Type[] NestedEnums { get; }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
+        /// Each array parameter may be null, to indicate a lack of values.
+        /// The parameter order is designed to make it feasible to format the generated code readably.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+        {
+            NestedTypes = nestedTypes ?? EmptyCodeInfo;
+            NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
+            ClrType = clrType;
+            Parser = parser;
+            PropertyNames = propertyNames ?? EmptyNames;
+            OneofNames = oneofNames ?? EmptyNames;
+        }
+
+        /// <summary>
+        /// Creates a GeneratedClrTypeInfo for a file descriptor, with only types and enums.
+        /// </summary>
+        public GeneratedClrTypeInfo(Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+            : this(null, null, null, null, nestedEnums, nestedTypes)
+        {
+        }
+    }
+}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs
deleted file mode 100644
index 8c52cd1..0000000
--- a/csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System;
-
-namespace Google.Protobuf.Reflection
-{
-    /// <summary>
-    /// Extra information provided by generated code when initializing a message or file descriptor.
-    /// These are constructed as required, and are not long-lived. Hand-written code should
-    /// never need to use this type.
-    /// </summary>
-    public sealed class GeneratedCodeInfo
-    {
-        private static readonly string[] EmptyNames = new string[0];
-        private static readonly GeneratedCodeInfo[] EmptyCodeInfo = new GeneratedCodeInfo[0];
-
-        /// <summary>
-        /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
-        /// </summary>
-        public Type ClrType { get; private set; }
-
-        /// <summary>
-        /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
-        /// for fields in the message for message descriptors.
-        /// </summary>
-        public string[] PropertyNames { get; private set; }
-
-        /// <summary>
-        /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
-        /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
-        /// there will be a "FooCase" property and a "ClearFoo" method.
-        /// </summary>
-        public string[] OneofNames { get; private set; }
-
-        /// <summary>
-        /// The reflection information for types within this file/message descriptor. Elements may be null
-        /// if there is no corresponding generated type, e.g. for map entry types.
-        /// </summary>
-        public GeneratedCodeInfo[] NestedTypes { get; private set; }
-
-        /// <summary>
-        /// The CLR types for enums within this file/message descriptor.
-        /// </summary>
-        public Type[] NestedEnums { get; private set; }
-
-        /// <summary>
-        /// Creates a GeneratedCodeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
-        /// Each array parameter may be null, to indicate a lack of values.
-        /// The parameter order is designed to make it feasible to format the generated code readably.
-        /// </summary>
-        public GeneratedCodeInfo(Type clrType, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedCodeInfo[] nestedTypes)
-        {
-            NestedTypes = nestedTypes ?? EmptyCodeInfo;
-            NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
-            ClrType = clrType;
-            PropertyNames = propertyNames ?? EmptyNames;
-            OneofNames = oneofNames ?? EmptyNames;
-        }
-
-        /// <summary>
-        /// Creates a GeneratedCodeInfo for a file descriptor, with only types and enums.
-        /// </summary>
-        public GeneratedCodeInfo(Type[] nestedEnums, GeneratedCodeInfo[] nestedTypes)
-            : this(null, null, null, nestedEnums, nestedTypes)
-        {
-        }
-    }
-}
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
index 82901f1..f5798d1 100644
--- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -56,139 +56,156 @@
             "google/protobuf/type.proto",
         };
 
-        private readonly DescriptorProto proto;
-        private readonly MessageDescriptor containingType;
-        private readonly IList<MessageDescriptor> nestedTypes;
-        private readonly IList<EnumDescriptor> enumTypes;
         private readonly IList<FieldDescriptor> fieldsInDeclarationOrder;
         private readonly IList<FieldDescriptor> fieldsInNumberOrder;
-        private readonly FieldCollection fields;
-        private readonly IList<OneofDescriptor> oneofs;
-        // CLR representation of the type described by this descriptor, if any.
-        private readonly Type generatedType;
+        private readonly IDictionary<string, FieldDescriptor> jsonFieldMap;
         
-        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedCodeInfo generatedCodeInfo)
+        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedClrTypeInfo generatedCodeInfo)
             : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
         {
-            this.proto = proto;
-            generatedType = generatedCodeInfo == null ? null : generatedCodeInfo.ClrType;
+            Proto = proto;
+            Parser = generatedCodeInfo?.Parser;
+            ClrType = generatedCodeInfo?.ClrType;
+            ContainingType = parent;
 
-            containingType = parent;
-
-            oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
+            // Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
+            // to see any nested oneofs, types or enums in "not actually generated" code... we do
+            // expect fields though (for map entry messages).
+            Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.OneofDecl,
                 (oneof, index) =>
-                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.OneofNames[index]));
+                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo.OneofNames[index]));
 
-            nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+            NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.NestedType,
                 (type, index) =>
-                new MessageDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
+                new MessageDescriptor(type, file, this, index, generatedCodeInfo.NestedTypes[index]));
 
-            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+            EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.EnumType,
                 (type, index) =>
-                new EnumDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
+                new EnumDescriptor(type, file, this, index, generatedCodeInfo.NestedEnums[index]));
 
             fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(
                 proto.Field,
                 (field, index) =>
-                new FieldDescriptor(field, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.PropertyNames[index]));
+                new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index]));
             fieldsInNumberOrder = new ReadOnlyCollection<FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray());
+            // TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
+            jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder);
             file.DescriptorPool.AddSymbol(this);
-            fields = new FieldCollection(this);
+            Fields = new FieldCollection(this);
         }
-                
-        /// <summary>
-        /// Returns the total number of nested types and enums, recursively.
-        /// </summary>
-        private int CountTotalGeneratedTypes()
+
+        private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields)
         {
-            return nestedTypes.Sum(nested => nested.CountTotalGeneratedTypes()) + enumTypes.Count;
+            var map = new Dictionary<string, FieldDescriptor>();
+            foreach (var field in fields)
+            {
+                map[JsonFormatter.ToCamelCase(field.Name)] = field;
+                map[field.Name] = field;
+            }
+            return new ReadOnlyDictionary<string, FieldDescriptor>(map);
         }
 
         /// <summary>
         /// The brief name of the descriptor's target.
         /// </summary>
-        public override string Name { get { return proto.Name; } }
+        public override string Name => Proto.Name;
 
-        internal DescriptorProto Proto { get { return proto; } }
+        internal DescriptorProto Proto { get; }
 
         /// <summary>
-        /// The generated type for this message, or <c>null</c> if the descriptor does not represent a generated type.
+        /// The CLR type used to represent message instances from this descriptor.
         /// </summary>
-        public Type GeneratedType { get { return generatedType; } }
+        /// <remarks>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. This is not represented in any
+        /// generated type, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public Type ClrType { get; }
+
+        /// <summary>
+        /// A parser for this message type.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
+        /// typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
+        /// </para>
+        /// <para>
+        /// The value returned by this property will be non-null for all regular fields. However,
+        /// if a message containing a map field is introspected, the list of nested messages will include
+        /// an auto-generated nested key/value pair message for the field. No message parser object is created for
+        /// such messages, so this property will return null in such cases.
+        /// </para>
+        /// <para>
+        /// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
+        /// will be the generated message type, not the native type used by reflection for fields of those types. Code
+        /// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
+        /// a wrapper type, and handle the result appropriately.
+        /// </para>
+        /// </remarks>
+        public MessageParser Parser { get; }
 
         /// <summary>
         /// Returns whether this message is one of the "well known types" which may have runtime/protoc support.
         /// </summary>
-        internal bool IsWellKnownType
-        {
-            get
-            {
-                return File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
-            }
-        }
+        internal bool IsWellKnownType => File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
+
+        /// <summary>
+        /// Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
+        /// with the addition of presence.
+        /// </summary>
+        internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
 
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// </value>
-        public MessageDescriptor ContainingType
-        {
-            get { return containingType; }
-        }
+        public MessageDescriptor ContainingType { get; }
 
         /// <value>
         /// A collection of fields, which can be retrieved by name or field number.
         /// </value>
-        public FieldCollection Fields
-        {
-            get { return fields; }
-        }
+        public FieldCollection Fields { get; }
 
         /// <value>
         /// An unmodifiable list of this message type's nested types.
         /// </value>
-        public IList<MessageDescriptor> NestedTypes
-        {
-            get { return nestedTypes; }
-        }
+        public IList<MessageDescriptor> NestedTypes { get; }
 
         /// <value>
         /// An unmodifiable list of this message type's enum types.
         /// </value>
-        public IList<EnumDescriptor> EnumTypes
-        {
-            get { return enumTypes; }
-        }
+        public IList<EnumDescriptor> EnumTypes { get; }
 
         /// <value>
         /// An unmodifiable list of the "oneof" field collections in this message type.
         /// </value>
-        public IList<OneofDescriptor> Oneofs
-        {
-            get { return oneofs; }
-        }
+        public IList<OneofDescriptor> Oneofs { get; }
 
         /// <summary>
         /// Finds a field by field name.
         /// </summary>
         /// <param name="name">The unqualified name of the field (e.g. "foo").</param>
         /// <returns>The field's descriptor, or null if not found.</returns>
-        public FieldDescriptor FindFieldByName(String name)
-        {
-            return File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
-        }
+        public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
 
         /// <summary>
         /// Finds a field by field number.
         /// </summary>
         /// <param name="number">The field number within this message type.</param>
         /// <returns>The field's descriptor, or null if not found.</returns>
-        public FieldDescriptor FindFieldByNumber(int number)
-        {
-            return File.DescriptorPool.FindFieldByNumber(this, number);
-        }
+        public FieldDescriptor FindFieldByNumber(int number) => File.DescriptorPool.FindFieldByNumber(this, number);
 
         /// <summary>
         /// Finds a nested descriptor by name. The is valid for fields, nested
@@ -196,18 +213,15 @@
         /// </summary>
         /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
         /// <returns>The descriptor, or null if not found.</returns>
-        public T FindDescriptor<T>(string name)
-            where T : class, IDescriptor
-        {
-            return File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
-        }
+        public T FindDescriptor<T>(string name)  where T : class, IDescriptor =>
+            File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
 
         /// <summary>
         /// Looks up and cross-links all fields and nested types.
         /// </summary>
         internal void CrossLink()
         {
-            foreach (MessageDescriptor message in nestedTypes)
+            foreach (MessageDescriptor message in NestedTypes)
             {
                 message.CrossLink();
             }
@@ -217,7 +231,7 @@
                 field.CrossLink();
             }
 
-            foreach (OneofDescriptor oneof in oneofs)
+            foreach (OneofDescriptor oneof in Oneofs)
             {
                 oneof.CrossLink();
             }
@@ -239,10 +253,7 @@
             /// Returns the fields in the message as an immutable list, in the order in which they
             /// are declared in the source .proto file.
             /// </value>
-            public IList<FieldDescriptor> InDeclarationOrder()
-            {
-                return messageDescriptor.fieldsInDeclarationOrder;
-            }
+            public IList<FieldDescriptor> InDeclarationOrder() => messageDescriptor.fieldsInDeclarationOrder;
 
             /// <value>
             /// Returns the fields in the message as an immutable list, in ascending field number
@@ -250,10 +261,17 @@
             /// index in the list to the field number; to retrieve a field by field number, it is better
             /// to use the <see cref="FieldCollection"/> indexer.
             /// </value>
-            public IList<FieldDescriptor> InFieldNumberOrder()
-            {
-                return messageDescriptor.fieldsInNumberOrder;
-            }
+            public IList<FieldDescriptor> InFieldNumberOrder() => messageDescriptor.fieldsInNumberOrder;
+
+            // TODO: consider making this public in the future. (Being conservative for now...)
+
+            /// <value>
+            /// Returns a read-only dictionary mapping the field names in this message as they're available
+            /// in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
+            /// in the message would result two entries, one with a key <c>fooBar</c> and one with a key
+            /// <c>foo_bar</c>, both referring to the same field.
+            /// </value>
+            internal IDictionary<string, FieldDescriptor> ByJsonName() => messageDescriptor.jsonFieldMap;
 
             /// <summary>
             /// Retrieves the descriptor for the field with the given number.
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
index d51ee52..22020ac 100644
--- a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
@@ -86,8 +86,7 @@
         /// in a particular message.
         /// </summary>
         /// <value>
-        /// The accessor used for reflective access, or <c>null</c> if reflection is not
-        /// supported by this descriptor.
+        /// The accessor used for reflective access.
         /// </value>
         public OneofAccessor Accessor { get { return accessor; } }
 
@@ -106,19 +105,15 @@
 
         private OneofAccessor CreateAccessor(string clrName)
         {
-            if (containingType.GeneratedType == null || clrName == null)
-            {
-                return null;
-            }
-            var caseProperty = containingType.GeneratedType.GetProperty(clrName + "Case");
+            var caseProperty = containingType.ClrType.GetProperty(clrName + "Case");
             if (caseProperty == null)
             {
-                throw new DescriptorValidationException(this, "Property " + clrName + "Case not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Property {clrName}Case not found in {containingType.ClrType}");
             }
-            var clearMethod = containingType.GeneratedType.GetMethod("Clear" + clrName);
+            var clearMethod = containingType.ClrType.GetMethod("Clear" + clrName);
             if (clearMethod == null)
             {
-                throw new DescriptorValidationException(this, "Method Clear" + clrName + " not found in " + containingType.GeneratedType);
+                throw new DescriptorValidationException(this, $"Method Clear{clrName} not found in {containingType.ClrType}");
             }
 
             return new OneofAccessor(caseProperty, clearMethod, this);
diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
index de92fbc..bbac217 100644
--- a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
@@ -61,7 +61,7 @@
             
             // TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
             object defaultValue =
-                typeof(IMessage).IsAssignableFrom(clrType) ? null
+                descriptor.FieldType == FieldType.Message ? null
                 : clrType == typeof(string) ? ""
                 : clrType == typeof(ByteString) ? ByteString.Empty
                 : Activator.CreateInstance(clrType);
diff --git a/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
new file mode 100644
index 0000000..e94e3e6
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Reflection/TypeRegistry.cs
@@ -0,0 +1,183 @@
+#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/
+//
+// 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.
+#endregion
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// An immutable registry of types which can be looked up by their full name.
+    /// </summary>
+    public sealed class TypeRegistry
+    {
+        /// <summary>
+        /// An empty type registry, containing no types.
+        /// </summary>
+        public static TypeRegistry Empty { get; } = new TypeRegistry(new Dictionary<string, MessageDescriptor>());
+
+        private readonly Dictionary<string, MessageDescriptor> fullNameToMessageMap;
+
+        private TypeRegistry(Dictionary<string, MessageDescriptor> fullNameToMessageMap)
+        {
+            this.fullNameToMessageMap = fullNameToMessageMap;
+        }
+
+        /// <summary>
+        /// Attempts to find a message descriptor by its full name.
+        /// </summary>
+        /// <param name="fullName">The full name of the message, which is the dot-separated
+        /// combination of package, containing messages and message name</param>
+        /// <returns>The message descriptor corresponding to <paramref name="fullName"/> or null
+        /// if there is no such message descriptor.</returns>
+        public MessageDescriptor Find(string fullName)
+        {
+            MessageDescriptor ret;
+            // Ignore the return value as ret will end up with the right value either way.
+            fullNameToMessageMap.TryGetValue(fullName, out ret);
+            return ret;
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromFiles(IEnumerable{FileDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(params FileDescriptor[] fileDescriptors)
+        {
+            return FromFiles((IEnumerable<FileDescriptor>) fileDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the specified set of file descriptors.
+        /// </summary>
+        /// <remarks>
+        /// All message types within all the specified files are added to the registry, and
+        /// the dependencies of the specified files are also added, recursively.
+        /// </remarks>
+        /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(fileDescriptors, nameof(fileDescriptors));
+            var builder = new Builder();
+            foreach (var file in fileDescriptors)
+            {
+                builder.AddFile(file);
+            }
+            return builder.Build();
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// This is a convenience overload for <see cref="FromMessages(IEnumerable{MessageDescriptor})"/>
+        /// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(params MessageDescriptor[] messageDescriptors)
+        {
+            return FromMessages((IEnumerable<MessageDescriptor>) messageDescriptors);
+        }
+
+        /// <summary>
+        /// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
+        /// </summary>
+        /// <remarks>
+        /// The specified message descriptors are only used to identify their file descriptors; the returned registry
+        /// contains all the types within the file descriptors which contain the specified message descriptors (and
+        /// the dependencies of those files), not just the specified messages.
+        /// </remarks>
+        /// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
+        /// Must not contain null values.</param>
+        /// <returns>A type registry for the given files.</returns>
+        public static TypeRegistry FromMessages(IEnumerable<MessageDescriptor> messageDescriptors)
+        {
+            ProtoPreconditions.CheckNotNull(messageDescriptors, nameof(messageDescriptors));
+            return FromFiles(messageDescriptors.Select(md => md.File));
+        }
+
+        /// <summary>
+        /// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
+        /// </summary>
+        private class Builder
+        {
+            private readonly Dictionary<string, MessageDescriptor> types;
+            private readonly HashSet<string> fileDescriptorNames;
+
+            internal Builder()
+            {
+                types = new Dictionary<string, MessageDescriptor>();
+                fileDescriptorNames = new HashSet<string>();
+            }
+
+            internal void AddFile(FileDescriptor fileDescriptor)
+            {
+                if (!fileDescriptorNames.Add(fileDescriptor.Name))
+                {
+                    return;
+                }
+                foreach (var dependency in fileDescriptor.Dependencies)
+                {
+                    AddFile(dependency);
+                }
+                foreach (var message in fileDescriptor.MessageTypes)
+                {
+                    AddMessage(message);
+                }
+            }
+
+            private void AddMessage(MessageDescriptor messageDescriptor)
+            {
+                foreach (var nestedType in messageDescriptor.NestedTypes)
+                {
+                    AddMessage(nestedType);
+                }
+                // This will overwrite any previous entry. Given that each file should
+                // only be added once, this could be a problem such as package A.B with type C,
+                // and package A with type B.C... it's unclear what we should do in that case.
+                types[messageDescriptor.FullName] = messageDescriptor;
+            }
+
+            internal TypeRegistry Build()
+            {
+                return new TypeRegistry(types);
+            }
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
index 204b37c..48cd99a 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
@@ -9,42 +9,73 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/any.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class AnyReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Any {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Any() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi", 
-              "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv", 
-              "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n", 
-              "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), new[]{ "TypeUrl", "Value" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/any.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static AnyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi",
+            "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv",
+            "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n",
+            "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), global::Google.Protobuf.WellKnownTypes.Any.Parser, new[]{ "TypeUrl", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  `Any` contains an arbitrary serialized message along with a URL
+  ///  that describes the type of the serialized message.
+  ///
+  ///  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": &lt;string>,
+  ///        "lastName": &lt;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"
+  ///      }
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Any : pb::IMessage<Any> {
     private static readonly pb::MessageParser<Any> _parser = new pb::MessageParser<Any>(() => new Any());
     public static pb::MessageParser<Any> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Any.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -66,21 +97,47 @@
       return new Any(this);
     }
 
+    /// <summary>Field number for the "type_url" field.</summary>
     public const int TypeUrlFieldNumber = 1;
     private string typeUrl_ = "";
+    /// <summary>
+    ///  A URL/resource name whose content describes the type of the
+    ///  serialized message.
+    ///
+    ///  For URLs which use the schema `http`, `https`, or no schema, the
+    ///  following restrictions and interpretations apply:
+    ///
+    ///  * If no schema is provided, `https` is assumed.
+    ///  * The last segment of the URL's path must represent the fully
+    ///    qualified name of the type (as in `path/google.protobuf.Duration`).
+    ///  * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+    ///    value in binary format, or produce an error.
+    ///  * Applications are allowed to cache lookup results based on the
+    ///    URL, or have them precompiled into a binary to avoid any
+    ///    lookup. Therefore, binary compatibility needs to be preserved
+    ///    on changes to types. (Use versioned type names to manage
+    ///    breaking changes.)
+    ///
+    ///  Schemas other than `http`, `https` (or the empty schema) might be
+    ///  used with implementation specific semantics.
+    /// </summary>
     public string TypeUrl {
       get { return typeUrl_; }
       set {
-        typeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 2;
     private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  Must be valid serialized data of the above specified type.
+    /// </summary>
     public pb::ByteString Value {
       get { return value_; }
       set {
-        value_ = pb::Preconditions.CheckNotNull(value, "value");
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -108,7 +165,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
index 082f743..9d43856 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs
@@ -72,7 +72,7 @@
         /// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
         public static Any Pack(IMessage message)
         {
-            Preconditions.CheckNotNull(message, "message");
+            ProtoPreconditions.CheckNotNull(message, "message");
             return new Any { TypeUrl = GetTypeUrl(message.Descriptor), Value = message.ToByteString() };
         }
     }
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
index a5f9509..de7aea3 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
@@ -9,52 +9,58 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/api.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class ApiReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Api {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Api() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Chlnb29nbGUvcHJvdG9idWYvYXBpLnByb3RvEg9nb29nbGUucHJvdG9idWYa", 
-              "JGdvb2dsZS9wcm90b2J1Zi9zb3VyY2VfY29udGV4dC5wcm90bxoaZ29vZ2xl", 
-              "L3Byb3RvYnVmL3R5cGUucHJvdG8isAEKA0FwaRIMCgRuYW1lGAEgASgJEigK", 
-              "B21ldGhvZHMYAiADKAsyFy5nb29nbGUucHJvdG9idWYuTWV0aG9kEigKB29w", 
-              "dGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEg8KB3ZlcnNp", 
-              "b24YBCABKAkSNgoOc291cmNlX2NvbnRleHQYBSABKAsyHi5nb29nbGUucHJv", 
-              "dG9idWYuU291cmNlQ29udGV4dCKsAQoGTWV0aG9kEgwKBG5hbWUYASABKAkS", 
-              "GAoQcmVxdWVzdF90eXBlX3VybBgCIAEoCRIZChFyZXF1ZXN0X3N0cmVhbWlu", 
-              "ZxgDIAEoCBIZChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25z", 
-              "ZV9zdHJlYW1pbmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5w", 
-              "cm90b2J1Zi5PcHRpb25CSAoTY29tLmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJv", 
-              "dG9QAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", 
-              "cHJvdG8z"));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.Proto.SourceContext.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor, },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), new[]{ "Name", "Methods", "Options", "Version", "SourceContext" }, null, null, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Method), new[]{ "Name", "RequestTypeUrl", "RequestStreaming", "ResponseTypeUrl", "ResponseStreaming", "Options" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/api.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static ApiReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chlnb29nbGUvcHJvdG9idWYvYXBpLnByb3RvEg9nb29nbGUucHJvdG9idWYa",
+            "JGdvb2dsZS9wcm90b2J1Zi9zb3VyY2VfY29udGV4dC5wcm90bxoaZ29vZ2xl",
+            "L3Byb3RvYnVmL3R5cGUucHJvdG8igQIKA0FwaRIMCgRuYW1lGAEgASgJEigK",
+            "B21ldGhvZHMYAiADKAsyFy5nb29nbGUucHJvdG9idWYuTWV0aG9kEigKB29w",
+            "dGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEg8KB3ZlcnNp",
+            "b24YBCABKAkSNgoOc291cmNlX2NvbnRleHQYBSABKAsyHi5nb29nbGUucHJv",
+            "dG9idWYuU291cmNlQ29udGV4dBImCgZtaXhpbnMYBiADKAsyFi5nb29nbGUu",
+            "cHJvdG9idWYuTWl4aW4SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3Rv",
+            "YnVmLlN5bnRheCLVAQoGTWV0aG9kEgwKBG5hbWUYASABKAkSGAoQcmVxdWVz",
+            "dF90eXBlX3VybBgCIAEoCRIZChFyZXF1ZXN0X3N0cmVhbWluZxgDIAEoCBIZ",
+            "ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
+            "bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
+            "cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
+            "eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCSwoTY29t",
+            "Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAaABAaICA0dQQqoCHkdvb2ds",
+            "ZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), global::Google.Protobuf.WellKnownTypes.Api.Parser, new[]{ "Name", "Methods", "Options", "Version", "SourceContext", "Mixins", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Method), global::Google.Protobuf.WellKnownTypes.Method.Parser, new[]{ "Name", "RequestTypeUrl", "RequestStreaming", "ResponseTypeUrl", "ResponseStreaming", "Options", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Mixin), global::Google.Protobuf.WellKnownTypes.Mixin.Parser, new[]{ "Name", "Root" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  Api is a light-weight descriptor for a protocol buffer service.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Api : pb::IMessage<Api> {
     private static readonly pb::MessageParser<Api> _parser = new pb::MessageParser<Api>(() => new Api());
     public static pb::MessageParser<Api> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Api.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -73,48 +79,91 @@
       options_ = other.options_.Clone();
       version_ = other.version_;
       SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      mixins_ = other.mixins_.Clone();
+      syntax_ = other.syntax_;
     }
 
     public Api Clone() {
       return new Api(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of this api, including package name
+    ///  followed by the api's simple name.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "methods" field.</summary>
     public const int MethodsFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Method> _repeated_methods_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Method.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> methods_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method>();
+    /// <summary>
+    ///  The methods of this api, in unspecified order.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> Methods {
       get { return methods_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the API.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
 
+    /// <summary>Field number for the "version" field.</summary>
     public const int VersionFieldNumber = 4;
     private string version_ = "";
+    /// <summary>
+    ///  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&lt;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.
+    /// </summary>
     public string Version {
       get { return version_; }
       set {
-        version_ = pb::Preconditions.CheckNotNull(value, "value");
+        version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "source_context" field.</summary>
     public const int SourceContextFieldNumber = 5;
     private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  Source context for the protocol buffer service represented by this
+    ///  message.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
       get { return sourceContext_; }
       set {
@@ -122,6 +171,31 @@
       }
     }
 
+    /// <summary>Field number for the "mixins" field.</summary>
+    public const int MixinsFieldNumber = 6;
+    private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Mixin> _repeated_mixins_codec
+        = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Mixin.Parser);
+    private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> mixins_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin>();
+    /// <summary>
+    ///  Included APIs. See [Mixin][].
+    /// </summary>
+    public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> Mixins {
+      get { return mixins_; }
+    }
+
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax of the service.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as Api);
     }
@@ -138,6 +212,8 @@
       if(!options_.Equals(other.options_)) return false;
       if (Version != other.Version) return false;
       if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if(!mixins_.Equals(other.mixins_)) return false;
+      if (Syntax != other.Syntax) return false;
       return true;
     }
 
@@ -148,11 +224,13 @@
       hash ^= options_.GetHashCode();
       if (Version.Length != 0) hash ^= Version.GetHashCode();
       if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      hash ^= mixins_.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -170,6 +248,11 @@
         output.WriteRawTag(42);
         output.WriteMessage(SourceContext);
       }
+      mixins_.WriteTo(output, _repeated_mixins_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
     }
 
     public int CalculateSize() {
@@ -185,6 +268,10 @@
       if (sourceContext_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
       }
+      size += mixins_.CalculateSize(_repeated_mixins_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
       return size;
     }
 
@@ -206,6 +293,10 @@
         }
         SourceContext.MergeFrom(other.SourceContext);
       }
+      mixins_.Add(other.mixins_);
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -238,19 +329,30 @@
             input.ReadMessage(sourceContext_);
             break;
           }
+          case 50: {
+            mixins_.AddEntriesFrom(input, _repeated_mixins_codec);
+            break;
+          }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
         }
       }
     }
 
   }
 
+  /// <summary>
+  ///  Method represents a method of an api.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Method : pb::IMessage<Method> {
     private static readonly pb::MessageParser<Method> _parser = new pb::MessageParser<Method>(() => new Method());
     public static pb::MessageParser<Method> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Api.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -270,32 +372,45 @@
       responseTypeUrl_ = other.responseTypeUrl_;
       responseStreaming_ = other.responseStreaming_;
       options_ = other.options_.Clone();
+      syntax_ = other.syntax_;
     }
 
     public Method Clone() {
       return new Method(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  The simple name of this method.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "request_type_url" field.</summary>
     public const int RequestTypeUrlFieldNumber = 2;
     private string requestTypeUrl_ = "";
+    /// <summary>
+    ///  A URL of the input message type.
+    /// </summary>
     public string RequestTypeUrl {
       get { return requestTypeUrl_; }
       set {
-        requestTypeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
+        requestTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "request_streaming" field.</summary>
     public const int RequestStreamingFieldNumber = 3;
     private bool requestStreaming_;
+    /// <summary>
+    ///  If true, the request is streamed.
+    /// </summary>
     public bool RequestStreaming {
       get { return requestStreaming_; }
       set {
@@ -303,17 +418,25 @@
       }
     }
 
+    /// <summary>Field number for the "response_type_url" field.</summary>
     public const int ResponseTypeUrlFieldNumber = 4;
     private string responseTypeUrl_ = "";
+    /// <summary>
+    ///  The URL of the output message type.
+    /// </summary>
     public string ResponseTypeUrl {
       get { return responseTypeUrl_; }
       set {
-        responseTypeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
+        responseTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "response_streaming" field.</summary>
     public const int ResponseStreamingFieldNumber = 5;
     private bool responseStreaming_;
+    /// <summary>
+    ///  If true, the response is streamed.
+    /// </summary>
     public bool ResponseStreaming {
       get { return responseStreaming_; }
       set {
@@ -321,14 +444,31 @@
       }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 6;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Any metadata attached to the method.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
 
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 7;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax of this method.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as Method);
     }
@@ -346,6 +486,7 @@
       if (ResponseTypeUrl != other.ResponseTypeUrl) return false;
       if (ResponseStreaming != other.ResponseStreaming) return false;
       if(!options_.Equals(other.options_)) return false;
+      if (Syntax != other.Syntax) return false;
       return true;
     }
 
@@ -357,11 +498,12 @@
       if (ResponseTypeUrl.Length != 0) hash ^= ResponseTypeUrl.GetHashCode();
       if (ResponseStreaming != false) hash ^= ResponseStreaming.GetHashCode();
       hash ^= options_.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -386,6 +528,10 @@
         output.WriteBool(ResponseStreaming);
       }
       options_.WriteTo(output, _repeated_options_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(56);
+        output.WriteEnum((int) Syntax);
+      }
     }
 
     public int CalculateSize() {
@@ -406,6 +552,9 @@
         size += 1 + 1;
       }
       size += options_.CalculateSize(_repeated_options_codec);
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
       return size;
     }
 
@@ -429,6 +578,9 @@
         ResponseStreaming = other.ResponseStreaming;
       }
       options_.Add(other.options_);
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -462,6 +614,226 @@
             options_.AddEntriesFrom(input, _repeated_options_codec);
             break;
           }
+          case 56: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  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";
+  ///        }
+  ///        ...
+  ///      }
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class Mixin : pb::IMessage<Mixin> {
+    private static readonly pb::MessageParser<Mixin> _parser = new pb::MessageParser<Mixin>(() => new Mixin());
+    public static pb::MessageParser<Mixin> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[2]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public Mixin() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public Mixin(Mixin other) : this() {
+      name_ = other.name_;
+      root_ = other.root_;
+    }
+
+    public Mixin Clone() {
+      return new Mixin(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    /// <summary>
+    ///  The fully qualified name of the API which is included.
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "root" field.</summary>
+    public const int RootFieldNumber = 2;
+    private string root_ = "";
+    /// <summary>
+    ///  If non-empty specifies a path under which inherited HTTP paths
+    ///  are rooted.
+    /// </summary>
+    public string Root {
+      get { return root_; }
+      set {
+        root_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as Mixin);
+    }
+
+    public bool Equals(Mixin other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      if (Root != other.Root) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      if (Root.Length != 0) hash ^= Root.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Root.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Root);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Root.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Root);
+      }
+      return size;
+    }
+
+    public void MergeFrom(Mixin other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+      if (other.Root.Length != 0) {
+        Root = other.Root;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Root = input.ReadString();
+            break;
+          }
         }
       }
     }
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
index aa34f2d..73e221d 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
@@ -9,43 +9,84 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/duration.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class DurationReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Duration {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Duration() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90", 
-              "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg", 
-              "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB", 
-              "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv", 
-              "dG8z"));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), new[]{ "Seconds", "Nanos" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/duration.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static DurationReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg",
+            "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB",
+            "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
+            "dG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), global::Google.Protobuf.WellKnownTypes.Duration.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  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 &lt; 0 &amp;&amp; duration.nanos > 0) {
+  ///        duration.seconds += 1;
+  ///        duration.nanos -= 1000000000;
+  ///      } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 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 &lt; 0) {
+  ///        end.seconds -= 1;
+  ///        end.nanos += 1000000000;
+  ///      } else if (end.nanos >= 1000000000) {
+  ///        end.seconds += 1;
+  ///        end.nanos -= 1000000000;
+  ///      }
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Duration : pb::IMessage<Duration> {
     private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
     public static pb::MessageParser<Duration> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Duration.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -67,8 +108,13 @@
       return new Duration(this);
     }
 
+    /// <summary>Field number for the "seconds" field.</summary>
     public const int SecondsFieldNumber = 1;
     private long seconds_;
+    /// <summary>
+    ///  Signed seconds of the span of time. Must be from -315,576,000,000
+    ///  to +315,576,000,000 inclusive.
+    /// </summary>
     public long Seconds {
       get { return seconds_; }
       set {
@@ -76,8 +122,17 @@
       }
     }
 
+    /// <summary>Field number for the "nanos" field.</summary>
     public const int NanosFieldNumber = 2;
     private int nanos_;
+    /// <summary>
+    ///  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.
+    /// </summary>
     public int Nanos {
       get { return nanos_; }
       set {
@@ -109,7 +164,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
index 18ebefd..f164bfd 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/DurationPartial.cs
@@ -31,12 +31,14 @@
 #endregion
 
 using System;
+using System.Globalization;
+using System.Text;
 
 namespace Google.Protobuf.WellKnownTypes
 {
     // Manually-written partial class for the Duration well-known type,
     // providing a conversion to TimeSpan and convenience operators.
-    public partial class Duration
+    public partial class Duration : ICustomDiagnosticMessage
     {
         /// <summary>
         /// The number of nanoseconds in a second.
@@ -48,14 +50,46 @@
         public const int NanosecondsPerTick = 100;
 
         /// <summary>
+        /// The maximum permitted number of seconds.
+        /// </summary>
+        public const long MaxSeconds = 315576000000L;
+
+        /// <summary>
+        /// The minimum permitted number of seconds.
+        /// </summary>
+        public const long MinSeconds = -315576000000L;
+
+        internal const int MaxNanoseconds = NanosecondsPerSecond - 1;
+        internal const int MinNanoseconds = -NanosecondsPerSecond + 1;
+
+        internal static bool IsNormalized(long seconds, int nanoseconds)
+        {
+            // Simple boundaries
+            if (seconds < MinSeconds || seconds > MaxSeconds ||
+                nanoseconds < MinNanoseconds || nanoseconds > MaxNanoseconds)
+            {
+                return false;
+            }
+            // We only have a problem is one is strictly negative and the other is
+            // strictly positive.
+            return Math.Sign(seconds) * Math.Sign(nanoseconds) != -1;
+        }
+
+        /// <summary>
         /// Converts this <see cref="Duration"/> to a <see cref="TimeSpan"/>.
         /// </summary>
         /// <remarks>If the duration is not a precise number of ticks, it is truncated towards 0.</remarks>
         /// <returns>The value of this duration, as a <c>TimeSpan</c>.</returns>
+        /// <exception cref="InvalidOperationException">This value isn't a valid normalized duration, as
+        /// described in the documentation.</exception>
         public TimeSpan ToTimeSpan()
         {
             checked
             {
+                if (!IsNormalized(Seconds, Nanos))
+                {
+                    throw new InvalidOperationException("Duration was not a valid normalized duration");
+                }
                 long ticks = Seconds * TimeSpan.TicksPerSecond + Nanos / NanosecondsPerTick;
                 return TimeSpan.FromTicks(ticks);
             }
@@ -84,7 +118,7 @@
         /// <returns>The negated value of this duration.</returns>
         public static Duration operator -(Duration value)
         {
-            Preconditions.CheckNotNull(value, "value");
+            ProtoPreconditions.CheckNotNull(value, "value");
             checked
             {
                 return Normalize(-value.Seconds, -value.Nanos);
@@ -99,8 +133,8 @@
         /// <returns></returns>
         public static Duration operator +(Duration lhs, Duration rhs)
         {
-            Preconditions.CheckNotNull(lhs, "lhs");
-            Preconditions.CheckNotNull(rhs, "rhs");
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
             checked
             {
                 return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
@@ -115,8 +149,8 @@
         /// <returns>The difference between the two specified durations.</returns>
         public static Duration operator -(Duration lhs, Duration rhs)
         {
-            Preconditions.CheckNotNull(lhs, "lhs");
-            Preconditions.CheckNotNull(rhs, "rhs");
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
             checked
             {
                 return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
@@ -147,5 +181,90 @@
             }
             return new Duration { Seconds = seconds, Nanos = nanoseconds };
         }
+
+        /// <summary>
+        /// Converts a duration specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>duration.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                var builder = new StringBuilder();
+                builder.Append('"');
+                // The seconds part will normally provide the minus sign if we need it, but not if it's 0...
+                if (seconds == 0 && nanoseconds < 0)
+                {
+                    builder.Append('-');
+                }
+
+                builder.Append(seconds.ToString("d", CultureInfo.InvariantCulture));
+                AppendNanoseconds(builder, Math.Abs(nanoseconds));
+                builder.Append("s\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                // Note: the double braces here are escaping for braces in format strings.
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Duration\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized duration value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Duration"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
+
+        /// <summary>
+        /// Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
+        /// case no "." is appended), or 3 6 or 9 digits. This is internal for use in Timestamp as well
+        /// as Duration.
+        /// </summary>
+        internal static void AppendNanoseconds(StringBuilder builder, int nanos)
+        {
+            if (nanos != 0)
+            {
+                builder.Append('.');
+                // Output to 3, 6 or 9 digits.
+                if (nanos % 1000000 == 0)
+                {
+                    builder.Append((nanos / 1000000).ToString("d3", CultureInfo.InvariantCulture));
+                }
+                else if (nanos % 1000 == 0)
+                {
+                    builder.Append((nanos / 1000).ToString("d6", CultureInfo.InvariantCulture));
+                }
+                else
+                {
+                    builder.Append(nanos.ToString("d9", CultureInfo.InvariantCulture));
+                }
+            }
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
index 7d699c1..6cad412 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
@@ -9,42 +9,52 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/empty.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class EmptyReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Empty {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Empty() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1", 
-              "ZiIHCgVFbXB0eUJKChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv", 
-              "UAGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy", 
-              "b3RvMw=="));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), null, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/empty.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static EmptyReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
+            "ZiIHCgVFbXB0eUJQChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
+            "UAGgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
+            "ZXNiBnByb3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), global::Google.Protobuf.WellKnownTypes.Empty.Parser, null, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  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 `{}`.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Empty : pb::IMessage<Empty> {
     private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty());
     public static pb::MessageParser<Empty> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Empty.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -84,7 +94,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
index 0dac440..2ba2b96 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
@@ -9,42 +9,164 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/field_mask.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class FieldMaskReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class FieldMask {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static FieldMask() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy", 
-              "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJOChNjb20uZ29v", 
-              "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABogIDR1BCqgIeR29vZ2xl", 
-              "LlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), new[]{ "Paths" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/field_mask.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static FieldMaskReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
+            "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v",
+            "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v",
+            "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), global::Google.Protobuf.WellKnownTypes.FieldMask.Parser, new[]{ "Paths" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  `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 applies to the
+  ///  top-level response message. In case of a REST get operation, the
+  ///  field mask applies directly to the response, but in case of a REST
+  ///  list operation, the mask instead applies to each individual message
+  ///  in the returned resource list. In case of a REST custom method,
+  ///  other definitions may be used. Where the mask applies will be
+  ///  clearly documented together with its declaration in the API.  In
+  ///  any case, the effect on the returned resource/resources is required
+  ///  behavior for APIs.
+  ///
+  ///  # Field Masks in Update Operations
+  ///
+  ///  A field mask in update operations specifies which fields of the
+  ///  targeted resource are going to be updated. The API is required
+  ///  to only change the values of the fields as specified in the mask
+  ///  and leave the others untouched. If a resource is passed in to
+  ///  describe the updated values, the API ignores the values of all
+  ///  fields not covered by the mask.
+  ///
+  ///  In order to reset a field's value to the default, the field must
+  ///  be in the mask and set to the default value in the provided resource.
+  ///  Hence, in order to reset all fields of a resource, provide a default
+  ///  instance of the resource and set all fields in the mask, or do
+  ///  not provide a mask as described below.
+  ///
+  ///  If a field mask is not present on update, the operation applies to
+  ///  all fields (as if a field mask of all fields has been specified).
+  ///  Note that in the presence of schema evolution, this may mean that
+  ///  fields the client does not know and has therefore not filled into
+  ///  the request will be reset to their default. If this is unwanted
+  ///  behavior, a specific service may require a client to always specify
+  ///  a field mask, producing an error if not.
+  ///
+  ///  As with get operations, the location of the resource which
+  ///  describes the updated values in the request message depends on the
+  ///  operation kind. In any case, the effect of the field mask is
+  ///  required to be honored by the API.
+  ///
+  ///  ## Considerations for HTTP REST
+  ///
+  ///  The HTTP kind of an update operation which uses a field mask must
+  ///  be set to PATCH instead of PUT in order to satisfy HTTP semantics
+  ///  (PUT must only be used for full updates).
+  ///
+  ///  # JSON Encoding of Field Masks
+  ///
+  ///  In JSON, a field mask is encoded as a single string where paths are
+  ///  separated by a comma. Fields name in each path are converted
+  ///  to/from lower-camel naming conventions.
+  ///
+  ///  As an example, consider the following message declarations:
+  ///
+  ///      message Profile {
+  ///        User user = 1;
+  ///        Photo photo = 2;
+  ///      }
+  ///      message User {
+  ///        string display_name = 1;
+  ///        string address = 2;
+  ///      }
+  ///
+  ///  In proto a field mask for `Profile` may look as such:
+  ///
+  ///      mask {
+  ///        paths: "user.display_name"
+  ///        paths: "photo"
+  ///      }
+  ///
+  ///  In JSON, the same mask is represented as below:
+  ///
+  ///      {
+  ///        mask: "user.displayName,photo"
+  ///      }
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class FieldMask : pb::IMessage<FieldMask> {
     private static readonly pb::MessageParser<FieldMask> _parser = new pb::MessageParser<FieldMask>(() => new FieldMask());
     public static pb::MessageParser<FieldMask> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.FieldMask.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -65,10 +187,14 @@
       return new FieldMask(this);
     }
 
+    /// <summary>Field number for the "paths" field.</summary>
     public const int PathsFieldNumber = 1;
     private static readonly pb::FieldCodec<string> _repeated_paths_codec
         = pb::FieldCodec.ForString(10);
     private readonly pbc::RepeatedField<string> paths_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The set of field mask paths.
+    /// </summary>
     public pbc::RepeatedField<string> Paths {
       get { return paths_; }
     }
@@ -95,7 +221,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
new file mode 100644
index 0000000..df1292d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -0,0 +1,122 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2016 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.
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    // Manually-written partial class for the FieldMask well-known type.
+    public partial class FieldMask : ICustomDiagnosticMessage
+    {
+        /// <summary>
+        /// Converts a timestamp  specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="paths">Paths in the field mask</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(IList<string> paths, bool diagnosticOnly)
+        {
+            var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
+            if (firstInvalid == null)
+            {
+                var builder = new StringBuilder();
+                JsonFormatter.WriteString(builder, string.Join(",", paths.Select(JsonFormatter.ToCamelCase)));
+                return builder.ToString();
+            }
+            else
+            {
+                if (diagnosticOnly)
+                {
+                    var builder = new StringBuilder();
+                    builder.Append("{ \"@warning\": \"Invalid FieldMask\", \"paths\": ");
+                    JsonFormatter.Default.WriteList(builder, (IList) paths);
+                    builder.Append(" }");
+                    return builder.ToString();
+                }
+                else
+                {
+                    throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {firstInvalid}");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Camel-case converter with added strictness for field mask formatting.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
+        private static bool ValidatePath(string input)
+        {
+            for (int i = 0; i < input.Length; i++)
+            {
+                char c = input[i];
+                if (c >= 'A' && c <= 'Z')
+                {
+                    return false;
+                }
+                if (c == '_' && i < input.Length - 1)
+                {
+                    char next = input[i + 1];
+                    if (next < 'a' || next > 'z')
+                    {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="FieldMask"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Paths, true);
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
index 8347999..a235ece 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
@@ -9,43 +9,46 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/source_context.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class SourceContextReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class SourceContext {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static SourceContext() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds", 
-              "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo", 
-              "CUJSChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q", 
-              "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv", 
-              "dG8z"));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), new[]{ "FileName" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/source_context.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static SourceContextReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
+            "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
+            "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q",
+            "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
+            "cHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), global::Google.Protobuf.WellKnownTypes.SourceContext.Parser, new[]{ "FileName" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  `SourceContext` represents information about the source of a
+  ///  protobuf element, like the file in which it is defined.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class SourceContext : pb::IMessage<SourceContext> {
     private static readonly pb::MessageParser<SourceContext> _parser = new pb::MessageParser<SourceContext>(() => new SourceContext());
     public static pb::MessageParser<SourceContext> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.SourceContext.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -66,12 +69,17 @@
       return new SourceContext(this);
     }
 
+    /// <summary>Field number for the "file_name" field.</summary>
     public const int FileNameFieldNumber = 1;
     private string fileName_ = "";
+    /// <summary>
+    ///  The path-qualified name of the .proto file that contained the associated
+    ///  protobuf element.  For example: `"google/protobuf/source.proto"`.
+    /// </summary>
     public string FileName {
       get { return fileName_; }
       set {
-        fileName_ = pb::Preconditions.CheckNotNull(value, "value");
+        fileName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -97,7 +105,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
index 1e8a823..8e2ce8c 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -9,61 +9,79 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/struct.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class StructReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Struct {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Struct() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i", 
-              "dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i", 
-              "dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB", 
-              "IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC", 
-              "OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv", 
-              "dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM", 
-              "c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K", 
-              "DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI", 
-              "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW", 
-              "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW", 
-              "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W", 
-              "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg", 
-              "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy", 
-              "b3RvMw=="));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), new[]{ "Fields" }, null, null, new pbr::GeneratedCodeInfo[] { null, }),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Value), new[]{ "NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue" }, new[]{ "Kind" }, null, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.ListValue), new[]{ "Values" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/struct.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static StructReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i",
+            "dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i",
+            "dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB",
+            "IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC",
+            "OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv",
+            "dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM",
+            "c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K",
+            "DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI",
+            "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW",
+            "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW",
+            "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W",
+            "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg",
+            "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy",
+            "b3RvMw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), global::Google.Protobuf.WellKnownTypes.Struct.Parser, new[]{ "Fields" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Value), global::Google.Protobuf.WellKnownTypes.Value.Parser, new[]{ "NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue" }, new[]{ "Kind" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.ListValue), global::Google.Protobuf.WellKnownTypes.ListValue.Parser, new[]{ "Values" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Enums
+  /// <summary>
+  ///  `NullValue` is a singleton enumeration to represent the null value for the
+  ///  `Value` type union.
+  ///
+  ///   The JSON representation for `NullValue` is JSON `null`.
+  /// </summary>
   public enum NullValue {
+    /// <summary>
+    ///  Null value.
+    /// </summary>
     NULL_VALUE = 0,
   }
 
   #endregion
 
   #region Messages
+  /// <summary>
+  ///  `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.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Struct : pb::IMessage<Struct> {
     private static readonly pb::MessageParser<Struct> _parser = new pb::MessageParser<Struct>(() => new Struct());
     public static pb::MessageParser<Struct> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Struct.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -84,10 +102,14 @@
       return new Struct(this);
     }
 
+    /// <summary>Field number for the "fields" field.</summary>
     public const int FieldsFieldNumber = 1;
     private static readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec _map_fields_codec
         = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10);
     private readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> fields_ = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Map of dynamically typed values.
+    /// </summary>
     public pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> Fields {
       get { return fields_; }
     }
@@ -114,7 +136,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -151,13 +173,21 @@
 
   }
 
+  /// <summary>
+  ///  `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.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Value : pb::IMessage<Value> {
     private static readonly pb::MessageParser<Value> _parser = new pb::MessageParser<Value>(() => new Value());
     public static pb::MessageParser<Value> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Struct.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -198,7 +228,11 @@
       return new Value(this);
     }
 
+    /// <summary>Field number for the "null_value" field.</summary>
     public const int NullValueFieldNumber = 1;
+    /// <summary>
+    ///  Represents a null value.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
       get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : global::Google.Protobuf.WellKnownTypes.NullValue.NULL_VALUE; }
       set {
@@ -207,7 +241,11 @@
       }
     }
 
+    /// <summary>Field number for the "number_value" field.</summary>
     public const int NumberValueFieldNumber = 2;
+    /// <summary>
+    ///  Represents a double value.
+    /// </summary>
     public double NumberValue {
       get { return kindCase_ == KindOneofCase.NumberValue ? (double) kind_ : 0D; }
       set {
@@ -216,16 +254,24 @@
       }
     }
 
+    /// <summary>Field number for the "string_value" field.</summary>
     public const int StringValueFieldNumber = 3;
+    /// <summary>
+    ///  Represents a string value.
+    /// </summary>
     public string StringValue {
       get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
       set {
-        kind_ = pb::Preconditions.CheckNotNull(value, "value");
+        kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
         kindCase_ = KindOneofCase.StringValue;
       }
     }
 
+    /// <summary>Field number for the "bool_value" field.</summary>
     public const int BoolValueFieldNumber = 4;
+    /// <summary>
+    ///  Represents a boolean value.
+    /// </summary>
     public bool BoolValue {
       get { return kindCase_ == KindOneofCase.BoolValue ? (bool) kind_ : false; }
       set {
@@ -234,7 +280,11 @@
       }
     }
 
+    /// <summary>Field number for the "struct_value" field.</summary>
     public const int StructValueFieldNumber = 5;
+    /// <summary>
+    ///  Represents a structured value.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.Struct StructValue {
       get { return kindCase_ == KindOneofCase.StructValue ? (global::Google.Protobuf.WellKnownTypes.Struct) kind_ : null; }
       set {
@@ -243,7 +293,11 @@
       }
     }
 
+    /// <summary>Field number for the "list_value" field.</summary>
     public const int ListValueFieldNumber = 6;
+    /// <summary>
+    ///  Represents a repeated `Value`.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.ListValue ListValue {
       get { return kindCase_ == KindOneofCase.ListValue ? (global::Google.Protobuf.WellKnownTypes.ListValue) kind_ : null; }
       set {
@@ -253,6 +307,7 @@
     }
 
     private object kind_;
+    /// <summary>Enum of possible cases for the "kind" oneof.</summary>
     public enum KindOneofCase {
       None = 0,
       NullValue = 1,
@@ -289,6 +344,7 @@
       if (BoolValue != other.BoolValue) return false;
       if (!object.Equals(StructValue, other.StructValue)) return false;
       if (!object.Equals(ListValue, other.ListValue)) return false;
+      if (KindCase != other.KindCase) return false;
       return true;
     }
 
@@ -300,11 +356,12 @@
       if (kindCase_ == KindOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
       if (kindCase_ == KindOneofCase.StructValue) hash ^= StructValue.GetHashCode();
       if (kindCase_ == KindOneofCase.ListValue) hash ^= ListValue.GetHashCode();
+      hash ^= (int) kindCase_;
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -432,13 +489,18 @@
 
   }
 
+  /// <summary>
+  ///  `ListValue` is a wrapper around a repeated field of values.
+  ///
+  ///  The JSON representation for `ListValue` is JSON array.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class ListValue : pb::IMessage<ListValue> {
     private static readonly pb::MessageParser<ListValue> _parser = new pb::MessageParser<ListValue>(() => new ListValue());
     public static pb::MessageParser<ListValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Struct.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -459,10 +521,14 @@
       return new ListValue(this);
     }
 
+    /// <summary>Field number for the "values" field.</summary>
     public const int ValuesFieldNumber = 1;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_values_codec
         = pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Value.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> values_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
+    /// <summary>
+    ///  Repeated field of dynamically typed values.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> Values {
       get { return values_; }
     }
@@ -489,7 +555,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
index d7c0954..318b0f6 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -9,43 +9,96 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/timestamp.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TimestampReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Timestamp {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Timestamp() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv", 
-              "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY", 
-              "AiABKAVCUQoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q", 
-              "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", 
-              "cHJvdG8z"));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), new[]{ "Seconds", "Nanos" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/timestamp.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static TimestampReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
+            "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
+            "AiABKAVCVAoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
+            "AaABAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl",
+            "c2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), global::Google.Protobuf.WellKnownTypes.Timestamp.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
   #region Messages
+  /// <summary>
+  ///  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(&amp;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(&amp;ft);
+  ///      UINT64 ticks = (((UINT64)ft.dwHighDateTime) &lt;&lt; 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)
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Timestamp : pb::IMessage<Timestamp> {
     private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
     public static pb::MessageParser<Timestamp> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Timestamp.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -67,8 +120,14 @@
       return new Timestamp(this);
     }
 
+    /// <summary>Field number for the "seconds" field.</summary>
     public const int SecondsFieldNumber = 1;
     private long seconds_;
+    /// <summary>
+    ///  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.
+    /// </summary>
     public long Seconds {
       get { return seconds_; }
       set {
@@ -76,8 +135,15 @@
       }
     }
 
+    /// <summary>Field number for the "nanos" field.</summary>
     public const int NanosFieldNumber = 2;
     private int nanos_;
+    /// <summary>
+    ///  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.
+    /// </summary>
     public int Nanos {
       get { return nanos_; }
       set {
@@ -109,7 +175,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
index 6858435..aa40347 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/TimestampPartial.cs
@@ -31,13 +31,25 @@
 #endregion
 
 using System;
+using System.Globalization;
+using System.Text;
 
 namespace Google.Protobuf.WellKnownTypes
 {
-    public partial class Timestamp
+    public partial class Timestamp : ICustomDiagnosticMessage
     {
         private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-        private static readonly long BclSecondsAtUnixEpoch = UnixEpoch.Ticks / TimeSpan.TicksPerSecond;
+        // Constants determined programmatically, but then hard-coded so they can be constant expressions.
+        private const long BclSecondsAtUnixEpoch = 62135596800;
+        internal const long UnixSecondsAtBclMaxValue = 253402300799;
+        internal const long UnixSecondsAtBclMinValue = -BclSecondsAtUnixEpoch;
+        internal const int MaxNanos = Duration.NanosecondsPerSecond - 1;
+
+        private static bool IsNormalized(long seconds, int nanoseconds) =>
+            nanoseconds >= 0 &&
+            nanoseconds <= MaxNanos &&
+            seconds >= UnixSecondsAtBclMinValue &&
+            seconds <= UnixSecondsAtBclMaxValue;
 
         /// <summary>
         /// Returns the difference between one <see cref="Timestamp"/> and another, as a <see cref="Duration"/>.
@@ -47,8 +59,8 @@
         /// <returns>The difference between the two specified timestamps.</returns>
         public static Duration operator -(Timestamp lhs, Timestamp rhs)
         {
-            Preconditions.CheckNotNull(lhs, "lhs");
-            Preconditions.CheckNotNull(rhs, "rhs");
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
             checked
             {
                 return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
@@ -63,8 +75,8 @@
         /// <returns>The result of adding the duration to the timestamp.</returns>
         public static Timestamp operator +(Timestamp lhs, Duration rhs)
         {
-            Preconditions.CheckNotNull(lhs, "lhs");
-            Preconditions.CheckNotNull(rhs, "rhs");
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
             checked
             {
                 return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
@@ -79,8 +91,8 @@
         /// <returns>The result of subtracting the duration from the timestamp.</returns>
         public static Timestamp operator -(Timestamp lhs, Duration rhs)
         {
-            Preconditions.CheckNotNull(lhs, "lhs");
-            Preconditions.CheckNotNull(rhs, "rhs");
+            ProtoPreconditions.CheckNotNull(lhs, "lhs");
+            ProtoPreconditions.CheckNotNull(rhs, "rhs");
             checked
             {
                 return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
@@ -97,8 +109,14 @@
         /// <see cref="DateTime"/> value precisely on a second.
         /// </remarks>
         /// <returns>This timestamp as a <c>DateTime</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
         public DateTime ToDateTime()
         {
+            if (!IsNormalized(Seconds, Nanos))
+            {
+                throw new InvalidOperationException(@"Timestamp contains invalid values: Seconds={Seconds}; Nanos={Nanos}");
+            }
             return UnixEpoch.AddSeconds(Seconds).AddTicks(Nanos / Duration.NanosecondsPerTick);
         }
 
@@ -112,6 +130,8 @@
         /// <see cref="DateTimeOffset"/> value precisely on a second.
         /// </remarks>
         /// <returns>This timestamp as a <c>DateTimeOffset</c>.</returns>
+        /// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
+        /// incorrectly normalized or is outside the valid range.</exception>
         public DateTimeOffset ToDateTimeOffset()
         {
             return new DateTimeOffset(ToDateTime(), TimeSpan.Zero);
@@ -163,5 +183,59 @@
             }
             return new Timestamp { Seconds = seconds, Nanos = nanoseconds };
         }
+
+        /// <summary>
+        /// Converts a timestamp specified in seconds/nanoseconds to a string.
+        /// </summary>
+        /// <remarks>
+        /// If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
+        /// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
+        /// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
+        /// </remarks>
+        /// <param name="seconds">Seconds portion of the duration.</param>
+        /// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
+        /// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
+        /// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
+        internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
+        {
+            if (IsNormalized(seconds, nanoseconds))
+            {
+                // Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
+                DateTime dateTime = UnixEpoch.AddSeconds(seconds);
+                var builder = new StringBuilder();
+                builder.Append('"');
+                builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture));
+                Duration.AppendNanoseconds(builder, nanoseconds);
+                builder.Append("Z\"");
+                return builder.ToString();
+            }
+            if (diagnosticOnly)
+            {
+                return string.Format(CultureInfo.InvariantCulture,
+                    "{{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
+                    seconds,
+                    nanoseconds);
+            }
+            else
+            {
+                throw new InvalidOperationException("Non-normalized timestamp value");
+            }
+        }
+
+        /// <summary>
+        /// Returns a string representation of this <see cref="Timestamp"/> for diagnostic purposes.
+        /// </summary>
+        /// <remarks>
+        /// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
+        /// when the value is non-normalized or out of range, a JSON object representation will be returned
+        /// instead, including a warning. This is to avoid exceptions being thrown when trying to
+        /// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
+        /// values.
+        /// </remarks>
+        /// <returns>A string representation of this value.</returns>
+        public string ToDiagnosticString()
+        {
+            return ToJson(Seconds, Nanos, true);
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
index ff2ecc5..8faa1d1 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
@@ -9,73 +9,96 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
-  namespace Proto {
+  /// <summary>Holder for reflection information generated from google/protobuf/type.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class TypeReflection {
 
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    public static partial class Type {
-
-      #region Descriptor
-      public static pbr::FileDescriptor Descriptor {
-        get { return descriptor; }
-      }
-      private static pbr::FileDescriptor descriptor;
-
-      static Type() {
-        byte[] descriptorData = global::System.Convert.FromBase64String(
-            string.Concat(
-              "Chpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxIPZ29vZ2xlLnByb3RvYnVm", 
-              "Ghlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGiRnb29nbGUvcHJvdG9idWYv", 
-              "c291cmNlX2NvbnRleHQucHJvdG8irgEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm", 
-              "CgZmaWVsZHMYAiADKAsyFi5nb29nbGUucHJvdG9idWYuRmllbGQSDgoGb25l", 
-              "b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu", 
-              "T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv", 
-              "YnVmLlNvdXJjZUNvbnRleHQimwUKBUZpZWxkEikKBGtpbmQYASABKA4yGy5n", 
-              "b29nbGUucHJvdG9idWYuRmllbGQuS2luZBI3CgtjYXJkaW5hbGl0eRgCIAEo", 
-              "DjIiLmdvb2dsZS5wcm90b2J1Zi5GaWVsZC5DYXJkaW5hbGl0eRIOCgZudW1i", 
-              "ZXIYAyABKAUSDAoEbmFtZRgEIAEoCRIQCgh0eXBlX3VybBgGIAEoCRITCgtv", 
-              "bmVvZl9pbmRleBgHIAEoBRIOCgZwYWNrZWQYCCABKAgSKAoHb3B0aW9ucxgJ", 
-              "IAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5PcHRpb24iuAIKBEtpbmQSEAoMVFlQ", 
-              "RV9VTktOT1dOEAASDwoLVFlQRV9ET1VCTEUQARIOCgpUWVBFX0ZMT0FUEAIS", 
-              "DgoKVFlQRV9JTlQ2NBADEg8KC1RZUEVfVUlOVDY0EAQSDgoKVFlQRV9JTlQz", 
-              "MhAFEhAKDFRZUEVfRklYRUQ2NBAGEhAKDFRZUEVfRklYRUQzMhAHEg0KCVRZ", 
-              "UEVfQk9PTBAIEg8KC1RZUEVfU1RSSU5HEAkSEAoMVFlQRV9NRVNTQUdFEAsS", 
-              "DgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJVFlQRV9FTlVN", 
-              "EA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVENjQQEBIPCgtU", 
-              "WVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2FyZGluYWxpdHkS", 
-              "FwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFMSVRZX09QVElP", 
-              "TkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRDQVJESU5BTElU", 
-              "WV9SRVBFQVRFRBADIqUBCgRFbnVtEgwKBG5hbWUYASABKAkSLQoJZW51bXZh", 
-              "bHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZRIoCgdvcHRp", 
-              "b25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2Cg5zb3VyY2Vf", 
-              "Y29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb250ZXh0", 
-              "IlMKCUVudW1WYWx1ZRIMCgRuYW1lGAEgASgJEg4KBm51bWJlchgCIAEoBRIo", 
-              "CgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbiI7CgZP", 
-              "cHRpb24SDAoEbmFtZRgBIAEoCRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5w", 
-              "cm90b2J1Zi5BbnlCSQoTY29tLmdvb2dsZS5wcm90b2J1ZkIJVHlwZVByb3Rv", 
-              "UAGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy", 
-              "b3RvMw=="));
-        descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
-            new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.Proto.Any.Descriptor, global::Google.Protobuf.WellKnownTypes.Proto.SourceContext.Descriptor, },
-            new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext" }, null, null, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), new[]{ "Name", "Enumvalue", "Options", "SourceContext" }, null, null, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), new[]{ "Name", "Number", "Options" }, null, null, null),
-              new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), new[]{ "Name", "Value" }, null, null, null)
-            }));
-      }
-      #endregion
-
+    #region Descriptor
+    /// <summary>File descriptor for google/protobuf/type.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
     }
+    private static pbr::FileDescriptor descriptor;
+
+    static TypeReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "Chpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxIPZ29vZ2xlLnByb3RvYnVm",
+            "Ghlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGiRnb29nbGUvcHJvdG9idWYv",
+            "c291cmNlX2NvbnRleHQucHJvdG8i1wEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm",
+            "CgZmaWVsZHMYAiADKAsyFi5nb29nbGUucHJvdG9idWYuRmllbGQSDgoGb25l",
+            "b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu",
+            "T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv",
+            "YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy",
+            "b3RvYnVmLlN5bnRheCLVBQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds",
+            "ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu",
+            "Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD",
+            "IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m",
+            "X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL",
+            "MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAkS",
+            "FQoNZGVmYXVsdF92YWx1ZRgLIAEoCSLIAgoES2luZBIQCgxUWVBFX1VOS05P",
+            "V04QABIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBF",
+            "X0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoM",
+            "VFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09M",
+            "EAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9N",
+            "RVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJ",
+            "VFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVE",
+            "NjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2Fy",
+            "ZGluYWxpdHkSFwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFM",
+            "SVRZX09QVElPTkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRD",
+            "QVJESU5BTElUWV9SRVBFQVRFRBADIs4BCgRFbnVtEgwKBG5hbWUYASABKAkS",
+            "LQoJZW51bXZhbHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1",
+            "ZRIoCgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2",
+            "Cg5zb3VyY2VfY29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3Vy",
+            "Y2VDb250ZXh0EicKBnN5bnRheBgFIAEoDjIXLmdvb2dsZS5wcm90b2J1Zi5T",
+            "eW50YXgiUwoJRW51bVZhbHVlEgwKBG5hbWUYASABKAkSDgoGbnVtYmVyGAIg",
+            "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
+            "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
+            "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
+            "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
+            "eXBlUHJvdG9QAaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
+            "d25UeXBlc2IGcHJvdG8z"));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
+          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName", "DefaultValue" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null)
+          }));
+    }
+    #endregion
+
   }
+  #region Enums
+  /// <summary>
+  ///  The syntax in which a protocol buffer element is defined.
+  /// </summary>
+  public enum Syntax {
+    /// <summary>
+    ///  Syntax `proto2`.
+    /// </summary>
+    SYNTAX_PROTO2 = 0,
+    /// <summary>
+    ///  Syntax `proto3`.
+    /// </summary>
+    SYNTAX_PROTO3 = 1,
+  }
+
+  #endregion
+
   #region Messages
+  /// <summary>
+  ///  A protocol buffer message type.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Type : pb::IMessage<Type> {
     private static readonly pb::MessageParser<Type> _parser = new pb::MessageParser<Type>(() => new Type());
     public static pb::MessageParser<Type> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -94,47 +117,68 @@
       oneofs_ = other.oneofs_.Clone();
       options_ = other.options_.Clone();
       SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
     }
 
     public Type Clone() {
       return new Type(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  The fully qualified message name.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "fields" field.</summary>
     public const int FieldsFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Field> _repeated_fields_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Field.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> fields_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field>();
+    /// <summary>
+    ///  The list of fields.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Field> Fields {
       get { return fields_; }
     }
 
+    /// <summary>Field number for the "oneofs" field.</summary>
     public const int OneofsFieldNumber = 3;
     private static readonly pb::FieldCodec<string> _repeated_oneofs_codec
         = pb::FieldCodec.ForString(26);
     private readonly pbc::RepeatedField<string> oneofs_ = new pbc::RepeatedField<string>();
+    /// <summary>
+    ///  The list of types appearing in `oneof` definitions in this type.
+    /// </summary>
     public pbc::RepeatedField<string> Oneofs {
       get { return oneofs_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 4;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
 
+    /// <summary>Field number for the "source_context" field.</summary>
     public const int SourceContextFieldNumber = 5;
     private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
       get { return sourceContext_; }
       set {
@@ -142,6 +186,19 @@
       }
     }
 
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 6;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as Type);
     }
@@ -158,6 +215,7 @@
       if(!oneofs_.Equals(other.oneofs_)) return false;
       if(!options_.Equals(other.options_)) return false;
       if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
       return true;
     }
 
@@ -168,11 +226,12 @@
       hash ^= oneofs_.GetHashCode();
       hash ^= options_.GetHashCode();
       if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -187,6 +246,10 @@
         output.WriteRawTag(42);
         output.WriteMessage(SourceContext);
       }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(48);
+        output.WriteEnum((int) Syntax);
+      }
     }
 
     public int CalculateSize() {
@@ -200,6 +263,9 @@
       if (sourceContext_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
       }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
       return size;
     }
 
@@ -219,6 +285,9 @@
         }
         SourceContext.MergeFrom(other.SourceContext);
       }
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -251,19 +320,26 @@
             input.ReadMessage(sourceContext_);
             break;
           }
+          case 48: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
         }
       }
     }
 
   }
 
+  /// <summary>
+  ///  A single field of a message type.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Field : pb::IMessage<Field> {
     private static readonly pb::MessageParser<Field> _parser = new pb::MessageParser<Field>(() => new Field());
     public static pb::MessageParser<Field> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -285,14 +361,20 @@
       oneofIndex_ = other.oneofIndex_;
       packed_ = other.packed_;
       options_ = other.options_.Clone();
+      jsonName_ = other.jsonName_;
+      defaultValue_ = other.defaultValue_;
     }
 
     public Field Clone() {
       return new Field(this);
     }
 
+    /// <summary>Field number for the "kind" field.</summary>
     public const int KindFieldNumber = 1;
     private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN;
+    /// <summary>
+    ///  The field type.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.Field.Types.Kind Kind {
       get { return kind_; }
       set {
@@ -300,8 +382,12 @@
       }
     }
 
+    /// <summary>Field number for the "cardinality" field.</summary>
     public const int CardinalityFieldNumber = 2;
     private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN;
+    /// <summary>
+    ///  The field cardinality.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality Cardinality {
       get { return cardinality_; }
       set {
@@ -309,8 +395,12 @@
       }
     }
 
+    /// <summary>Field number for the "number" field.</summary>
     public const int NumberFieldNumber = 3;
     private int number_;
+    /// <summary>
+    ///  The field number.
+    /// </summary>
     public int Number {
       get { return number_; }
       set {
@@ -318,26 +408,40 @@
       }
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 4;
     private string name_ = "";
+    /// <summary>
+    ///  The field name.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "type_url" field.</summary>
     public const int TypeUrlFieldNumber = 6;
     private string typeUrl_ = "";
+    /// <summary>
+    ///  The field type URL, without the scheme, for message or enumeration
+    ///  types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
+    /// </summary>
     public string TypeUrl {
       get { return typeUrl_; }
       set {
-        typeUrl_ = pb::Preconditions.CheckNotNull(value, "value");
+        typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "oneof_index" field.</summary>
     public const int OneofIndexFieldNumber = 7;
     private int oneofIndex_;
+    /// <summary>
+    ///  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.
+    /// </summary>
     public int OneofIndex {
       get { return oneofIndex_; }
       set {
@@ -345,8 +449,12 @@
       }
     }
 
+    /// <summary>Field number for the "packed" field.</summary>
     public const int PackedFieldNumber = 8;
     private bool packed_;
+    /// <summary>
+    ///  Whether to use alternative packed wire representation.
+    /// </summary>
     public bool Packed {
       get { return packed_; }
       set {
@@ -354,14 +462,44 @@
       }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 9;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  The protocol buffer options.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
 
+    /// <summary>Field number for the "json_name" field.</summary>
+    public const int JsonNameFieldNumber = 10;
+    private string jsonName_ = "";
+    /// <summary>
+    ///  The field JSON name.
+    /// </summary>
+    public string JsonName {
+      get { return jsonName_; }
+      set {
+        jsonName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "default_value" field.</summary>
+    public const int DefaultValueFieldNumber = 11;
+    private string defaultValue_ = "";
+    /// <summary>
+    ///  The string value of the default value of this field. Proto2 syntax only.
+    /// </summary>
+    public string DefaultValue {
+      get { return defaultValue_; }
+      set {
+        defaultValue_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as Field);
     }
@@ -381,6 +519,8 @@
       if (OneofIndex != other.OneofIndex) return false;
       if (Packed != other.Packed) return false;
       if(!options_.Equals(other.options_)) return false;
+      if (JsonName != other.JsonName) return false;
+      if (DefaultValue != other.DefaultValue) return false;
       return true;
     }
 
@@ -394,11 +534,13 @@
       if (OneofIndex != 0) hash ^= OneofIndex.GetHashCode();
       if (Packed != false) hash ^= Packed.GetHashCode();
       hash ^= options_.GetHashCode();
+      if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
+      if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -431,6 +573,14 @@
         output.WriteBool(Packed);
       }
       options_.WriteTo(output, _repeated_options_codec);
+      if (JsonName.Length != 0) {
+        output.WriteRawTag(82);
+        output.WriteString(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(DefaultValue);
+      }
     }
 
     public int CalculateSize() {
@@ -457,6 +607,12 @@
         size += 1 + 1;
       }
       size += options_.CalculateSize(_repeated_options_codec);
+      if (JsonName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
+      }
+      if (DefaultValue.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
+      }
       return size;
     }
 
@@ -486,6 +642,12 @@
         Packed = other.Packed;
       }
       options_.Add(other.options_);
+      if (other.JsonName.Length != 0) {
+        JsonName = other.JsonName;
+      }
+      if (other.DefaultValue.Length != 0) {
+        DefaultValue = other.DefaultValue;
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -527,38 +689,123 @@
             options_.AddEntriesFrom(input, _repeated_options_codec);
             break;
           }
+          case 82: {
+            JsonName = input.ReadString();
+            break;
+          }
+          case 90: {
+            DefaultValue = input.ReadString();
+            break;
+          }
         }
       }
     }
 
     #region Nested types
+    /// <summary>Container for nested types declared in the Field message type.</summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     public static partial class Types {
+      /// <summary>
+      ///  Basic field types.
+      /// </summary>
       public enum Kind {
+        /// <summary>
+        ///  Field type unknown.
+        /// </summary>
         TYPE_UNKNOWN = 0,
+        /// <summary>
+        ///  Field type double.
+        /// </summary>
         TYPE_DOUBLE = 1,
+        /// <summary>
+        ///  Field type float.
+        /// </summary>
         TYPE_FLOAT = 2,
+        /// <summary>
+        ///  Field type int64.
+        /// </summary>
         TYPE_INT64 = 3,
+        /// <summary>
+        ///  Field type uint64.
+        /// </summary>
         TYPE_UINT64 = 4,
+        /// <summary>
+        ///  Field type int32.
+        /// </summary>
         TYPE_INT32 = 5,
+        /// <summary>
+        ///  Field type fixed64.
+        /// </summary>
         TYPE_FIXED64 = 6,
+        /// <summary>
+        ///  Field type fixed32.
+        /// </summary>
         TYPE_FIXED32 = 7,
+        /// <summary>
+        ///  Field type bool.
+        /// </summary>
         TYPE_BOOL = 8,
+        /// <summary>
+        ///  Field type string.
+        /// </summary>
         TYPE_STRING = 9,
+        /// <summary>
+        ///  Field type group. Proto2 syntax only, and deprecated.
+        /// </summary>
+        TYPE_GROUP = 10,
+        /// <summary>
+        ///  Field type message.
+        /// </summary>
         TYPE_MESSAGE = 11,
+        /// <summary>
+        ///  Field type bytes.
+        /// </summary>
         TYPE_BYTES = 12,
+        /// <summary>
+        ///  Field type uint32.
+        /// </summary>
         TYPE_UINT32 = 13,
+        /// <summary>
+        ///  Field type enum.
+        /// </summary>
         TYPE_ENUM = 14,
+        /// <summary>
+        ///  Field type sfixed32.
+        /// </summary>
         TYPE_SFIXED32 = 15,
+        /// <summary>
+        ///  Field type sfixed64.
+        /// </summary>
         TYPE_SFIXED64 = 16,
+        /// <summary>
+        ///  Field type sint32.
+        /// </summary>
         TYPE_SINT32 = 17,
+        /// <summary>
+        ///  Field type sint64.
+        /// </summary>
         TYPE_SINT64 = 18,
       }
 
+      /// <summary>
+      ///  Whether a field is optional, required, or repeated.
+      /// </summary>
       public enum Cardinality {
+        /// <summary>
+        ///  For fields with unknown cardinality.
+        /// </summary>
         CARDINALITY_UNKNOWN = 0,
+        /// <summary>
+        ///  For optional fields.
+        /// </summary>
         CARDINALITY_OPTIONAL = 1,
+        /// <summary>
+        ///  For required fields. Proto2 syntax only.
+        /// </summary>
         CARDINALITY_REQUIRED = 2,
+        /// <summary>
+        ///  For repeated fields.
+        /// </summary>
         CARDINALITY_REPEATED = 3,
       }
 
@@ -567,13 +814,16 @@
 
   }
 
+  /// <summary>
+  ///  Enum type definition.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Enum : pb::IMessage<Enum> {
     private static readonly pb::MessageParser<Enum> _parser = new pb::MessageParser<Enum>(() => new Enum());
     public static pb::MessageParser<Enum> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -591,39 +841,56 @@
       enumvalue_ = other.enumvalue_.Clone();
       options_ = other.options_.Clone();
       SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
+      syntax_ = other.syntax_;
     }
 
     public Enum Clone() {
       return new Enum(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  Enum type name.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "enumvalue" field.</summary>
     public const int EnumvalueFieldNumber = 2;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.EnumValue> _repeated_enumvalue_codec
         = pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.EnumValue.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> enumvalue_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue>();
+    /// <summary>
+    ///  Enum value definitions.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.EnumValue> Enumvalue {
       get { return enumvalue_; }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
 
+    /// <summary>Field number for the "source_context" field.</summary>
     public const int SourceContextFieldNumber = 4;
     private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
+    /// <summary>
+    ///  The source context.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
       get { return sourceContext_; }
       set {
@@ -631,6 +898,19 @@
       }
     }
 
+    /// <summary>Field number for the "syntax" field.</summary>
+    public const int SyntaxFieldNumber = 5;
+    private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2;
+    /// <summary>
+    ///  The source syntax.
+    /// </summary>
+    public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
+      get { return syntax_; }
+      set {
+        syntax_ = value;
+      }
+    }
+
     public override bool Equals(object other) {
       return Equals(other as Enum);
     }
@@ -646,6 +926,7 @@
       if(!enumvalue_.Equals(other.enumvalue_)) return false;
       if(!options_.Equals(other.options_)) return false;
       if (!object.Equals(SourceContext, other.SourceContext)) return false;
+      if (Syntax != other.Syntax) return false;
       return true;
     }
 
@@ -655,11 +936,12 @@
       hash ^= enumvalue_.GetHashCode();
       hash ^= options_.GetHashCode();
       if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode();
       return hash;
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -673,6 +955,10 @@
         output.WriteRawTag(34);
         output.WriteMessage(SourceContext);
       }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        output.WriteRawTag(40);
+        output.WriteEnum((int) Syntax);
+      }
     }
 
     public int CalculateSize() {
@@ -685,6 +971,9 @@
       if (sourceContext_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
       }
+      if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
+      }
       return size;
     }
 
@@ -703,6 +992,9 @@
         }
         SourceContext.MergeFrom(other.SourceContext);
       }
+      if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) {
+        Syntax = other.Syntax;
+      }
     }
 
     public void MergeFrom(pb::CodedInputStream input) {
@@ -731,19 +1023,26 @@
             input.ReadMessage(sourceContext_);
             break;
           }
+          case 40: {
+            syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
+            break;
+          }
         }
       }
     }
 
   }
 
+  /// <summary>
+  ///  Enum value definition.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class EnumValue : pb::IMessage<EnumValue> {
     private static readonly pb::MessageParser<EnumValue> _parser = new pb::MessageParser<EnumValue>(() => new EnumValue());
     public static pb::MessageParser<EnumValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -766,17 +1065,25 @@
       return new EnumValue(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  Enum value name.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "number" field.</summary>
     public const int NumberFieldNumber = 2;
     private int number_;
+    /// <summary>
+    ///  Enum value number.
+    /// </summary>
     public int Number {
       get { return number_; }
       set {
@@ -784,10 +1091,14 @@
       }
     }
 
+    /// <summary>Field number for the "options" field.</summary>
     public const int OptionsFieldNumber = 3;
     private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
         = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
     private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
+    /// <summary>
+    ///  Protocol buffer options.
+    /// </summary>
     public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
       get { return options_; }
     }
@@ -818,7 +1129,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -883,13 +1194,17 @@
 
   }
 
+  /// <summary>
+  ///  A protocol buffer option, which can be attached to a message, field,
+  ///  enumeration, etc.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Option : pb::IMessage<Option> {
     private static readonly pb::MessageParser<Option> _parser = new pb::MessageParser<Option>(() => new Option());
     public static pb::MessageParser<Option> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Proto.Type.Descriptor.MessageTypes[4]; }
+      get { return global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -911,17 +1226,25 @@
       return new Option(this);
     }
 
+    /// <summary>Field number for the "name" field.</summary>
     public const int NameFieldNumber = 1;
     private string name_ = "";
+    /// <summary>
+    ///  The option's name. For example, `"java_package"`.
+    /// </summary>
     public string Name {
       get { return name_; }
       set {
-        name_ = pb::Preconditions.CheckNotNull(value, "value");
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 2;
     private global::Google.Protobuf.WellKnownTypes.Any value_;
+    /// <summary>
+    ///  The option's value. For example, `"com.google.protobuf"`.
+    /// </summary>
     public global::Google.Protobuf.WellKnownTypes.Any Value {
       get { return value_; }
       set {
@@ -953,7 +1276,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
new file mode 100644
index 0000000..d34b560
--- /dev/null
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs
@@ -0,0 +1,99 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+namespace Google.Protobuf.WellKnownTypes
+{
+    public partial class Value
+    {
+        /// <summary>
+        /// Convenience method to create a Value message with a string value.
+        /// </summary>
+        /// <param name="value">Value to set for the StringValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForString(string value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StringValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a number value.
+        /// </summary>
+        /// <param name="value">Value to set for the NumberValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForNumber(double value)
+        {
+            return new Value { NumberValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a Boolean value.
+        /// </summary>
+        /// <param name="value">Value to set for the BoolValue property.</param>
+        /// <returns>A newly-created Value message with the given value.</returns>
+        public static Value ForBool(bool value)
+        {
+            return new Value { BoolValue = value };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with a null initial value.
+        /// </summary>
+        /// <returns>A newly-created Value message a null initial value.</returns>
+        public static Value ForNull()
+        {
+            return new Value { NullValue = 0 };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial list of values.
+        /// </summary>
+        /// <remarks>The values provided are not cloned; the references are copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial list value.</returns>
+        public static Value ForList(params Value[] values)
+        {
+            ProtoPreconditions.CheckNotNull(values, "values");
+            return new Value { ListValue = new ListValue { Values = { values } } };
+        }
+
+        /// <summary>
+        /// Convenience method to create a Value message with an initial struct value
+        /// </summary>
+        /// <remarks>The value provided is not cloned; the reference is copied directly.</remarks>
+        /// <returns>A newly-created Value message an initial struct value.</returns>
+        public static Value ForStruct(Struct value)
+        {
+            ProtoPreconditions.CheckNotNull(value, "value");
+            return new Value { StructValue = value };
+        }
+    }
+}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
index 9ecaf47..d6796d1 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
@@ -9,52 +9,60 @@
 using scg = global::System.Collections.Generic;
 namespace Google.Protobuf.WellKnownTypes {
 
+  /// <summary>Holder for reflection information generated from google/protobuf/wrappers.proto</summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-  public static partial class Wrappers {
+  public static partial class WrappersReflection {
 
     #region Descriptor
+    /// <summary>File descriptor for google/protobuf/wrappers.proto</summary>
     public static pbr::FileDescriptor Descriptor {
       get { return descriptor; }
     }
     private static pbr::FileDescriptor descriptor;
 
-    static Wrappers() {
+    static WrappersReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
-            "Ch5nb29nbGUvcHJvdG9idWYvd3JhcHBlcnMucHJvdG8SD2dvb2dsZS5wcm90", 
-            "b2J1ZiIcCgtEb3VibGVWYWx1ZRINCgV2YWx1ZRgBIAEoASIbCgpGbG9hdFZh", 
-            "bHVlEg0KBXZhbHVlGAEgASgCIhsKCkludDY0VmFsdWUSDQoFdmFsdWUYASAB", 
-            "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1", 
-            "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo", 
-            "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS", 
-            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJN", 
-            "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGiAgNHUEKq", 
-            "Ah5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
-      descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            "Ch5nb29nbGUvcHJvdG9idWYvd3JhcHBlcnMucHJvdG8SD2dvb2dsZS5wcm90",
+            "b2J1ZiIcCgtEb3VibGVWYWx1ZRINCgV2YWx1ZRgBIAEoASIbCgpGbG9hdFZh",
+            "bHVlEg0KBXZhbHVlGAEgASgCIhsKCkludDY0VmFsdWUSDQoFdmFsdWUYASAB",
+            "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1",
+            "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo",
+            "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS",
+            "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT",
+            "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi",
+            "AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv",
+            "Mw=="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
-          new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.DoubleValue), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FloatValue), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int64Value), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt64Value), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int32Value), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt32Value), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BoolValue), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.StringValue), new[]{ "Value" }, null, null, null),
-            new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BytesValue), new[]{ "Value" }, null, null, null)
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.DoubleValue), global::Google.Protobuf.WellKnownTypes.DoubleValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FloatValue), global::Google.Protobuf.WellKnownTypes.FloatValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int64Value), global::Google.Protobuf.WellKnownTypes.Int64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt64Value), global::Google.Protobuf.WellKnownTypes.UInt64Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Int32Value), global::Google.Protobuf.WellKnownTypes.Int32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.UInt32Value), global::Google.Protobuf.WellKnownTypes.UInt32Value.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BoolValue), global::Google.Protobuf.WellKnownTypes.BoolValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.StringValue), global::Google.Protobuf.WellKnownTypes.StringValue.Parser, new[]{ "Value" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.BytesValue), global::Google.Protobuf.WellKnownTypes.BytesValue.Parser, new[]{ "Value" }, null, null, null)
           }));
     }
     #endregion
 
   }
   #region Messages
+  /// <summary>
+  ///  Wrapper message for `double`.
+  ///
+  ///  The JSON representation for `DoubleValue` is JSON number.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class DoubleValue : pb::IMessage<DoubleValue> {
     private static readonly pb::MessageParser<DoubleValue> _parser = new pb::MessageParser<DoubleValue>(() => new DoubleValue());
     public static pb::MessageParser<DoubleValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[0]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[0]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -75,8 +83,12 @@
       return new DoubleValue(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private double value_;
+    /// <summary>
+    ///  The double value.
+    /// </summary>
     public double Value {
       get { return value_; }
       set {
@@ -106,7 +118,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -150,13 +162,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `float`.
+  ///
+  ///  The JSON representation for `FloatValue` is JSON number.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class FloatValue : pb::IMessage<FloatValue> {
     private static readonly pb::MessageParser<FloatValue> _parser = new pb::MessageParser<FloatValue>(() => new FloatValue());
     public static pb::MessageParser<FloatValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[1]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[1]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -177,8 +194,12 @@
       return new FloatValue(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private float value_;
+    /// <summary>
+    ///  The float value.
+    /// </summary>
     public float Value {
       get { return value_; }
       set {
@@ -208,7 +229,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -252,13 +273,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `int64`.
+  ///
+  ///  The JSON representation for `Int64Value` is JSON string.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Int64Value : pb::IMessage<Int64Value> {
     private static readonly pb::MessageParser<Int64Value> _parser = new pb::MessageParser<Int64Value>(() => new Int64Value());
     public static pb::MessageParser<Int64Value> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[2]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[2]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -279,8 +305,12 @@
       return new Int64Value(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private long value_;
+    /// <summary>
+    ///  The int64 value.
+    /// </summary>
     public long Value {
       get { return value_; }
       set {
@@ -310,7 +340,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -354,13 +384,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `uint64`.
+  ///
+  ///  The JSON representation for `UInt64Value` is JSON string.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class UInt64Value : pb::IMessage<UInt64Value> {
     private static readonly pb::MessageParser<UInt64Value> _parser = new pb::MessageParser<UInt64Value>(() => new UInt64Value());
     public static pb::MessageParser<UInt64Value> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[3]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[3]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -381,8 +416,12 @@
       return new UInt64Value(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private ulong value_;
+    /// <summary>
+    ///  The uint64 value.
+    /// </summary>
     public ulong Value {
       get { return value_; }
       set {
@@ -412,7 +451,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -456,13 +495,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `int32`.
+  ///
+  ///  The JSON representation for `Int32Value` is JSON number.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class Int32Value : pb::IMessage<Int32Value> {
     private static readonly pb::MessageParser<Int32Value> _parser = new pb::MessageParser<Int32Value>(() => new Int32Value());
     public static pb::MessageParser<Int32Value> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[4]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[4]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -483,8 +527,12 @@
       return new Int32Value(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private int value_;
+    /// <summary>
+    ///  The int32 value.
+    /// </summary>
     public int Value {
       get { return value_; }
       set {
@@ -514,7 +562,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -558,13 +606,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `uint32`.
+  ///
+  ///  The JSON representation for `UInt32Value` is JSON number.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class UInt32Value : pb::IMessage<UInt32Value> {
     private static readonly pb::MessageParser<UInt32Value> _parser = new pb::MessageParser<UInt32Value>(() => new UInt32Value());
     public static pb::MessageParser<UInt32Value> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[5]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[5]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -585,8 +638,12 @@
       return new UInt32Value(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private uint value_;
+    /// <summary>
+    ///  The uint32 value.
+    /// </summary>
     public uint Value {
       get { return value_; }
       set {
@@ -616,7 +673,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -660,13 +717,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `bool`.
+  ///
+  ///  The JSON representation for `BoolValue` is JSON `true` and `false`.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class BoolValue : pb::IMessage<BoolValue> {
     private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue());
     public static pb::MessageParser<BoolValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[6]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[6]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -687,8 +749,12 @@
       return new BoolValue(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private bool value_;
+    /// <summary>
+    ///  The bool value.
+    /// </summary>
     public bool Value {
       get { return value_; }
       set {
@@ -718,7 +784,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -762,13 +828,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `string`.
+  ///
+  ///  The JSON representation for `StringValue` is JSON string.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class StringValue : pb::IMessage<StringValue> {
     private static readonly pb::MessageParser<StringValue> _parser = new pb::MessageParser<StringValue>(() => new StringValue());
     public static pb::MessageParser<StringValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[7]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[7]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -789,12 +860,16 @@
       return new StringValue(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private string value_ = "";
+    /// <summary>
+    ///  The string value.
+    /// </summary>
     public string Value {
       get { return value_; }
       set {
-        value_ = pb::Preconditions.CheckNotNull(value, "value");
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -820,7 +895,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
@@ -864,13 +939,18 @@
 
   }
 
+  /// <summary>
+  ///  Wrapper message for `bytes`.
+  ///
+  ///  The JSON representation for `BytesValue` is JSON string.
+  /// </summary>
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
   public sealed partial class BytesValue : pb::IMessage<BytesValue> {
     private static readonly pb::MessageParser<BytesValue> _parser = new pb::MessageParser<BytesValue>(() => new BytesValue());
     public static pb::MessageParser<BytesValue> Parser { get { return _parser; } }
 
     public static pbr::MessageDescriptor Descriptor {
-      get { return global::Google.Protobuf.WellKnownTypes.Wrappers.Descriptor.MessageTypes[8]; }
+      get { return global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor.MessageTypes[8]; }
     }
 
     pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -891,12 +971,16 @@
       return new BytesValue(this);
     }
 
+    /// <summary>Field number for the "value" field.</summary>
     public const int ValueFieldNumber = 1;
     private pb::ByteString value_ = pb::ByteString.Empty;
+    /// <summary>
+    ///  The bytes value.
+    /// </summary>
     public pb::ByteString Value {
       get { return value_; }
       set {
-        value_ = pb::Preconditions.CheckNotNull(value, "value");
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
       }
     }
 
@@ -922,7 +1006,7 @@
     }
 
     public override string ToString() {
-      return pb::JsonFormatter.Default.Format(this);
+      return pb::JsonFormatter.ToDiagnosticString(this);
     }
 
     public void WriteTo(pb::CodedOutputStream output) {
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
similarity index 81%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
index cb6ca1b..9f620eb 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs
@@ -1,3 +1,4 @@
+#region Copyright notice and license
 // Protocol Buffers - Google's data interchange format
 // Copyright 2008 Google Inc.  All rights reserved.
 // https://developers.google.com/protocol-buffers/
@@ -27,17 +28,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
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
-
-package protobuf_unittest;
-
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
+namespace Google.Protobuf.WellKnownTypes
+{
+    public static partial class WrappersReflection
+    {
+        /// <summary>
+        /// Field number for the single "value" field in all wrapper types.
+        /// </summary>
+        internal const int WrapperValueFieldNumber = Int32Value.ValueFieldNumber;
+    }
 }
diff --git a/csharp/src/Google.Protobuf/packages.config b/csharp/src/Google.Protobuf/packages.config
new file mode 100644
index 0000000..40b8fd9
--- /dev/null
+++ b/csharp/src/Google.Protobuf/packages.config
@@ -0,0 +1,4 @@
+<?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/examples/Makefile b/examples/Makefile
index 8dc9083..51f1342 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -5,6 +5,8 @@
 all: cpp java python
 
 cpp:    add_person_cpp    list_people_cpp
+go:     add_person_go     list_people_go
+gotest: add_person_gotest list_people_gotest
 java:   add_person_java   list_people_java
 python: add_person_python list_people_python
 
@@ -13,6 +15,8 @@
 	rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
 	rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
 	rm -f *.pyc
+	rm -f protoc_middleman_go tutorial/*.pb.go add_person_go list_people_go
+	rmdir tutorial 2>/dev/null || true
 	rmdir com/example/tutorial 2>/dev/null || true
 	rmdir com/example 2>/dev/null || true
 	rmdir com 2>/dev/null || true
@@ -21,6 +25,11 @@
 	protoc --cpp_out=. --java_out=. --python_out=. addressbook.proto
 	@touch protoc_middleman
 
+protoc_middleman_go: addressbook.proto
+	mkdir tutorial # make directory for go package
+	protoc --go_out=tutorial addressbook.proto
+	@touch protoc_middleman_go
+
 add_person_cpp: add_person.cc protoc_middleman
 	pkg-config --cflags protobuf  # fails if protobuf is not installed
 	c++ add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
@@ -29,6 +38,18 @@
 	pkg-config --cflags protobuf  # fails if protobuf is not installed
 	c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`
 
+add_person_go: add_person.go protoc_middleman_go
+	go build -o add_person_go add_person.go
+
+add_person_gotest: add_person_test.go add_person_go
+	go test add_person.go add_person_test.go
+
+list_people_go: list_people.go protoc_middleman_go
+	go build -o list_people_go list_people.go
+
+list_people_gotest: list_people.go list_people_go
+	go test list_people.go list_people_test.go
+
 javac_middleman: AddPerson.java ListPeople.java protoc_middleman
 	javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
 	@touch javac_middleman
diff --git a/examples/README.txt b/examples/README.txt
index f5530a5..b33f841 100644
--- a/examples/README.txt
+++ b/examples/README.txt
@@ -27,3 +27,28 @@
 * Note that on some platforms you may have to edit the Makefile and remove
 "-lpthread" from the linker commands (perhaps replacing it with something else).
 We didn't do this automatically because we wanted to keep the example simple.
+
+## Go ##
+
+The Go example requires a plugin to the protocol buffer compiler, so it is not
+build with all the other examples.  See:
+  https://github.com/golang/protobuf
+for more information about Go protocol buffer support.
+
+First, install the Protocol Buffers compiler (protoc).
+Then, install the Go Protocol Buffers plugin
+($GOPATH/bin must be in your $PATH for protoc to find it):
+  go get github.com/golang/protobuf/protoc-gen-go
+
+Build the Go samples in this directory with "make go".  This creates the
+following executable files in the current directory:
+  add_person_go      list_people_go
+To run the example:
+  ./add_person_go addressbook.data
+to add a person to the protocol buffer encoded file addressbook.data.  The file
+is created if it does not exist.  To view the data, run:
+  ./list_people_go addressbook.data
+
+Observe that the C++, Python, and Java examples in this directory run in a
+similar way and can view/modify files created by the Go example and vice
+versa.
diff --git a/examples/add_person.go b/examples/add_person.go
new file mode 100644
index 0000000..4f2e7f7
--- /dev/null
+++ b/examples/add_person.go
@@ -0,0 +1,133 @@
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func promptForAddress(r io.Reader) (*pb.Person, error) {
+	// A protocol buffer can be created like any struct.
+	p := &pb.Person{}
+
+	rd := bufio.NewReader(r)
+	fmt.Print("Enter person ID number: ")
+	// An int32 field in the .proto file is represented as an int32 field
+	// in the generated Go struct.
+	if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil {
+		return p, err
+	}
+
+	fmt.Print("Enter name: ")
+	name, err := rd.ReadString('\n')
+	if err != nil {
+		return p, err
+	}
+	// A string field in the .proto file results in a string field in Go.
+	// We trim the whitespace because rd.ReadString includes the trailing
+	// newline character in its output.
+	p.Name = strings.TrimSpace(name)
+
+	fmt.Print("Enter email address (blank for none): ")
+	email, err := rd.ReadString('\n')
+	if err != nil {
+		return p, err
+	}
+	p.Email = strings.TrimSpace(email)
+
+	for {
+		fmt.Print("Enter a phone number (or leave blank to finish): ")
+		phone, err := rd.ReadString('\n')
+		if err != nil {
+			return p, err
+		}
+		phone = strings.TrimSpace(phone)
+		if phone == "" {
+			break
+		}
+		// The PhoneNumber message type is nested within the Person
+		// message in the .proto file.  This results in a Go struct
+		// named using the name of the parent prefixed to the name of
+		// the nested message.  Just as with pb.Person, it can be
+		// created like any other struct.
+		pn := &pb.Person_PhoneNumber{
+			Number: phone,
+		}
+
+		fmt.Print("Is this a mobile, home, or work phone? ")
+		ptype, err := rd.ReadString('\n')
+		if err != nil {
+			return p, err
+		}
+		ptype = strings.TrimSpace(ptype)
+
+		// A proto enum results in a Go constant for each enum value.
+		switch ptype {
+		case "mobile":
+			pn.Type = pb.Person_MOBILE
+		case "home":
+			pn.Type = pb.Person_HOME
+		case "work":
+			pn.Type = pb.Person_WORK
+		default:
+			fmt.Printf("Unknown phone type %q.  Using default.\n", ptype)
+		}
+
+		// A repeated proto field maps to a slice field in Go.  We can
+		// append to it like any other slice.
+		p.Phones = append(p.Phones, pn)
+	}
+
+	return p, nil
+}
+
+// Main reads the entire address book from a file, adds one person based on
+// user input, then writes it back out to the same file.
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatalf("Usage:  %s ADDRESS_BOOK_FILE\n", os.Args[0])
+	}
+	fname := os.Args[1]
+
+	// Read the existing address book.
+	in, err := ioutil.ReadFile(fname)
+	if err != nil {
+		if os.IsNotExist(err) {
+			fmt.Printf("%s: File not found.  Creating new file.\n", fname)
+		} else {
+			log.Fatalln("Error reading file:", err)
+		}
+	}
+
+	// [START marshal_proto]
+	book := &pb.AddressBook{}
+	// [START_EXCLUDE]
+	if err := proto.Unmarshal(in, book); err != nil {
+		log.Fatalln("Failed to parse address book:", err)
+	}
+
+	// Add an address.
+	addr, err := promptForAddress(os.Stdin)
+	if err != nil {
+		log.Fatalln("Error with address:", err)
+	}
+	book.People = append(book.People, addr)
+	// [END_EXCLUDE]
+
+	// Write the new address book back to disk.
+	out, err := proto.Marshal(book)
+	if err != nil {
+		log.Fatalln("Failed to encode address book:", err)
+	}
+	if err := ioutil.WriteFile(fname, out, 0644); err != nil {
+		log.Fatalln("Failed to write address book:", err)
+	}
+	// [END marshal_proto]
+}
diff --git a/examples/add_person.py b/examples/add_person.py
index fd81c98..0b69857 100755
--- a/examples/add_person.py
+++ b/examples/add_person.py
@@ -43,9 +43,8 @@
 
 # Read the existing address book.
 try:
-  f = open(sys.argv[1], "rb")
-  address_book.ParseFromString(f.read())
-  f.close()
+  with open(sys.argv[1], "rb") as f:
+    address_book.ParseFromString(f.read())
 except IOError:
   print sys.argv[1] + ": File not found.  Creating a new file."
 
@@ -53,6 +52,5 @@
 PromptForAddress(address_book.people.add())
 
 # Write the new address book back to disk.
-f = open(sys.argv[1], "wb")
-f.write(address_book.SerializeToString())
-f.close()
+with open(sys.argv[1], "wb") as f:
+  f.write(address_book.SerializeToString())
diff --git a/examples/add_person_test.go b/examples/add_person_test.go
new file mode 100644
index 0000000..0507db6
--- /dev/null
+++ b/examples/add_person_test.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func TestPromptForAddressReturnsAddress(t *testing.T) {
+	in := `12345
+Example Name
+name@example.com
+123-456-7890
+home
+222-222-2222
+mobile
+111-111-1111
+work
+777-777-7777
+unknown
+
+`
+	got, err := promptForAddress(strings.NewReader(in))
+	if err != nil {
+		t.Fatalf("promptForAddress(%q) had unexpected error: %s", in, err.Error())
+	}
+	if got.Id != 12345 {
+		t.Errorf("promptForAddress(%q) got %d, want ID %d", in, got.Id, 12345)
+	}
+	if got.Name != "Example Name" {
+		t.Errorf("promptForAddress(%q) => want name %q, got %q", "Example Name", got.Name)
+	}
+	if got.Email != "name@example.com" {
+		t.Errorf("promptForAddress(%q) => want email %q, got %q", "name@example.com", got.Email)
+	}
+
+	want := []*pb.Person_PhoneNumber{
+		{Number: "123-456-7890", Type: pb.Person_HOME},
+		{Number: "222-222-2222", Type: pb.Person_MOBILE},
+		{Number: "111-111-1111", Type: pb.Person_WORK},
+		{Number: "777-777-7777", Type: pb.Person_MOBILE},
+	}
+	if len(got.Phones) != len(want) {
+		t.Errorf("want %d phone numbers, got %d", len(want), len(got.Phones))
+	}
+	phones := len(got.Phones)
+	if phones > len(want) {
+		phones = len(want)
+	}
+	for i := 0; i < phones; i++ {
+		if !proto.Equal(got.Phones[i], want[i]) {
+			t.Errorf("want phone %q, got %q", *want[i], *got.Phones[i])
+		}
+
+	}
+}
diff --git a/examples/addressbook.proto b/examples/addressbook.proto
index bfdceea..23cc2f9 100644
--- a/examples/addressbook.proto
+++ b/examples/addressbook.proto
@@ -1,16 +1,29 @@
 // See README.txt for information and build instructions.
+//
+// Note: START and END tags are used in comments to define sections used in
+// tutorials.  They are not part of the syntax for Protocol Buffers.
+//
+// To get an in-depth walkthrough of this file and the related examples, see:
+// https://developers.google.com/protocol-buffers/docs/tutorials
 
+// [START declaration]
 syntax = "proto3";
-
 package tutorial;
+// [END declaration]
 
+// [START java_declaration]
 option java_package = "com.example.tutorial";
 option java_outer_classname = "AddressBookProtos";
-option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
+// [END java_declaration]
 
+// [START csharp_declaration]
+option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
+// [END csharp_declaration]
+
+// [START messages]
 message Person {
   string name = 1;
-  int32 id = 2;        // Unique ID number for this person.
+  int32 id = 2;  // Unique ID number for this person.
   string email = 3;
 
   enum PhoneType {
@@ -31,3 +44,4 @@
 message AddressBook {
   repeated Person people = 1;
 }
+// [END messages]
diff --git a/examples/list_people.go b/examples/list_people.go
new file mode 100644
index 0000000..70bc589
--- /dev/null
+++ b/examples/list_people.go
@@ -0,0 +1,61 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+
+	"github.com/golang/protobuf/proto"
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func writePerson(w io.Writer, p *pb.Person) {
+	fmt.Fprintln(w, "Person ID:", p.Id)
+	fmt.Fprintln(w, "  Name:", p.Name)
+	if p.Email != "" {
+		fmt.Fprintln(w, "  E-mail address:", p.Email)
+	}
+
+	for _, pn := range p.Phones {
+		switch pn.Type {
+		case pb.Person_MOBILE:
+			fmt.Fprint(w, "  Mobile phone #: ")
+		case pb.Person_HOME:
+			fmt.Fprint(w, "  Home phone #: ")
+		case pb.Person_WORK:
+			fmt.Fprint(w, "  Work phone #: ")
+		}
+		fmt.Fprintln(w, pn.Number)
+	}
+}
+
+func listPeople(w io.Writer, book *pb.AddressBook) {
+	for _, p := range book.People {
+		writePerson(w, p)
+	}
+}
+
+// Main reads the entire address book from a file and prints all the
+// information inside.
+func main() {
+	if len(os.Args) != 2 {
+		log.Fatalf("Usage:  %s ADDRESS_BOOK_FILE\n", os.Args[0])
+	}
+	fname := os.Args[1]
+
+	// [START unmarshal_proto]
+	// Read the existing address book.
+	in, err := ioutil.ReadFile(fname)
+	if err != nil {
+		log.Fatalln("Error reading file:", err)
+	}
+	book := &pb.AddressBook{}
+	if err := proto.Unmarshal(in, book); err != nil {
+		log.Fatalln("Failed to parse address book:", err)
+	}
+	// [END unmarshal_proto]
+
+	listPeople(os.Stdout, book)
+}
diff --git a/examples/list_people.py b/examples/list_people.py
index 755de90..f131872 100755
--- a/examples/list_people.py
+++ b/examples/list_people.py
@@ -31,8 +31,7 @@
 address_book = addressbook_pb2.AddressBook()
 
 # Read the existing address book.
-f = open(sys.argv[1], "rb")
-address_book.ParseFromString(f.read())
-f.close()
+with open(sys.argv[1], "rb") as f:
+  address_book.ParseFromString(f.read())
 
 ListPeople(address_book)
diff --git a/examples/list_people_test.go b/examples/list_people_test.go
new file mode 100644
index 0000000..87d6ad6
--- /dev/null
+++ b/examples/list_people_test.go
@@ -0,0 +1,120 @@
+package main
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+
+	pb "github.com/google/protobuf/examples/tutorial"
+)
+
+func TestWritePersonWritesPerson(t *testing.T) {
+	buf := new(bytes.Buffer)
+	// [START populate_proto]
+	p := pb.Person{
+		Id:    1234,
+		Name:  "John Doe",
+		Email: "jdoe@example.com",
+		Phones: []*pb.Person_PhoneNumber{
+			{Number: "555-4321", Type: pb.Person_HOME},
+		},
+	}
+	// [END populate_proto]
+	writePerson(buf, &p)
+	got := buf.String()
+	want := `Person ID: 1234
+  Name: John Doe
+  E-mail address: jdoe@example.com
+  Home phone #: 555-4321
+`
+	if got != want {
+		t.Errorf("writePerson(%s) =>\n\t%q, want %q", p.String(), got, want)
+	}
+}
+
+func TestListPeopleWritesList(t *testing.T) {
+	buf := new(bytes.Buffer)
+	in := pb.AddressBook{[]*pb.Person{
+		{
+			Name:  "John Doe",
+			Id:    101,
+			Email: "john@example.com",
+		},
+		{
+			Name: "Jane Doe",
+			Id:   102,
+		},
+		{
+			Name:  "Jack Doe",
+			Id:    201,
+			Email: "jack@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-555-5555", Type: pb.Person_WORK},
+			},
+		},
+		{
+			Name:  "Jack Buck",
+			Id:    301,
+			Email: "buck@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-555-0000", Type: pb.Person_HOME},
+				{Number: "555-555-0001", Type: pb.Person_MOBILE},
+				{Number: "555-555-0002", Type: pb.Person_WORK},
+			},
+		},
+		{
+			Name:  "Janet Doe",
+			Id:    1001,
+			Email: "janet@example.com",
+			Phones: []*pb.Person_PhoneNumber{
+				{Number: "555-777-0000"},
+				{Number: "555-777-0001", Type: pb.Person_HOME},
+			},
+		},
+	}}
+	listPeople(buf, &in)
+	want := strings.Split(`Person ID: 101
+  Name: John Doe
+  E-mail address: john@example.com
+Person ID: 102
+  Name: Jane Doe
+Person ID: 201
+  Name: Jack Doe
+  E-mail address: jack@example.com
+  Work phone #: 555-555-5555
+Person ID: 301
+  Name: Jack Buck
+  E-mail address: buck@example.com
+  Home phone #: 555-555-0000
+  Mobile phone #: 555-555-0001
+  Work phone #: 555-555-0002
+Person ID: 1001
+  Name: Janet Doe
+  E-mail address: janet@example.com
+  Mobile phone #: 555-777-0000
+  Home phone #: 555-777-0001
+`, "\n")
+	got := strings.Split(buf.String(), "\n")
+	if len(got) != len(want) {
+		t.Errorf(
+			"listPeople(%s) =>\n\t%q has %d lines, want %d",
+			in.String(),
+			buf.String(),
+			len(got),
+			len(want))
+	}
+	lines := len(got)
+	if lines > len(want) {
+		lines = len(want)
+	}
+	for i := 0; i < lines; i++ {
+		if got[i] != want[i] {
+			t.Errorf(
+				"listPeople(%s) =>\n\tline %d %q, want %q",
+				in.String(),
+				i,
+				got[i],
+				want[i])
+		}
+	}
+}
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index cd90689..81b8a0d 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -10,6 +10,8 @@
 #   to make when building protoc.  This is particularly useful for passing
 #   -j4 to run 4 jobs simultaneously.
 
+set -e
+
 if test ! -e src/google/protobuf/stubs/common.h; then
   cat >&2 << __EOF__
 Could not find source code.  Make sure you are running this script from the
@@ -43,51 +45,48 @@
 
 CORE_PROTO_IS_CORRECT=0
 PROCESS_ROUND=1
+TMP=$(mktemp -d)
 echo "Updating descriptor protos..."
 while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
 do
   echo "Round $PROCESS_ROUND"
   CORE_PROTO_IS_CORRECT=1
-  for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
-    BASE_NAME=${PROTO_FILE%.*}
-    cp ${BASE_NAME}.pb.h ${BASE_NAME}.pb.h.tmp
-    cp ${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc.tmp
-  done
-  cp google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp
-  cp google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp
 
   make $@ protoc &&
-    ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. ${RUNTIME_PROTO_FILES[@]} && \
-    ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:. google/protobuf/compiler/plugin.proto
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
+    ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto
 
   for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
     BASE_NAME=${PROTO_FILE%.*}
-    diff ${BASE_NAME}.pb.h ${BASE_NAME}.pb.h.tmp > /dev/null
+    diff ${BASE_NAME}.pb.h $TMP/${BASE_NAME}.pb.h > /dev/null
     if test $? -ne 0; then
       CORE_PROTO_IS_CORRECT=0
     fi
-    diff ${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc.tmp > /dev/null
+    diff ${BASE_NAME}.pb.cc $TMP/${BASE_NAME}.pb.cc > /dev/null
     if test $? -ne 0; then
       CORE_PROTO_IS_CORRECT=0
     fi
   done
 
-  diff google/protobuf/compiler/plugin.pb.h google/protobuf/compiler/plugin.pb.h.tmp > /dev/null
+  diff google/protobuf/compiler/plugin.pb.h $TMP/google/protobuf/compiler/plugin.pb.h > /dev/null
   if test $? -ne 0; then
     CORE_PROTO_IS_CORRECT=0
   fi
-  diff google/protobuf/compiler/plugin.pb.cc google/protobuf/compiler/plugin.pb.cc.tmp > /dev/null
+  diff google/protobuf/compiler/plugin.pb.cc $TMP/google/protobuf/compiler/plugin.pb.cc > /dev/null
   if test $? -ne 0; then
     CORE_PROTO_IS_CORRECT=0
   fi
 
-  for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
-    BASE_NAME=${PROTO_FILE%.*}
-    rm ${BASE_NAME}.pb.h.tmp
-    rm ${BASE_NAME}.pb.cc.tmp
-  done
-  rm google/protobuf/compiler/plugin.pb.h.tmp
-  rm google/protobuf/compiler/plugin.pb.cc.tmp
+  # Only override the output if the files are different to avoid re-compilation
+  # of the protoc.
+  if [ $CORE_PROTO_IS_CORRECT -ne 1 ]; then
+    for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
+      BASE_NAME=${PROTO_FILE%.*}
+      mv $TMP/${BASE_NAME}.pb.h ${BASE_NAME}.pb.h
+      mv $TMP/${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc
+    done
+    mv $TMP/google/protobuf/compiler/plugin.pb.* google/protobuf/compiler/
+  fi
 
   PROCESS_ROUND=$((PROCESS_ROUND + 1))
 done
@@ -97,3 +96,8 @@
   echo "Generating messages for objc."
   objectivec/generate_descriptors_proto.sh $@
 fi
+
+if test -x csharp/generate_protos.sh; then
+  echo "Generating messages for C#."
+  csharp/generate_protos.sh $@
+fi
diff --git a/gmock.BUILD b/gmock.BUILD
index 66cddea..82abf27 100644
--- a/gmock.BUILD
+++ b/gmock.BUILD
@@ -4,6 +4,11 @@
         "gmock-1.7.0/gtest/src/gtest-all.cc",
         "gmock-1.7.0/src/gmock-all.cc",
     ],
+    hdrs = glob([
+        "gmock-1.7.0/**/*.h",
+        "gmock-1.7.0/gtest/src/*.cc",
+        "gmock-1.7.0/src/*.cc",
+    ]),
     includes = [
         "gmock-1.7.0",
         "gmock-1.7.0/gtest",
diff --git a/java/core/generate-sources-build.xml b/java/core/generate-sources-build.xml
new file mode 100644
index 0000000..0996e5f
--- /dev/null
+++ b/java/core/generate-sources-build.xml
@@ -0,0 +1,20 @@
+<project name="generate-sources">
+    <echo message="Running protoc ..."/>
+    <mkdir dir="${generated.sources.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=${generated.sources.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/duration.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/empty.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/field_mask.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/source_context.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/struct.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/timestamp.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/type.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/wrappers.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/compiler/plugin.proto"/>
+    </exec>
+</project>
\ No newline at end of file
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
new file mode 100644
index 0000000..ab415db
--- /dev/null
+++ b/java/core/generate-test-sources-build.xml
@@ -0,0 +1,43 @@
+<project name="generate-test-sources">
+    <mkdir dir="${generated.testsources.dir}"/>
+    <exec executable="${protoc}">
+        <arg value="--java_out=${generated.testsources.dir}"/>
+        <arg value="--proto_path=${protobuf.source.dir}"/>
+        <arg value="--proto_path=${test.proto.dir}"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_mset_wire_format.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_optimize_for.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite_imports_nonlite.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_no_generic_services.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_well_known_types.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lazy_fields_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/lite_equals_and_hash.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/non_nested_extension_lite.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test2.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/outer_class_name_test3.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_bad_identifiers.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_check_utf8_size.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/test_custom_options.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_lite_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_for_proto2_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
+    </exec>
+</project>
\ No newline at end of file
diff --git a/java/core/pom.xml b/java/core/pom.xml
new file mode 100644
index 0000000..74d5ead
--- /dev/null
+++ b/java/core/pom.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-2</version>
+  </parent>
+
+  <artifactId>protobuf-java</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Protocol Buffers [Core]</name>
+  <description>
+    Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <!-- Include core protos in the bundle as resources -->
+    <resources>
+      <resource>
+        <directory>${protobuf.source.dir}</directory>
+        <includes>
+          <include>google/protobuf/any.proto</include>
+          <include>google/protobuf/api.proto</include>
+          <include>google/protobuf/descriptor.proto</include>
+          <include>google/protobuf/duration.proto</include>
+          <include>google/protobuf/empty.proto</include>
+          <include>google/protobuf/field_mask.proto</include>
+          <include>google/protobuf/source_context.proto</include>
+          <include>google/protobuf/struct.proto</include>
+          <include>google/protobuf/timestamp.proto</include>
+          <include>google/protobuf/type.proto</include>
+          <include>google/protobuf/wrappers.proto</include>
+          <include>google/protobuf/compiler/plugin.proto</include>
+        </includes>
+      </resource>
+    </resources>
+
+    <plugins>
+      <!-- Use Antrun plugin to generate sources with protoc -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate core protos -->
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+
+          <!-- Generate the test protos -->
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="generate-test-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Add the generated sources to the build -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
+          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+        </configuration>
+      </plugin>
+
+      <!-- OSGI bundle configuration -->
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <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=${project.version}</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
similarity index 97%
rename from java/src/main/java/com/google/protobuf/AbstractMessage.java
rename to java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index cc89173..9f418f2 100644
--- a/java/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
 import com.google.protobuf.Internal.EnumLite;
@@ -161,10 +162,18 @@
     Descriptors.Descriptor descriptor = entry.getDescriptorForType();
     Descriptors.FieldDescriptor key = descriptor.findFieldByName("key");
     Descriptors.FieldDescriptor value = descriptor.findFieldByName("value");
-    result.put(entry.getField(key), entry.getField(value));
+    Object fieldValue = entry.getField(value);
+    if (fieldValue instanceof EnumValueDescriptor) {
+      fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
+    }
+    result.put(entry.getField(key), fieldValue);
     while (iterator.hasNext()) {
       entry = (Message) iterator.next();
-      result.put(entry.getField(key), entry.getField(value));
+      fieldValue = entry.getField(value);
+      if (fieldValue instanceof EnumValueDescriptor) {
+        fieldValue = ((EnumValueDescriptor) fieldValue).getNumber();
+      }
+      result.put(entry.getField(key), fieldValue);
     }
     return result;
   }
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/AbstractMessageLite.java
rename to java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
diff --git a/java/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/AbstractParser.java
rename to java/core/src/main/java/com/google/protobuf/AbstractParser.java
diff --git a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/AbstractProtobufList.java
rename to java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
rename to java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java
diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/core/src/main/java/com/google/protobuf/BlockingService.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/BlockingService.java
rename to java/core/src/main/java/com/google/protobuf/BlockingService.java
diff --git a/java/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
similarity index 95%
rename from java/src/main/java/com/google/protobuf/BooleanArrayList.java
rename to java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 45492d2..70e042f 100644
--- a/java/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -68,10 +68,17 @@
   private int size;
 
   /**
-   * Constructs a new mutable {@code BooleanArrayList}.
+   * Constructs a new mutable {@code BooleanArrayList} with default capacity.
    */
   BooleanArrayList() {
-    array = new boolean[DEFAULT_CAPACITY];
+    this(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList} with the provided capacity.
+   */
+  BooleanArrayList(int capacity) {
+    array = new boolean[capacity];
     size = 0;
   }
 
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
similarity index 66%
rename from java/src/main/java/com/google/protobuf/ByteString.java
rename to java/core/src/main/java/com/google/protobuf/ByteString.java
index b092bc3..305236f 100644
--- a/java/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -1,38 +1,13 @@
-// 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.
+// Copyright 2007 Google Inc.  All rights reserved.
 
 package com.google.protobuf;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
@@ -41,6 +16,7 @@
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -81,7 +57,14 @@
   /**
    * Empty {@code ByteString}.
    */
-  public static final ByteString EMPTY = new LiteralByteString(new byte[0]);
+  public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
+
+  /**
+   * Cached hash value. Intentionally accessed via a data race, which
+   * is safe because of the Java Memory Model's "no out-of-thin-air values"
+   * guarantees for ints. A value of 0 implies that the hash has not been set.
+   */
+  private int hash = 0;
 
   // This constructor is here to prevent subclassing outside of this package,
   ByteString() {}
@@ -105,7 +88,38 @@
    *
    * @return the iterator
    */
-  public abstract ByteIterator iterator();
+  @Override
+  public final ByteIterator iterator() {
+    return new ByteIterator() {
+      private int position = 0;
+      private final int limit = size();
+
+      @Override
+      public boolean hasNext() {
+        return position < limit;
+      }
+
+      @Override
+      public Byte next() {
+        // Boxing calls Byte.valueOf(byte), which does not instantiate.
+        return nextByte();
+      }
+
+      @Override
+      public byte nextByte() {
+        try {
+          return byteAt(position++);
+        } catch (ArrayIndexOutOfBoundsException e) {
+          throw new NoSuchElementException(e.getMessage());
+        }
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
 
   /**
    * This interface extends {@code Iterator<Byte>}, so that we can return an
@@ -134,7 +148,7 @@
    *
    * @return true if this is zero bytes long
    */
-  public boolean isEmpty() {
+  public final boolean isEmpty() {
     return size() == 0;
   }
 
@@ -150,7 +164,7 @@
    * @throws IndexOutOfBoundsException if {@code beginIndex < 0} or
    *     {@code beginIndex > size()}.
    */
-  public ByteString substring(int beginIndex) {
+  public final ByteString substring(int beginIndex) {
     return substring(beginIndex, size());
   }
 
@@ -175,7 +189,7 @@
    *         argument is a prefix of the byte sequence represented by
    *         this string; <code>false</code> otherwise.
    */
-  public boolean startsWith(ByteString prefix) {
+  public final boolean startsWith(ByteString prefix) {
     return size() >= prefix.size() &&
            substring(0, prefix.size()).equals(prefix);
   }
@@ -189,7 +203,7 @@
    *         argument is a suffix of the byte sequence represented by
    *         this string; <code>false</code> otherwise.
    */
-  public boolean endsWith(ByteString suffix) {
+  public final boolean endsWith(ByteString suffix) {
     return size() >= suffix.size() &&
         substring(size() - suffix.size()).equals(suffix);
   }
@@ -220,6 +234,24 @@
   public static ByteString copyFrom(byte[] bytes) {
     return copyFrom(bytes, 0, bytes.length);
   }
+  
+  /**
+   * Wraps the given bytes into a {@code ByteString}. Intended for internal only
+   * usage to force a classload of ByteString before LiteralByteString.
+   */
+  static ByteString wrap(byte[] bytes) {
+    // TODO(dweis): Return EMPTY when bytes are empty to reduce allocations?
+    return new LiteralByteString(bytes);
+  }
+
+  /**
+   * Wraps the given bytes into a {@code ByteString}. Intended for internal only
+   * usage to force a classload of ByteString before BoundedByteString and
+   * LiteralByteString.
+   */
+  static ByteString wrap(byte[] bytes, int offset, int length) {
+    return new BoundedByteString(bytes, offset, length);
+  }
 
   /**
    * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
@@ -309,8 +341,7 @@
    */
   public static ByteString readFrom(InputStream streamToDrain)
       throws IOException {
-    return readFrom(
-        streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
+    return readFrom(streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
   }
 
   /**
@@ -383,10 +414,10 @@
 
       if (bytesRead == 0) {
         return null;
-      } else {
-        // Always make a copy since InputStream could steal a reference to buf.
-        return ByteString.copyFrom(buf, 0, bytesRead);
       }
+
+      // Always make a copy since InputStream could steal a reference to buf.
+      return ByteString.copyFrom(buf, 0, bytesRead);
   }
 
   // =================================================================
@@ -402,12 +433,10 @@
    * @param other string to concatenate
    * @return a new {@code ByteString} instance
    */
-  public ByteString concat(ByteString other) {
-    int thisSize = size();
-    int otherSize = other.size();
-    if ((long) thisSize + otherSize >= Integer.MAX_VALUE) {
+  public final ByteString concat(ByteString other) {
+    if (Integer.MAX_VALUE - size() < other.size()) {
       throw new IllegalArgumentException("ByteString would be too long: " +
-                                         thisSize + "+" + otherSize);
+          size() + "+" + other.size());
     }
 
     return RopeByteString.concatenate(this, other);
@@ -426,29 +455,29 @@
    * @return new {@code ByteString}
    */
   public static ByteString copyFrom(Iterable<ByteString> byteStrings) {
-    Collection<ByteString> collection;
+    // Determine the size;
+    final int size;
     if (!(byteStrings instanceof Collection)) {
-      collection = new ArrayList<ByteString>();
-      for (ByteString byteString : byteStrings) {
-        collection.add(byteString);
+      int tempSize = 0;
+      for (Iterator<ByteString> iter = byteStrings.iterator(); iter.hasNext();
+          iter.next(), ++tempSize) {
       }
+      size = tempSize;
     } else {
-      collection = (Collection<ByteString>) byteStrings;
+      size = ((Collection<ByteString>) byteStrings).size();
     }
-    ByteString result;
-    if (collection.isEmpty()) {
-      result = EMPTY;
-    } else {
-      result = balancedConcat(collection.iterator(), collection.size());
+
+    if (size == 0) {
+      return EMPTY;
     }
-    return result;
+
+    return balancedConcat(byteStrings.iterator(), size);
   }
 
   // Internal function used by copyFrom(Iterable<ByteString>).
   // Create a balanced concatenation of the next "length" elements from the
   // iterable.
-  private static ByteString balancedConcat(Iterator<ByteString> iterator,
-      int length) {
+  private static ByteString balancedConcat(Iterator<ByteString> iterator, int length) {
     assert length >= 1;
     ByteString result;
     if (length == 1) {
@@ -486,25 +515,10 @@
    * @throws IndexOutOfBoundsException if an offset or size is negative or too
    *     large
    */
-  public void copyTo(byte[] target, int sourceOffset, int targetOffset,
+  public final void copyTo(byte[] target, int sourceOffset, int targetOffset,
       int numberToCopy) {
-    if (sourceOffset < 0) {
-      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
-    }
-    if (targetOffset < 0) {
-      throw new IndexOutOfBoundsException("Target offset < 0: " + targetOffset);
-    }
-    if (numberToCopy < 0) {
-      throw new IndexOutOfBoundsException("Length < 0: " + numberToCopy);
-    }
-    if (sourceOffset + numberToCopy > size()) {
-      throw new IndexOutOfBoundsException(
-          "Source end offset < 0: " + (sourceOffset + numberToCopy));
-    }
-    if (targetOffset + numberToCopy > target.length) {
-      throw new IndexOutOfBoundsException(
-          "Target end offset < 0: " + (targetOffset + numberToCopy));
-    }
+    checkRange(sourceOffset, sourceOffset + numberToCopy, size());
+    checkRange(targetOffset, targetOffset + numberToCopy, target.length);
     if (numberToCopy > 0) {
       copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
     }
@@ -534,8 +548,8 @@
    *
    * @return copied bytes
    */
-  public byte[] toByteArray() {
-    int size = size();
+  public final byte[] toByteArray() {
+    final int size = size();
     if (size == 0) {
       return Internal.EMPTY_BYTE_ARRAY;
     }
@@ -548,6 +562,10 @@
    * Writes the complete contents of this byte string to
    * the specified output stream argument.
    *
+   * <p>It is assumed that the {@link OutputStream} will not modify the contents passed it
+   * it. It may be possible for a malicious {@link OutputStream} to corrupt
+   * the data underlying the {@link ByteString}.
+   *
    * @param  out  the output stream to which to write the data.
    * @throws IOException  if an I/O error occurs.
    */
@@ -563,30 +581,20 @@
    * @throws IndexOutOfBoundsException if an offset or size is negative or too
    *     large
    */
-  void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
+  final void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
       throws IOException {
-    if (sourceOffset < 0) {
-      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
-    }
-    if (numberToWrite < 0) {
-      throw new IndexOutOfBoundsException("Length < 0: " + numberToWrite);
-    }
-    if (sourceOffset + numberToWrite > size()) {
-      throw new IndexOutOfBoundsException(
-          "Source end offset exceeded: " + (sourceOffset + numberToWrite));
-    }
+    checkRange(sourceOffset, sourceOffset + numberToWrite, size());
     if (numberToWrite > 0) {
       writeToInternal(out, sourceOffset, numberToWrite);
     }
-
   }
 
   /**
    * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes
    * all error checking has already been done.
    */
-  abstract void writeToInternal(OutputStream out, int sourceOffset,
-      int numberToWrite) throws IOException;
+  abstract void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite)
+      throws IOException;
 
   /**
    * Constructs a read-only {@code java.nio.ByteBuffer} whose content
@@ -618,7 +626,7 @@
    * @return new string
    * @throws UnsupportedEncodingException if charset isn't recognized
    */
-  public String toString(String charsetName)
+  public final String toString(String charsetName)
       throws UnsupportedEncodingException {
     try {
       return toString(Charset.forName(charsetName));
@@ -636,7 +644,7 @@
    * @param charset encode using this charset
    * @return new string
    */
-  public String toString(Charset charset) {
+  public final String toString(Charset charset) {
     return size() == 0 ? "" : toStringInternal(charset);
   }
 
@@ -657,7 +665,7 @@
    *
    * @return new string using UTF-8 encoding
    */
-  public String toStringUtf8() {
+  public final String toStringUtf8() {
     return toString(Internal.UTF_8);
   }
 
@@ -716,13 +724,51 @@
   public abstract boolean equals(Object o);
 
   /**
-   * Return a non-zero hashCode depending only on the sequence of bytes
-   * in this ByteString.
+   * Base class for leaf {@link ByteString}s (i.e. non-ropes).
+   */
+  abstract static class LeafByteString extends ByteString {
+    @Override
+    protected final int getTreeDepth() {
+      return 0;
+    }
+
+    @Override
+    protected final boolean isBalanced() {
+      return true;
+    }
+
+    /**
+     * Check equality of the substring of given length of this object starting at
+     * zero with another {@code ByteString} substring starting at offset.
+     *
+     * @param other  what to compare a substring in
+     * @param offset offset into other
+     * @param length number of bytes to compare
+     * @return true for equality of substrings, else false.
+     */
+    abstract boolean equalsRange(ByteString other, int offset, int length);
+  }
+
+  /**
+   * Compute the hashCode using the traditional algorithm from {@link
+   * ByteString}.
    *
-   * @return hashCode value for this object
+   * @return hashCode value
    */
   @Override
-  public abstract int hashCode();
+  public final int hashCode() {
+    int h = hash;
+
+    if (h == 0) {
+      int size = size();
+      h = partialHash(size, 0, size);
+      if (h == 0) {
+        h = 1;
+      }
+      hash = h;
+    }
+    return h;
+  }
 
   // =================================================================
   // Input stream
@@ -1034,7 +1080,9 @@
    *
    * @return value of cached hash code or 0 if not computed yet
    */
-  protected abstract int peekCachedHashCode();
+  protected final int peekCachedHashCode() {
+    return hash;
+  }
 
   /**
    * Compute the hash across the value bytes starting with the given hash, and
@@ -1049,9 +1097,360 @@
    */
   protected abstract int partialHash(int h, int offset, int length);
 
+  /**
+   * Checks that the given index falls within the specified array size.
+   *
+   * @param index the index position to be tested
+   * @param size the length of the array
+   * @throws ArrayIndexOutOfBoundsException if the index does not fall within the array.
+   */
+  static void checkIndex(int index, int size) {
+    if ((index | (size - (index + 1))) < 0) {
+      if (index < 0) {
+        throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
+      }
+      throw new ArrayIndexOutOfBoundsException("Index > length: " + index + ", " + size);
+    }
+  }
+
+  /**
+   * Checks that the given range falls within the bounds of an array
+   *
+   * @param startIndex the start index of the range (inclusive)
+   * @param endIndex the end index of the range (exclusive)
+   * @param size the size of the array.
+   * @return the length of the range.
+   * @throws ArrayIndexOutOfBoundsException some or all of the range falls outside of the array.
+   */
+  static int checkRange(int startIndex, int endIndex, int size) {
+    final int length = endIndex - startIndex;
+    if ((startIndex | endIndex | length | (size - endIndex)) < 0) {
+      if (startIndex < 0) {
+        throw new IndexOutOfBoundsException("Beginning index: " + startIndex + " < 0");
+      }
+      if (endIndex < startIndex) {
+        throw new IndexOutOfBoundsException(
+            "Beginning index larger than ending index: " + startIndex + ", " + endIndex);
+      }
+      // endIndex >= size
+      throw new IndexOutOfBoundsException("End index: " + endIndex + " >= " + size);
+    }
+    return length;
+  }
+
   @Override
-  public String toString() {
+  public final String toString() {
     return String.format("<ByteString@%s size=%d>",
         Integer.toHexString(System.identityHashCode(this)), size());
   }
+  
+  /**
+   * This class implements a {@link com.google.protobuf.ByteString} backed by a
+   * single array of bytes, contiguous in memory. It supports substring by
+   * pointing to only a sub-range of the underlying byte array, meaning that a
+   * substring will reference the full byte-array of the string it's made from,
+   * exactly as with {@link String}.
+   *
+   * @author carlanton@google.com (Carl Haverl)
+   */
+  // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
+  // static initializer loads LiteralByteString and another thread loads LiteralByteString.
+  private static class LiteralByteString extends ByteString.LeafByteString {
+    private static final long serialVersionUID = 1L;
+
+    protected final byte[] bytes;
+
+    /**
+     * Creates a {@code LiteralByteString} backed by the given array, without
+     * copying.
+     *
+     * @param bytes array to wrap
+     */
+    LiteralByteString(byte[] bytes) {
+      this.bytes = bytes;
+    }
+
+    @Override
+    public byte byteAt(int index) {
+      // Unlike most methods in this class, this one is a direct implementation
+      // ignoring the potential offset because we need to do range-checking in the
+      // substring case anyway.
+      return bytes[index];
+    }
+
+    @Override
+    public int size() {
+      return bytes.length;
+    }
+
+    // =================================================================
+    // ByteString -> substring
+
+    @Override
+    public final ByteString substring(int beginIndex, int endIndex) {
+      final int length = checkRange(beginIndex, endIndex, size());
+
+      if (length == 0) {
+        return ByteString.EMPTY;
+      }
+
+      return new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex, length);
+    }
+
+    // =================================================================
+    // ByteString -> byte[]
+
+    @Override
+    protected void copyToInternal(
+        byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
+      // Optimized form, not for subclasses, since we don't call
+      // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
+      // TODO(nathanmittler): Is not calling getOffsetIntoBytes really saving that much?
+      System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
+    }
+
+    @Override
+    public final void copyTo(ByteBuffer target) {
+      target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes
+    }
+
+    @Override
+    public final ByteBuffer asReadOnlyByteBuffer() {
+      return ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size()).asReadOnlyBuffer();
+    }
+
+    @Override
+    public final List<ByteBuffer> asReadOnlyByteBufferList() {
+      return Collections.singletonList(asReadOnlyByteBuffer());
+    }
+
+    @Override
+    public final void writeTo(OutputStream outputStream) throws IOException {
+      outputStream.write(toByteArray());
+    }
+
+    @Override
+    final void writeToInternal(OutputStream outputStream, int sourceOffset, int numberToWrite)
+        throws IOException {
+      outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset, numberToWrite);
+    }
+
+    @Override
+    protected final String toStringInternal(Charset charset) {
+      return new String(bytes, getOffsetIntoBytes(), size(), charset);
+    }
+
+    // =================================================================
+    // UTF-8 decoding
+
+    @Override
+    public final boolean isValidUtf8() {
+      int offset = getOffsetIntoBytes();
+      return Utf8.isValidUtf8(bytes, offset, offset + size());
+    }
+
+    @Override
+    protected final int partialIsValidUtf8(int state, int offset, int length) {
+      int index = getOffsetIntoBytes() + offset;
+      return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
+    }
+
+    // =================================================================
+    // equals() and hashCode()
+
+    @Override
+    public final boolean equals(Object other) {
+      if (other == this) {
+        return true;
+      }
+      if (!(other instanceof ByteString)) {
+        return false;
+      }
+
+      if (size() != ((ByteString) other).size()) {
+        return false;
+      }
+      if (size() == 0) {
+        return true;
+      }
+
+      if (other instanceof LiteralByteString) {
+        LiteralByteString otherAsLiteral = (LiteralByteString) other;
+        // If we know the hash codes and they are not equal, we know the byte
+        // strings are not equal.
+        int thisHash = peekCachedHashCode();
+        int thatHash = otherAsLiteral.peekCachedHashCode();
+        if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) {
+          return false;
+        }
+
+        return equalsRange((LiteralByteString) other, 0, size());
+      } else {
+        // RopeByteString and NioByteString.
+        return other.equals(this);
+      }
+    }
+
+    /**
+     * Check equality of the substring of given length of this object starting at
+     * zero with another {@code LiteralByteString} substring starting at offset.
+     *
+     * @param other  what to compare a substring in
+     * @param offset offset into other
+     * @param length number of bytes to compare
+     * @return true for equality of substrings, else false.
+     */
+    @Override
+    final boolean equalsRange(ByteString other, int offset, int length) {
+      if (length > other.size()) {
+        throw new IllegalArgumentException("Length too large: " + length + size());
+      }
+      if (offset + length > other.size()) {
+        throw new IllegalArgumentException(
+            "Ran off end of other: " + offset + ", " + length + ", " + other.size());
+      }
+
+      if (other instanceof LiteralByteString) {
+        LiteralByteString lbsOther = (LiteralByteString) other;
+        byte[] thisBytes = bytes;
+        byte[] otherBytes = lbsOther.bytes;
+        int thisLimit = getOffsetIntoBytes() + length;
+        for (
+            int thisIndex = getOffsetIntoBytes(),
+                otherIndex = lbsOther.getOffsetIntoBytes() + offset;
+            (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
+          if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      return other.substring(offset, offset + length).equals(substring(0, length));
+    }
+
+    @Override
+    protected final int partialHash(int h, int offset, int length) {
+      return Internal.partialHash(h, bytes, getOffsetIntoBytes() + offset, length);
+    }
+
+    // =================================================================
+    // Input stream
+
+    @Override
+    public final InputStream newInput() {
+      return new ByteArrayInputStream(bytes, getOffsetIntoBytes(), size()); // No copy
+    }
+
+    @Override
+    public final CodedInputStream newCodedInput() {
+      // We trust CodedInputStream not to modify the bytes, or to give anyone
+      // else access to them.
+      return CodedInputStream.newInstance(
+          bytes, getOffsetIntoBytes(), size(), true /* bufferIsImmutable */);
+    }
+
+    // =================================================================
+    // Internal methods
+
+    /**
+     * Offset into {@code bytes[]} to use, non-zero for substrings.
+     *
+     * @return always 0 for this class
+     */
+    protected int getOffsetIntoBytes() {
+      return 0;
+    }
+  }
+  
+  /**
+   * This class is used to represent the substring of a {@link ByteString} over a
+   * single byte array. In terms of the public API of {@link ByteString}, you end
+   * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
+   * ByteString#substring(int, int)}.
+   *
+   * <p>This class contains most of the overhead involved in creating a substring
+   * from a {@link LiteralByteString}.  The overhead involves some range-checking
+   * and two extra fields.
+   *
+   * @author carlanton@google.com (Carl Haverl)
+   */
+  // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
+  // static initializer loads LiteralByteString and another thread loads BoundedByteString.
+  private static final class BoundedByteString extends LiteralByteString {
+
+    private final int bytesOffset;
+    private final int bytesLength;
+
+    /**
+     * Creates a {@code BoundedByteString} backed by the sub-range of given array,
+     * without copying.
+     *
+     * @param bytes  array to wrap
+     * @param offset index to first byte to use in bytes
+     * @param length number of bytes to use from bytes
+     * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
+     *                                  or if {@code offset + length >
+     *                                  bytes.length}.
+     */
+    BoundedByteString(byte[] bytes, int offset, int length) {
+      super(bytes);
+      checkRange(offset, offset + length, bytes.length);
+
+      this.bytesOffset = offset;
+      this.bytesLength = length;
+    }
+
+    /**
+     * Gets the byte at the given index.
+     * Throws {@link ArrayIndexOutOfBoundsException}
+     * for backwards-compatibility reasons although it would more properly be
+     * {@link IndexOutOfBoundsException}.
+     *
+     * @param index index of byte
+     * @return the value
+     * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+     */
+    @Override
+    public byte byteAt(int index) {
+      // We must check the index ourselves as we cannot rely on Java array index
+      // checking for substrings.
+      checkIndex(index, size());
+      return bytes[bytesOffset + index];
+    }
+
+    @Override
+    public int size() {
+      return bytesLength;
+    }
+
+    @Override
+    protected int getOffsetIntoBytes() {
+      return bytesOffset;
+    }
+
+    // =================================================================
+    // ByteString -> byte[]
+
+    @Override
+    protected void copyToInternal(byte[] target, int sourceOffset, int targetOffset,
+        int numberToCopy) {
+      System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
+          targetOffset, numberToCopy);
+    }
+
+    // =================================================================
+    // Serializable
+
+    private static final long serialVersionUID = 1L;
+
+    Object writeReplace() {
+      return ByteString.wrap(toByteArray());
+    }
+
+    private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
+      throw new InvalidObjectException(
+          "BoundedByteStream instances are not to be serialized directly");
+    }
+  }
 }
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
similarity index 88%
rename from java/src/main/java/com/google/protobuf/CodedInputStream.java
rename to java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index d201f7c..b3118ee 100644
--- a/java/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -70,7 +70,15 @@
    */
   public static CodedInputStream newInstance(final byte[] buf, final int off,
                                              final int len) {
-    CodedInputStream result = new CodedInputStream(buf, off, len);
+    return newInstance(buf, off, len, false);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  public static CodedInputStream newInstance(final byte[] buf, final int off,
+                                             final int len, boolean bufferIsImmutable) {
+    CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable);
     try {
       // Some uses of CodedInputStream can be more efficient if they know
       // exactly how many bytes are available.  By pushing the end point of the
@@ -113,31 +121,6 @@
     }
   }
 
-  /**
-   * Create a new CodedInputStream wrapping a LiteralByteString.
-   */
-  static CodedInputStream newInstance(LiteralByteString byteString) {
-    CodedInputStream result = new CodedInputStream(byteString);
-    try {
-      // Some uses of CodedInputStream can be more efficient if they know
-      // exactly how many bytes are available.  By pushing the end point of the
-      // buffer as a limit, we allow them to get this information via
-      // getBytesUntilLimit().  Pushing a limit that we know is at the end of
-      // the stream can never hurt, since we can never past that point anyway.
-      result.pushLimit(byteString.size());
-    } catch (InvalidProtocolBufferException ex) {
-      // The only reason pushLimit() might throw an exception here is if len
-      // is negative. Normally pushLimit()'s parameter comes directly off the
-      // wire, so it's important to catch exceptions in case of corrupt or
-      // malicious data. However, in this case, we expect that len is not a
-      // user-supplied value, so we can assume that it being negative indicates
-      // a programming error. Therefore, throwing an unchecked exception is
-      // appropriate.
-      throw new IllegalArgumentException(ex);
-    }
-    return result;
-  }
-
   // -----------------------------------------------------------------
 
   /**
@@ -506,7 +489,7 @@
       // Fast path:  We already have the bytes in a contiguous buffer, so
       //   just copy directly from it.
       final ByteString result = bufferIsImmutable && enableAliasing
-          ? new BoundedByteString(buffer, bufferPos, size)
+          ? ByteString.wrap(buffer, bufferPos, size)
           : ByteString.copyFrom(buffer, bufferPos, size);
       bufferPos += size;
       return result;
@@ -514,7 +497,7 @@
       return ByteString.EMPTY;
     } else {
       // Slow path:  Build a byte array first then copy it.
-      return new LiteralByteString(readRawBytesSlowPath(size));
+      return ByteString.wrap(readRawBytesSlowPath(size));
     }
   }
 
@@ -886,13 +869,13 @@
   private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
   private static final int BUFFER_SIZE = 4096;
 
-  private CodedInputStream(final byte[] buffer, final int off, final int len) {
+  private CodedInputStream(final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) {
     this.buffer = buffer;
     bufferSize = off + len;
     bufferPos = off;
     totalBytesRetired = -off;
     input = null;
-    bufferIsImmutable = false;
+    this.bufferIsImmutable = bufferIsImmutable;
   }
 
   private CodedInputStream(final InputStream input) {
@@ -904,15 +887,6 @@
     bufferIsImmutable = false;
   }
 
-  private CodedInputStream(final LiteralByteString byteString) {
-    buffer = byteString.bytes;
-    bufferPos = byteString.getOffsetIntoBytes();
-    bufferSize = bufferPos + byteString.size();
-    totalBytesRetired = -bufferPos;
-    input = null;
-    bufferIsImmutable = true;
-  }
-
   public void enableAliasing(boolean enabled) {
     this.enableAliasing = enabled;
   }
@@ -1056,20 +1030,6 @@
   private RefillCallback refillCallback = null;
 
   /**
-   * Ensures that at least {@code n} bytes are available in the buffer, reading
-   * more bytes from the input if necessary to make it so.  Caller must ensure
-   * that the requested space is less than BUFFER_SIZE.
-   *
-   * @throws InvalidProtocolBufferException The end of the stream or the current
-   *                                        limit was reached.
-   */
-  private void ensureAvailable(int n) throws IOException {
-    if (bufferSize - bufferPos < n) {
-      refillBuffer(n);
-    }
-  }
-
-  /**
    * Reads more bytes from the input, making at least {@code n} bytes available
    * in the buffer.  Caller must ensure that the requested space is not yet
    * available, and that the requested space is less than BUFFER_SIZE.
@@ -1180,86 +1140,97 @@
       }
     }
 
-    if (totalBytesRetired + bufferPos + size > currentLimit) {
+    // Verify that the message size so far has not exceeded sizeLimit.
+    int currentMessageSize = totalBytesRetired + bufferPos + size;
+    if (currentMessageSize > sizeLimit) {
+      throw InvalidProtocolBufferException.sizeLimitExceeded();
+    }
+
+    // Verify that the message size so far has not exceeded currentLimit.
+    if (currentMessageSize > currentLimit) {
       // Read to the end of the stream anyway.
       skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
-      // Then fail.
       throw InvalidProtocolBufferException.truncatedMessage();
     }
 
-    if (size < BUFFER_SIZE) {
-      // Reading more bytes than are in the buffer, but not an excessive number
-      // of bytes.  We can safely allocate the resulting array ahead of time.
+    // We need the input stream to proceed.
+    if (input == null) {
+      throw InvalidProtocolBufferException.truncatedMessage();
+    }
 
-      // First copy what we have.
+    final int originalBufferPos = bufferPos;
+    final int bufferedBytes = bufferSize - bufferPos;
+
+    // Mark the current buffer consumed.
+    totalBytesRetired += bufferSize;
+    bufferPos = 0;
+    bufferSize = 0;
+
+    // Determine the number of bytes we need to read from the input stream.
+    int sizeLeft = size - bufferedBytes;
+    // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
+    if (sizeLeft < BUFFER_SIZE || sizeLeft <= input.available()) {
+      // Either the bytes we need are known to be available, or the required buffer is
+      // within an allowed threshold - go ahead and allocate the buffer now.
       final byte[] bytes = new byte[size];
-      int pos = bufferSize - bufferPos;
-      System.arraycopy(buffer, bufferPos, bytes, 0, pos);
-      bufferPos = bufferSize;
 
-      // We want to refill the buffer and then copy from the buffer into our
-      // byte array rather than reading directly into our byte array because
-      // the input may be unbuffered.
-      ensureAvailable(size - pos);
-      System.arraycopy(buffer, 0, bytes, pos, size - pos);
-      bufferPos = size - pos;
+      // Copy all of the buffered bytes to the result buffer.
+      System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
 
-      return bytes;
-    } else {
-      // The size is very large.  For security reasons, we can't allocate the
-      // entire byte array yet.  The size comes directly from the input, so a
-      // maliciously-crafted message could provide a bogus very large size in
-      // order to trick the app into allocating a lot of memory.  We avoid this
-      // by allocating and reading only a small chunk at a time, so that the
-      // malicious message must actually *be* extremely large to cause
-      // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
-
-      // Remember the buffer markers since we'll have to copy the bytes out of
-      // it later.
-      final int originalBufferPos = bufferPos;
-      final int originalBufferSize = bufferSize;
-
-      // Mark the current buffer consumed.
-      totalBytesRetired += bufferSize;
-      bufferPos = 0;
-      bufferSize = 0;
-
-      // Read all the rest of the bytes we need.
-      int sizeLeft = size - (originalBufferSize - originalBufferPos);
-      final List<byte[]> chunks = new ArrayList<byte[]>();
-
-      while (sizeLeft > 0) {
-        final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
-        int pos = 0;
-        while (pos < chunk.length) {
-          final int n = (input == null) ? -1 :
-            input.read(chunk, pos, chunk.length - pos);
-          if (n == -1) {
-            throw InvalidProtocolBufferException.truncatedMessage();
-          }
-          totalBytesRetired += n;
-          pos += n;
+      // Fill the remaining bytes from the input stream.
+      int pos = bufferedBytes;
+      while (pos < bytes.length) {
+        int n = input.read(bytes, pos, size - pos);
+        if (n == -1) {
+          throw InvalidProtocolBufferException.truncatedMessage();
         }
-        sizeLeft -= chunk.length;
-        chunks.add(chunk);
+        totalBytesRetired += n;
+        pos += n;
       }
 
-      // OK, got everything.  Now concatenate it all into one buffer.
-      final byte[] bytes = new byte[size];
-
-      // Start by copying the leftover bytes from this.buffer.
-      int pos = originalBufferSize - originalBufferPos;
-      System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
-
-      // And now all the chunks.
-      for (final byte[] chunk : chunks) {
-        System.arraycopy(chunk, 0, bytes, pos, chunk.length);
-        pos += chunk.length;
-      }
-
-      // Done.
       return bytes;
     }
+
+    // The size is very large.  For security reasons, we can't allocate the
+    // entire byte array yet.  The size comes directly from the input, so a
+    // maliciously-crafted message could provide a bogus very large size in
+    // order to trick the app into allocating a lot of memory.  We avoid this
+    // by allocating and reading only a small chunk at a time, so that the
+    // malicious message must actually *be* extremely large to cause
+    // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+    final List<byte[]> chunks = new ArrayList<byte[]>();
+
+    while (sizeLeft > 0) {
+      // TODO(nathanmittler): Consider using a value larger than BUFFER_SIZE.
+      final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
+      int pos = 0;
+      while (pos < chunk.length) {
+        final int n = input.read(chunk, pos, chunk.length - pos);
+        if (n == -1) {
+          throw InvalidProtocolBufferException.truncatedMessage();
+        }
+        totalBytesRetired += n;
+        pos += n;
+      }
+      sizeLeft -= chunk.length;
+      chunks.add(chunk);
+    }
+
+    // OK, got everything.  Now concatenate it all into one buffer.
+    final byte[] bytes = new byte[size];
+
+    // Start by copying the leftover bytes from this.buffer.
+    System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
+
+    // And now all the chunks.
+    int pos = bufferedBytes;
+    for (final byte[] chunk : chunks) {
+      System.arraycopy(chunk, 0, bytes, pos, chunk.length);
+      pos += chunk.length;
+    }
+
+    // Done.
+    return bytes;
   }
 
   /**
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
similarity index 94%
rename from java/src/main/java/com/google/protobuf/CodedOutputStream.java
rename to java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 291bd20..d8ebad2 100644
--- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -53,7 +53,7 @@
  * @author kneton@google.com Kenton Varda
  */
 public final class CodedOutputStream {
-  
+
   private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
 
   // TODO(dweis): Consider migrating to a ByteBuffer.
@@ -243,19 +243,6 @@
   }
 
 
-  /**
-   * Write a group represented by an {@link UnknownFieldSet}.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #writeGroup}.
-   */
-  @Deprecated
-  public void writeUnknownGroup(final int fieldNumber,
-                                final MessageLite value)
-                                throws IOException {
-    writeGroup(fieldNumber, value);
-  }
-
   /** Write an embedded message field, including tag, to the stream. */
   public void writeMessage(final int fieldNumber, final MessageLite value)
                            throws IOException {
@@ -428,7 +415,7 @@
     try {
       efficientWriteStringNoTag(value);
     } catch (UnpairedSurrogateException e) {
-      logger.log(Level.WARNING, 
+      logger.log(Level.WARNING,
           "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e);
       inefficientWriteStringNoTag(value);
     }
@@ -449,10 +436,10 @@
    * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed,
    * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the
    * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}.
-   * 
+   *
    * @param value the string to write to the stream
-   * 
-   * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16. 
+   *
+   * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16.
    */
   private void efficientWriteStringNoTag(final String value) throws IOException {
     // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
@@ -510,18 +497,6 @@
   }
 
 
-  /**
-   * Write a group represented by an {@link UnknownFieldSet}.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #writeGroupNoTag}.
-   */
-  @Deprecated
-  public void writeUnknownGroupNoTag(final MessageLite value)
-      throws IOException {
-    writeGroupNoTag(value);
-  }
-
   /** Write an embedded message field to the stream. */
   public void writeMessageNoTag(final MessageLite value) throws IOException {
     writeRawVarint32(value.getSerializedSize());
@@ -685,20 +660,6 @@
   }
 
   /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field represented by an {@code UnknownFieldSet}, including
-   * tag.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #computeGroupSize}.
-   */
-  @Deprecated
-  public static int computeUnknownGroupSize(final int fieldNumber,
-                                            final MessageLite value) {
-    return computeGroupSize(fieldNumber, value);
-  }
-
-  /**
    * Compute the number of bytes that would be needed to encode an
    * embedded message field, including tag.
    */
@@ -927,19 +888,6 @@
   }
 
   /**
-   * Compute the number of bytes that would be needed to encode a
-   * {@code group} field represented by an {@code UnknownFieldSet}, including
-   * tag.
-   *
-   * @deprecated UnknownFieldSet now implements MessageLite, so you can just
-   *             call {@link #computeUnknownGroupSizeNoTag}.
-   */
-  @Deprecated
-  public static int computeUnknownGroupSizeNoTag(final MessageLite value) {
-    return computeGroupSizeNoTag(value);
-  }
-
-  /**
    * Compute the number of bytes that would be needed to encode an embedded
    * message field.
    */
@@ -1295,10 +1243,10 @@
    * negative.
    */
   public static int computeRawVarint32Size(final int value) {
-    if ((value & (0xffffffff <<  7)) == 0) return 1;
-    if ((value & (0xffffffff << 14)) == 0) return 2;
-    if ((value & (0xffffffff << 21)) == 0) return 3;
-    if ((value & (0xffffffff << 28)) == 0) return 4;
+    if ((value & (~0 <<  7)) == 0) return 1;
+    if ((value & (~0 << 14)) == 0) return 2;
+    if ((value & (~0 << 21)) == 0) return 3;
+    if ((value & (~0 << 28)) == 0) return 4;
     return 5;
   }
 
@@ -1316,17 +1264,16 @@
   }
 
   /** Compute the number of bytes that would be needed to encode a varint. */
-  public static int computeRawVarint64Size(final long value) {
-    if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
-    if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
-    if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
-    if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
-    if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
-    if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
-    if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
-    if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
-    if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
-    return 10;
+  public static int computeRawVarint64Size(long value) {
+    // handle two popular special cases up front ...
+    if ((value & (~0L << 7)) == 0L) return 1;
+    if (value < 0L) return 10;
+    // ... leaving us with 8 remaining, which we can divide and conquer
+    int n = 2;
+    if ((value & (~0L << 35)) != 0L) { n += 4; value >>>= 28; }
+    if ((value & (~0L << 21)) != 0L) { n += 2; value >>>= 14; }
+    if ((value & (~0L << 14)) != 0L) { n += 1; }
+    return n;
   }
 
   /** Write a little-endian 32-bit integer. */
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
similarity index 98%
rename from java/src/main/java/com/google/protobuf/Descriptors.java
rename to java/core/src/main/java/com/google/protobuf/Descriptors.java
index 7cfc47f..5e15cfb 100644
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -889,6 +889,11 @@
      */
     public String getFullName() { return fullName; }
 
+    /** Get the JSON name of this field. */
+    public String getJsonName() {
+      return jsonName;
+    }
+
     /**
      * Get the field's java type.  This is just for convenience.  Every
      * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
@@ -1079,6 +1084,7 @@
 
     private FieldDescriptorProto proto;
     private final String fullName;
+    private final String jsonName;
     private final FileDescriptor file;
     private final Descriptor extensionScope;
 
@@ -1157,6 +1163,38 @@
       private final Object defaultDefault;
     }
 
+    // TODO(xiaofeng): Implement it consistently across different languages. See b/24751348.
+    private static String fieldNameToLowerCamelCase(String name) {
+      StringBuilder result = new StringBuilder(name.length());
+      boolean isNextUpperCase = false;
+      for (int i = 0; i < name.length(); i++) {
+        Character ch = name.charAt(i);
+        if (Character.isLowerCase(ch)) {
+          if (isNextUpperCase) {
+            result.append(Character.toUpperCase(ch));
+          } else {
+            result.append(ch);
+          }
+          isNextUpperCase = false;
+        } else if (Character.isUpperCase(ch)) {
+          if (i == 0) {
+            // Force first letter to lower-case.
+            result.append(Character.toLowerCase(ch));
+          } else {
+            // Capital letters after the first are left as-is.
+            result.append(ch);
+          }
+          isNextUpperCase = false;
+        } else if (Character.isDigit(ch)) {
+          result.append(ch);
+          isNextUpperCase = false;
+        } else {
+          isNextUpperCase = true;
+        }
+      }
+      return result.toString();
+    }
+
     private FieldDescriptor(final FieldDescriptorProto proto,
                             final FileDescriptor file,
                             final Descriptor parent,
@@ -1167,6 +1205,11 @@
       this.proto = proto;
       fullName = computeFullName(file, parent, proto.getName());
       this.file = file;
+      if (proto.hasJsonName()) {
+        jsonName = proto.getJsonName();
+      } else {
+        jsonName = fieldNameToLowerCamelCase(proto.getName());
+      }
 
       if (proto.hasType()) {
         type = Type.valueOf(proto.getType());
diff --git a/java/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
similarity index 95%
rename from java/src/main/java/com/google/protobuf/DoubleArrayList.java
rename to java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index 90ebe10..bcc9d6e 100644
--- a/java/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -68,10 +68,17 @@
   private int size;
 
   /**
-   * Constructs a new mutable {@code DoubleArrayList}.
+   * Constructs a new mutable {@code DoubleArrayList} with default capacity.
    */
   DoubleArrayList() {
-    array = new double[DEFAULT_CAPACITY];
+    this(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} with the provided capacity.
+   */
+  DoubleArrayList(int capacity) {
+    array = new double[capacity];
     size = 0;
   }
 
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/DynamicMessage.java
rename to java/core/src/main/java/com/google/protobuf/DynamicMessage.java
diff --git a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
new file mode 100644
index 0000000..6f41fb8
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java
@@ -0,0 +1,36 @@
+package com.google.protobuf;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates a public API that can change at any time, and has no guarantee of API stability and
+ * backward-compatibility.
+ *
+ * <p>Usage guidelines:
+ * <ol>
+ * <li>This annotation is used only on public API. Internal interfaces should not use it.</li>
+ * <li>This annotation should only be added to new APIs. Adding it to an existing API is
+ * considered API-breaking.</li>
+ * <li>Removing this annotation from an API gives it stable status.</li>
+ * </ol>
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+    ElementType.ANNOTATION_TYPE,
+    ElementType.CONSTRUCTOR,
+    ElementType.FIELD,
+    ElementType.METHOD,
+    ElementType.PACKAGE,
+    ElementType.TYPE})
+@Documented
+public @interface ExperimentalApi {
+  /**
+   * Context information such as links to discussion thread, tracking issue etc.
+   */
+  String value() default "";
+}
+
diff --git a/java/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/Extension.java
rename to java/core/src/main/java/com/google/protobuf/Extension.java
diff --git a/java/src/main/java/com/google/protobuf/ExtensionLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionLite.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionLite.java
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionRegistry.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
rename to java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/FieldSet.java
rename to java/core/src/main/java/com/google/protobuf/FieldSet.java
diff --git a/java/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
similarity index 95%
rename from java/src/main/java/com/google/protobuf/FloatArrayList.java
rename to java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 293eaff..033b5ee 100644
--- a/java/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -67,10 +67,17 @@
   private int size;
 
   /**
-   * Constructs a new mutable {@code FloatArrayList}.
+   * Constructs a new mutable {@code FloatArrayList} with default capacity.
    */
   FloatArrayList() {
-    array = new float[DEFAULT_CAPACITY];
+    this(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} with the provided capacity.
+   */
+  FloatArrayList(int capacity) {
+    array = new float[capacity];
     size = 0;
   }
 
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
similarity index 97%
rename from java/src/main/java/com/google/protobuf/GeneratedMessage.java
rename to java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index d84fa75..ceb97a4 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -36,15 +36,13 @@
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
-import com.google.protobuf.GeneratedMessageLite.ExtendableMessage;
-import com.google.protobuf.GeneratedMessageLite.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.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -276,6 +274,60 @@
     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);
@@ -667,7 +719,7 @@
           "No map fields found in " + getClass().getName());
     }
 
-    /** Like {@link internalGetMapField} but return a mutable version. */
+    /** 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
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
similarity index 84%
rename from java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
rename to java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index a535b71..81e1862 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -62,9 +62,8 @@
 
   private static final long serialVersionUID = 1L;
 
-  /** For use by generated code only.  */
-  protected UnknownFieldSetLite unknownFields =
-      UnknownFieldSetLite.getDefaultInstance();
+  /** For use by generated code only. Lazily initialized to reduce allocations. */
+  protected UnknownFieldSetLite unknownFields = null;
   
   /** For use by generated code only.  */
   protected int memoizedSerializedSize = -1;
@@ -84,19 +83,61 @@
     return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
   }
 
+  // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
+  // mutable during the parsing constructor and immutable after. This allows us to avoid
+  // any unnecessary intermediary allocations while reducing the generated code size.
+
   /**
-   * Called by subclasses to parse an unknown field. For use by generated code
-   * only.
+   * Lazily initializes unknown fields.
+   */
+  private final void ensureUnknownFieldsInitialized() {
+    if (unknownFields == null) {
+      unknownFields = UnknownFieldSetLite.newInstance();
+    }
+  }
+  
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   * 
    * @return {@code true} unless the tag is an end-group tag.
    */
-  protected static boolean parseUnknownField(
-      CodedInputStream input,
-      UnknownFieldSetLite.Builder unknownFields,
-      ExtensionRegistryLite extensionRegistry,
-      int tag) throws IOException {
+  protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
+    // This will avoid the allocation of unknown fields when a group tag is encountered.
+    if (WireFormat.getTagWireType(tag) == WireFormat.WIRETYPE_END_GROUP) {
+      return false;
+    }
+    
+    ensureUnknownFieldsInitialized();
     return unknownFields.mergeFieldFrom(tag, input);
   }
 
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   */
+  protected void mergeVarintField(int tag, int value) {
+    ensureUnknownFieldsInitialized();
+    unknownFields.mergeVarintField(tag, value);
+  }
+  
+  /**
+   * Called by subclasses to parse an unknown field. For use by generated code only.
+   */
+  protected void mergeLengthDelimitedField(int fieldNumber, ByteString value) {
+    ensureUnknownFieldsInitialized();
+    unknownFields.mergeLengthDelimitedField(fieldNumber, value);
+  }
+  
+  /**
+   * Called by subclasses to complete parsing. For use by generated code only.
+   */
+  protected void doneParsing() {
+    if (unknownFields == null) {
+      unknownFields = UnknownFieldSetLite.getDefaultInstance();
+    } else {
+      unknownFields.makeImmutable();
+    }
+  }
+
   public final boolean isInitialized() {
     return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
   }
@@ -171,7 +212,7 @@
    * <p>For use by generated code only.
    */
   protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) {
-    this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
+    this.unknownFields = UnknownFieldSetLite.mutableCopyOf(this.unknownFields, unknownFields);
   }
 
   @SuppressWarnings("unchecked")
@@ -225,7 +266,13 @@
 
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public MessageType buildPartial() {
+      if (isBuilt) {
+        return instance;
+      }
+      
       instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+      instance.unknownFields.makeImmutable();
+      
       isBuilt = true;
       return instance;
     }
@@ -249,18 +296,6 @@
     public MessageType getDefaultInstanceForType() {
       return defaultInstance;
     }
-
-    /**
-     * Called by subclasses to parse an unknown field.
-     * @return {@code true} unless the tag is an end-group tag.
-     */
-    protected boolean parseUnknownField(
-        CodedInputStream input,
-        UnknownFieldSetLite.Builder unknownFields,
-        ExtensionRegistryLite extensionRegistry,
-        int tag) throws IOException {
-      return unknownFields.mergeFieldFrom(tag, input);
-    }
     
     public BuilderType mergeFrom(
         com.google.protobuf.CodedInputStream input,
@@ -334,6 +369,130 @@
       extensions.mergeFrom(((ExtendableMessage) other).extensions);
     }
     
+    /**
+     * Parse an unknown field or an extension. For use by generated code only.
+     * 
+     * <p>For use by generated code only.
+     * 
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected <MessageType extends MessageLite> boolean parseUnknownField(
+        MessageType defaultInstance,
+        CodedInputStream input,
+        ExtensionRegistryLite extensionRegistry,
+        int tag) throws IOException {
+      int wireType = WireFormat.getTagWireType(tag);
+      int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+      // TODO(dweis): How much bytecode would be saved by not requiring the generated code to
+      //     provide the default instance?
+      GeneratedExtension<MessageType, ?> extension = extensionRegistry.findLiteExtensionByNumber(
+          defaultInstance, fieldNumber);
+
+      boolean unknown = false;
+      boolean packed = false;
+      if (extension == null) {
+        unknown = true;  // Unknown field.
+      } else if (wireType == FieldSet.getWireFormatForFieldType(
+                   extension.descriptor.getLiteType(),
+                   false  /* isPacked */)) {
+        packed = false;  // Normal, unpacked value.
+      } else if (extension.descriptor.isRepeated &&
+                 extension.descriptor.type.isPackable() &&
+                 wireType == FieldSet.getWireFormatForFieldType(
+                   extension.descriptor.getLiteType(),
+                   true  /* isPacked */)) {
+        packed = true;  // Packed value.
+      } else {
+        unknown = true;  // Wrong wire type.
+      }
+
+      if (unknown) {  // Unknown field or wrong wire type.  Skip.
+        return parseUnknownField(tag, input);
+      }
+
+      if (packed) {
+        int length = input.readRawVarint32();
+        int limit = input.pushLimit(length);
+        if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+          while (input.getBytesUntilLimit() > 0) {
+            int rawValue = input.readEnum();
+            Object value =
+                extension.descriptor.getEnumType().findValueByNumber(rawValue);
+            if (value == null) {
+              // If the number isn't recognized as a valid value for this
+              // enum, drop it (don't even add it to unknownFields).
+              return true;
+            }
+            extensions.addRepeatedField(extension.descriptor,
+                                        extension.singularToFieldSetType(value));
+          }
+        } else {
+          while (input.getBytesUntilLimit() > 0) {
+            Object value =
+                FieldSet.readPrimitiveField(input,
+                                            extension.descriptor.getLiteType(),
+                                            /*checkUtf8=*/ false);
+            extensions.addRepeatedField(extension.descriptor, value);
+          }
+        }
+        input.popLimit(limit);
+      } else {
+        Object value;
+        switch (extension.descriptor.getLiteJavaType()) {
+          case MESSAGE: {
+            MessageLite.Builder subBuilder = null;
+            if (!extension.descriptor.isRepeated()) {
+              MessageLite existingValue =
+                  (MessageLite) extensions.getField(extension.descriptor);
+              if (existingValue != null) {
+                subBuilder = existingValue.toBuilder();
+              }
+            }
+            if (subBuilder == null) {
+              subBuilder = extension.getMessageDefaultInstance()
+                  .newBuilderForType();
+            }
+            if (extension.descriptor.getLiteType() ==
+                WireFormat.FieldType.GROUP) {
+              input.readGroup(extension.getNumber(),
+                              subBuilder, extensionRegistry);
+            } else {
+              input.readMessage(subBuilder, extensionRegistry);
+            }
+            value = subBuilder.build();
+            break;
+          }
+          case ENUM:
+            int rawValue = input.readEnum();
+            value = extension.descriptor.getEnumType()
+                             .findValueByNumber(rawValue);
+            // If the number isn't recognized as a valid value for this enum,
+            // write it to unknown fields object.
+            if (value == null) {
+              mergeVarintField(fieldNumber, rawValue);
+              return true;
+            }
+            break;
+          default:
+            value = FieldSet.readPrimitiveField(input,
+                extension.descriptor.getLiteType(),
+                /*checkUtf8=*/ false);
+            break;
+        }
+
+        if (extension.descriptor.isRepeated()) {
+          extensions.addRepeatedField(extension.descriptor,
+                                      extension.singularToFieldSetType(value));
+        } else {
+          extensions.setField(extension.descriptor,
+                              extension.singularToFieldSetType(value));
+        }
+      }
+
+      return true;
+    }
+    
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
       if (extension.getContainingTypeDefaultInstance() !=
@@ -404,11 +563,10 @@
     }
 
 
-    /**
-     * Used by parsing constructors in generated classes.
-     */
-    protected static void makeExtensionsImmutable(
-        FieldSet<ExtensionDescriptor> extensions) {
+    @Override
+    protected final void doneParsing() {
+      super.doneParsing();
+      
       extensions.makeImmutable();
     }
 
@@ -619,131 +777,6 @@
     }
   }
 
-  //-----------------------------------------------------------------
-
-  /**
-   * Parse an unknown field or an extension. For use by generated code only.
-   * @return {@code true} unless the tag is an end-group tag.
-   */
-  protected static <MessageType extends MessageLite>
-      boolean parseUnknownField(
-          FieldSet<ExtensionDescriptor> extensions,
-          MessageType defaultInstance,
-          CodedInputStream input,
-          UnknownFieldSetLite.Builder unknownFields,
-          ExtensionRegistryLite extensionRegistry,
-          int tag) throws IOException {
-    int wireType = WireFormat.getTagWireType(tag);
-    int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
-    GeneratedExtension<MessageType, ?> extension =
-      extensionRegistry.findLiteExtensionByNumber(
-          defaultInstance, fieldNumber);
-
-    boolean unknown = false;
-    boolean packed = false;
-    if (extension == null) {
-      unknown = true;  // Unknown field.
-    } else if (wireType == FieldSet.getWireFormatForFieldType(
-                 extension.descriptor.getLiteType(),
-                 false  /* isPacked */)) {
-      packed = false;  // Normal, unpacked value.
-    } else if (extension.descriptor.isRepeated &&
-               extension.descriptor.type.isPackable() &&
-               wireType == FieldSet.getWireFormatForFieldType(
-                 extension.descriptor.getLiteType(),
-                 true  /* isPacked */)) {
-      packed = true;  // Packed value.
-    } else {
-      unknown = true;  // Wrong wire type.
-    }
-
-    if (unknown) {  // Unknown field or wrong wire type.  Skip.
-      return unknownFields.mergeFieldFrom(tag, input);
-    }
-
-    if (packed) {
-      int length = input.readRawVarint32();
-      int limit = input.pushLimit(length);
-      if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
-        while (input.getBytesUntilLimit() > 0) {
-          int rawValue = input.readEnum();
-          Object value =
-              extension.descriptor.getEnumType().findValueByNumber(rawValue);
-          if (value == null) {
-            // If the number isn't recognized as a valid value for this
-            // enum, drop it (don't even add it to unknownFields).
-            return true;
-          }
-          extensions.addRepeatedField(extension.descriptor,
-                                      extension.singularToFieldSetType(value));
-        }
-      } else {
-        while (input.getBytesUntilLimit() > 0) {
-          Object value =
-              FieldSet.readPrimitiveField(input,
-                                          extension.descriptor.getLiteType(),
-                                          /*checkUtf8=*/ false);
-          extensions.addRepeatedField(extension.descriptor, value);
-        }
-      }
-      input.popLimit(limit);
-    } else {
-      Object value;
-      switch (extension.descriptor.getLiteJavaType()) {
-        case MESSAGE: {
-          MessageLite.Builder subBuilder = null;
-          if (!extension.descriptor.isRepeated()) {
-            MessageLite existingValue =
-                (MessageLite) extensions.getField(extension.descriptor);
-            if (existingValue != null) {
-              subBuilder = existingValue.toBuilder();
-            }
-          }
-          if (subBuilder == null) {
-            subBuilder = extension.getMessageDefaultInstance()
-                .newBuilderForType();
-          }
-          if (extension.descriptor.getLiteType() ==
-              WireFormat.FieldType.GROUP) {
-            input.readGroup(extension.getNumber(),
-                            subBuilder, extensionRegistry);
-          } else {
-            input.readMessage(subBuilder, extensionRegistry);
-          }
-          value = subBuilder.build();
-          break;
-        }
-        case ENUM:
-          int rawValue = input.readEnum();
-          value = extension.descriptor.getEnumType()
-                           .findValueByNumber(rawValue);
-          // If the number isn't recognized as a valid value for this enum,
-          // write it to unknown fields object.
-          if (value == null) {
-            unknownFields.mergeVarintField(fieldNumber, rawValue);
-            return true;
-          }
-          break;
-        default:
-          value = FieldSet.readPrimitiveField(input,
-              extension.descriptor.getLiteType(),
-              /*checkUtf8=*/ false);
-          break;
-      }
-
-      if (extension.descriptor.isRepeated()) {
-        extensions.addRepeatedField(extension.descriptor,
-                                    extension.singularToFieldSetType(value));
-      } else {
-        extensions.setField(extension.descriptor,
-                            extension.singularToFieldSetType(value));
-      }
-    }
-
-    return true;
-  }
-
   // -----------------------------------------------------------------
 
   /** For use by generated code only. */
@@ -893,7 +926,7 @@
           extends ExtensionLite<ContainingType, Type> {
 
     /**
-     * Create a new isntance with the given parameters.
+     * Create a new instance with the given parameters.
      *
      * The last parameter {@code singularType} is only needed for enum types.
      * We store integer values for enum types in a {@link ExtendableMessage}
@@ -905,7 +938,7 @@
         final Type defaultValue,
         final MessageLite messageDefaultInstance,
         final ExtensionDescriptor descriptor,
-        Class singularType) {
+        final Class singularType) {
       // Defensive checks to verify the correct initialization order of
       // GeneratedExtensions and their related GeneratedMessages.
       if (containingTypeDefaultInstance == null) {
@@ -921,24 +954,12 @@
       this.defaultValue = defaultValue;
       this.messageDefaultInstance = messageDefaultInstance;
       this.descriptor = descriptor;
-
-      // Use Java reflection to invoke the static method {@code valueOf} of
-      // enum types in order to convert integers to concrete enum objects.
-      this.singularType = singularType;
-      if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
-        this.enumValueOf = getMethodOrDie(
-            singularType, "valueOf", int.class);
-      } else {
-        this.enumValueOf = null;
-      }
     }
 
     final ContainingType containingTypeDefaultInstance;
     final Type defaultValue;
     final MessageLite messageDefaultInstance;
     final ExtensionDescriptor descriptor;
-    final Class singularType;
-    final Method enumValueOf;
 
     /**
      * Default instance of the type being extended, used to identify that type.
@@ -980,7 +1001,7 @@
 
     Object singularFromFieldSetType(final Object value) {
       if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
-        return invokeOrDie(enumValueOf, null, (Integer) value);
+        return descriptor.enumTypeMap.findValueByNumber((Integer) value);
       } else {
         return value;
       }
@@ -1157,6 +1178,10 @@
     return new IntArrayList();
   }
   
+  protected static IntList newIntListWithCapacity(int capacity) {
+    return new IntArrayList(capacity);
+  }
+  
   protected static IntList newIntList(List<Integer> toCopy) {
     return new IntArrayList(toCopy);
   }
@@ -1164,10 +1189,14 @@
   protected static IntList emptyIntList() {
     return IntArrayList.emptyList();
   }
-  
+
   protected static LongList newLongList() {
     return new LongArrayList();
   }
+
+  protected static LongList newLongListWithCapacity(int capacity) {
+    return new LongArrayList(capacity);
+  }
   
   protected static LongList newLongList(List<Long> toCopy) {
     return new LongArrayList(toCopy);
@@ -1181,6 +1210,10 @@
     return new FloatArrayList();
   }
   
+  protected static FloatList newFloatListWithCapacity(int capacity) {
+    return new FloatArrayList(capacity);
+  }
+  
   protected static FloatList newFloatList(List<Float> toCopy) {
     return new FloatArrayList(toCopy);
   }
@@ -1193,6 +1226,10 @@
     return new DoubleArrayList();
   }
   
+  protected static DoubleList newDoubleListWithCapacity(int capacity) {
+    return new DoubleArrayList(capacity);
+  }
+  
   protected static DoubleList newDoubleList(List<Double> toCopy) {
     return new DoubleArrayList(toCopy);
   }
@@ -1205,6 +1242,10 @@
     return new BooleanArrayList();
   }
   
+  protected static BooleanList newBooleanListWithCapacity(int capacity) {
+    return new BooleanArrayList(capacity);
+  }
+  
   protected static BooleanList newBooleanList(List<Boolean> toCopy) {
     return new BooleanArrayList(toCopy);
   }
@@ -1221,6 +1262,10 @@
     return new ProtobufArrayList<E>(toCopy);
   }
   
+  protected static <E> ProtobufList<E> newProtobufListWithCapacity(int capacity) {
+    return new ProtobufArrayList<E>(capacity);
+  }
+  
   protected static <E> ProtobufList<E> emptyProtobufList() {
     return ProtobufArrayList.emptyList();
   }
diff --git a/java/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
similarity index 96%
rename from java/src/main/java/com/google/protobuf/IntArrayList.java
rename to java/core/src/main/java/com/google/protobuf/IntArrayList.java
index f7609cc..f4e68ed 100644
--- a/java/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -67,10 +67,17 @@
   private int size;
 
   /**
-   * Constructs a new mutable {@code IntArrayList}.
+   * Constructs a new mutable {@code IntArrayList} with default capacity.
    */
   IntArrayList() {
-    array = new int[DEFAULT_CAPACITY];
+    this(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} with the provided capacity.
+   */
+  IntArrayList(int capacity) {
+    array = new int[capacity];
     size = 0;
   }
 
diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
similarity index 95%
rename from java/src/main/java/com/google/protobuf/Internal.java
rename to java/core/src/main/java/com/google/protobuf/Internal.java
index 1190199..e19b6dc 100644
--- a/java/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -283,10 +283,32 @@
     // ByteString with the same content. This is to ensure that the generated
     // hashCode() method will return the same value as the pure reflection
     // based hashCode() method.
-    return LiteralByteString.hashCode(bytes);
+    return Internal.hashCode(bytes, 0, bytes.length);
+  }
+  
+  /**
+   * Helper method for implementing {@link LiteralByteString#hashCode()}.
+   */
+  static int hashCode(byte[] bytes, int offset, int length) {
+    // The hash code for a byte array should be the same as the hash code for a
+    // ByteString with the same content. This is to ensure that the generated
+    // hashCode() method will return the same value as the pure reflection
+    // based hashCode() method.
+    int h = Internal.partialHash(length, bytes, offset, length);
+    return h == 0 ? 1 : h;
   }
 
   /**
+   * Helper method for continuously hashing bytes.
+   */
+  static int partialHash(int h, byte[] bytes, int offset, int length) {
+    for (int i = offset; i < offset + length; i++) {
+      h = h * 31 + bytes[i];
+    }
+    return h;
+  }
+  
+  /**
    * Helper method for implementing {@link Message#equals(Object)} for bytes
    * field.
    */
@@ -337,8 +359,7 @@
   public static int hashCodeByteBuffer(ByteBuffer bytes) {
     if (bytes.hasArray()) {
       // Fast path.
-      int h = LiteralByteString.hashCode(bytes.capacity(), bytes.array(),
-          bytes.arrayOffset(), bytes.capacity());
+      int h = partialHash(bytes.capacity(), bytes.array(), bytes.arrayOffset(), bytes.capacity());
       return h == 0 ? 1 : h;
     } else {
       // Read the data into a temporary byte array before calculating the
@@ -353,7 +374,7 @@
         final int length = duplicated.remaining() <= bufferSize ?
             duplicated.remaining() : bufferSize;
         duplicated.get(buffer, 0, length);
-        h = LiteralByteString.hashCode(h, buffer, 0, length);
+        h = partialHash(h, buffer, 0, length);
       }
       return h == 0 ? 1 : h;
     }
@@ -385,7 +406,6 @@
   public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
       CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
 
-
   /**
    * Provides an immutable view of {@code List<T>} around a {@code List<F>}.
    *
diff --git a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
similarity index 92%
rename from java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
rename to java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
index 0a76105..85ce7b2 100644
--- a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -46,6 +46,10 @@
     super(description);
   }
 
+  public InvalidProtocolBufferException(IOException e) {
+    super(e.getMessage(), e);
+  }
+
   /**
    * Attaches an unfinished message to the exception to support best-effort
    * parsing in {@code Parser} interface.
@@ -66,6 +70,14 @@
     return unfinishedMessage;
   }
 
+  /**
+   * Unwraps the underlying {@link IOException} if this exception was caused by an I/O
+   * problem. Otherwise, returns {@code this}.
+   */
+  public IOException unwrapIOException() {
+    return getCause() instanceof IOException ? (IOException) getCause() : this;
+  }
+
   static InvalidProtocolBufferException truncatedMessage() {
     return new InvalidProtocolBufferException(
       "While parsing a protocol message, the input ended unexpectedly " +
diff --git a/java/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java
similarity index 98%
rename from java/src/main/java/com/google/protobuf/LazyField.java
rename to java/core/src/main/java/com/google/protobuf/LazyField.java
index 3da8b90..5e0a485 100644
--- a/java/src/main/java/com/google/protobuf/LazyField.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyField.java
@@ -39,14 +39,14 @@
  *
  * Most of key methods are implemented in {@link LazyFieldLite} but this class
  * can contain default instance of the message to provide {@code hashCode()},
- * {@code euqals()} and {@code toString()}.
+ * {@code equals()} and {@code toString()}.
  *
  * @author xiangl@google.com (Xiang Li)
  */
 public class LazyField extends LazyFieldLite {
 
   /**
-   * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and
+   * Carry a message's default instance which is used by {@code hashCode()}, {@code equals()} and
    * {@code toString()}.
    */
   private final MessageLite defaultInstance;
diff --git a/java/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/LazyFieldLite.java
rename to java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/LazyStringArrayList.java
rename to java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
diff --git a/java/src/main/java/com/google/protobuf/LazyStringList.java b/java/core/src/main/java/com/google/protobuf/LazyStringList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/LazyStringList.java
rename to java/core/src/main/java/com/google/protobuf/LazyStringList.java
diff --git a/java/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
similarity index 95%
rename from java/src/main/java/com/google/protobuf/LongArrayList.java
rename to java/core/src/main/java/com/google/protobuf/LongArrayList.java
index 298617f..ebe6202 100644
--- a/java/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -67,10 +67,17 @@
   private int size;
 
   /**
-   * Constructs a new mutable {@code LongArrayList}.
+   * Constructs a new mutable {@code LongArrayList} with default capacity.
    */
   LongArrayList() {
-    array = new long[DEFAULT_CAPACITY];
+    this(DEFAULT_CAPACITY);
+  }
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} with the provided capacity.
+   */
+  LongArrayList(int capacity) {
+    array = new long[capacity];
     size = 0;
   }
 
diff --git a/java/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MapEntry.java
rename to java/core/src/main/java/com/google/protobuf/MapEntry.java
diff --git a/java/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MapEntryLite.java
rename to java/core/src/main/java/com/google/protobuf/MapEntryLite.java
diff --git a/java/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MapField.java
rename to java/core/src/main/java/com/google/protobuf/MapField.java
diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
similarity index 97%
rename from java/src/main/java/com/google/protobuf/MapFieldLite.java
rename to java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index c17fa7b..960b633 100644
--- a/java/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Internal.EnumLite;
+
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -44,7 +46,7 @@
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
  */
-public class MapFieldLite<K, V> implements MutabilityOracle {
+public final class MapFieldLite<K, V> implements MutabilityOracle {
   private MutatabilityAwareMap<K, V> mapData;
   private boolean isMutable;
   
@@ -134,10 +136,11 @@
   
   private static int calculateHashCodeForObject(Object a) {
     if (a instanceof byte[]) {
-      return LiteralByteString.hashCode((byte[]) a);
+      return Internal.hashCode((byte[]) a);
     }
-    if (a instanceof Internal.EnumLite) {
-      return Internal.hashEnum((Internal.EnumLite) a);
+    // Enums should be stored as integers internally.
+    if (a instanceof EnumLite) {
+      throw new UnsupportedOperationException();
     }
     return a.hashCode();
   }
diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/Message.java
rename to java/core/src/main/java/com/google/protobuf/Message.java
diff --git a/java/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageLite.java
rename to java/core/src/main/java/com/google/protobuf/MessageLite.java
diff --git a/java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
rename to java/core/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
diff --git a/java/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageOrBuilder.java
rename to java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
diff --git a/java/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MessageReflection.java
rename to java/core/src/main/java/com/google/protobuf/MessageReflection.java
diff --git a/java/src/main/java/com/google/protobuf/MutabilityOracle.java b/java/core/src/main/java/com/google/protobuf/MutabilityOracle.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/MutabilityOracle.java
rename to java/core/src/main/java/com/google/protobuf/MutabilityOracle.java
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
new file mode 100644
index 0000000..f71e41b
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -0,0 +1,309 @@
+// 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 java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.InvalidMarkException;
+import java.nio.channels.Channels;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A {@link ByteString} that wraps around a {@link ByteBuffer}.
+ */
+final class NioByteString extends ByteString.LeafByteString {
+  private final ByteBuffer buffer;
+
+  NioByteString(ByteBuffer buffer) {
+    if (buffer == null) {
+      throw new NullPointerException("buffer");
+    }
+
+    this.buffer = buffer.slice();
+  }
+
+  // =================================================================
+  // Serializable
+
+  /**
+   * Magic method that lets us override serialization behavior.
+   */
+  private Object writeReplace() {
+    return ByteString.copyFrom(buffer.slice());
+  }
+
+  /**
+   * Magic method that lets us override deserialization behavior.
+   */
+  private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
+    throw new InvalidObjectException("NioByteString instances are not to be serialized directly");
+  }
+
+  // =================================================================
+
+  @Override
+  public byte byteAt(int index) {
+    try {
+      return buffer.get(index);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw e;
+    } catch (IndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException(e.getMessage());
+    }
+  }
+
+  @Override
+  public int size() {
+    return buffer.remaining();
+  }
+
+  @Override
+  public ByteString substring(int beginIndex, int endIndex) {
+    try {
+      ByteBuffer slice = slice(beginIndex, endIndex);
+      return new NioByteString(slice);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw e;
+    } catch (IndexOutOfBoundsException e) {
+      throw new ArrayIndexOutOfBoundsException(e.getMessage());
+    }
+  }
+
+  @Override
+  protected void copyToInternal(
+      byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
+    ByteBuffer slice = buffer.slice();
+    slice.position(sourceOffset);
+    slice.get(target, targetOffset, numberToCopy);
+  }
+
+  @Override
+  public void copyTo(ByteBuffer target) {
+    target.put(buffer.slice());
+  }
+
+  @Override
+  public void writeTo(OutputStream out) throws IOException {
+    writeToInternal(out, buffer.position(), buffer.remaining());
+  }
+
+  @Override
+  boolean equalsRange(ByteString other, int offset, int length) {
+    return substring(0, length).equals(other.substring(offset, offset + length));
+  }
+
+  @Override
+  void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) throws IOException {
+    if (buffer.hasArray()) {
+      // Optimized write for array-backed buffers.
+      // Note that we're taking the risk that a malicious OutputStream could modify the array.
+      int bufferOffset = buffer.arrayOffset() + buffer.position() + sourceOffset;
+      out.write(buffer.array(), bufferOffset, numberToWrite);
+      return;
+    }
+
+    // Slow path
+    if (out instanceof FileOutputStream || numberToWrite >= 8192) {
+      // Use a channel to write out the ByteBuffer.
+      Channels.newChannel(out).write(slice(sourceOffset, sourceOffset + numberToWrite));
+    } else {
+      // Just copy the data to an array and write it.
+      out.write(toByteArray());
+    }
+  }
+
+  @Override
+  public ByteBuffer asReadOnlyByteBuffer() {
+    return buffer.asReadOnlyBuffer();
+  }
+
+  @Override
+  public List<ByteBuffer> asReadOnlyByteBufferList() {
+    return Collections.singletonList(asReadOnlyByteBuffer());
+  }
+
+  @Override
+  protected String toStringInternal(Charset charset) {
+    byte[] bytes;
+    int offset;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      offset = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      offset = 0;
+    }
+    return new String(bytes, offset, size(), charset);
+  }
+
+  @Override
+  public boolean isValidUtf8() {
+    // TODO(nathanmittler): add a ByteBuffer fork for Utf8.isValidUtf8 to avoid the copy
+    byte[] bytes;
+    int startIndex;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      startIndex = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      startIndex = 0;
+    }
+    return Utf8.isValidUtf8(bytes, startIndex, startIndex + size());
+  }
+
+  @Override
+  protected int partialIsValidUtf8(int state, int offset, int length) {
+    // TODO(nathanmittler): TODO add a ByteBuffer fork for Utf8.partialIsValidUtf8 to avoid the copy
+    byte[] bytes;
+    int startIndex;
+    if (buffer.hasArray()) {
+      bytes = buffer.array();
+      startIndex = buffer.arrayOffset() + buffer.position();
+    } else {
+      bytes = toByteArray();
+      startIndex = 0;
+    }
+    return Utf8.partialIsValidUtf8(state, bytes, startIndex, startIndex + size());
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == this) {
+      return true;
+    }
+    if (!(other instanceof ByteString)) {
+      return false;
+    }
+    ByteString otherString = ((ByteString) other);
+    if (size() != otherString.size()) {
+      return false;
+    }
+    if (size() == 0) {
+      return true;
+    }
+    if (other instanceof NioByteString) {
+      return buffer.equals(((NioByteString) other).buffer);
+    }
+    if (other instanceof RopeByteString) {
+      return other.equals(this);
+    }
+    return buffer.equals(otherString.asReadOnlyByteBuffer());
+  }
+
+  @Override
+  protected int partialHash(int h, int offset, int length) {
+    for (int i = offset; i < offset + length; i++) {
+      h = h * 31 + buffer.get(i);
+    }
+    return h;
+  }
+
+  @Override
+  public InputStream newInput() {
+    return new InputStream() {
+      private final ByteBuffer buf = buffer.slice();
+
+      @Override
+      public void mark(int readlimit) {
+        buf.mark();
+      }
+
+      @Override
+      public boolean markSupported() {
+        return true;
+      }
+
+      @Override
+      public void reset() throws IOException {
+        try {
+          buf.reset();
+        } catch (InvalidMarkException e) {
+          throw new IOException(e);
+        }
+      }
+
+      @Override
+      public int available() throws IOException {
+        return buf.remaining();
+      }
+
+      @Override
+      public int read() throws IOException {
+        if (!buf.hasRemaining()) {
+          return -1;
+        }
+        return buf.get() & 0xFF;
+      }
+
+      @Override
+      public int read(byte[] bytes, int off, int len) throws IOException {
+        if (!buf.hasRemaining()) {
+          return -1;
+        }
+
+        len = Math.min(len, buf.remaining());
+        buf.get(bytes, off, len);
+        return len;
+      }
+    };
+  }
+
+  @Override
+  public CodedInputStream newCodedInput() {
+    return CodedInputStream.newInstance(buffer);
+  }
+
+  /**
+   * Creates a slice of a range of this buffer.
+   *
+   * @param beginIndex the beginning index of the slice (inclusive).
+   * @param endIndex the end index of the slice (exclusive).
+   * @return the requested slice.
+   */
+  private ByteBuffer slice(int beginIndex, int endIndex) {
+    if (beginIndex < buffer.position() || endIndex > buffer.limit() || beginIndex > endIndex) {
+      throw new IllegalArgumentException(
+          String.format("Invalid indices [%d, %d]", beginIndex, endIndex));
+    }
+
+    ByteBuffer slice = buffer.slice();
+    slice.position(beginIndex - buffer.position());
+    slice.limit(endIndex - buffer.position());
+    return slice;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
similarity index 92%
rename from java/src/main/java/com/google/protobuf/Parser.java
rename to java/core/src/main/java/com/google/protobuf/Parser.java
index 227c02b..3fa11c3 100644
--- a/java/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import java.io.IOException;
 import java.io.InputStream;
 
 /**
@@ -37,9 +38,20 @@
  *
  * The implementation should be stateless and thread-safe.
  *
+ * <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.
+ *
  * @author liujisi@google.com (Pherl Liu)
  */
 public interface Parser<MessageType> {
+
+  // NB(jh): Other parts of the protobuf API that parse messages distinguish between an I/O problem
+  // (like failure reading bytes from a socket) and invalid data (encoding error) via the type of
+  // thrown exception. But it would be source-incompatible to make the methods in this interface do
+  // so since they were originally spec'ed to only throw InvalidProtocolBufferException. So callers
+  // must inspect the cause of the exception to distinguish these two cases.
+
   /**
    * Parses a message of {@code MessageType} from the input.
    *
diff --git a/java/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
similarity index 97%
rename from java/src/main/java/com/google/protobuf/ProtobufArrayList.java
rename to java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
index 759368c..d2f82ac 100644
--- a/java/src/main/java/com/google/protobuf/ProtobufArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -60,6 +60,10 @@
     list = new ArrayList<E>(toCopy);
   }
   
+  ProtobufArrayList(int capacity) {
+    list = new ArrayList<E>(capacity);
+  }
+  
   @Override
   public void add(int index, E element) {
     ensureIsMutable();
diff --git a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
rename to java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
diff --git a/java/src/main/java/com/google/protobuf/ProtocolStringList.java b/java/core/src/main/java/com/google/protobuf/ProtocolStringList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ProtocolStringList.java
rename to java/core/src/main/java/com/google/protobuf/ProtocolStringList.java
diff --git a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
rename to java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
diff --git a/java/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
similarity index 82%
rename from java/src/main/java/com/google/protobuf/RopeByteString.java
rename to java/core/src/main/java/com/google/protobuf/RopeByteString.java
index 2c33262..8badfab 100644
--- a/java/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -69,7 +69,7 @@
  *
  * @author carlanton@google.com (Carl Haverl)
  */
-class RopeByteString extends ByteString {
+final class RopeByteString extends ByteString {
 
   /**
    * BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
@@ -151,21 +151,24 @@
    * @return concatenation representing the same sequence as the given strings
    */
   static ByteString concatenate(ByteString left, ByteString right) {
-    ByteString result;
-    RopeByteString leftRope =
-        (left instanceof RopeByteString) ? (RopeByteString) left : null;
     if (right.size() == 0) {
-      result = left;
-    } else if (left.size() == 0) {
-      result = right;
-    } else {
-      int newLength = left.size() + right.size();
-      if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
-        // Optimization from BAP95: For short (leaves in paper, but just short
-        // here) total length, do a copy of data to a new leaf.
-        result = concatenateBytes(left, right);
-      } else if (leftRope != null
-          && leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
+      return left;
+    }
+
+    if (left.size() == 0) {
+      return right;
+    }
+
+    final int newLength = left.size() + right.size();
+    if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
+      // Optimization from BAP95: For short (leaves in paper, but just short
+      // here) total length, do a copy of data to a new leaf.
+      return concatenateBytes(left, right);
+    }
+
+    if (left instanceof RopeByteString) {
+      final RopeByteString leftRope = (RopeByteString) left;
+      if (leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
         // Optimization from BAP95: As an optimization of the case where the
         // ByteString is constructed by repeated concatenate, recognize the case
         // where a short string is concatenated to a left-hand node whose
@@ -177,30 +180,29 @@
         // new parent node so that the depth of the result is the same as the
         // given left tree.
         ByteString newRight = concatenateBytes(leftRope.right, right);
-        result = new RopeByteString(leftRope.left, newRight);
-      } else if (leftRope != null
-          && leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
+        return new RopeByteString(leftRope.left, newRight);
+      }
+
+      if (leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
           && leftRope.getTreeDepth() > right.getTreeDepth()) {
         // Typically for concatenate-built strings the left-side is deeper than
         // the right.  This is our final attempt to concatenate without
-        // increasing the tree depth.  We'll redo the the node on the RHS.  This
+        // increasing the tree depth.  We'll redo the node on the RHS.  This
         // is yet another optimization for building the string by repeatedly
         // concatenating on the right.
         ByteString newRight = new RopeByteString(leftRope.right, right);
-        result = new RopeByteString(leftRope.left, newRight);
-      } else {
-        // Fine, we'll add a node and increase the tree depth--unless we
-        // rebalance ;^)
-        int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
-        if (newLength >= minLengthByDepth[newDepth]) {
-          // The tree is shallow enough, so don't rebalance
-          result = new RopeByteString(left, right);
-        } else {
-          result = new Balancer().balance(left, right);
-        }
+        return new RopeByteString(leftRope.left, newRight);
       }
     }
-    return result;
+
+    // Fine, we'll add a node and increase the tree depth--unless we rebalance ;^)
+    int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
+    if (newLength >= minLengthByDepth[newDepth]) {
+      // The tree is shallow enough, so don't rebalance
+      return new RopeByteString(left, right);
+    }
+
+    return new Balancer().balance(left, right);
   }
 
   /**
@@ -211,14 +213,14 @@
    * @param right string on the right
    * @return string formed by copying data bytes
    */
-  private static LiteralByteString concatenateBytes(ByteString left,
+  private static ByteString concatenateBytes(ByteString left,
       ByteString right) {
     int leftSize = left.size();
     int rightSize = right.size();
     byte[] bytes = new byte[leftSize + rightSize];
     left.copyTo(bytes, 0, 0, leftSize);
     right.copyTo(bytes, 0, leftSize, rightSize);
-    return new LiteralByteString(bytes);  // Constructor wraps bytes
+    return ByteString.wrap(bytes);  // Constructor wraps bytes
   }
 
   /**
@@ -248,22 +250,14 @@
    */
   @Override
   public byte byteAt(int index) {
-    if (index < 0) {
-      throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
-    }
-    if (index > totalLength) {
-      throw new ArrayIndexOutOfBoundsException(
-          "Index > length: " + index + ", " + totalLength);
-    }
+    checkIndex(index, totalLength);
 
-    byte result;
     // Find the relevant piece by recursive descent
     if (index < leftLength) {
-      result = left.byteAt(index);
-    } else {
-      result = right.byteAt(index - leftLength);
+      return left.byteAt(index);
     }
-    return result;
+
+    return right.byteAt(index - leftLength);
   }
 
   @Override
@@ -309,48 +303,36 @@
    */
   @Override
   public ByteString substring(int beginIndex, int endIndex) {
-    if (beginIndex < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index: " + beginIndex + " < 0");
-    }
-    if (endIndex > totalLength) {
-      throw new IndexOutOfBoundsException(
-          "End index: " + endIndex + " > " + totalLength);
-    }
-    int substringLength = endIndex - beginIndex;
-    if (substringLength < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index larger than ending index: " + beginIndex + ", "
-              + endIndex);
+    final int length = checkRange(beginIndex, endIndex, totalLength);
+
+    if (length == 0) {
+      // Empty substring
+      return ByteString.EMPTY;
     }
 
-    ByteString result;
-    if (substringLength == 0) {
-      // Empty substring
-      result = ByteString.EMPTY;
-    } else if (substringLength == totalLength) {
+    if (length == totalLength) {
       // The whole string
-      result = this;
-    } else {
-      // Proper substring
-      if (endIndex <= leftLength) {
-        // Substring on the left
-        result = left.substring(beginIndex, endIndex);
-      } else if (beginIndex >= leftLength) {
-        // Substring on the right
-        result = right
-            .substring(beginIndex - leftLength, endIndex - leftLength);
-      } else {
-        // Split substring
-        ByteString leftSub = left.substring(beginIndex);
-        ByteString rightSub = right.substring(0, endIndex - leftLength);
-        // Intentionally not rebalancing, since in many cases these two
-        // substrings will already be less deep than the top-level
-        // RopeByteString we're taking a substring of.
-        result = new RopeByteString(leftSub, rightSub);
-      }
+      return this;
     }
-    return result;
+
+    // Proper substring
+    if (endIndex <= leftLength) {
+      // Substring on the left
+      return left.substring(beginIndex, endIndex);
+    }
+
+    if (beginIndex >= leftLength) {
+      // Substring on the right
+      return right.substring(beginIndex - leftLength, endIndex - leftLength);
+    }
+
+    // Split substring
+    ByteString leftSub = left.substring(beginIndex);
+    ByteString rightSub = right.substring(0, endIndex - leftLength);
+    // Intentionally not rebalancing, since in many cases these two
+    // substrings will already be less deep than the top-level
+    // RopeByteString we're taking a substring of.
+    return new RopeByteString(leftSub, rightSub);
   }
 
   // =================================================================
@@ -391,7 +373,7 @@
     List<ByteBuffer> result = new ArrayList<ByteBuffer>();
     PieceIterator pieces = new PieceIterator(this);
     while (pieces.hasNext()) {
-      LiteralByteString byteString = pieces.next();
+      LeafByteString byteString = pieces.next();
       result.add(byteString.asReadOnlyByteBuffer());
     }
     return result;
@@ -471,11 +453,10 @@
     // hashCode if it's already computed.  It's arguable we should compute the
     // hashCode here, and if we're going to be testing a bunch of byteStrings,
     // it might even make sense.
-    if (hash != 0) {
-      int cachedOtherHash = otherByteString.peekCachedHashCode();
-      if (cachedOtherHash != 0 && hash != cachedOtherHash) {
-        return false;
-      }
+    int thisHash = peekCachedHashCode();
+    int thatHash = otherByteString.peekCachedHashCode();
+    if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) {
+      return false;
     }
 
     return equalsFragments(otherByteString);
@@ -492,12 +473,12 @@
    */
   private boolean equalsFragments(ByteString other) {
     int thisOffset = 0;
-    Iterator<LiteralByteString> thisIter = new PieceIterator(this);
-    LiteralByteString thisString = thisIter.next();
+    Iterator<LeafByteString> thisIter = new PieceIterator(this);
+    LeafByteString thisString = thisIter.next();
 
     int thatOffset = 0;
-    Iterator<LiteralByteString> thatIter = new PieceIterator(other);
-    LiteralByteString thatString = thatIter.next();
+    Iterator<LeafByteString> thatIter = new PieceIterator(other);
+    LeafByteString thatString = thatIter.next();
 
     int pos = 0;
     while (true) {
@@ -536,33 +517,6 @@
     }
   }
 
-  /**
-   * Cached hash value.  Intentionally accessed via a data race, which is safe
-   * because of the Java Memory Model's "no out-of-thin-air values" guarantees
-   * for ints.
-   */
-  private int hash = 0;
-
-  @Override
-  public int hashCode() {
-    int h = hash;
-
-    if (h == 0) {
-      h = totalLength;
-      h = partialHash(h, 0, totalLength);
-      if (h == 0) {
-        h = 1;
-      }
-      hash = h;
-    }
-    return h;
-  }
-
-  @Override
-  protected int peekCachedHashCode() {
-    return hash;
-  }
-
   @Override
   protected int partialHash(int h, int offset, int length) {
     int toIndex = offset + length;
@@ -714,34 +668,34 @@
    * <p>This iterator is used to implement
    * {@link RopeByteString#equalsFragments(ByteString)}.
    */
-  private static class PieceIterator implements Iterator<LiteralByteString> {
+  private static class PieceIterator implements Iterator<LeafByteString> {
 
     private final Stack<RopeByteString> breadCrumbs =
         new Stack<RopeByteString>();
-    private LiteralByteString next;
+    private LeafByteString next;
 
     private PieceIterator(ByteString root) {
       next = getLeafByLeft(root);
     }
 
-    private LiteralByteString getLeafByLeft(ByteString root) {
+    private LeafByteString getLeafByLeft(ByteString root) {
       ByteString pos = root;
       while (pos instanceof RopeByteString) {
         RopeByteString rbs = (RopeByteString) pos;
         breadCrumbs.push(rbs);
         pos = rbs.left;
       }
-      return (LiteralByteString) pos;
+      return (LeafByteString) pos;
     }
 
-    private LiteralByteString getNextNonEmptyLeaf() {
+    private LeafByteString getNextNonEmptyLeaf() {
       while (true) {
         // Almost always, we go through this loop exactly once.  However, if
         // we discover an empty string in the rope, we toss it and try again.
         if (breadCrumbs.isEmpty()) {
           return null;
         } else {
-          LiteralByteString result = getLeafByLeft(breadCrumbs.pop().right);
+          LeafByteString result = getLeafByLeft(breadCrumbs.pop().right);
           if (!result.isEmpty()) {
             return result;
           }
@@ -749,6 +703,7 @@
       }
     }
 
+    @Override
     public boolean hasNext() {
       return next != null;
     }
@@ -758,15 +713,17 @@
      *
      * @return next non-empty LiteralByteString or {@code null}
      */
-    public LiteralByteString next() {
+    @Override
+    public LeafByteString next() {
       if (next == null) {
         throw new NoSuchElementException();
       }
-      LiteralByteString result = next;
+      LeafByteString result = next;
       next = getNextNonEmptyLeaf();
       return result;
     }
 
+    @Override
     public void remove() {
       throw new UnsupportedOperationException();
     }
@@ -778,55 +735,14 @@
   private static final long serialVersionUID = 1L;
 
   Object writeReplace() {
-    return new LiteralByteString(toByteArray());
+    return ByteString.wrap(toByteArray());
   }
 
-  private void readObject(ObjectInputStream in) throws IOException {
+  private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
     throw new InvalidObjectException(
         "RopeByteStream instances are not to be serialized directly");
   }
 
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new RopeByteIterator();
-  }
-
-  private class RopeByteIterator implements ByteString.ByteIterator {
-
-    private final PieceIterator pieces;
-    private ByteIterator bytes;
-    int bytesRemaining;
-
-    private RopeByteIterator() {
-      pieces = new PieceIterator(RopeByteString.this);
-      bytes = pieces.next().iterator();
-      bytesRemaining = size();
-    }
-
-    public boolean hasNext() {
-      return (bytesRemaining > 0);
-    }
-
-    public Byte next() {
-      return nextByte(); // Does not instantiate a Byte
-    }
-
-    public byte nextByte() {
-      if (!bytes.hasNext()) {
-        bytes = pieces.next().iterator();
-      }
-      --bytesRemaining;
-      return bytes.nextByte();
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-
   /**
    * This class is the {@link RopeByteString} equivalent for
    * {@link ByteArrayInputStream}.
@@ -835,7 +751,7 @@
     // Iterates through the pieces of the rope
     private PieceIterator pieceIterator;
     // The current piece
-    private LiteralByteString currentPiece;
+    private LeafByteString currentPiece;
     // The size of the current piece
     private int currentPieceSize;
     // The index of the next byte to read in the current piece
@@ -872,7 +788,7 @@
     /**
      * Internal implementation of read and skip.  If b != null, then read the
      * next {@code length} bytes into the buffer {@code b} at
-     * offset {@code offset}.  If b == null, then skip the next {@code length)
+     * offset {@code offset}.  If b == null, then skip the next {@code length}
      * bytes.
      * <p>
      * This method assumes that all error checking has already happened.
diff --git a/java/src/main/java/com/google/protobuf/RpcCallback.java b/java/core/src/main/java/com/google/protobuf/RpcCallback.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcCallback.java
rename to java/core/src/main/java/com/google/protobuf/RpcCallback.java
diff --git a/java/src/main/java/com/google/protobuf/RpcChannel.java b/java/core/src/main/java/com/google/protobuf/RpcChannel.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcChannel.java
rename to java/core/src/main/java/com/google/protobuf/RpcChannel.java
diff --git a/java/src/main/java/com/google/protobuf/RpcController.java b/java/core/src/main/java/com/google/protobuf/RpcController.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcController.java
rename to java/core/src/main/java/com/google/protobuf/RpcController.java
diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/RpcUtil.java
rename to java/core/src/main/java/com/google/protobuf/RpcUtil.java
diff --git a/java/src/main/java/com/google/protobuf/Service.java b/java/core/src/main/java/com/google/protobuf/Service.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/Service.java
rename to java/core/src/main/java/com/google/protobuf/Service.java
diff --git a/java/src/main/java/com/google/protobuf/ServiceException.java b/java/core/src/main/java/com/google/protobuf/ServiceException.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/ServiceException.java
rename to java/core/src/main/java/com/google/protobuf/ServiceException.java
diff --git a/java/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/SingleFieldBuilder.java
rename to java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
diff --git a/java/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/SmallSortedMap.java
rename to java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
similarity index 96%
rename from java/src/main/java/com/google/protobuf/TextFormat.java
rename to java/core/src/main/java/com/google/protobuf/TextFormat.java
index b4f4ce7..c99b528 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -119,6 +119,21 @@
   }
 
   /**
+   * Generates a human readable form of the field, useful for debugging
+   * and other purposes, with no newline characters.
+   */
+  public static String shortDebugString(final FieldDescriptor field,
+                                        final Object value) {
+    try {
+      final StringBuilder sb = new StringBuilder();
+      SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
+      return sb.toString().trim();
+    } catch (IOException e) {
+        throw new IllegalStateException(e);
+    }
+  }
+
+  /**
    * Generates a human readable form of the unknown fields, useful for debugging
    * and other purposes, with no newline characters.
    */
@@ -1059,6 +1074,18 @@
     private ParseException floatParseException(final NumberFormatException e) {
       return parseException("Couldn't parse number: " + e.getMessage());
     }
+    
+    /**
+     * Returns a {@link UnknownFieldParseException} with the line and column
+     * numbers of the previous token in the description, and the unknown field
+     * name, suitable for throwing.
+     */
+    public UnknownFieldParseException unknownFieldParseExceptionPreviousToken(
+        final String unknownField, final String description) {
+      // Note:  People generally prefer one-based line and column numbers.
+      return new UnknownFieldParseException(
+        previousLine + 1, previousColumn + 1, unknownField, description);
+    }
   }
 
   /** Thrown when parsing an invalid text format message. */
@@ -1106,6 +1133,45 @@
       return column;
     }
   }
+  
+  /**
+   * Thrown when encountering an unknown field while parsing
+   * a text format message.
+   */
+  public static class UnknownFieldParseException extends ParseException {
+    private final String unknownField;
+
+    /**
+     * Create a new instance, with -1 as the line and column numbers, and an
+     * empty unknown field name.
+     */
+    public UnknownFieldParseException(final String message) {
+      this(-1, -1, "", message);
+    }
+
+    /**
+     * Create a new instance
+     *
+     * @param line the line number where the parse error occurred,
+     * using 1-offset.
+     * @param column the column number where the parser error occurred,
+     * using 1-offset.
+     * @param unknownField the name of the unknown field found while parsing.
+     */
+    public UnknownFieldParseException(final int line, final int column,
+        final String unknownField, final String message) {
+      super(line, column, message);
+      this.unknownField = unknownField;
+    }
+
+    /**
+     * Return the name of the unknown field encountered while parsing the
+     * protocol buffer string.
+     */
+    public String getUnknownField() {
+      return unknownField;
+    }
+  }
 
   private static final Parser PARSER = Parser.newBuilder().build();
 
@@ -1373,7 +1439,8 @@
 
         if (field == null) {
           if (!allowUnknownFields) {
-            throw tokenizer.parseExceptionPreviousToken(
+            throw tokenizer.unknownFieldParseExceptionPreviousToken(
+              name,
               "Message type \"" + type.getFullName()
               + "\" has no field named \"" + name + "\".");
           } else {
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java
diff --git a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java b/java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/UninitializedMessageException.java
rename to java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/UnknownFieldSet.java
rename to java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
similarity index 60%
rename from java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
rename to java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
index 45d5fc3..435ad4d 100644
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -45,12 +45,13 @@
  * @author dweis@google.com (Daniel Weis)
  */
 public final class UnknownFieldSetLite {
-
-  private static final int[] EMPTY_INT_ARRAY = new int[0];
-  private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+  
+  // Arbitrarily chosen.
+  // TODO(dweis): Tune this number?
+  private static final int MIN_CAPACITY = 8;
 
   private static final UnknownFieldSetLite DEFAULT_INSTANCE =
-      new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY);
+      new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */);
 
   /**
    * Get an empty {@code UnknownFieldSetLite}.
@@ -62,25 +63,32 @@
   }
 
   /**
-   * Create a new {@link Builder}.
+   * Returns an empty {@code UnknownFieldSetLite.Builder}.
    *
    * <p>For use by generated code only.
    */
   public static Builder newBuilder() {
     return new Builder();
   }
+  
+  /**
+   * Returns a new mutable instance.
+   */
+  static UnknownFieldSetLite newInstance() {
+    return new UnknownFieldSetLite();
+  }
 
   /**
-   * Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and
+   * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and
    * {@code second}.
    */
-  static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) {
+  static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) {
     int count = first.count + second.count;
     int[] tags = Arrays.copyOf(first.tags, count);
     System.arraycopy(second.tags, 0, tags, first.count, second.count);
     Object[] objects = Arrays.copyOf(first.objects, count);
     System.arraycopy(second.objects, 0, objects, first.count, second.count);
-    return new UnknownFieldSetLite(count, tags, objects);
+    return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
   }
   
   /**
@@ -102,14 +110,45 @@
    * The lazily computed serialized size of the set.
    */
   private int memoizedSerializedSize = -1;
+  
+  /**
+   * Indicates that this object is mutable. 
+   */
+  private boolean isMutable;
 
   /**
+   * Constructs a mutable {@code UnknownFieldSetLite}.
+   */
+  private UnknownFieldSetLite() {
+    this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */);
+  }
+  
+  /**
    * Constructs the {@code UnknownFieldSetLite}.
    */
-  private UnknownFieldSetLite(int count, int[] tags, Object[] objects) {
+  private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) {
     this.count = count;
     this.tags = tags;
     this.objects = objects;
+    this.isMutable = isMutable;
+  }
+  
+  /**
+   * Marks this object as immutable.
+   * 
+   * <p>Future calls to methods that attempt to modify this object will throw.
+   */
+  public void makeImmutable() {
+    this.isMutable = false;
+  }
+  
+  /**
+   * Throws an {@link UnsupportedOperationException} if immutable.
+   */
+  void checkMutable() {
+    if (!isMutable) {
+      throw new UnsupportedOperationException(); 
+    }
   }
 
   /**
@@ -223,6 +262,114 @@
     return hashCode;
   }
 
+  private void storeField(int tag, Object value) {
+    ensureCapacity();
+    
+    tags[count] = tag;
+    objects[count] = value;
+    count++;
+  }
+  
+  /**
+   * Ensures that our arrays are long enough to store more metadata.
+   */
+  private void ensureCapacity() {
+    if (count == tags.length) {        
+      int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
+      int newLength = count + increment;
+        
+      tags = Arrays.copyOf(tags, newLength);
+      objects = Arrays.copyOf(objects, newLength);
+    }
+  }
+  
+  /**
+   * Parse a single field from {@code input} and merge it into this set.
+   *
+   * <p>For use by generated code only.
+   *
+   * @param tag The field's tag number, which was already parsed.
+   * @return {@code false} if the tag is an end group tag.
+   */
+  boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
+    checkMutable();
+    final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+    switch (WireFormat.getTagWireType(tag)) {
+      case WireFormat.WIRETYPE_VARINT:
+        storeField(tag, input.readInt64());
+        return true;
+      case WireFormat.WIRETYPE_FIXED32:
+        storeField(tag, input.readFixed32());
+        return true;
+      case WireFormat.WIRETYPE_FIXED64:
+        storeField(tag, input.readFixed64());
+        return true;
+      case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+        storeField(tag, input.readBytes());
+        return true;
+      case WireFormat.WIRETYPE_START_GROUP:
+        final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite();
+        subFieldSet.mergeFrom(input);
+        input.checkLastTagWas(
+            WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+        storeField(tag, subFieldSet);
+        return true;
+      case WireFormat.WIRETYPE_END_GROUP:
+        return false;
+      default:
+        throw InvalidProtocolBufferException.invalidWireType();
+    }
+  }
+
+  /**
+   * Convenience method for merging a new field containing a single varint
+   * value. This is used in particular when an unknown enum value is
+   * encountered.
+   *
+   * <p>For use by generated code only.
+   */
+  UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) {
+    checkMutable();
+    if (fieldNumber == 0) {
+      throw new IllegalArgumentException("Zero is not a valid field number.");
+    }
+
+    storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
+    
+    return this;
+  }
+
+  /**
+   * Convenience method for merging a length-delimited field.
+   *
+   * <p>For use by generated code only.
+   */
+  UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {  
+    checkMutable();
+    if (fieldNumber == 0) {
+      throw new IllegalArgumentException("Zero is not a valid field number.");
+    }
+
+    storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
+    
+    return this;
+  }
+  
+  /**
+   * Parse an entire message from {@code input} and merge its fields into
+   * this set.
+   */
+  private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException {
+    // Ensures initialization in mergeFieldFrom.
+    while (true) {
+      final int tag = input.readTag();
+      if (tag == 0 || !mergeFieldFrom(tag, input)) {
+        break;
+      }
+    }
+    return this;
+  }
+  
   /**
    * Builder for {@link UnknownFieldSetLite}s.
    *
@@ -230,54 +377,27 @@
    *
    * <p>For use by generated code only.
    */
+  // TODO(dweis): Update the mutable API to no longer need this builder and delete.
   public static final class Builder {
-    
-    // Arbitrarily chosen.
-    // TODO(dweis): Tune this number?
-    private static final int MIN_CAPACITY = 8;
-    
-    private int count = 0;
-    private int[] tags = EMPTY_INT_ARRAY;
-    private Object[] objects = EMPTY_OBJECT_ARRAY;
 
-    private boolean built;
-
-    /**
-     * Constructs a {@code Builder}.
-     */
-    private Builder() {}
+    private UnknownFieldSetLite set;
+    
+    private Builder() {
+      this.set = null;
+    }
 
     /**
      * Ensures internal state is initialized for use.
      */
     private void ensureNotBuilt() {
-      if (built) {
-        throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
+      if (set == null) {
+        set = new UnknownFieldSetLite();
       }
-    }
-    
-    private void storeField(int tag, Object value) {
-      ensureCapacity();
       
-      tags[count] = tag;
-      objects[count] = value;
-      count++;
+      set.checkMutable();
     }
     
     /**
-     * Ensures that our arrays are long enough to store more metadata.
-     */
-    private void ensureCapacity() {
-      if (count == tags.length) {        
-        int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
-        int newLength = count + increment;
-          
-        tags = Arrays.copyOf(tags, newLength);
-        objects = Arrays.copyOf(objects, newLength);
-      }
-    }
-
-    /**
      * Parse a single field from {@code input} and merge it into this set.
      *
      * <p>For use by generated code only.
@@ -285,36 +405,9 @@
      * @param tag The field's tag number, which was already parsed.
      * @return {@code false} if the tag is an end group tag.
      */
-    public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
-                                  throws IOException {
+    boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
       ensureNotBuilt();
-
-      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
-      switch (WireFormat.getTagWireType(tag)) {
-        case WireFormat.WIRETYPE_VARINT:
-          storeField(tag, input.readInt64());
-          return true;
-        case WireFormat.WIRETYPE_FIXED32:
-          storeField(tag, input.readFixed32());
-          return true;
-        case WireFormat.WIRETYPE_FIXED64:
-          storeField(tag, input.readFixed64());
-          return true;
-        case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-          storeField(tag, input.readBytes());
-          return true;
-        case WireFormat.WIRETYPE_START_GROUP:
-          final Builder subBuilder = newBuilder();
-          subBuilder.mergeFrom(input);
-          input.checkLastTagWas(
-              WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
-          storeField(tag, subBuilder.build());
-          return true;
-        case WireFormat.WIRETYPE_END_GROUP:
-          return false;
-        default:
-          throw InvalidProtocolBufferException.invalidWireType();
-      }
+      return set.mergeFieldFrom(tag, input);
     }
 
     /**
@@ -324,71 +417,42 @@
      *
      * <p>For use by generated code only.
      */
-    public Builder mergeVarintField(int fieldNumber, int value) {
-      if (fieldNumber == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
+    Builder mergeVarintField(int fieldNumber, int value) {
       ensureNotBuilt();
-
-      storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
-      
+      set.mergeVarintField(fieldNumber, value);
       return this;
     }
-
+    
     /**
      * Convenience method for merging a length-delimited field.
      *
      * <p>For use by generated code only.
      */
-    public Builder mergeLengthDelimitedField(
-        final int fieldNumber, final ByteString value) {  
-      if (fieldNumber == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      ensureNotBuilt();
-
-      storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
-      
+    public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
+      ensureNotBuilt();  
+      set.mergeLengthDelimitedField(fieldNumber, value);
       return this;
     }
     
     /**
-     * Parse an entire message from {@code input} and merge its fields into
-     * this set.
-     */
-    private Builder mergeFrom(final CodedInputStream input) throws IOException {
-      // Ensures initialization in mergeFieldFrom.
-      while (true) {
-        final int tag = input.readTag();
-        if (tag == 0 || !mergeFieldFrom(tag, input)) {
-          break;
-        }
-      }
-      return this;
-    }
-
-    /**
      * Build the {@link UnknownFieldSetLite} and return it.
      *
      * <p>Once {@code build()} has been called, the {@code Builder} will no
      * longer be usable.  Calling any method after {@code build()} will result
-     * in undefined behavior and can cause a {@code IllegalStateException} to be
-     * thrown.
+     * in undefined behavior and can cause an
+     * {@code UnsupportedOperationException} to be thrown.
      *
      * <p>For use by generated code only.
      */
     public UnknownFieldSetLite build() {
-      if (built) {
-        throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
-      }
-
-      built = true;
-      
-      if (count == 0) {
+      if (set == null) {
         return DEFAULT_INSTANCE;
       }
+      
+      set.checkMutable();
+      set.makeImmutable();
 
-      return new UnknownFieldSetLite(count, tags, objects);
+      return set;
     }
   }
 }
diff --git a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
rename to java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
new file mode 100644
index 0000000..f443ee3
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -0,0 +1,63 @@
+// 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 java.nio.ByteBuffer;
+
+/**
+ * Provides a number of unsafe byte operations to be used by advanced applications with high
+ * performance requirements. These methods are referred to as "unsafe" due to the fact that they
+ * potentially expose the backing buffer of a {@link ByteString} to the application.
+ *
+ * <p><strong>DISCLAIMER:</strong> The methods in this class should only be called if it is
+ * guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a
+ * {@link ByteString} can lead to unexpected and undesirable consequences in your application,
+ * and will likely be difficult to debug. Proceed with caution!
+ */
+@ExperimentalApi
+public final class UnsafeByteOperations {
+  private UnsafeByteOperations() {}
+
+  /**
+   * An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer.
+   *
+   * @param buffer the Java NIO buffer to be wrapped.
+   * @return a {@link ByteString} backed by the provided buffer.
+   */
+  public static ByteString unsafeWrap(ByteBuffer buffer) {
+    if (buffer.hasArray()) {
+      final int offset = buffer.arrayOffset();
+      return ByteString.wrap(buffer.array(), offset + buffer.position(), buffer.remaining());
+    } else {
+      return new NioByteString(buffer);
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
similarity index 97%
rename from java/src/main/java/com/google/protobuf/Utf8.java
rename to java/core/src/main/java/com/google/protobuf/Utf8.java
index 0699778..48c7e9e 100644
--- a/java/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -360,8 +360,8 @@
   
   static class UnpairedSurrogateException extends IllegalArgumentException {
     
-    private UnpairedSurrogateException(int index) {
-      super("Unpaired surrogate at index " + index);
+    private UnpairedSurrogateException(int index, int length) {
+      super("Unpaired surrogate at index " + index + " of " + length);
     }
   }
   
@@ -417,7 +417,7 @@
           // Check that we have a well-formed surrogate pair.
           int cp = Character.codePointAt(sequence, i);
           if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
-            throw new UnpairedSurrogateException(i);
+            throw new UnpairedSurrogateException(i, utf16Length);
           }
           i++;
         }
@@ -457,7 +457,7 @@
         final char low;
         if (i + 1 == sequence.length()
                 || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
-          throw new UnpairedSurrogateException((i - 1));
+          throw new UnpairedSurrogateException((i - 1), utf16Length);
         }
         int codePoint = Character.toCodePoint(c, low);
         bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
@@ -470,7 +470,7 @@
         if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
             && (i + 1 == sequence.length()
                 || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
-          throw new UnpairedSurrogateException(i);
+          throw new UnpairedSurrogateException(i, utf16Length);
         }
         throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
       }
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/core/src/main/java/com/google/protobuf/WireFormat.java
similarity index 100%
rename from java/src/main/java/com/google/protobuf/WireFormat.java
rename to java/core/src/main/java/com/google/protobuf/WireFormat.java
diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/AbstractMessageTest.java
rename to java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
diff --git a/java/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/AnyTest.java
rename to java/core/src/test/java/com/google/protobuf/AnyTest.java
diff --git a/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
similarity index 97%
rename from java/src/test/java/com/google/protobuf/BooleanArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index df89c26..b8ad1fe 100644
--- a/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -310,10 +310,6 @@
   }
   
   private void assertImmutable(BooleanArrayList list) {
-    if (list.contains(1)) {
-      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
-    }
-    
     try {
       list.add(false);
       fail();
@@ -413,7 +409,7 @@
     }
     
     try {
-      list.removeAll(Collections.singleton(1));
+      list.removeAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -434,7 +430,7 @@
     }
     
     try {
-      list.retainAll(Collections.singleton(1));
+      list.retainAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
similarity index 94%
rename from java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
rename to java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
index 447e6ef..7a8a0a5 100644
--- a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java
@@ -62,7 +62,7 @@
   @Override
   public void testToString() throws UnsupportedEncodingException {
     String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(Internal.UTF_8));
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     ByteString chopped = unicode.substring(2, unicode.size() - 6);
     assertEquals(classUnderTest + ".substring() must have the expected type",
         classUnderTest, getActualClassName(chopped));
@@ -73,9 +73,9 @@
   }
 
   @Override
-  public void testCharsetToString() throws UnsupportedEncodingException {
+  public void testCharsetToString() {
     String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(Internal.UTF_8));
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     ByteString chopped = unicode.substring(2, unicode.size() - 6);
     assertEquals(classUnderTest + ".substring() must have the expected type",
         classUnderTest, getActualClassName(chopped));
diff --git a/java/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
similarity index 97%
rename from java/src/test/java/com/google/protobuf/ByteStringTest.java
rename to java/core/src/test/java/com/google/protobuf/ByteStringTest.java
index 8af5dcd..5267c16 100644
--- a/java/src/test/java/com/google/protobuf/ByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -39,7 +39,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -129,7 +128,7 @@
         isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
   }
 
-  public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
+  public void testCopyFrom_StringEncoding() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString byteString = ByteString.copyFrom(testString, UTF_16);
     byte[] testBytes = testString.getBytes(UTF_16);
@@ -137,7 +136,7 @@
         isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
   }
 
-  public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
+  public void testCopyFrom_Utf8() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString byteString = ByteString.copyFromUtf8(testString);
     byte[] testBytes = testString.getBytes(Internal.UTF_8);
@@ -154,6 +153,7 @@
         isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
     // Call copyFrom on an iteration that's not a collection
     ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
+      @Override
       public Iterator<ByteString> iterator() {
         return pieces.iterator();
       }
@@ -399,7 +399,7 @@
     }
   }
 
-  public void testToStringUtf8() throws UnsupportedEncodingException {
+  public void testToStringUtf8() {
     String testString = "I love unicode \u1234\u5678 characters";
     byte[] testBytes = testString.getBytes(Internal.UTF_8);
     ByteString byteString = ByteString.copyFrom(testBytes);
@@ -419,7 +419,7 @@
 
   // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
   // write sizes
-  public void testNewOutput_ArrayWrite() throws IOException {
+  public void testNewOutput_ArrayWrite() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
     int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
@@ -442,7 +442,7 @@
 
   // Test newOutput() using a variety of buffer sizes, but writing all the
   // characters using write(byte);
-  public void testNewOutput_WriteChar() throws IOException {
+  public void testNewOutput_WriteChar() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
     int[] bufferSizes = {0, 1, 128, 256, length / 2,
@@ -461,7 +461,7 @@
 
   // Test newOutput() in which we write the bytes using a variety of methods
   // and sizes, and in which we repeatedly call toByteString() in the middle.
-  public void testNewOutput_Mixed() throws IOException {
+  public void testNewOutput_Mixed() {
     Random rng = new Random(1);
     byte[] bytes = getTestBytes();
     int length = bytes.length;
@@ -494,7 +494,7 @@
     }
   }
 
-  public void testNewOutputEmpty() throws IOException {
+  public void testNewOutputEmpty() {
     // Make sure newOutput() correctly builds empty byte strings
     ByteString byteString = ByteString.newOutput().toByteString();
     assertEquals(ByteString.EMPTY, byteString);
@@ -655,11 +655,11 @@
     // trees of empty leaves, to make a string that will fail this test.
     for (int i = 1; i < duo.size(); ++i) {
       assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
-          duo.substring(i - 1, i) instanceof LiteralByteString);
+          duo.substring(i - 1, i) instanceof ByteString.LeafByteString);
     }
     for (int i = 1; i < quintet.size(); ++i) {
       assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
-          quintet.substring(i - 1, i) instanceof LiteralByteString);
+          quintet.substring(i - 1, i) instanceof ByteString.LeafByteString);
     }
   }
 
@@ -724,7 +724,7 @@
     }
     data1[1] = (byte) 11;
     // Test LiteralByteString.writeTo(OutputStream,int,int)
-    LiteralByteString left = new LiteralByteString(data1);
+    ByteString left = ByteString.wrap(data1);
     byte[] result = substringUsingWriteTo(left, 1, 1);
     assertEquals(1, result.length);
     assertEquals((byte) 11, result[0]);
@@ -733,7 +733,7 @@
     for (int i = 0; i < data1.length; i++) {
       data2[i] = (byte) 2;
     }
-    LiteralByteString right = new LiteralByteString(data2);
+    ByteString right = ByteString.wrap(data2);
     // Concatenate two ByteStrings to create a RopeByteString.
     ByteString root = left.concat(right);
     // Make sure we are actually testing a RopeByteString with a simple tree
diff --git a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/CheckUtf8Test.java
rename to java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java
diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
rename to java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
similarity index 92%
rename from java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
rename to java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
index 360e759..6018ea5 100644
--- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -37,6 +37,7 @@
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -80,8 +81,8 @@
    * checks that the result matches the given bytes.
    */
   private void assertWriteVarint(byte[] data, long value) throws Exception {
-    // Only do 32-bit write if the value fits in 32 bits.
-    if ((value >>> 32) == 0) {
+    // Only test 32-bit write if the value fits into an int.
+    if (value == (int) value) {
       ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
       CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
       output.writeRawVarint32((int) value);
@@ -107,8 +108,8 @@
 
     // Try different block sizes.
     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
-      // Only do 32-bit write if the value fits in 32 bits.
-      if ((value >>> 32) == 0) {
+      // Only test 32-bit write if the value fits into an int.
+      if (value == (int) value) {
         ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
         CodedOutputStream output =
           CodedOutputStream.newInstance(rawOutput, blockSize);
@@ -128,6 +129,42 @@
     }
   }
 
+  private void assertVarintRoundTrip(long value) throws Exception {
+    {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint64(value);
+      output.flush();
+      byte[] bytes = rawOutput.toByteArray();
+      assertEquals(bytes.length, CodedOutputStream.computeRawVarint64Size(value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(value, input.readRawVarint64());
+    }
+
+    if (value == (int) value) {
+      ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+      CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+      output.writeRawVarint32((int) value);
+      output.flush();
+      byte[] bytes = rawOutput.toByteArray();
+      assertEquals(bytes.length, CodedOutputStream.computeRawVarint32Size((int) value));
+      CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes));
+      assertEquals(value, input.readRawVarint32());
+    }
+  }
+
+  /** Checks that invariants are maintained for varint round trip input and output. */
+  public void testVarintRoundTrips() throws Exception {
+    assertVarintRoundTrip(0L);
+    for (int bits = 0; bits < 64; bits++) {
+      long value = 1L << bits;
+      assertVarintRoundTrip(value);
+      assertVarintRoundTrip(value + 1);
+      assertVarintRoundTrip(value - 1);
+      assertVarintRoundTrip(-value);
+    }
+  }
+
   /** Tests writeRawVarint32() and writeRawVarint64(). */
   public void testWriteVarint() throws Exception {
     assertWriteVarint(bytes(0x00), 0);
diff --git a/java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
rename to java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
similarity index 97%
rename from java/src/test/java/com/google/protobuf/DescriptorsTest.java
rename to java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index edd7fc4..82ff34a 100644
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -46,6 +46,7 @@
 import com.google.protobuf.Descriptors.ServiceDescriptor;
 import com.google.protobuf.test.UnittestImport;
 import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
 import protobuf_unittest.TestCustomOptions;
 import protobuf_unittest.UnittestCustomOptions;
 import protobuf_unittest.UnittestProto;
@@ -115,7 +116,8 @@
     assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
     assertNull(file.findEnumTypeByName("NoSuchType"));
     assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
-    assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
+    assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
+                               ImportEnumForMap.getDescriptor()),
                  UnittestImport.getDescriptor().getEnumTypes());
     for (int i = 0; i < file.getEnumTypes().size(); i++) {
       assertEquals(i, file.getEnumTypes().get(i).getIndex());
@@ -272,6 +274,15 @@
     assertFalse(repeatedField.isRequired());
     assertTrue(repeatedField.isRepeated());
   }
+  
+  public void testFieldDescriptorJsonName() throws Exception {
+    FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
+    FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+    FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+    assertEquals("a", requiredField.getJsonName());
+    assertEquals("optionalInt32", optionalField.getJsonName());
+    assertEquals("repeatedInt32", repeatedField.getJsonName());
+  }
 
   public void testFieldDescriptorDefault() throws Exception {
     Descriptor d = TestAllTypes.getDescriptor();
diff --git a/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/DoubleArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index e7a73d7..d3deaa0 100644
--- a/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -310,7 +310,7 @@
   }
   
   private void assertImmutable(DoubleArrayList list) {
-    if (list.contains(1)) {
+    if (list.contains(1D)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     
@@ -413,7 +413,7 @@
     }
     
     try {
-      list.removeAll(Collections.singleton(1));
+      list.removeAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -434,7 +434,7 @@
     }
     
     try {
-      list.retainAll(Collections.singleton(1));
+      list.retainAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/DynamicMessageTest.java
rename to java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
diff --git a/java/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/FieldPresenceTest.java
rename to java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
diff --git a/java/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/FloatArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index 8f3e93d..a5e6542 100644
--- a/java/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -310,7 +310,7 @@
   }
   
   private void assertImmutable(FloatArrayList list) {
-    if (list.contains(1)) {
+    if (list.contains(1F)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     
@@ -413,7 +413,7 @@
     }
     
     try {
-      list.removeAll(Collections.singleton(1));
+      list.removeAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -434,7 +434,7 @@
     }
     
     try {
-      list.retainAll(Collections.singleton(1));
+      list.retainAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
rename to java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
rename to java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
diff --git a/java/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/IntArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
diff --git a/java/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/IsValidUtf8Test.java
rename to java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
diff --git a/java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
rename to java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyFieldTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyFieldTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
diff --git a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
rename to java/core/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
diff --git a/java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
rename to java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java
diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/LiteTest.java
rename to java/core/src/test/java/com/google/protobuf/LiteTest.java
diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
similarity index 95%
rename from java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
rename to java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 7dfda2a..68b55ce 100644
--- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -75,9 +75,7 @@
   }
 
   protected String getActualClassName(Object object) {
-    String actualClassName = object.getClass().getName();
-    actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
-    return actualClassName;
+    return object.getClass().getSimpleName();
   }
 
   public void testByteAt() {
@@ -350,14 +348,14 @@
 
   public void testToString() throws UnsupportedEncodingException {
     String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(Internal.UTF_8));
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     String roundTripString = unicode.toString(UTF_8);
     assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
   }
 
-  public void testCharsetToString() throws UnsupportedEncodingException {
+  public void testCharsetToString() {
     String testString = "I love unicode \u1234\u5678 characters";
-    LiteralByteString unicode = new LiteralByteString(testString.getBytes(Internal.UTF_8));
+    ByteString unicode = ByteString.wrap(testString.getBytes(Internal.UTF_8));
     String roundTripString = unicode.toString(Internal.UTF_8);
     assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
   }
@@ -365,7 +363,7 @@
   public void testToString_returnsCanonicalEmptyString() {
     assertSame(classUnderTest + " must be the same string references",
         ByteString.EMPTY.toString(Internal.UTF_8),
-        new LiteralByteString(new byte[]{}).toString(Internal.UTF_8));
+        ByteString.wrap(new byte[]{}).toString(Internal.UTF_8));
   }
 
   public void testToString_raisesException() {
@@ -377,7 +375,7 @@
     }
 
     try {
-      new LiteralByteString(referenceBytes).toString("invalid");
+      ByteString.wrap(referenceBytes).toString("invalid");
       fail("Should have thrown an exception.");
     } catch (UnsupportedEncodingException expected) {
       // This is success
@@ -390,15 +388,15 @@
     assertFalse(classUnderTest + " must not equal the empty string",
         stringUnderTest.equals(ByteString.EMPTY));
     assertEquals(classUnderTest + " empty strings must be equal",
-        new LiteralByteString(new byte[]{}), stringUnderTest.substring(55, 55));
+        ByteString.wrap(new byte[]{}), stringUnderTest.substring(55, 55));
     assertEquals(classUnderTest + " must equal another string with the same value",
-        stringUnderTest, new LiteralByteString(referenceBytes));
+        stringUnderTest, ByteString.wrap(referenceBytes));
 
     byte[] mungedBytes = new byte[referenceBytes.length];
     System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
     mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
     assertFalse(classUnderTest + " must not equal every string with the same length",
-        stringUnderTest.equals(new LiteralByteString(mungedBytes)));
+        stringUnderTest.equals(ByteString.wrap(mungedBytes)));
   }
 
   public void testHashCode() {
diff --git a/java/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/LongArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index 3a52ec7..1bd094f 100644
--- a/java/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -310,7 +310,7 @@
   }
   
   private void assertImmutable(LongArrayList list) {
-    if (list.contains(1)) {
+    if (list.contains(1L)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
     
@@ -413,7 +413,7 @@
     }
     
     try {
-      list.removeAll(Collections.singleton(1));
+      list.removeAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -434,7 +434,7 @@
     }
     
     try {
-      list.retainAll(Collections.singleton(1));
+      list.retainAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
rename to java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/MapForProto2Test.java
rename to java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/MapTest.java
rename to java/core/src/test/java/com/google/protobuf/MapTest.java
diff --git a/java/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/MessageTest.java
rename to java/core/src/test/java/com/google/protobuf/MessageTest.java
diff --git a/java/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/NestedBuildersTest.java
rename to java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
new file mode 100644
index 0000000..e40a366
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -0,0 +1,545 @@
+// 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 static com.google.protobuf.Internal.UTF_8;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for {@link NioByteString}.
+ */
+public class NioByteStringTest extends TestCase {
+  private static final ByteString EMPTY = new NioByteString(ByteBuffer.wrap(new byte[0]));
+  private static final String CLASSNAME = NioByteString.class.getSimpleName();
+  private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L);
+  private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode();
+  private static final ByteBuffer BUFFER = ByteBuffer.wrap(BYTES.clone());
+  private static final ByteString TEST_STRING = new NioByteString(BUFFER);
+
+  public void testExpectedType() {
+    String actualClassName = getActualClassName(TEST_STRING);
+    assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName);
+  }
+
+  protected String getActualClassName(Object object) {
+    String actualClassName = object.getClass().getName();
+    actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
+    return actualClassName;
+  }
+
+  public void testByteAt() {
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < BYTES.length; ++i) {
+      stillEqual = (BYTES[i] == TEST_STRING.byteAt(i));
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+  }
+
+  public void testByteIterator() {
+    boolean stillEqual = true;
+    ByteString.ByteIterator iter = TEST_STRING.iterator();
+    for (int i = 0; stillEqual && i < BYTES.length; ++i) {
+      stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte());
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes", stillEqual);
+    assertFalse(CLASSNAME + " must have exhausted the itertor", iter.hasNext());
+
+    try {
+      iter.nextByte();
+      fail("Should have thrown an exception.");
+    } catch (NoSuchElementException e) {
+      // This is success
+    }
+  }
+
+  public void testByteIterable() {
+    boolean stillEqual = true;
+    int j = 0;
+    for (byte quantum : TEST_STRING) {
+      stillEqual = (BYTES[j] == quantum);
+      ++j;
+    }
+    assertTrue(CLASSNAME + " must capture the right bytes as Bytes", stillEqual);
+    assertEquals(CLASSNAME + " iterable character count", BYTES.length, j);
+  }
+
+  public void testSize() {
+    assertEquals(CLASSNAME + " must have the expected size", BYTES.length,
+        TEST_STRING.size());
+  }
+
+  public void testGetTreeDepth() {
+    assertEquals(CLASSNAME + " must have depth 0", 0, TEST_STRING.getTreeDepth());
+  }
+
+  public void testIsBalanced() {
+    assertTrue(CLASSNAME + " is technically balanced", TEST_STRING.isBalanced());
+  }
+
+  public void testCopyTo_ByteArrayOffsetLength() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+    int sourceOffset = 213;
+    TEST_STRING.copyTo(destination, sourceOffset, destinationOffset, length);
+    boolean stillEqual = true;
+    for (int i = 0; stillEqual && i < length; ++i) {
+      stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset];
+    }
+    assertTrue(CLASSNAME + ".copyTo(4 arg) must give the expected bytes", stillEqual);
+  }
+
+  public void testCopyTo_ByteArrayOffsetLengthErrors() {
+    int destinationOffset = 50;
+    int length = 100;
+    byte[] destination = new byte[destinationOffset + length];
+
+    try {
+      // Copy one too many bytes
+      TEST_STRING.copyTo(destination, TEST_STRING.size() + 1 - length,
+          destinationOffset, length);
+      fail("Should have thrown an exception when copying too many bytes of a "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative sourceOffset
+      TEST_STRING.copyTo(destination, -1, destinationOffset, length);
+      fail("Should have thrown an exception when given a negative sourceOffset in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative destinationOffset
+      TEST_STRING.copyTo(destination, 0, -1, length);
+      fail("Should have thrown an exception when given a negative destinationOffset in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal negative size
+      TEST_STRING.copyTo(destination, 0, 0, -1);
+      fail("Should have thrown an exception when given a negative size in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large sourceOffset
+      TEST_STRING.copyTo(destination, 2 * TEST_STRING.size(), 0, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+
+    try {
+      // Copy with illegal too-large destinationOffset
+      TEST_STRING.copyTo(destination, 0, 2 * destination.length, length);
+      fail("Should have thrown an exception when the destinationOffset is too large in "
+          + CLASSNAME);
+    } catch (IndexOutOfBoundsException expected) {
+      // This is success
+    }
+  }
+
+  public void testCopyTo_ByteBuffer() {
+    // Same length.
+    ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length);
+    TEST_STRING.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes",
+        BUFFER, myBuffer);
+
+    // Target buffer bigger than required.
+    myBuffer = ByteBuffer.allocate(TEST_STRING.size() + 1);
+    TEST_STRING.copyTo(myBuffer);
+    myBuffer.flip();
+    assertEquals(BUFFER, myBuffer);
+
+    // Target buffer has no space.
+    myBuffer = ByteBuffer.allocate(0);
+    try {
+      TEST_STRING.copyTo(myBuffer);
+      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+    } catch (BufferOverflowException e) {
+      // Expected.
+    }
+
+    // Target buffer too small.
+    myBuffer = ByteBuffer.allocate(1);
+    try {
+      TEST_STRING.copyTo(myBuffer);
+      fail("Should have thrown an exception when target ByteBuffer has insufficient capacity");
+    } catch (BufferOverflowException e) {
+      // Expected.
+    }
+  }
+
+  public void testMarkSupported() {
+    InputStream stream = TEST_STRING.newInput();
+    assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported());
+  }
+
+  public void testMarkAndReset() throws IOException {
+    int fraction = TEST_STRING.size() / 3;
+
+    InputStream stream = TEST_STRING.newInput();
+    stream.mark(TEST_STRING.size()); // First, mark() the end.
+
+    skipFully(stream, fraction); // Skip a large fraction, but not all.
+    assertEquals(
+        CLASSNAME + ": after skipping to the 'middle', half the bytes are available",
+        (TEST_STRING.size() - fraction), stream.available());
+    stream.reset();
+    assertEquals(
+        CLASSNAME + ": after resetting, all bytes are available",
+        TEST_STRING.size(), stream.available());
+
+    skipFully(stream, TEST_STRING.size()); // Skip to the end.
+    assertEquals(
+        CLASSNAME + ": after skipping to the end, no more bytes are available",
+        0, stream.available());
+  }
+
+  /**
+   * Discards {@code n} bytes of data from the input stream. This method
+   * will block until the full amount has been skipped. Does not close the
+   * stream.
+   * <p>Copied from com.google.common.io.ByteStreams to avoid adding dependency.
+   *
+   * @param in the input stream to read from
+   * @param n the number of bytes to skip
+   * @throws EOFException if this stream reaches the end before skipping all
+   *     the bytes
+   * @throws IOException if an I/O error occurs, or the stream does not
+   *     support skipping
+   */
+  static void skipFully(InputStream in, long n) throws IOException {
+    long toSkip = n;
+    while (n > 0) {
+      long amt = in.skip(n);
+      if (amt == 0) {
+        // Force a blocking read to avoid infinite loop
+        if (in.read() == -1) {
+          long skipped = toSkip - n;
+          throw new EOFException("reached end of stream after skipping "
+              + skipped + " bytes; " + toSkip + " bytes expected");
+        }
+        n--;
+      } else {
+        n -= amt;
+      }
+    }
+  }
+
+  public void testAsReadOnlyByteBuffer() {
+    ByteBuffer byteBuffer = TEST_STRING.asReadOnlyByteBuffer();
+    byte[] roundTripBytes = new byte[BYTES.length];
+    assertTrue(byteBuffer.remaining() == BYTES.length);
+    assertTrue(byteBuffer.isReadOnly());
+    byteBuffer.get(roundTripBytes);
+    assertTrue(CLASSNAME + ".asReadOnlyByteBuffer() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testAsReadOnlyByteBufferList() {
+    List<ByteBuffer> byteBuffers = TEST_STRING.asReadOnlyByteBufferList();
+    int bytesSeen = 0;
+    byte[] roundTripBytes = new byte[BYTES.length];
+    for (ByteBuffer byteBuffer : byteBuffers) {
+      int thisLength = byteBuffer.remaining();
+      assertTrue(byteBuffer.isReadOnly());
+      assertTrue(bytesSeen + thisLength <= BYTES.length);
+      byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
+      bytesSeen += thisLength;
+    }
+    assertTrue(bytesSeen == BYTES.length);
+    assertTrue(CLASSNAME + ".asReadOnlyByteBufferTest() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testToByteArray() {
+    byte[] roundTripBytes = TEST_STRING.toByteArray();
+    assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testWriteTo() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    TEST_STRING.writeTo(bos);
+    byte[] roundTripBytes = bos.toByteArray();
+    assertTrue(CLASSNAME + ".writeTo() must give back the same bytes",
+        Arrays.equals(BYTES, roundTripBytes));
+  }
+
+  public void testNewOutput() throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    ByteString.Output output = ByteString.newOutput();
+    TEST_STRING.writeTo(output);
+    assertEquals("Output Size returns correct result",
+        output.size(), TEST_STRING.size());
+    output.writeTo(bos);
+    assertTrue("Output.writeTo() must give back the same bytes",
+        Arrays.equals(BYTES, bos.toByteArray()));
+
+    // write the output stream to itself! This should cause it to double
+    output.writeTo(output);
+    assertEquals("Writing an output stream to itself is successful",
+        TEST_STRING.concat(TEST_STRING), output.toByteString());
+
+    output.reset();
+    assertEquals("Output.reset() resets the output", 0, output.size());
+    assertEquals("Output.reset() resets the output",
+        EMPTY, output.toByteString());
+  }
+
+  public void testToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = forString(testString);
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+  }
+
+  public void testCharsetToString() {
+    String testString = "I love unicode \u1234\u5678 characters";
+    ByteString unicode = forString(testString);
+    String roundTripString = unicode.toString(UTF_8);
+    assertEquals(CLASSNAME + " unicode must match", testString, roundTripString);
+  }
+
+  public void testToString_returnsCanonicalEmptyString() {
+    assertSame(CLASSNAME + " must be the same string references",
+        EMPTY.toString(UTF_8),
+        new NioByteString(ByteBuffer.wrap(new byte[0])).toString(UTF_8));
+  }
+
+  public void testToString_raisesException() {
+    try {
+      EMPTY.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+
+    try {
+      TEST_STRING.toString("invalid");
+      fail("Should have thrown an exception.");
+    } catch (UnsupportedEncodingException expected) {
+      // This is success
+    }
+  }
+
+  public void testEquals() {
+    assertEquals(CLASSNAME + " must not equal null", false, TEST_STRING.equals(null));
+    assertEquals(CLASSNAME + " must equal self", TEST_STRING, TEST_STRING);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        EMPTY, TEST_STRING.substring(55, 55));
+    assertEquals(CLASSNAME + " must equal another string with the same value",
+        TEST_STRING, new NioByteString(BUFFER));
+
+    byte[] mungedBytes = mungedBytes();
+    assertFalse(CLASSNAME + " must not equal every string with the same length",
+        TEST_STRING.equals(new NioByteString(ByteBuffer.wrap(mungedBytes))));
+  }
+
+  public void testEqualsLiteralByteString() {
+    ByteString literal = ByteString.copyFrom(BYTES);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal,
+        TEST_STRING);
+    assertEquals(CLASSNAME + " must equal LiteralByteString with same value", TEST_STRING,
+        literal);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(ByteString.EMPTY));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY, TEST_STRING.substring(55, 55));
+
+    literal = ByteString.copyFrom(mungedBytes());
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        TEST_STRING.equals(literal));
+    assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length",
+        literal.equals(TEST_STRING));
+  }
+
+  public void testEqualsRopeByteString() {
+    ByteString p1 = ByteString.copyFrom(BYTES, 0, 5);
+    ByteString p2 = ByteString.copyFrom(BYTES, 5, BYTES.length - 5);
+    ByteString rope = p1.concat(p2);
+
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope,
+        TEST_STRING);
+    assertEquals(CLASSNAME + " must equal RopeByteString with same value", TEST_STRING,
+        rope);
+    assertFalse(CLASSNAME + " must not equal the empty string",
+        TEST_STRING.equals(ByteString.EMPTY.concat(ByteString.EMPTY)));
+    assertEquals(CLASSNAME + " empty strings must be equal",
+        ByteString.EMPTY.concat(ByteString.EMPTY), TEST_STRING.substring(55, 55));
+
+    byte[] mungedBytes = mungedBytes();
+    p1 = ByteString.copyFrom(mungedBytes, 0, 5);
+    p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5);
+    rope = p1.concat(p2);
+    assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
+        TEST_STRING.equals(rope));
+    assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length",
+        rope.equals(TEST_STRING));
+  }
+
+  private byte[] mungedBytes() {
+    byte[] mungedBytes = new byte[BYTES.length];
+    System.arraycopy(BYTES, 0, mungedBytes, 0, BYTES.length);
+    mungedBytes[mungedBytes.length - 5] = (byte) (mungedBytes[mungedBytes.length - 5] ^ 0xFF);
+    return mungedBytes;
+  }
+
+  public void testHashCode() {
+    int hash = TEST_STRING.hashCode();
+    assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash);
+  }
+
+  public void testPeekCachedHashCode() {
+    ByteString newString = new NioByteString(BUFFER);
+    assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0,
+        newString.peekCachedHashCode());
+    newString.hashCode();
+    assertEquals(CLASSNAME + ".peekCachedHashCode should return zero at first",
+        EXPECTED_HASH, newString.peekCachedHashCode());
+  }
+
+  public void testPartialHash() {
+    // partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
+    // This test would fail if the expected hash were 1.  It's not.
+    int hash = TEST_STRING.partialHash(TEST_STRING.size(), 0, TEST_STRING.size());
+    assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode",
+        EXPECTED_HASH, hash);
+  }
+
+  public void testNewInput() throws IOException {
+    InputStream input = TEST_STRING.newInput();
+    assertEquals("InputStream.available() returns correct value",
+        TEST_STRING.size(), input.available());
+    boolean stillEqual = true;
+    for (byte referenceByte : BYTES) {
+      int expectedInt = (referenceByte & 0xFF);
+      stillEqual = (expectedInt == input.read());
+    }
+    assertEquals("InputStream.available() returns correct value",
+        0, input.available());
+    assertTrue(CLASSNAME + " must give the same bytes from the InputStream", stillEqual);
+    assertEquals(CLASSNAME + " InputStream must now be exhausted", -1, input.read());
+  }
+
+  public void testNewInput_skip() throws IOException {
+    InputStream input = TEST_STRING.newInput();
+    int stringSize = TEST_STRING.size();
+    int nearEndIndex = stringSize * 2 / 3;
+    long skipped1 = input.skip(nearEndIndex);
+    assertEquals("InputStream.skip()", skipped1, nearEndIndex);
+    assertEquals("InputStream.available()",
+        stringSize - skipped1, input.available());
+    assertTrue("InputStream.mark() is available", input.markSupported());
+    input.mark(0);
+    assertEquals("InputStream.skip(), read()",
+        TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+    assertEquals("InputStream.available()",
+        stringSize - skipped1 - 1, input.available());
+    long skipped2 = input.skip(stringSize);
+    assertEquals("InputStream.skip() incomplete",
+        skipped2, stringSize - skipped1 - 1);
+    assertEquals("InputStream.skip(), no more input", 0, input.available());
+    assertEquals("InputStream.skip(), no more input", -1, input.read());
+    input.reset();
+    assertEquals("InputStream.reset() succeded",
+        stringSize - skipped1, input.available());
+    assertEquals("InputStream.reset(), read()",
+        TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read());
+  }
+
+  public void testNewCodedInput() throws IOException {
+    CodedInputStream cis = TEST_STRING.newCodedInput();
+    byte[] roundTripBytes = cis.readRawBytes(BYTES.length);
+    assertTrue(CLASSNAME + " must give the same bytes back from the CodedInputStream",
+        Arrays.equals(BYTES, roundTripBytes));
+    assertTrue(CLASSNAME + " CodedInputStream must now be exhausted", cis.isAtEnd());
+  }
+
+  /**
+   * Make sure we keep things simple when concatenating with empty. See also
+   * {@link ByteStringTest#testConcat_empty()}.
+   */
+  public void testConcat_empty() {
+    assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME,
+        TEST_STRING.concat(EMPTY), TEST_STRING);
+    assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME,
+        EMPTY.concat(TEST_STRING), TEST_STRING);
+  }
+
+  public void testJavaSerialization() throws Exception {
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    ObjectOutputStream oos = new ObjectOutputStream(out);
+    oos.writeObject(TEST_STRING);
+    oos.close();
+    byte[] pickled = out.toByteArray();
+    InputStream in = new ByteArrayInputStream(pickled);
+    ObjectInputStream ois = new ObjectInputStream(in);
+    Object o = ois.readObject();
+    assertTrue("Didn't get a ByteString back", o instanceof ByteString);
+    assertEquals("Should get an equal ByteString back", TEST_STRING, o);
+  }
+
+  private static ByteString forString(String str) {
+    return new NioByteString(ByteBuffer.wrap(str.getBytes(UTF_8)));
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
new file mode 100644
index 0000000..37fa242
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -0,0 +1,211 @@
+package com.google.protobuf;
+
+import com.google.protobuf.DescriptorProtos.DescriptorProto;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser}
+ * interface are specified to only throw {@link InvalidProtocolBufferException}. But we really want
+ * to distinguish between invalid protos vs. actual I/O errors (like failures reading from a
+ * socket, etc.). So, when we're not using the parser directly, an {@link IOException} should be
+ * thrown where appropriate, instead of always an {@link InvalidProtocolBufferException}.
+ *
+ * @author jh@squareup.com (Joshua Humphries)
+ */
+public class ParseExceptionsTest {
+
+  private interface ParseTester {
+    DescriptorProto parse(InputStream in) throws IOException;
+  }
+
+  private byte serializedProto[];
+
+  private void setup() {
+    serializedProto = DescriptorProto.getDescriptor().toProto().toByteArray();
+  }
+
+  private void setupDelimited() {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    try {
+      DescriptorProto.getDescriptor().toProto().writeDelimitedTo(bos);
+    } catch (IOException e) {
+      fail("Exception not expected: " + e);
+    }
+    serializedProto = bos.toByteArray();
+  }
+
+  @Test public void message_parseFrom_InputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(in);
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance());
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_CodedInputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(CodedInputStream.newInstance(in));
+      }
+    });
+  }
+
+  @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseFrom(CodedInputStream.newInstance(in),
+            ExtensionRegistry.newInstance());
+      }
+    });
+  }
+
+  @Test public void message_parseDelimitedFrom_InputStream() {
+    setupDelimited();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseDelimitedFrom(in);
+      }
+    });
+  }
+
+  @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() {
+    setupDelimited();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance());
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.newBuilder().mergeFrom(in).build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.newBuilder().mergeFrom(in, ExtensionRegistry.newInstance()).build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_CodedInputStream() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() {
+    setup();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        return DescriptorProto.newBuilder()
+            .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()).build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeDelimitedFrom_InputStream() {
+    setupDelimited();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+        builder.mergeDelimitedFrom(in);
+        return builder.build();
+      }
+    });
+  }
+
+  @Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() {
+    setupDelimited();
+    verifyExceptions(new ParseTester() {
+      public DescriptorProto parse(InputStream in) throws IOException {
+        DescriptorProto.Builder builder = DescriptorProto.newBuilder();
+        builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance());
+        return builder.build();
+      }
+    });
+  }
+
+  private void verifyExceptions(ParseTester parseTester) {
+    // No exception
+    try {
+      assertEquals(DescriptorProto.getDescriptor().toProto(),
+          parseTester.parse(new ByteArrayInputStream(serializedProto)));
+    } catch (IOException e) {
+      fail("No exception expected: " + e);
+    }
+
+    // IOException
+    try {
+      // using a "broken" stream that will throw part-way through reading the message
+      parseTester.parse(broken(new ByteArrayInputStream(serializedProto)));
+      fail("IOException expected but not thrown");
+    } catch (IOException e) {
+      assertFalse(e instanceof InvalidProtocolBufferException);
+    }
+
+    // InvalidProtocolBufferException
+    try {
+      // make the serialized proto invalid
+      for (int i = 0; i < 50; i++) {
+        serializedProto[i] = -1;
+      }
+      parseTester.parse(new ByteArrayInputStream(serializedProto));
+      fail("InvalidProtocolBufferException expected but not thrown");
+    } catch (IOException e) {
+      assertTrue(e instanceof InvalidProtocolBufferException);
+    }
+  }
+
+  private InputStream broken(InputStream i) {
+    return new FilterInputStream(i) {
+      int count = 0;
+
+      @Override public int read() throws IOException {
+        if (count++ >= 50) {
+          throw new IOException("I'm broken!");
+        }
+        return super.read();
+      }
+
+      @Override public int read(byte b[], int off, int len) throws IOException {
+        if ((count += len) >= 50) {
+          throw new IOException("I'm broken!");
+        }
+        return super.read(b, off, len);
+      }
+    };
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/ParserTest.java
rename to java/core/src/test/java/com/google/protobuf/ParserTest.java
diff --git a/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
rename to java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
index f9f5e9c..245c3de 100644
--- a/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -243,7 +243,7 @@
     }
     
     try {
-      list.removeAll(Collections.<Double>emptyList());
+      list.removeAll(Collections.emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
@@ -264,7 +264,7 @@
     }
     
     try {
-      list.retainAll(Collections.<Double>emptyList());
+      list.retainAll(Collections.emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
diff --git a/java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
rename to java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
index cc38559..dc56f2e 100644
--- a/java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java
@@ -96,7 +96,7 @@
   }
 
   @Override
-  public void testCharsetToString() throws UnsupportedEncodingException {
+  public void testCharsetToString() {
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
     int copies = 250;
diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/RopeByteStringTest.java
rename to java/core/src/test/java/com/google/protobuf/RopeByteStringTest.java
diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/ServiceTest.java
rename to java/core/src/test/java/com/google/protobuf/ServiceTest.java
diff --git a/java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
rename to java/core/src/test/java/com/google/protobuf/SingleFieldBuilderTest.java
diff --git a/java/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/SmallSortedMapTest.java
rename to java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java
diff --git a/java/src/test/java/com/google/protobuf/TestBadIdentifiers.java b/java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/TestBadIdentifiers.java
rename to java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
similarity index 97%
rename from java/src/test/java/com/google/protobuf/TestUtil.java
rename to java/core/src/test/java/com/google/protobuf/TestUtil.java
index 792e866..01acb88 100644
--- a/java/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -300,6 +300,16 @@
   }
 
   /**
+   * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by
+   * {@link #setAllFields(TestAllTypesLite.Builder)}.
+   */
+  public static TestAllTypesLite.Builder getAllLiteSetBuilder() {
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    setAllFields(builder);
+    return builder;
+  }
+
+  /**
    * Get a {@code TestAllExtensions} with all fields set as they would be by
    * {@link #setAllExtensions(TestAllExtensions.Builder)}.
    */
@@ -339,6 +349,150 @@
     setPackedExtensions(builder);
     return builder.build();
   }
+  
+  /**
+   * Set every field of {@code builder} to the values expected by
+   * {@code assertAllFieldsSet()}.
+   */
+  public static void setAllFields(TestAllTypesLite.Builder builder) {
+    builder.setOptionalInt32   (101);
+    builder.setOptionalInt64   (102);
+    builder.setOptionalUint32  (103);
+    builder.setOptionalUint64  (104);
+    builder.setOptionalSint32  (105);
+    builder.setOptionalSint64  (106);
+    builder.setOptionalFixed32 (107);
+    builder.setOptionalFixed64 (108);
+    builder.setOptionalSfixed32(109);
+    builder.setOptionalSfixed64(110);
+    builder.setOptionalFloat   (111);
+    builder.setOptionalDouble  (112);
+    builder.setOptionalBool    (true);
+    builder.setOptionalString  ("115");
+    builder.setOptionalBytes   (toBytes("116"));
+
+    builder.setOptionalGroup(
+        TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build());
+    builder.setOptionalNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+    builder.setOptionalForeignMessage(
+        ForeignMessageLite.newBuilder().setC(119).build());
+    builder.setOptionalImportMessage(
+        ImportMessageLite.newBuilder().setD(120).build());
+    builder.setOptionalPublicImportMessage(
+        PublicImportMessageLite.newBuilder().setE(126).build());
+    builder.setOptionalLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build());
+
+    builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.setOptionalStringPiece("124");
+    builder.setOptionalCord("125");
+
+    // -----------------------------------------------------------------
+
+    builder.addRepeatedInt32   (201);
+    builder.addRepeatedInt64   (202);
+    builder.addRepeatedUint32  (203);
+    builder.addRepeatedUint64  (204);
+    builder.addRepeatedSint32  (205);
+    builder.addRepeatedSint64  (206);
+    builder.addRepeatedFixed32 (207);
+    builder.addRepeatedFixed64 (208);
+    builder.addRepeatedSfixed32(209);
+    builder.addRepeatedSfixed64(210);
+    builder.addRepeatedFloat   (211);
+    builder.addRepeatedDouble  (212);
+    builder.addRepeatedBool    (true);
+    builder.addRepeatedString  ("215");
+    builder.addRepeatedBytes   (toBytes("216"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(219).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(220).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR);
+
+    builder.addRepeatedStringPiece("224");
+    builder.addRepeatedCord("225");
+
+    // Add a second one of each field.
+    builder.addRepeatedInt32   (301);
+    builder.addRepeatedInt64   (302);
+    builder.addRepeatedUint32  (303);
+    builder.addRepeatedUint64  (304);
+    builder.addRepeatedSint32  (305);
+    builder.addRepeatedSint64  (306);
+    builder.addRepeatedFixed32 (307);
+    builder.addRepeatedFixed64 (308);
+    builder.addRepeatedSfixed32(309);
+    builder.addRepeatedSfixed64(310);
+    builder.addRepeatedFloat   (311);
+    builder.addRepeatedDouble  (312);
+    builder.addRepeatedBool    (false);
+    builder.addRepeatedString  ("315");
+    builder.addRepeatedBytes   (toBytes("316"));
+
+    builder.addRepeatedGroup(
+        TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build());
+    builder.addRepeatedNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+    builder.addRepeatedForeignMessage(
+        ForeignMessageLite.newBuilder().setC(319).build());
+    builder.addRepeatedImportMessage(
+        ImportMessageLite.newBuilder().setD(320).build());
+    builder.addRepeatedLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build());
+
+    builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ);
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ);
+    builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ);
+
+    builder.addRepeatedStringPiece("324");
+    builder.addRepeatedCord("325");
+
+    // -----------------------------------------------------------------
+
+    builder.setDefaultInt32   (401);
+    builder.setDefaultInt64   (402);
+    builder.setDefaultUint32  (403);
+    builder.setDefaultUint64  (404);
+    builder.setDefaultSint32  (405);
+    builder.setDefaultSint64  (406);
+    builder.setDefaultFixed32 (407);
+    builder.setDefaultFixed64 (408);
+    builder.setDefaultSfixed32(409);
+    builder.setDefaultSfixed64(410);
+    builder.setDefaultFloat   (411);
+    builder.setDefaultDouble  (412);
+    builder.setDefaultBool    (false);
+    builder.setDefaultString  ("415");
+    builder.setDefaultBytes   (toBytes("416"));
+
+    builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO);
+    builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO);
+    builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO);
+
+    builder.setDefaultStringPiece("424");
+    builder.setDefaultCord("425");
+
+    builder.setOneofUint32(601);
+    builder.setOneofNestedMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build());
+    builder.setOneofString("603");
+    builder.setOneofBytes(toBytes("604"));
+  }
 
   /**
    * Set every field of {@code message} to the values expected by
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
similarity index 98%
rename from java/src/test/java/com/google/protobuf/TextFormatTest.java
rename to java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index 8294b86..1df4fad 100644
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -830,6 +830,22 @@
             .build()));
   }
 
+  public void testShortDebugString_field() {
+    final FieldDescriptor dataField =
+      OneString.getDescriptor().findFieldByName("data");
+    assertEquals(
+      "data: \"test data\"",
+      TextFormat.shortDebugString(dataField, "test data"));
+
+    final FieldDescriptor optionalField =
+      TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+    final Object value = NestedMessage.newBuilder().setBb(42).build();
+
+    assertEquals(
+      "optional_nested_message { bb: 42 }",
+      TextFormat.shortDebugString(optionalField, value));
+  }
+
   public void testShortDebugString_unknown() {
     assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
         + " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
diff --git a/java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
rename to java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
similarity index 72%
rename from java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
rename to java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
index e76b4a6..dc98737 100644
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -30,6 +30,8 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
 import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
@@ -52,7 +54,40 @@
         UnknownFieldSetLite.newBuilder()
             .build());
   }
+  
+  public void testBuilderReuse() throws IOException {
+    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+    builder.mergeVarintField(10, 2);
+    builder.build();
 
+    try {
+      builder.build();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+
+    try {
+      builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+
+    try {
+      builder.mergeVarintField(5, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // Expected.
+    }
+  }
+
+  public void testBuilderReuse_empty() {
+    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+    builder.build();
+    builder.build();
+  }
+  
   public void testDefaultInstance() {
     UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
 
@@ -67,10 +102,10 @@
 
     CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
 
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeFieldFrom(input.readTag(), input);
+    UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+    instance.mergeFieldFrom(input.readTag(), input);
 
-    assertEquals(foo.toByteString(), toByteString(builder.build()));
+    assertEquals(foo.toByteString(), toByteString(instance));
   }
 
   public void testSerializedSize() throws IOException {
@@ -80,18 +115,18 @@
 
     CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
 
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeFieldFrom(input.readTag(), input);
+    UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+    instance.mergeFieldFrom(input.readTag(), input);
 
-    assertEquals(foo.toByteString().size(), builder.build().getSerializedSize());
+    assertEquals(foo.toByteString().size(), instance.getSerializedSize());
   }
 
   public void testMergeVarintField() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.mergeVarintField(10, 2);
 
     CodedInputStream input =
-        CodedInputStream.newInstance(toByteString(builder.build()).toByteArray());
+        CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
 
     int tag = input.readTag();
     assertEquals(10, WireFormat.getTagFieldNumber(tag));
@@ -101,11 +136,11 @@
   }
 
   public void testMergeVarintField_negative() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+    UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance();
     builder.mergeVarintField(10, -6);
 
     CodedInputStream input =
-        CodedInputStream.newInstance(toByteString(builder.build()).toByteArray());
+        CodedInputStream.newInstance(toByteString(builder).toByteArray());
 
     int tag = input.readTag();
     assertEquals(10, WireFormat.getTagFieldNumber(tag));
@@ -115,13 +150,11 @@
   }
 
   public void testEqualsAndHashCode() {
-    UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder();
-    builder1.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields1 = builder1.build();
+    UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance();
+    unknownFields1.mergeVarintField(10, 2);
 
-    UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder();
-    builder2.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields2 = builder2.build();
+    UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance();
+    unknownFields2.mergeVarintField(10, 2);
 
     assertEquals(unknownFields1, unknownFields2);
     assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode());
@@ -129,12 +162,11 @@
     assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode());
   }
 
-  public void testConcat() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-    UnknownFieldSetLite unknownFields = builder.build();
-
-    unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields);
+  public void testMutableCopyOf() throws IOException {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.mergeVarintField(10, 2);
+    unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields);
+    unknownFields.checkMutable();
 
     CodedInputStream input =
         CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
@@ -151,53 +183,15 @@
     assertTrue(input.isAtEnd());
   }
 
-  public void testConcat_empty() {
-    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat(
+  public void testMutableCopyOf_empty() {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.mutableCopyOf(
         UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance());
+    unknownFields.checkMutable();
 
     assertEquals(0, unknownFields.getSerializedSize());
     assertEquals(ByteString.EMPTY, toByteString(unknownFields));
   }
 
-  public void testBuilderReuse() throws IOException {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.mergeVarintField(10, 2);
-    builder.build();
-
-    try {
-      builder.build();
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-
-    try {
-      builder.mergeVarintField(5, 1);
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-  }
-
-  public void testBuilderReuse_empty() {
-    UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
-    builder.build();
-
-    try {
-      builder.build();
-      fail();
-    } catch (IllegalStateException e) {
-      // Expected.
-    }
-  }
-
   public void testRoundTrips() throws InvalidProtocolBufferException {
     Foo foo = Foo.newBuilder()
         .setValue(1)
@@ -301,6 +295,64 @@
       // Expected.
     }
   }
+  
+  public void testMakeImmutable() throws Exception {
+    UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+    unknownFields.makeImmutable();
+    
+    try {
+      unknownFields.mergeVarintField(1, 1);
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    try {
+      unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello"));
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    try {
+      unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0]));
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
+  
+  public void testEndToEnd() throws Exception {
+    TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.parseFrom(new byte[0]);
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.newBuilder().build();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    testAllTypes = TestAllTypesLite.newBuilder()
+        .setDefaultBool(true)
+        .build();
+    try {
+      testAllTypes.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+    
+    TestAllExtensionsLite testAllExtensions = TestAllExtensionsLite.newBuilder()
+        .mergeFrom(TestAllExtensionsLite.newBuilder()
+            .setExtension(UnittestLite.optionalInt32ExtensionLite, 2)
+            .build().toByteArray())
+        .build();
+    try {
+      testAllExtensions.unknownFields.checkMutable();
+      fail();
+    } catch (UnsupportedOperationException expected) {}
+  }
 
   private ByteString toByteString(UnknownFieldSetLite unknownFields) {
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
rename to java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
diff --git a/java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
rename to java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
diff --git a/java/src/test/java/com/google/protobuf/WellKnownTypesTest.java b/java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/WellKnownTypesTest.java
rename to java/core/src/test/java/com/google/protobuf/WellKnownTypesTest.java
diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java
similarity index 100%
rename from java/src/test/java/com/google/protobuf/WireFormatTest.java
rename to java/core/src/test/java/com/google/protobuf/WireFormatTest.java
diff --git a/java/src/test/java/com/google/protobuf/any_test.proto b/java/core/src/test/proto/com/google/protobuf/any_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/any_test.proto
rename to java/core/src/test/proto/com/google/protobuf/any_test.proto
diff --git a/java/src/test/java/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/field_presence_test.proto
rename to java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
diff --git a/java/src/test/java/com/google/protobuf/lazy_fields_lite.proto b/java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/lazy_fields_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/lazy_fields_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/lite_equals_and_hash.proto
rename to java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
diff --git a/java/src/test/java/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/map_for_proto2_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
diff --git a/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/map_initialization_order_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
diff --git a/java/src/test/java/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
similarity index 99%
rename from java/src/test/java/com/google/protobuf/map_test.proto
rename to java/core/src/test/proto/com/google/protobuf/map_test.proto
index 2f7709b..2280ac0 100644
--- a/java/src/test/java/com/google/protobuf/map_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -36,7 +36,6 @@
 option java_outer_classname = "MapTestProto";
 option java_generate_equals_and_hash = true;
 
-
 message TestMap {
   message MessageValue {
     int32 value = 1;
diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/multiple_files_test.proto
rename to java/core/src/test/proto/com/google/protobuf/multiple_files_test.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_builders_test.proto b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_builders_test.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_extension.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_extension.proto
diff --git a/java/src/test/java/com/google/protobuf/nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/nested_extension_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/nested_extension_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/non_nested_extension.proto
rename to java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
diff --git a/java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/non_nested_extension_lite.proto
rename to java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test2.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test2.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
diff --git a/java/src/test/java/com/google/protobuf/outer_class_name_test3.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/outer_class_name_test3.proto
rename to java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
similarity index 94%
rename from java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
rename to java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
index dc08261..2b1f65e 100644
--- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
+++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -45,7 +45,6 @@
 option java_outer_classname = "TestBadIdentifiersProto";
 option java_generate_equals_and_hash = true;
 
-
 message TestMessage {
   optional string cached_size = 1;
   optional string serialized_size = 2;
@@ -140,11 +139,11 @@
   optional bytes bytes_field_count = 14;
   optional TestMessage message_field_count = 15;
 
-  repeated int32 Int32Field = 21;
-  repeated TestEnum EnumField = 22;
-  repeated string StringField = 23;
-  repeated bytes BytesField = 24;
-  repeated TestMessage MessageField = 25;
+  repeated int32 Int32Field = 21;  // NO_PROTO3
+  repeated TestEnum EnumField = 22;  // NO_PROTO3
+  repeated string StringField = 23;  // NO_PROTO3
+  repeated bytes BytesField = 24;  // NO_PROTO3
+  repeated TestMessage MessageField = 25;  // NO_PROTO3
 
   // This field conflicts with "int32_field" as they both generate
   // the method getInt32FieldList().
diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_check_utf8.proto
rename to java/core/src/test/proto/com/google/protobuf/test_check_utf8.proto
diff --git a/java/src/test/java/com/google/protobuf/test_check_utf8_size.proto b/java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_check_utf8_size.proto
rename to java/core/src/test/proto/com/google/protobuf/test_check_utf8_size.proto
diff --git a/java/src/test/java/com/google/protobuf/test_custom_options.proto b/java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_custom_options.proto
rename to java/core/src/test/proto/com/google/protobuf/test_custom_options.proto
diff --git a/java/src/test/java/com/google/protobuf/test_extra_interfaces.proto b/java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
similarity index 100%
rename from java/src/test/java/com/google/protobuf/test_extra_interfaces.proto
rename to java/core/src/test/proto/com/google/protobuf/test_extra_interfaces.proto
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
new file mode 100644
index 0000000..70c7d04
--- /dev/null
+++ b/java/lite/pom.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-2</version>
+  </parent>
+
+  <artifactId>protobuf-lite</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Protocol Buffers [Lite]</name>
+  <description>A trimmed-down version of the Protocol Buffers library.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymockclassextension</artifactId>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <core.root>../core</core.root>
+    <test.proto.dir>${core.root}/src/test/proto</test.proto.dir>
+  </properties>
+
+  <build>
+    <sourceDirectory>${core.root}/src/main/java</sourceDirectory>
+    <testSourceDirectory>${core.root}/src/test/java</testSourceDirectory>
+
+    <plugins>
+      <!-- Use Antrun plugin to generate sources with protoc -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate core protos -->
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="${core.root}/generate-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+
+          <!-- Generate the test protos -->
+          <execution>
+            <id>generate-test-sources</id>
+            <phase>generate-test-sources</phase>
+            <configuration>
+              <target>
+                <ant antfile="${core.root}/generate-test-sources-build.xml"/>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Only compile a subset of the files -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
+          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+          <includes>
+            <include>**/AbstractMessageLite.java</include>
+            <include>**/AbstractParser.java</include>
+            <include>**/AbstractProtobufList.java</include>
+            <include>**/BooleanArrayList.java</include>
+            <include>**/ByteString.java</include>
+            <include>**/CodedInputStream.java</include>
+            <include>**/CodedOutputStream.java</include>
+            <include>**/DoubleArrayList.java</include>
+            <include>**/ExtensionLite.java</include>
+            <include>**/ExtensionRegistryLite.java</include>
+            <include>**/FieldSet.java</include>
+            <include>**/FloatArrayList.java</include>
+            <include>**/GeneratedMessageLite.java</include>
+            <include>**/IntArrayList.java</include>
+            <include>**/Internal.java</include>
+            <include>**/InvalidProtocolBufferException.java</include>
+            <include>**/LazyFieldLite.java</include>
+            <include>**/LazyStringArrayList.java</include>
+            <include>**/LazyStringList.java</include>
+            <include>**/LongArrayList.java</include>
+            <include>**/MapEntryLite.java</include>
+            <include>**/MapFieldLite.java</include>
+            <include>**/MessageLite.java</include>
+            <include>**/MessageLiteOrBuilder.java</include>
+            <include>**/MessageLiteToString.java</include>
+            <include>**/MutabilityOracle.java</include>
+            <include>**/NioByteString.java</include>
+            <include>**/Parser.java</include>
+            <include>**/ProtobufArrayList.java</include>
+            <include>**/ProtocolStringList.java</include>
+            <include>**/RopeByteString.java</include>
+            <include>**/SmallSortedMap.java</include>
+            <include>**/TextFormatEscaper.java</include>
+            <include>**/UninitializedMessageException.java</include>
+            <include>**/UnknownFieldSetLite.java</include>
+            <include>**/UnmodifiableLazyStringList.java</include>
+            <include>**/UnsafeByteOperations.java</include>
+            <include>**/Utf8.java</include>
+            <include>**/WireFormat.java</include>
+          </includes>
+          <testIncludes>
+            <testInclude>**/*Lite.java</testInclude>
+            <testInclude>**/BooleanArrayListTest.java</testInclude>
+            <testInclude>**/DoubleArrayListTest.java</testInclude>
+            <testInclude>**/FloatArrayListTest.java</testInclude>
+            <testInclude>**/IntArrayListTest.java</testInclude>
+            <testInclude>**/LazyMessageLiteTest.java</testInclude>
+            <testInclude>**/LiteTest.java</testInclude>
+            <testInclude>**/LongArrayListTest.java</testInclude>
+            <testInclude>**/NioByteStringTest.java</testInclude>
+            <testInclude>**/ProtobufArrayListTest.java</testInclude>
+            <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
+          </testIncludes>
+        </configuration>
+      </plugin>
+
+      <!-- OSGI bundle configuration -->
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+            <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+            <Export-Package>com.google.${project.artifactId};version=${project.version}</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/java/pom.xml b/java/pom.xml
index 8b81b64..d5719ed 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -8,17 +8,33 @@
     <artifactId>google</artifactId>
     <version>1</version>
   </parent>
+
   <groupId>com.google.protobuf</groupId>
-  <artifactId>protobuf-java</artifactId>
-  <version>3.0.0-beta-1</version>
-  <packaging>bundle</packaging>
-  <name>Protocol Buffer Java API</name>
+  <artifactId>protobuf-parent</artifactId>
+  <version>3.0.0-beta-2</version>
+  <packaging>pom</packaging>
+
+  <name>Protocol Buffers [Parent]</name>
+  <inceptionYear>2008</inceptionYear>
+  <url>https://developers.google.com/protocol-buffers/</url>
   <description>
     Protocol Buffers are a way of encoding structured data in an efficient yet
     extensible format.
   </description>
-  <inceptionYear>2008</inceptionYear>
-  <url>https://developers.google.com/protocol-buffers/</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+    <!-- These are relative to the submodules -->
+    <protobuf.basedir>${project.basedir}/../..</protobuf.basedir>
+    <protobuf.source.dir>${protobuf.basedir}/src</protobuf.source.dir>
+    <protoc>${protobuf.source.dir}/protoc</protoc>
+    <test.proto.dir>src/test/proto</test.proto.dir>
+    <generated.sources.dir>${project.build.directory}/generated-sources</generated.sources.dir>
+    <generated.testsources.dir>${project.build.directory}/generated-test-sources</generated.testsources.dir>
+  </properties>
+
   <licenses>
     <license>
       <name>New BSD license</name>
@@ -26,215 +42,116 @@
       <distribution>repo</distribution>
     </license>
   </licenses>
+
   <scm>
     <url>https://github.com/google/protobuf</url>
-    <connection>
-      scm:git:https://github.com/google/protobuf.git
-    </connection>
+    <connection>scm:git:https://github.com/google/protobuf.git</connection>
   </scm>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.4</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
-      <version>2.2</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymockclassextension</artifactId>
-      <version>2.2.1</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
+
+  <distributionManagement>
+    <snapshotRepository>
+      <id>sonatype-nexus-staging</id>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+    </snapshotRepository>
+    <repository>
+      <id>sonatype-nexus-staging</id>
+      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+    </repository>
+  </distributionManagement>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.4</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymock</artifactId>
+        <version>2.2</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymockclassextension</artifactId>
+        <version>2.2.1</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>com.google.guava</groupId>
+        <artifactId>guava</artifactId>
+        <version>18.0</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <includes>
-            <include>**/*Test.java</include>
-          </includes>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>generate-sources</id>
-            <phase>generate-sources</phase>
-            <configuration>
-              <tasks>
-                <mkdir dir="target/generated-sources" />
-                <exec executable="../src/protoc">
-                  <arg value="--java_out=target/generated-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="../src/google/protobuf/any.proto" />
-                  <arg value="../src/google/protobuf/api.proto" />
-                  <arg value="../src/google/protobuf/descriptor.proto" />
-                  <arg value="../src/google/protobuf/duration.proto" />
-                  <arg value="../src/google/protobuf/empty.proto" />
-                  <arg value="../src/google/protobuf/field_mask.proto" />
-                  <arg value="../src/google/protobuf/source_context.proto" />
-                  <arg value="../src/google/protobuf/struct.proto" />
-                  <arg value="../src/google/protobuf/timestamp.proto" />
-                  <arg value="../src/google/protobuf/type.proto" />
-                  <arg value="../src/google/protobuf/wrappers.proto" />
-                </exec>
-              </tasks>
-              <sourceRoot>target/generated-sources</sourceRoot>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-          <execution>
-            <id>generate-test-sources</id>
-            <phase>generate-test-sources</phase>
-            <configuration>
-              <tasks>
-                <mkdir dir="target/generated-test-sources" />
-                <exec executable="../src/protoc">
-                  <arg value="--java_out=target/generated-test-sources" />
-                  <arg value="--proto_path=../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../src/google/protobuf/unittest.proto" />
-                  <arg value="../src/google/protobuf/unittest_import.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_public.proto" />
-                  <arg value="../src/google/protobuf/unittest_mset.proto" />
-                  <arg value="../src/google/protobuf/unittest_mset_wire_format.proto" />
-                  <arg value="src/test/java/com/google/protobuf/lazy_fields_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/lite_equals_and_hash.proto" />
-                  <arg
-                    value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_builders_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_extension.proto" />
-                  <arg value="src/test/java/com/google/protobuf/nested_extension_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/non_nested_extension.proto" />
-                  <arg value="src/test/java/com/google/protobuf/non_nested_extension_lite.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test2.proto" />
-                  <arg value="src/test/java/com/google/protobuf/outer_class_name_test3.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_bad_identifiers.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_check_utf8.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_check_utf8_size.proto" />
-                  <arg value="src/test/java/com/google/protobuf/test_custom_options.proto" />
-                  <arg
-                    value="../src/google/protobuf/unittest_optimize_for.proto" />
-                  <arg
-                    value="../src/google/protobuf/unittest_custom_options.proto" />
-                  <arg value="../src/google/protobuf/unittest_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_import_public_lite.proto" />
-                  <arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
-                  <arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
-                  <arg value="../src/google/protobuf/unittest_no_generic_services.proto" />
-                  <arg value="../src/google/protobuf/unittest_well_known_types.proto" />
-                  <arg value="src/test/java/com/google/protobuf/any_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/field_presence_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_for_proto2_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_test.proto" />
-                  <arg value="src/test/java/com/google/protobuf/map_initialization_order_test.proto" />
-                </exec>
-              </tasks>
-              <testSourceRoot>target/generated-test-sources</testSourceRoot>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <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-beta-1</Export-Package>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-    <resources>
-      <resource>
-        <directory>../src</directory>
-        <includes>
-          <include>google/protobuf/any.proto</include>
-          <include>google/protobuf/api.proto</include>
-          <include>google/protobuf/descriptor.proto</include>
-          <include>google/protobuf/duration.proto</include>
-          <include>google/protobuf/empty.proto</include>
-          <include>google/protobuf/field_mask.proto</include>
-          <include>google/protobuf/source_context.proto</include>
-          <include>google/protobuf/struct.proto</include>
-          <include>google/protobuf/timestamp.proto</include>
-          <include>google/protobuf/type.proto</include>
-          <include>google/protobuf/wrappers.proto</include>
-        </includes>
-      </resource>
-    </resources>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.3</version>
+          <configuration>
+            <source>1.6</source>
+            <target>1.6</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-source-plugin</artifactId>
+          <version>2.4</version>
+          <executions>
+            <execution>
+              <id>attach-sources</id>
+              <goals>
+                <goal>jar-no-fork</goal>
+              </goals>
+            </execution>
+          </executions>
+        </plugin>
+        <plugin>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <version>2.10.3</version>
+          <executions>
+            <execution>
+              <id>attach-javadocs</id>
+              <goals>
+                <goal>jar</goal>
+              </goals>
+            </execution>
+          </executions>
+        </plugin>
+        <plugin>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>2.6</version>
+        </plugin>
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>build-helper-maven-plugin</artifactId>
+          <version>1.10</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>3.0.1</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-antrun-plugin</artifactId>
+          <version>1.8</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
   </build>
+
   <profiles>
     <profile>
       <id>release</id>
-      <distributionManagement>
-        <snapshotRepository>
-          <id>sonatype-nexus-staging</id>
-          <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-        </snapshotRepository>
-        <repository>
-          <id>sonatype-nexus-staging</id>
-          <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-        </repository>
-      </distributionManagement>
       <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>
-            <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-gpg-plugin</artifactId>
-            <version>1.5</version>
+            <version>1.6</version>
             <executions>
               <execution>
                 <id>sign-artifacts</id>
@@ -248,93 +165,23 @@
           <plugin>
             <groupId>org.sonatype.plugins</groupId>
             <artifactId>nexus-staging-maven-plugin</artifactId>
-            <version>1.6.3</version>
+            <version>1.6.6</version>
             <extensions>true</extensions>
             <configuration>
-               <serverId>sonatype-nexus-staging</serverId>
-               <nexusUrl>https://oss.sonatype.org/</nexusUrl>
-               <autoReleaseAfterClose>false</autoReleaseAfterClose>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-    <profile>
-      <id>lite</id>
-      <build>
-        <plugins>
-          <plugin>
-            <artifactId>maven-compiler-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/AbstractMessageLite.java</include>
-                <include>**/AbstractParser.java</include>
-                <include>**/AbstractProtobufList.java</include>
-                <include>**/BoundedByteString.java</include>
-                <include>**/BooleanArrayList.java</include>
-                <include>**/ByteString.java</include>
-                <include>**/CodedInputStream.java</include>
-                <include>**/CodedOutputStream.java</include>
-                <include>**/DoublerrayList.java</include>
-                <include>**/ExtensionLite.java</include>
-                <include>**/ExtensionRegistryLite.java</include>
-                <include>**/FieldSet.java</include>
-                <include>**/FloatArrayList.java</include>
-                <include>**/GeneratedMessageLite.java</include>
-                <include>**/IntArrayList.java</include>
-                <include>**/Internal.java</include>
-                <include>**/InvalidProtocolBufferException.java</include>
-                <include>**/LazyFieldLite.java</include>
-                <include>**/LazyStringArrayList.java</include>
-                <include>**/LazyStringList.java</include>
-                <include>**/LiteralByteString.java</include>
-                <include>**/LongArrayList.java</include>
-                <include>**/MapEntryLite.java</include>
-                <include>**/MapFieldLite.java</include>
-                <include>**/MessageLite.java</include>
-                <include>**/MessageLiteOrBuilder.java</include>
-                <include>**/MutabilityOracle.java</include>
-                <include>**/Parser.java</include>
-                <include>**/ProtobufArrayList.java</include>
-                <include>**/ProtocolStringList.java</include>
-                <include>**/RopeByteString.java</include>
-                <include>**/SmallSortedMap.java</include>
-                <include>**/UninitializedMessageException.java</include>
-                <include>**/UnknownFieldSetLite.java</include>
-                <include>**/UnmodifiableLazyStringList.java</include>
-                <include>**/Utf8.java</include>
-                <include>**/WireFormat.java</include>
-              </includes>
-              <testIncludes>
-                <testInclude>**/*Lite.java</testInclude>
-                <testInclude>**/BooleanArrayListTest.java</testInclude>
-                <testInclude>**/DoubleArrayListTest.java</testInclude>
-                <testInclude>**/FloatArrayListTest.java</testInclude>
-                <testInclude>**/IntArrayListTest.java</testInclude>
-                <testInclude>**/LazyMessageLiteTest.java</testInclude>
-                <testInclude>**/LiteTest.java</testInclude>
-                <testInclude>**/LongArrayListTest.java</testInclude>
-                <testInclude>**/ProtobufArrayListTest.java</testInclude>
-                <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
-              </testIncludes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-surefire-plugin</artifactId>
-            <configuration>
-              <includes>
-                <include>**/*Test.java</include>
-              </includes>
-            </configuration>
-          </plugin>
-          <plugin>
-            <artifactId>maven-jar-plugin</artifactId>
-            <configuration>
-              <classifier>lite</classifier>
+              <serverId>sonatype-nexus-staging</serverId>
+              <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+              <autoReleaseAfterClose>false</autoReleaseAfterClose>
             </configuration>
           </plugin>
         </plugins>
       </build>
     </profile>
   </profiles>
+
+  <modules>
+    <module>core</module>
+    <module>lite</module>
+    <module>util</module>
+  </modules>
+
 </project>
diff --git a/java/src/main/java/com/google/protobuf/BoundedByteString.java b/java/src/main/java/com/google/protobuf/BoundedByteString.java
deleted file mode 100644
index b4c3fb1..0000000
--- a/java/src/main/java/com/google/protobuf/BoundedByteString.java
+++ /dev/null
@@ -1,180 +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 java.io.IOException;
-import java.io.InvalidObjectException;
-import java.io.ObjectInputStream;
-import java.util.NoSuchElementException;
-
-/**
- * This class is used to represent the substring of a {@link ByteString} over a
- * single byte array. In terms of the public API of {@link ByteString}, you end
- * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
- * ByteString#substring(int, int)}.
- *
- * <p>This class contains most of the overhead involved in creating a substring
- * from a {@link LiteralByteString}.  The overhead involves some range-checking
- * and two extra fields.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-class BoundedByteString extends LiteralByteString {
-
-  private final int bytesOffset;
-  private final int bytesLength;
-
-  /**
-   * Creates a {@code BoundedByteString} backed by the sub-range of given array,
-   * without copying.
-   *
-   * @param bytes  array to wrap
-   * @param offset index to first byte to use in bytes
-   * @param length number of bytes to use from bytes
-   * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
-   *                                  or if {@code offset + length >
-   *                                  bytes.length}.
-   */
-  BoundedByteString(byte[] bytes, int offset, int length) {
-    super(bytes);
-    if (offset < 0) {
-      throw new IllegalArgumentException("Offset too small: " + offset);
-    }
-    if (length < 0) {
-      throw new IllegalArgumentException("Length too small: " + offset);
-    }
-    if ((long) offset + length > bytes.length) {
-      throw new IllegalArgumentException(
-          "Offset+Length too large: " + offset + "+" + length);
-    }
-
-    this.bytesOffset = offset;
-    this.bytesLength = length;
-  }
-
-  /**
-   * Gets the byte at the given index.
-   * Throws {@link ArrayIndexOutOfBoundsException}
-   * for backwards-compatibility reasons although it would more properly be
-   * {@link IndexOutOfBoundsException}.
-   *
-   * @param index index of byte
-   * @return the value
-   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
-   */
-  @Override
-  public byte byteAt(int index) {
-    // We must check the index ourselves as we cannot rely on Java array index
-    // checking for substrings.
-    if (index < 0) {
-      throw new ArrayIndexOutOfBoundsException("Index too small: " + index);
-    }
-    if (index >= size()) {
-      throw new ArrayIndexOutOfBoundsException(
-          "Index too large: " + index + ", " + size());
-    }
-
-    return bytes[bytesOffset + index];
-  }
-
-  @Override
-  public int size() {
-    return bytesLength;
-  }
-
-  @Override
-  protected int getOffsetIntoBytes() {
-    return bytesOffset;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  @Override
-  protected void copyToInternal(byte[] target, int sourceOffset, 
-      int targetOffset, int numberToCopy) {
-    System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
-        targetOffset, numberToCopy);
-  }
-
-  // =================================================================
-  // Serializable
-
-  private static final long serialVersionUID = 1L;
-
-  Object writeReplace() {
-    return new LiteralByteString(toByteArray());
-  }
-
-  private void readObject(ObjectInputStream in) throws IOException {
-    throw new InvalidObjectException(
-        "BoundedByteStream instances are not to be serialized directly");
-  }
-
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new BoundedByteIterator();
-  }
-
-  private class BoundedByteIterator implements ByteIterator {
-
-    private int position;
-    private final int limit;
-
-    private BoundedByteIterator() {
-      position = getOffsetIntoBytes();
-      limit = position + size();
-    }
-
-    public boolean hasNext() {
-      return (position < limit);
-    }
-
-    public Byte next() {
-      // Boxing calls Byte.valueOf(byte), which does not instantiate.
-      return nextByte();
-    }
-
-    public byte nextByte() {
-      if (position >= limit) {
-        throw new NoSuchElementException();
-      }
-      return bytes[position++];
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-}
diff --git a/java/src/main/java/com/google/protobuf/LiteralByteString.java b/java/src/main/java/com/google/protobuf/LiteralByteString.java
deleted file mode 100644
index c5a8512..0000000
--- a/java/src/main/java/com/google/protobuf/LiteralByteString.java
+++ /dev/null
@@ -1,372 +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 java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * This class implements a {@link com.google.protobuf.ByteString} backed by a
- * single array of bytes, contiguous in memory. It supports substring by
- * pointing to only a sub-range of the underlying byte array, meaning that a
- * substring will reference the full byte-array of the string it's made from,
- * exactly as with {@link String}.
- *
- * @author carlanton@google.com (Carl Haverl)
- */
-class LiteralByteString extends ByteString {
-
-  private static final long serialVersionUID = 1L;
-
-  protected final byte[] bytes;
-
-  /**
-   * Creates a {@code LiteralByteString} backed by the given array, without
-   * copying.
-   *
-   * @param bytes array to wrap
-   */
-  LiteralByteString(byte[] bytes) {
-    this.bytes = bytes;
-  }
-
-  @Override
-  public byte byteAt(int index) {
-    // Unlike most methods in this class, this one is a direct implementation
-    // ignoring the potential offset because we need to do range-checking in the
-    // substring case anyway.
-    return bytes[index];
-  }
-
-  @Override
-  public int size() {
-    return bytes.length;
-  }
-
-  // =================================================================
-  // ByteString -> substring
-
-  @Override
-  public ByteString substring(int beginIndex, int endIndex) {
-    if (beginIndex < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index: " + beginIndex + " < 0");
-    }
-    if (endIndex > size()) {
-      throw new IndexOutOfBoundsException("End index: " + endIndex + " > " +
-          size());
-    }
-    int substringLength = endIndex - beginIndex;
-    if (substringLength < 0) {
-      throw new IndexOutOfBoundsException(
-          "Beginning index larger than ending index: " + beginIndex + ", "
-              + endIndex);
-    }
-
-    ByteString result;
-    if (substringLength == 0) {
-      result = ByteString.EMPTY;
-    } else {
-      result = new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex,
-          substringLength);
-    }
-    return result;
-  }
-
-  // =================================================================
-  // ByteString -> byte[]
-
-  @Override
-  protected void copyToInternal(byte[] target, int sourceOffset,
-      int targetOffset, int numberToCopy) {
-    // Optimized form, not for subclasses, since we don't call
-    // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
-    System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
-  }
-
-  @Override
-  public void copyTo(ByteBuffer target) {
-    target.put(bytes, getOffsetIntoBytes(), size());  // Copies bytes
-  }
-
-  @Override
-  public ByteBuffer asReadOnlyByteBuffer() {
-    ByteBuffer byteBuffer =
-        ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size());
-    return byteBuffer.asReadOnlyBuffer();
-  }
-
-  @Override
-  public List<ByteBuffer> asReadOnlyByteBufferList() {
-    // Return the ByteBuffer generated by asReadOnlyByteBuffer() as a singleton
-    List<ByteBuffer> result = new ArrayList<ByteBuffer>(1);
-    result.add(asReadOnlyByteBuffer());
-    return result;
- }
-
- @Override
-  public void writeTo(OutputStream outputStream) throws IOException {
-    outputStream.write(toByteArray());
-  }
-
-  @Override
-  void writeToInternal(OutputStream outputStream, int sourceOffset,
-      int numberToWrite) throws IOException {
-    outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset,
-        numberToWrite);
-  }
-
-  @Override
-  protected String toStringInternal(Charset charset) {
-    return new String(bytes, getOffsetIntoBytes(), size(), charset);
-  }
-
-  // =================================================================
-  // UTF-8 decoding
-
-  @Override
-  public boolean isValidUtf8() {
-    int offset = getOffsetIntoBytes();
-    return Utf8.isValidUtf8(bytes, offset, offset + size());
-  }
-
-  @Override
-  protected int partialIsValidUtf8(int state, int offset, int length) {
-    int index = getOffsetIntoBytes() + offset;
-    return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
-  }
-
-  // =================================================================
-  // equals() and hashCode()
-
-  @Override
-  public boolean equals(Object other) {
-    if (other == this) {
-      return true;
-    }
-    if (!(other instanceof ByteString)) {
-      return false;
-    }
-
-    if (size() != ((ByteString) other).size()) {
-      return false;
-    }
-    if (size() == 0) {
-      return true;
-    }
-
-    if (other instanceof LiteralByteString) {
-      LiteralByteString otherAsLiteral = (LiteralByteString) other;
-      // If we know the hash codes and they are not equal, we know the byte
-      // strings are not equal.
-      if (hash != 0
-          && otherAsLiteral.hash != 0
-          && hash != otherAsLiteral.hash) {
-        return false;
-      }
-
-      return equalsRange((LiteralByteString) other, 0, size());
-    } else if (other instanceof RopeByteString) {
-      return other.equals(this);
-    } else {
-      throw new IllegalArgumentException(
-          "Has a new type of ByteString been created? Found "
-              + other.getClass());
-    }
-  }
-
-  /**
-   * Check equality of the substring of given length of this object starting at
-   * zero with another {@code LiteralByteString} substring starting at offset.
-   *
-   * @param other  what to compare a substring in
-   * @param offset offset into other
-   * @param length number of bytes to compare
-   * @return true for equality of substrings, else false.
-   */
-  boolean equalsRange(LiteralByteString other, int offset, int length) {
-    if (length > other.size()) {
-      throw new IllegalArgumentException(
-          "Length too large: " + length + size());
-    }
-    if (offset + length > other.size()) {
-      throw new IllegalArgumentException(
-          "Ran off end of other: " + offset + ", " + length + ", " +
-              other.size());
-    }
-
-    byte[] thisBytes = bytes;
-    byte[] otherBytes = other.bytes;
-    int thisLimit = getOffsetIntoBytes() + length;
-    for (int thisIndex = getOffsetIntoBytes(), otherIndex =
-        other.getOffsetIntoBytes() + offset;
-        (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
-      if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Cached hash value.  Intentionally accessed via a data race, which
-   * is safe because of the Java Memory Model's "no out-of-thin-air values"
-   * guarantees for ints.
-   */
-  private int hash = 0;
-
-  /**
-   * Compute the hashCode using the traditional algorithm from {@link
-   * ByteString}.
-   *
-   * @return hashCode value
-   */
-  @Override
-  public int hashCode() {
-    int h = hash;
-
-    if (h == 0) {
-      int size = size();
-      h = partialHash(size, 0, size);
-      if (h == 0) {
-        h = 1;
-      }
-      hash = h;
-    }
-    return h;
-  }
-
-  @Override
-  protected int peekCachedHashCode() {
-    return hash;
-  }
-
-  @Override
-  protected int partialHash(int h, int offset, int length) {
-    return hashCode(h, bytes, getOffsetIntoBytes() + offset, length);
-  }
-
-  static int hashCode(int h, byte[] bytes, int offset, int length) {
-    for (int i = offset; i < offset + length; i++) {
-      h = h * 31 + bytes[i];
-    }
-    return h;
-  }
-
-  static int hashCode(byte[] bytes) {
-    int h = hashCode(bytes.length, bytes, 0, bytes.length);
-    return h == 0 ? 1 : h;
-  }
-
-  // =================================================================
-  // Input stream
-
-  @Override
-  public InputStream newInput() {
-    return new ByteArrayInputStream(bytes, getOffsetIntoBytes(),
-        size());  // No copy
-  }
-
-  @Override
-  public CodedInputStream newCodedInput() {
-    // We trust CodedInputStream not to modify the bytes, or to give anyone
-    // else access to them.
-    return CodedInputStream.newInstance(this);
-  }
-
-  // =================================================================
-  // ByteIterator
-
-  @Override
-  public ByteIterator iterator() {
-    return new LiteralByteIterator();
-  }
-
-  private class LiteralByteIterator implements ByteIterator {
-    private int position;
-    private final int limit;
-
-    private LiteralByteIterator() {
-      position = 0;
-      limit = size();
-    }
-
-    public boolean hasNext() {
-      return (position < limit);
-    }
-
-    public Byte next() {
-      // Boxing calls Byte.valueOf(byte), which does not instantiate.
-      return nextByte();
-    }
-
-    public byte nextByte() {
-      try {
-        return bytes[position++];
-      } catch (ArrayIndexOutOfBoundsException e) {
-        throw new NoSuchElementException(e.getMessage());
-      }
-    }
-
-    public void remove() {
-      throw new UnsupportedOperationException();
-    }
-  }
-
-  // =================================================================
-  // Internal methods
-
-  @Override
-  protected int getTreeDepth() {
-    return 0;
-  }
-
-  @Override
-  protected boolean isBalanced() {
-    return true;
-  }
-
-  /**
-   * Offset into {@code bytes[]} to use, non-zero for substrings.
-   *
-   * @return always 0 for this class
-   */
-  protected int getOffsetIntoBytes() {
-    return 0;
-  }
-}
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 44a5662..26c12c8 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -4,110 +4,73 @@
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
-    <groupId>com.google</groupId>
-    <artifactId>google</artifactId>
-    <version>1</version>
+    <groupId>com.google.protobuf</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>3.0.0-beta-2</version>
   </parent>
-  <groupId>com.google.protobuf</groupId>
+
   <artifactId>protobuf-java-util</artifactId>
-  <version>3.0.0-beta-1</version>
   <packaging>bundle</packaging>
-  <name>Protocol Buffer Java API</name>
-  <description>
-    Protocol Buffers are a way of encoding structured data in an efficient yet
-    extensible format.
-  </description>
-  <inceptionYear>2008</inceptionYear>
-  <url>https://developers.google.com/protocol-buffers/</url>
-  <licenses>
-    <license>
-      <name>New BSD license</name>
-      <url>http://www.opensource.org/licenses/bsd-license.php</url>
-      <distribution>repo</distribution>
-    </license>
-  </licenses>
-  <scm>
-    <url>https://github.com/google/protobuf</url>
-    <connection>
-      scm:git:https://github.com/google/protobuf.git
-    </connection>
-  </scm>
+
+  <name>Protocol Buffers [Util]</name>
+  <description>Utilities for Protocol Buffers</description>
+
   <dependencies>
     <dependency>
-      <groupId>com.google.protobuf</groupId>
+      <groupId>${project.groupId}</groupId>
       <artifactId>protobuf-java</artifactId>
-      <version>3.0.0-beta-1</version>
-      <scope>compile</scope>
+      <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
-      <version>18.0</version>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.3</version>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
-      <version>4.4</version>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
-      <version>2.2</version>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymockclassextension</artifactId>
-      <version>2.2.1</version>
-      <scope>test</scope>
     </dependency>
   </dependencies>
+
+  <properties>
+    <!-- Use the core proto dir so that we can call the core generation script -->
+    <test.proto.dir>../core/src/test/proto</test.proto.dir>
+  </properties>
+
   <build>
     <plugins>
       <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.5</source>
-          <target>1.5</target>
-        </configuration>
-      </plugin>
-      <plugin>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <includes>
-            <include>**/*Test.java</include>
-            <include>../src/main/java/com/google/protobuf/TestUtil.java</include>
-          </includes>
-        </configuration>
-      </plugin>
-      <plugin>
         <artifactId>maven-antrun-plugin</artifactId>
         <executions>
+          <!-- Generate the test protos -->
           <execution>
             <id>generate-test-sources</id>
             <phase>generate-test-sources</phase>
             <configuration>
-              <tasks>
-                <mkdir dir="target/generated-test-sources" />
-                <exec executable="../../src/protoc">
-                  <arg value="--java_out=target/generated-test-sources" />
-                  <arg value="--proto_path=../../src" />
-                  <arg value="--proto_path=src/test/java" />
-                  <arg value="../../src/google/protobuf/unittest.proto" />
-                  <arg value="../../src/google/protobuf/unittest_import.proto" />
-                  <arg value="../../src/google/protobuf/unittest_import_public.proto" />
-                  <arg value="src/test/java/com/google/protobuf/util/json_test.proto" />
+              <target>
+                <!-- Generate all of the test protos from the core module -->
+                <ant antfile="../core/generate-test-sources-build.xml"/>
+
+                <!-- Generate additional test protos for this module -->
+                <exec executable="${protoc}">
+                  <arg value="--java_out=${generated.testsources.dir}" />
+                  <arg value="--proto_path=${protobuf.source.dir}" />
+                  <arg value="--proto_path=src/test/proto" />
+                  <arg value="src/test/proto/com/google/protobuf/util/json_test.proto" />
                 </exec>
-              </tasks>
-              <testSourceRoot>target/generated-test-sources</testSourceRoot>
+              </target>
             </configuration>
             <goals>
               <goal>run</goal>
@@ -115,6 +78,16 @@
           </execution>
         </executions>
       </plugin>
+
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <!-- Add the generated test sources to the build -->
+          <generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
+        </configuration>
+      </plugin>
+
+      <!-- Configure the OSGI bundle -->
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
@@ -123,80 +96,20 @@
           <instructions>
             <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
             <Bundle-SymbolicName>com.google.protobuf.util</Bundle-SymbolicName>
-            <Export-Package>com.google.protobuf.util;version=3.0.0-beta-1</Export-Package>
+            <Export-Package>com.google.protobuf.util;version=${project.version}</Export-Package>
           </instructions>
         </configuration>
       </plugin>
+
+      <!-- Configure the fat jar to include all dependencies -->
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
-  <profiles>
-    <profile>
-      <id>release</id>
-      <distributionManagement>
-        <snapshotRepository>
-          <id>sonatype-nexus-staging</id>
-          <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-        </snapshotRepository>
-        <repository>
-          <id>sonatype-nexus-staging</id>
-          <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-        </repository>
-      </distributionManagement>
-      <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>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-gpg-plugin</artifactId>
-            <version>1.5</version>
-            <executions>
-              <execution>
-                <id>sign-artifacts</id>
-                <phase>verify</phase>
-                <goals>
-                  <goal>sign</goal>
-                </goals>
-              </execution>
-            </executions>
-          </plugin>
-          <plugin>
-            <groupId>org.sonatype.plugins</groupId>
-            <artifactId>nexus-staging-maven-plugin</artifactId>
-            <version>1.6.3</version>
-            <extensions>true</extensions>
-            <configuration>
-               <serverId>sonatype-nexus-staging</serverId>
-               <nexusUrl>https://oss.sonatype.org/</nexusUrl>
-               <autoReleaseAfterClose>false</autoReleaseAfterClose>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
 </project>
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
index 7bf8785..0b3060a 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -30,6 +30,9 @@
 
 package com.google.protobuf.util;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.primitives.Ints;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.FieldMask;
@@ -37,7 +40,6 @@
 import com.google.protobuf.Message;
 
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
@@ -53,6 +55,7 @@
    * Converts a FieldMask to a string.
    */
   public static String toString(FieldMask fieldMask) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Joiner here instead.
     StringBuilder result = new StringBuilder();
     boolean first = true;
     for (String value : fieldMask.getPathsList()) {
@@ -74,6 +77,7 @@
    * Parses from a string to a FieldMask.
    */
   public static FieldMask fromString(String value) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
     return fromStringList(
         null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
@@ -83,8 +87,8 @@
    * 
    * @throws IllegalArgumentException if any of the field path is invalid.
    */
-  public static FieldMask fromString(Class<? extends Message> type, String value)
-      throws IllegalArgumentException {
+  public static FieldMask fromString(Class<? extends Message> type, String value) {
+    // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
     return fromStringList(
         type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
@@ -94,9 +98,9 @@
    *
    * @throws IllegalArgumentException if any of the field path is not valid.
    */
+  // TODO(xiaofeng): Consider renaming fromStrings()
   public static FieldMask fromStringList(
-      Class<? extends Message> type, List<String> paths)
-      throws IllegalArgumentException {
+      Class<? extends Message> type, Iterable<String> paths) {
     FieldMask.Builder builder = FieldMask.newBuilder();
     for (String path : paths) {
       if (path.isEmpty()) {
@@ -113,15 +117,74 @@
   }
 
   /**
+   * Constructs a FieldMask from the passed field numbers.
+   *
+   * @throws IllegalArgumentException if any of the fields are invalid for the message.
+   */
+  public static FieldMask fromFieldNumbers(Class<? extends Message> type, int... fieldNumbers) {
+    return fromFieldNumbers(type, Ints.asList(fieldNumbers));
+  }
+
+  /**
+   * Constructs a FieldMask from the passed field numbers.
+   *
+   * @throws IllegalArgumentException if any of the fields are invalid for the message.
+   */
+  public static FieldMask fromFieldNumbers(
+      Class<? extends Message> type, Iterable<Integer> fieldNumbers) {
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
+    FieldMask.Builder builder = FieldMask.newBuilder();
+    for (Integer fieldNumber : fieldNumbers) {
+      FieldDescriptor field = descriptor.findFieldByNumber(fieldNumber);
+      checkArgument(
+          field != null,
+          String.format("%s is not a valid field number for %s.", fieldNumber, type));
+      builder.addPaths(field.getName());
+    }
+    return builder.build();
+  }
+
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Class<? extends Message> type, FieldMask fieldMask) {
+    Descriptor descriptor =
+        Internal.getDefaultInstance(type).getDescriptorForType();
+    
+    return isValid(descriptor, fieldMask);
+  }
+  
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Descriptor descriptor, FieldMask fieldMask) {
+    for (String path : fieldMask.getPathsList()) {
+      if (!isValid(descriptor, path)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
    * Checks whether a given field path is valid.
    */
   public static boolean isValid(Class<? extends Message> type, String path) {
+    Descriptor descriptor =
+        Internal.getDefaultInstance(type).getDescriptorForType();
+    
+    return isValid(descriptor, path);
+  }
+
+  /**
+   * Checks whether paths in a given fields mask are valid.
+   */
+  public static boolean isValid(Descriptor descriptor, String path) {
     String[] parts = path.split(FIELD_SEPARATOR_REGEX);
     if (parts.length == 0) {
       return false;
     }
-    Descriptor descriptor =
-        Internal.getDefaultInstance(type).getDescriptorForType();
     for (String name : parts) {
       if (descriptor == null) {
         return false;
@@ -171,7 +234,7 @@
   /**
    * Options to customize merging behavior.
    */
-  public static class MergeOptions {
+  public static final class MergeOptions {
     private boolean replaceMessageFields = false;
     private boolean replaceRepeatedFields = false;
 
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 c9a3915..d13ff0e 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
@@ -78,6 +78,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import java.util.logging.Logger;
 
 /**
@@ -99,7 +100,7 @@
    * Creates a {@link Printer} with default configurations.
    */
   public static Printer printer() {
-    return new Printer(TypeRegistry.getEmptyTypeRegistry());
+    return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
   }
   
   /**
@@ -107,9 +108,16 @@
    */
   public static class Printer {
     private final TypeRegistry registry;
-    
-    private Printer(TypeRegistry registry) {
+    private final boolean includingDefaultValueFields;
+    private final boolean preservingProtoFieldNames;
+
+    private Printer(
+        TypeRegistry registry,
+        boolean includingDefaultValueFields,
+        boolean preservingProtoFieldNames) {
       this.registry = registry;
+      this.includingDefaultValueFields = includingDefaultValueFields;
+      this.preservingProtoFieldNames = preservingProtoFieldNames;
     }
     
     /**
@@ -122,7 +130,27 @@
       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
         throw new IllegalArgumentException("Only one registry is allowed.");
       }
-      return new Printer(registry);
+      return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames);
+    }
+
+    /**
+     * Creates a new {@link Printer} that will also print fields set to their
+     * defaults. Empty repeated fields and map fields will be printed as well.
+     * The new Printer clones all other configurations from the current
+     * {@link Printer}.
+     */
+    public Printer includingDefaultValueFields() {
+      return new Printer(registry, true, preservingProtoFieldNames);
+    }
+
+    /**
+     * Creates a new {@link Printer} that is configured to use the original proto
+     * field names as defined in the .proto file rather than converting them to
+     * lowerCamelCase. The new Printer clones all other configurations from the
+     * current {@link Printer}.
+     */
+    public Printer preservingProtoFieldNames() {
+      return new Printer(registry, includingDefaultValueFields, true);
     }
     
     /**
@@ -136,7 +164,8 @@
         throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
-      new PrinterImpl(registry, output).print(message);
+      new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
+          .print(message);
     }
 
     /**
@@ -298,7 +327,7 @@
 
       private void addFile(FileDescriptor file) {
         // Skip the file if it's already added.
-        if (files.contains(file.getName())) {
+        if (!files.add(file.getFullName())) {
           return;
         }
         for (FileDescriptor dependency : file.getDependencies()) {
@@ -397,6 +426,8 @@
    */
   private static final class PrinterImpl {
     private final TypeRegistry registry;
+    private final boolean includingDefaultValueFields;
+    private final boolean preservingProtoFieldNames;
     private final TextGenerator generator;
     // We use Gson to help handle string escapes.
     private final Gson gson;
@@ -405,8 +436,14 @@
       private static final Gson DEFAULT_GSON = new Gson();
     }
 
-    PrinterImpl(TypeRegistry registry, Appendable jsonOutput) {
+    PrinterImpl(
+        TypeRegistry registry,
+        boolean includingDefaultValueFields,
+        boolean preservingProtoFieldNames,
+        Appendable jsonOutput) {
       this.registry = registry;
+      this.includingDefaultValueFields = includingDefaultValueFields;
+      this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.generator = new TextGenerator(jsonOutput);
       this.gson = GsonHolder.DEFAULT_GSON;
     }
@@ -647,13 +684,23 @@
         generator.print("\"@type\": " + gson.toJson(typeUrl));
         printedField = true;
       }
-      for (Map.Entry<FieldDescriptor, Object> field
-          : message.getAllFields().entrySet()) {
-        // Skip unknown enum fields.
-        if (field.getValue() instanceof EnumValueDescriptor
-            && ((EnumValueDescriptor) field.getValue()).getIndex() == -1) {
-          continue;
+      Map<FieldDescriptor, Object> fieldsToPrint = null;
+      if (includingDefaultValueFields) {
+        fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
+        for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
+          if (field.isOptional()
+              && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
+              && !message.hasField(field)) {
+            // Always skip empty optional message fields. If not we will recurse indefinitely if
+            // a message has itself as a sub-field.
+            continue;
+          }
+          fieldsToPrint.put(field, message.getField(field));
         }
+      } else {
+        fieldsToPrint = message.getAllFields();
+      }
+      for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) {
         if (printedField) {
           // Add line-endings for the previous field.
           generator.print(",\n");
@@ -673,7 +720,11 @@
 
     private void printField(FieldDescriptor field, Object value)
         throws IOException {
-      generator.print("\"" + fieldNameToCamelName(field.getName()) + "\": ");
+      if (preservingProtoFieldNames) {
+        generator.print("\"" + field.getName() + "\": ");
+      } else {
+        generator.print("\"" + field.getJsonName() + "\": ");
+      }
       if (field.isMapField()) {
         printMapFieldValue(field, value);
       } else if (field.isRepeated()) {
@@ -689,11 +740,6 @@
       generator.print("[");
       boolean printedElement = false;
       for (Object element : (List) value) {
-        // Skip unknown enum entries.
-        if (element instanceof EnumValueDescriptor
-            && ((EnumValueDescriptor) element).getIndex() == -1) {
-          continue;
-        }
         if (printedElement) {
           generator.print(", ");
         } else {
@@ -720,11 +766,6 @@
         Message entry = (Message) element;
         Object entryKey = entry.getField(keyField);
         Object entryValue = entry.getField(valueField);
-        // Skip unknown enum entries.
-        if (entryValue instanceof EnumValueDescriptor
-            && ((EnumValueDescriptor) entryValue).getIndex() == -1) {
-          continue;
-        }
         if (printedElement) {
           generator.print(",\n");
         } else {
@@ -871,8 +912,13 @@
               generator.print("\"");
             }
           } else {
-            generator.print(
-                "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+            if (((EnumValueDescriptor) value).getIndex() == -1) {
+              generator.print(
+                  String.valueOf(((EnumValueDescriptor) value).getNumber()));
+            } else {
+              generator.print(
+                  "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+            }
           }
           break;
 
@@ -916,38 +962,6 @@
     }
     return parts[1];
   }
-
-  private static String fieldNameToCamelName(String name) {
-    StringBuilder result = new StringBuilder(name.length());
-    boolean isNextUpperCase = false;
-    for (int i = 0; i < name.length(); i++) {
-      Character ch = name.charAt(i);
-      if (Character.isLowerCase(ch)) {
-        if (isNextUpperCase) {
-          result.append(Character.toUpperCase(ch));
-        } else {
-          result.append(ch);
-        }
-        isNextUpperCase = false;
-      } else if (Character.isUpperCase(ch)) {
-        if (i == 0 && !isNextUpperCase) {
-          // Force first letter to lower-case unless explicitly told to
-          // capitalize it.
-          result.append(Character.toLowerCase(ch));
-        } else {
-          // Capital letters after the first are left as-is.
-          result.append(ch);
-        }
-        isNextUpperCase = false;
-      } else if (Character.isDigit(ch)) {
-        result.append(ch);
-        isNextUpperCase = true;
-      } else {
-        isNextUpperCase = true;
-      }
-    }
-    return result.toString();
-  }
   
   private static class ParserImpl {
     private final TypeRegistry registry;
@@ -1085,7 +1099,8 @@
         Map<String, FieldDescriptor> fieldNameMap =
             new HashMap<String, FieldDescriptor>();
         for (FieldDescriptor field : descriptor.getFields()) {
-          fieldNameMap.put(fieldNameToCamelName(field.getName()), field);
+          fieldNameMap.put(field.getName(), field);
+          fieldNameMap.put(field.getJsonName(), field);
         }
         fieldNameMaps.put(descriptor, fieldNameMap);
         return fieldNameMap;
@@ -1244,7 +1259,25 @@
     
     private void mergeField(FieldDescriptor field, JsonElement json,
         Message.Builder builder) throws InvalidProtocolBufferException {
-      if (json instanceof JsonNull) {
+      if (field.isRepeated()) {
+        if (builder.getRepeatedFieldCount(field) > 0) {
+          throw new InvalidProtocolBufferException(
+              "Field " + field.getFullName() + " has already been set.");
+        }
+      } else {
+        if (builder.hasField(field)) {
+          throw new InvalidProtocolBufferException(
+              "Field " + field.getFullName() + " has already been set.");
+        }
+        if (field.getContainingOneof() != null
+            && builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
+          FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
+          throw new InvalidProtocolBufferException(
+              "Cannot set field " + field.getFullName() + " because another field "
+              + other.getFullName() + " belonging to the same oneof has already been set ");
+        }
+      }
+      if (field.isRepeated() && json instanceof JsonNull) {
         // We allow "null" as value for all field types and treat it as if the
         // field is not present.
         return;
@@ -1282,7 +1315,8 @@
         Object value = parseFieldValue(
             valueField, entry.getValue(), entryBuilder);
         if (value == null) {
-          value = getDefaultValue(valueField, entryBuilder);
+          throw new InvalidProtocolBufferException(
+              "Map value cannot be null.");
         }
         entryBuilder.setField(keyField, key);
         entryBuilder.setField(valueField, value);
@@ -1341,7 +1375,8 @@
       for (int i = 0; i < array.size(); ++i) {
         Object value = parseFieldValue(field, array.get(i), builder);
         if (value == null) {
-          value = getDefaultValue(field, builder);
+          throw new InvalidProtocolBufferException(
+              "Repeated field elements cannot be null");
         }
         builder.addRepeatedField(field, value);
       }
@@ -1352,6 +1387,15 @@
       try {
         return Integer.parseInt(json.getAsString());
       } catch (Exception e) {
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal value = new BigDecimal(json.getAsString());
+        return value.intValueExact();
+      } catch (Exception e) {
         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
       }
     }
@@ -1361,7 +1405,16 @@
       try {
         return Long.parseLong(json.getAsString());
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an int64 value: " + json);
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal value = new BigDecimal(json.getAsString());
+        return value.longValueExact();
+      } catch (Exception e) {
+        throw new InvalidProtocolBufferException("Not an int32 value: " + json);
       }
     }
     
@@ -1377,6 +1430,21 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
+        // Fall through.
+      }
+      // JSON doesn't distinguish between integer values and floating point values so "1" and
+      // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
+      // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
+      try {
+        BigDecimal decimalValue = new BigDecimal(json.getAsString());
+        BigInteger value = decimalValue.toBigIntegerExact();
+        if (value.signum() < 0 || value.compareTo(new BigInteger("FFFFFFFF", 16)) > 0) {
+          throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
+        }
+        return value.intValue();
+      } catch (InvalidProtocolBufferException e) {
+        throw e;
+      } catch (Exception e) {
         throw new InvalidProtocolBufferException(
             "Not an uint32 value: " + json);
       }
@@ -1388,7 +1456,8 @@
     private long parseUint64(JsonElement json)
         throws InvalidProtocolBufferException {
       try {
-        BigInteger value = new BigInteger(json.getAsString());
+        BigDecimal decimalValue = new BigDecimal(json.getAsString());
+        BigInteger value = decimalValue.toBigIntegerExact();
         if (value.compareTo(BigInteger.ZERO) < 0
             || value.compareTo(MAX_UINT64) > 0) {
           throw new InvalidProtocolBufferException(
@@ -1488,7 +1557,12 @@
       return json.getAsString();
     }
     
-    private ByteString parseBytes(JsonElement json) {
+    private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
+      String encoded = json.getAsString();
+      if (encoded.length() % 4 != 0) {
+        throw new InvalidProtocolBufferException(
+            "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
+      }
       return ByteString.copyFrom(
           BaseEncoding.base64().decode(json.getAsString()));
     }
@@ -1498,9 +1572,25 @@
       String value = json.getAsString();
       EnumValueDescriptor result = enumDescriptor.findValueByName(value);
       if (result == null) {
-        throw new InvalidProtocolBufferException(
-            "Invalid enum value: " + value + " for enum type: "
-            + enumDescriptor.getFullName());
+        // Try to interpret the value as a number.
+        try {
+          int numericValue = parseInt32(json);
+          if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
+            result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericValue);
+          } else {
+            result = enumDescriptor.findValueByNumber(numericValue);
+          }
+        } catch (InvalidProtocolBufferException e) {
+          // Fall through. This exception is about invalid int32 value we get from parseInt32() but
+          // that's not the exception we want the user to see. Since result == null, we will throw
+          // an exception later.
+        }
+        
+        if (result == null) {
+          throw new InvalidProtocolBufferException(
+              "Invalid enum value: " + value + " for enum type: "
+              + enumDescriptor.getFullName());
+        }
       }
       return result;
     }
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
index 6e4b7c0..3033182 100644
--- a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -58,8 +58,12 @@
   private static final long MILLIS_PER_SECOND = 1000;
   private static final long MICROS_PER_SECOND = 1000000;
 
-  private static final SimpleDateFormat timestampFormat =
-    createTimestampFormat();
+  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
+      new ThreadLocal<SimpleDateFormat>() {
+        protected SimpleDateFormat initialValue() {
+          return createTimestampFormat();
+        }
+      };
 
   private static SimpleDateFormat createTimestampFormat() {
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
@@ -96,7 +100,7 @@
       throw new IllegalArgumentException("Timestamp is out of range.");
     }
     Date date = new Date(timestamp.getSeconds() * MILLIS_PER_SECOND);
-    result.append(timestampFormat.format(date));
+    result.append(timestampFormat.get().format(date));
     // Format the nanos part.
     if (timestamp.getNanos() < 0 || timestamp.getNanos() >= NANOS_PER_SECOND) {
       throw new IllegalArgumentException("Timestamp has invalid nanos value.");
@@ -147,7 +151,7 @@
       secondValue = timeValue.substring(0, pointPosition);
       nanoValue = timeValue.substring(pointPosition + 1);
     }
-    Date date = timestampFormat.parse(secondValue);
+    Date date = timestampFormat.get().parse(secondValue);
     long seconds = date.getTime() / MILLIS_PER_SECOND;
     int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
     // Parse timezone offsets.
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
index 67fbe0b..a312fc3 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -53,6 +53,21 @@
         NestedTestAllTypes.class, "payload.nonexist"));
     
     assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")));
+    
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist"));
+    
+    assertTrue(FieldMaskUtil.isValid(
+        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
+    assertFalse(FieldMaskUtil.isValid(
+        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
+    
+    assertTrue(FieldMaskUtil.isValid(
         NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
     // Repeated fields cannot have sub-paths.
     assertFalse(FieldMaskUtil.isValid(
@@ -74,7 +89,7 @@
       addPaths("bar").addPaths("").build();
     assertEquals("foo,bar", FieldMaskUtil.toString(mask));
   }
-  
+
   public void testFromString() throws Exception {
     FieldMask mask = FieldMaskUtil.fromString("");
     assertEquals(0, mask.getPathsCount());
@@ -85,16 +100,16 @@
     assertEquals(2, mask.getPathsCount());
     assertEquals("foo", mask.getPaths(0));
     assertEquals("bar.baz", mask.getPaths(1));
-    
+
     // Empty field paths are ignore.
     mask = FieldMaskUtil.fromString(",foo,,bar,");
     assertEquals(2, mask.getPathsCount());
     assertEquals("foo", mask.getPaths(0));
     assertEquals("bar", mask.getPaths(1));
-    
+
     // Check whether the field paths are valid if a class parameter is provided.
     mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
-    
+
     try {
       mask = FieldMaskUtil.fromString(
           NestedTestAllTypes.class, "payload,nonexist");
@@ -103,6 +118,31 @@
       // Expected.
     }
   }
+
+  public void testFromFieldNumbers() throws Exception {
+    FieldMask mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class);
+    assertEquals(0, mask.getPathsCount());
+    mask =
+        FieldMaskUtil.fromFieldNumbers(
+            TestAllTypes.class, TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER);
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("optional_int32", mask.getPaths(0));
+    mask =
+        FieldMaskUtil.fromFieldNumbers(
+            TestAllTypes.class,
+            TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER,
+            TestAllTypes.OPTIONAL_INT64_FIELD_NUMBER);
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("optional_int32", mask.getPaths(0));
+    assertEquals("optional_int64", mask.getPaths(1));
+
+    try {
+      int invalidFieldNumber = 1000;
+      mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class, invalidFieldNumber);
+      fail("Exception is expected.");
+    } catch (IllegalArgumentException expected) {
+    }
+  }
   
   public void testUnion() throws Exception {
     // Only test a simple case here and expect
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 ddf5ad2..c0eb033 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
@@ -51,9 +51,11 @@
 import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedEnum;
 import com.google.protobuf.util.JsonTestProto.TestAllTypes.NestedMessage;
 import com.google.protobuf.util.JsonTestProto.TestAny;
+import com.google.protobuf.util.JsonTestProto.TestCustomJsonName;
 import com.google.protobuf.util.JsonTestProto.TestDuration;
 import com.google.protobuf.util.JsonTestProto.TestFieldMask;
 import com.google.protobuf.util.JsonTestProto.TestMap;
+import com.google.protobuf.util.JsonTestProto.TestOneof;
 import com.google.protobuf.util.JsonTestProto.TestStruct;
 import com.google.protobuf.util.JsonTestProto.TestTimestamp;
 import com.google.protobuf.util.JsonTestProto.TestWrappers;
@@ -196,9 +198,6 @@
   }
   
   public void testUnknownEnumValues() throws Exception {
-    // Unknown enum values will be dropped.
-    // TODO(xiaofeng): We may want to revisit this (whether we should omit
-    // unknown enum values).
     TestAllTypes message = TestAllTypes.newBuilder()
         .setOptionalNestedEnumValue(12345)
         .addRepeatedNestedEnumValue(12345)
@@ -206,8 +205,10 @@
         .build();
     assertEquals(
         "{\n"
-        + "  \"repeatedNestedEnum\": [\"FOO\"]\n"
+        + "  \"optionalNestedEnum\": 12345,\n"
+        + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
         + "}", toJsonString(message));
+    assertRoundTripEquals(message);
     
     TestMap.Builder mapBuilder = TestMap.newBuilder();
     mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
@@ -216,9 +217,11 @@
     assertEquals(
         "{\n" 
         + "  \"int32ToEnumMap\": {\n" 
-        + "    \"1\": \"FOO\"\n" 
+        + "    \"1\": \"FOO\",\n"
+        + "    \"2\": 12345\n"
         + "  }\n" 
         + "}", toJsonString(mapMessage));
+    assertRoundTripEquals(mapMessage);
   }
   
   public void testSpecialFloatValues() throws Exception {
@@ -263,6 +266,35 @@
     assertEquals(true, message.getOptionalBool());
   }
   
+  public void testParserAcceptFloatingPointValueForIntegerField() throws Exception {
+    // Test that numeric values like "1.000", "1e5" will also be accepted.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    mergeFromJson(
+        "{\n"
+            + "  \"repeatedInt32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
+            + "  \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n"
+            + "}", builder);
+    int[] expectedValues = new int[]{1, 100000, 1, 100000};
+    assertEquals(4, builder.getRepeatedInt32Count());
+    assertEquals(4, builder.getRepeatedUint32Count());
+    assertEquals(4, builder.getRepeatedInt64Count());
+    assertEquals(4, builder.getRepeatedUint64Count());
+    for (int i = 0; i < 4; ++i) {
+      assertEquals(expectedValues[i], builder.getRepeatedInt32(i));
+      assertEquals(expectedValues[i], builder.getRepeatedUint32(i));
+      assertEquals(expectedValues[i], builder.getRepeatedInt64(i));
+      assertEquals(expectedValues[i], builder.getRepeatedUint64(i));
+    }
+    
+    // Non-integers will still be rejected.
+    assertRejects("optionalInt32", "1.5");
+    assertRejects("optionalUint32", "1.5");
+    assertRejects("optionalInt64", "1.5");
+    assertRejects("optionalUint64", "1.5");
+  }
+  
   private void assertRejects(String name, String value) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
@@ -285,6 +317,7 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     // Both numeric form and string form are accepted.
     mergeFromJson("{\"" + name + "\":" + value + "}", builder);
+    builder.clear();
     mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
   }
   
@@ -370,84 +403,74 @@
     TestAllTypes message = builder.build();
     assertEquals(TestAllTypes.getDefaultInstance(), message);
     
-    // Repeated field elements can also be null.
-    builder = TestAllTypes.newBuilder();
-    mergeFromJson(
-        "{\n"
-        + "  \"repeatedInt32\": [null, null],\n"
-        + "  \"repeatedInt64\": [null, null],\n"
-        + "  \"repeatedUint32\": [null, null],\n"
-        + "  \"repeatedUint64\": [null, null],\n"
-        + "  \"repeatedSint32\": [null, null],\n"
-        + "  \"repeatedSint64\": [null, null],\n"
-        + "  \"repeatedFixed32\": [null, null],\n"
-        + "  \"repeatedFixed64\": [null, null],\n"
-        + "  \"repeatedSfixed32\": [null, null],\n"
-        + "  \"repeatedSfixed64\": [null, null],\n"
-        + "  \"repeatedFloat\": [null, null],\n"
-        + "  \"repeatedDouble\": [null, null],\n"
-        + "  \"repeatedBool\": [null, null],\n"
-        + "  \"repeatedString\": [null, null],\n"
-        + "  \"repeatedBytes\": [null, null],\n"
-        + "  \"repeatedNestedMessage\": [null, null],\n"
-        + "  \"repeatedNestedEnum\": [null, null]\n"
-        + "}", builder);
-    message = builder.build();
-    // "null" elements will be parsed to default values.
-    assertEquals(2, message.getRepeatedInt32Count());
-    assertEquals(0, message.getRepeatedInt32(0));
-    assertEquals(0, message.getRepeatedInt32(1));
-    assertEquals(2, message.getRepeatedInt32Count());
-    assertEquals(0, message.getRepeatedInt32(0));
-    assertEquals(0, message.getRepeatedInt32(1));
-    assertEquals(2, message.getRepeatedInt64Count());
-    assertEquals(0, message.getRepeatedInt64(0));
-    assertEquals(0, message.getRepeatedInt64(1));
-    assertEquals(2, message.getRepeatedUint32Count());
-    assertEquals(0, message.getRepeatedUint32(0));
-    assertEquals(0, message.getRepeatedUint32(1));
-    assertEquals(2, message.getRepeatedUint64Count());
-    assertEquals(0, message.getRepeatedUint64(0));
-    assertEquals(0, message.getRepeatedUint64(1));
-    assertEquals(2, message.getRepeatedSint32Count());
-    assertEquals(0, message.getRepeatedSint32(0));
-    assertEquals(0, message.getRepeatedSint32(1));
-    assertEquals(2, message.getRepeatedSint64Count());
-    assertEquals(0, message.getRepeatedSint64(0));
-    assertEquals(0, message.getRepeatedSint64(1));
-    assertEquals(2, message.getRepeatedFixed32Count());
-    assertEquals(0, message.getRepeatedFixed32(0));
-    assertEquals(0, message.getRepeatedFixed32(1));
-    assertEquals(2, message.getRepeatedFixed64Count());
-    assertEquals(0, message.getRepeatedFixed64(0));
-    assertEquals(0, message.getRepeatedFixed64(1));
-    assertEquals(2, message.getRepeatedSfixed32Count());
-    assertEquals(0, message.getRepeatedSfixed32(0));
-    assertEquals(0, message.getRepeatedSfixed32(1));
-    assertEquals(2, message.getRepeatedSfixed64Count());
-    assertEquals(0, message.getRepeatedSfixed64(0));
-    assertEquals(0, message.getRepeatedSfixed64(1));
-    assertEquals(2, message.getRepeatedFloatCount());
-    assertEquals(0f, message.getRepeatedFloat(0));
-    assertEquals(0f, message.getRepeatedFloat(1));
-    assertEquals(2, message.getRepeatedDoubleCount());
-    assertEquals(0.0, message.getRepeatedDouble(0));
-    assertEquals(0.0, message.getRepeatedDouble(1));
-    assertEquals(2, message.getRepeatedBoolCount());
-    assertFalse(message.getRepeatedBool(0));
-    assertFalse(message.getRepeatedBool(1));
-    assertEquals(2, message.getRepeatedStringCount());
-    assertTrue(message.getRepeatedString(0).isEmpty());
-    assertTrue(message.getRepeatedString(1).isEmpty());
-    assertEquals(2, message.getRepeatedBytesCount());
-    assertTrue(message.getRepeatedBytes(0).isEmpty());
-    assertTrue(message.getRepeatedBytes(1).isEmpty());
-    assertEquals(2, message.getRepeatedNestedMessageCount());
-    assertEquals(NestedMessage.getDefaultInstance(), message.getRepeatedNestedMessage(0));
-    assertEquals(NestedMessage.getDefaultInstance(), message.getRepeatedNestedMessage(1));
-    assertEquals(2, message.getRepeatedNestedEnumCount());
-    assertEquals(0, message.getRepeatedNestedEnumValue(0));
-    assertEquals(0, message.getRepeatedNestedEnumValue(1));
+    // Repeated field elements cannot be null.
+    try {
+      builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedInt32\": [null, null],\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+    
+    try {
+      builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedNestedMessage\": [null, null],\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+  }
+  
+  public void testParserRejectDuplicatedFields() throws Exception {
+    // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last
+    // one if multiple entries have the same name. This is not the desired behavior but it can
+    // only be fixed by using our own parser. Here we only test the cases where the names are
+    // different but still referring to the same field.
+    
+    // Duplicated optional fields. 
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+              + "  \"optionalNestedMessage\": {},\n"
+              + "  \"optional_nested_message\": {}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+    
+    // Duplicated repeated fields.
+    try {
+      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"repeatedNestedMessage\": [null, null],\n"
+          + "  \"repeated_nested_message\": [null, null]\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+    
+    // Duplicated oneof fields.
+    try {
+      TestOneof.Builder builder = TestOneof.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"oneofInt32\": 1,\n"
+          + "  \"oneof_int32\": 2\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
   }
   
   public void testMapFields() throws Exception {
@@ -592,18 +615,30 @@
     assertRoundTripEquals(message);
   }
   
-  public void testMapNullValueIsDefault() throws Exception {
-    TestMap.Builder builder = TestMap.newBuilder();
-    mergeFromJson(
-        "{\n"
-        + "  \"int32ToInt32Map\": {\"1\": null},\n"
-        + "  \"int32ToMessageMap\": {\"2\": null}\n"
-        + "}", builder);
-    TestMap message = builder.build();
-    assertTrue(message.getInt32ToInt32Map().containsKey(1));
-    assertEquals(0, message.getInt32ToInt32Map().get(1).intValue());
-    assertTrue(message.getInt32ToMessageMap().containsKey(2));
-    assertEquals(0, message.getInt32ToMessageMap().get(2).getValue());
+  public void testMapNullValueIsRejected() throws Exception {
+    try {
+      TestMap.Builder builder = TestMap.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"int32ToInt32Map\": {null: 1},\n"
+          + "  \"int32ToMessageMap\": {null: 2}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
+    
+    try {
+      TestMap.Builder builder = TestMap.newBuilder();
+      mergeFromJson(
+          "{\n"
+          + "  \"int32ToInt32Map\": {\"1\": null},\n"
+          + "  \"int32ToMessageMap\": {\"2\": null}\n"
+          + "}", builder);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Exception expected.
+    }
   }
   
   public void testParserAcceptNonQuotedObjectKey() throws Exception {
@@ -743,6 +778,15 @@
         + "  }\n"
         + "}", toJsonString(message));
     assertRoundTripEquals(message);
+    
+    builder = TestStruct.newBuilder();
+    builder.setValue(Value.newBuilder().setNullValueValue(0).build());
+    message = builder.build();
+    assertEquals(
+        "{\n"
+        + "  \"value\": null\n"
+        + "}", toJsonString(message));
+    assertRoundTripEquals(message);
   }
   
   public void testAnyFields() throws Exception {
@@ -891,6 +935,15 @@
         + "  }\n"
         + "}", printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
+    Value.Builder valueBuilder = Value.newBuilder();
+    valueBuilder.setNumberValue(1);
+    anyMessage = Any.pack(valueBuilder.build());
+    assertEquals(
+        "{\n"
+        + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+        + "  \"value\": 1.0\n"
+        + "}", printer.print(anyMessage));
+    assertRoundTripEquals(anyMessage, registry);
   }
   
   public void testParserMissingTypeUrl() throws Exception {
@@ -949,16 +1002,9 @@
   }
   
   public void testParserRejectInvalidBase64() throws Exception {
-    try {
-      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalBytes\": \"!@#$\"\n"
-          + "}", builder);
-      fail("Exception is expected.");
-    } catch (InvalidProtocolBufferException e) {
-      // Expected.
-    } 
+    assertRejects("optionalBytes", "!@#$");
+    // We use standard BASE64 with paddings.
+    assertRejects("optionalBytes", "AQI");
   }
   
   public void testParserRejectInvalidEnumValue() throws Exception {
@@ -973,4 +1019,138 @@
       // Expected.
     } 
   }
+
+  public void testCustomJsonName() throws Exception {
+    TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
+    assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
+    assertRoundTripEquals(message);
+  }
+
+  public void testIncludingDefaultValueFields() throws Exception {
+    TestAllTypes message = TestAllTypes.getDefaultInstance();
+    assertEquals("{\n}", JsonFormat.printer().print(message));
+    assertEquals(
+        "{\n"
+            + "  \"optionalInt32\": 0,\n"
+            + "  \"optionalInt64\": \"0\",\n"
+            + "  \"optionalUint32\": 0,\n"
+            + "  \"optionalUint64\": \"0\",\n"
+            + "  \"optionalSint32\": 0,\n"
+            + "  \"optionalSint64\": \"0\",\n"
+            + "  \"optionalFixed32\": 0,\n"
+            + "  \"optionalFixed64\": \"0\",\n"
+            + "  \"optionalSfixed32\": 0,\n"
+            + "  \"optionalSfixed64\": \"0\",\n"
+            + "  \"optionalFloat\": 0.0,\n"
+            + "  \"optionalDouble\": 0.0,\n"
+            + "  \"optionalBool\": false,\n"
+            + "  \"optionalString\": \"\",\n"
+            + "  \"optionalBytes\": \"\",\n"
+            + "  \"optionalNestedEnum\": \"FOO\",\n"
+            + "  \"repeatedInt32\": [],\n"
+            + "  \"repeatedInt64\": [],\n"
+            + "  \"repeatedUint32\": [],\n"
+            + "  \"repeatedUint64\": [],\n"
+            + "  \"repeatedSint32\": [],\n"
+            + "  \"repeatedSint64\": [],\n"
+            + "  \"repeatedFixed32\": [],\n"
+            + "  \"repeatedFixed64\": [],\n"
+            + "  \"repeatedSfixed32\": [],\n"
+            + "  \"repeatedSfixed64\": [],\n"
+            + "  \"repeatedFloat\": [],\n"
+            + "  \"repeatedDouble\": [],\n"
+            + "  \"repeatedBool\": [],\n"
+            + "  \"repeatedString\": [],\n"
+            + "  \"repeatedBytes\": [],\n"
+            + "  \"repeatedNestedMessage\": [],\n"
+            + "  \"repeatedNestedEnum\": []\n"
+            + "}",
+        JsonFormat.printer().includingDefaultValueFields().print(message));
+
+    TestMap mapMessage = TestMap.getDefaultInstance();
+    assertEquals("{\n}", JsonFormat.printer().print(mapMessage));
+    assertEquals(
+        "{\n"
+            + "  \"int32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"int64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"uint32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"uint64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sint32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sint64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"fixed32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"fixed64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sfixed32ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"sfixed64ToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"boolToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"stringToInt32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToInt64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToUint32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToUint64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSint32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSint64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFixed32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFixed64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSfixed32Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToSfixed64Map\": {\n"
+            + "  },\n"
+            + "  \"int32ToFloatMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToDoubleMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToBoolMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToStringMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToBytesMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToMessageMap\": {\n"
+            + "  },\n"
+            + "  \"int32ToEnumMap\": {\n"
+            + "  }\n"
+            + "}",
+        JsonFormat.printer().includingDefaultValueFields().print(mapMessage));
+  }
+
+  public void testPreservingProtoFieldNames() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
+    assertEquals("{\n" + "  \"optionalInt32\": 12345\n" + "}", JsonFormat.printer().print(message));
+    assertEquals(
+        "{\n" + "  \"optional_int32\": 12345\n" + "}",
+        JsonFormat.printer().preservingProtoFieldNames().print(message));
+
+    // The json_name field option is ignored when configured to use original proto field names.
+    TestCustomJsonName messageWithCustomJsonName =
+        TestCustomJsonName.newBuilder().setValue(12345).build();
+    assertEquals(
+        "{\n" + "  \"value\": 12345\n" + "}",
+        JsonFormat.printer().preservingProtoFieldNames().print(messageWithCustomJsonName));
+
+    // Parsers accept both original proto field names and lowerCamelCase names.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    JsonFormat.parser().merge("{\"optionalInt32\": 12345}", builder);
+    assertEquals(12345, builder.getOptionalInt32());
+    builder.clear();
+    JsonFormat.parser().merge("{\"optional_int32\": 54321}", builder);
+    assertEquals(54321, builder.getOptionalInt32());
+  }
 }
diff --git a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
index fe5617e..4c31b2b 100644
--- a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
@@ -38,6 +38,8 @@
 import org.junit.Assert;
 
 import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
 
 /** Unit tests for {@link TimeUtil}. */
 public class TimeUtilTest extends TestCase {
@@ -76,6 +78,71 @@
     assertEquals("1970-01-01T08:00:00.010Z", TimeUtil.toString(value));
   }
 
+  private volatile boolean stopParsingThreads = false;
+  private volatile String errorMessage = "";
+
+  private class ParseTimestampThread extends Thread {
+    private final String[] strings;
+    private final Timestamp[] values;
+    public ParseTimestampThread(String[] strings, Timestamp[] values) {
+      this.strings = strings;
+      this.values = values;
+    }
+
+    @Override
+    public void run() {
+      int index = 0;
+      while (!stopParsingThreads) {
+        Timestamp result;
+        try {
+          result = TimeUtil.parseTimestamp(strings[index]);
+        } catch (ParseException e) {
+          errorMessage = "Failed to parse timestamp: " + strings[index];
+          break;
+        }
+        if (result.getSeconds() != values[index].getSeconds()
+            || result.getNanos() != values[index].getNanos()) {
+          errorMessage = "Actual result: " + result.toString() + ", expected: "
+              + values[index].toString();
+          break;
+        }
+        index = (index + 1) % strings.length;
+      }
+    }
+  }
+
+  public void testTimestampConcurrentParsing() throws Exception {
+    String[] timestampStrings = new String[]{
+      "0001-01-01T00:00:00Z",
+      "9999-12-31T23:59:59.999999999Z",
+      "1970-01-01T00:00:00Z",
+      "1969-12-31T23:59:59.999Z",
+    };
+    Timestamp[] timestampValues = new Timestamp[timestampStrings.length];
+    for (int i = 0; i < timestampStrings.length; i++) {
+      timestampValues[i] = TimeUtil.parseTimestamp(timestampStrings[i]);
+    }
+
+    final int THREAD_COUNT = 16;
+    final int RUNNING_TIME = 5000;  // in milliseconds.
+    final List<Thread> threads = new ArrayList<Thread>();
+
+    stopParsingThreads = false;
+    errorMessage = "";
+    for (int i = 0; i < THREAD_COUNT; i++) {
+      Thread thread = new ParseTimestampThread(
+          timestampStrings, timestampValues);
+      thread.start();
+      threads.add(thread);
+    }
+    Thread.sleep(RUNNING_TIME);
+    stopParsingThreads = true;
+    for (Thread thread : threads) {
+      thread.join();
+    }
+    Assert.assertEquals("", errorMessage);
+  }
+
   public void testTimetampInvalidFormat() throws Exception {
     try {
       // Value too small.
diff --git a/java/util/src/test/java/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
similarity index 95%
rename from java/util/src/test/java/com/google/protobuf/util/json_test.proto
rename to java/util/src/test/proto/com/google/protobuf/util/json_test.proto
index b2753af..509c1d6 100644
--- a/java/util/src/test/java/com/google/protobuf/util/json_test.proto
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
@@ -90,6 +90,13 @@
   repeated NestedEnum repeated_nested_enum = 51;
 }
 
+message TestOneof {
+  oneof oneof_field {
+    int32 oneof_int32 = 1;
+    TestAllTypes.NestedMessage oneof_nested_message = 2;
+  }
+}
+
 message TestMap {
   // Instead of testing all combinations (too many), we only make sure all
   // valid types have been used at least in one field as key and in one
@@ -151,8 +158,13 @@
 
 message TestStruct {
   google.protobuf.Struct struct_value = 1;
+  google.protobuf.Value value = 2;
 }
 
 message TestAny {
   google.protobuf.Any any_value = 1;
 }
+
+message TestCustomJsonName {
+  int32 value = 1 [json_name = "@value"];
+}
diff --git a/javanano/pom.xml b/javanano/pom.xml
index 1a95a43..2c9dd94 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-4</version>
+  <version>3.0.0-alpha-5</version>
   <packaging>bundle</packaging>
   <name>Protocol Buffer JavaNano API</name>
   <description>
@@ -165,7 +165,7 @@
           <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-4</Export-Package>
+            <Export-Package>com.google.protobuf;version=3.0.0-alpha-5</Export-Package>
           </instructions>
         </configuration>
       </plugin>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
index eca9c0d..b49a97f 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -32,13 +32,13 @@
 
 
 /**
- * A custom version of {@link android.util.SparseArray} with the minimal API
+ * A custom version of {@code android.util.SparseArray} with the minimal API
  * for storing {@link FieldData} objects.
  *
  * <p>This class is an internal implementation detail of nano and should not
  * be called directly by clients.
  *
- * Based on {@link android.support.v4.util.SpareArrayCompat}.
+ * Based on {@code android.support.v4.util.SpareArrayCompat}.
  */
 public final class FieldArray implements Cloneable {
     private static final FieldData DELETED = new FieldData();
diff --git a/js/README.md b/js/README.md
new file mode 100644
index 0000000..15d48c8
--- /dev/null
+++ b/js/README.md
@@ -0,0 +1,159 @@
+Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
+Copyright 2008 Google Inc.
+
+This directory contains the JavaScript Protocol Buffers runtime library.
+
+The library is currently compatible with:
+
+1. CommonJS-style imports (eg. `var protos = require('my-protos');`)
+2. Closure-style imports (eg. `goog.require('my.package.MyProto');`)
+
+Support for ES6-style imports is not implemented yet.  Browsers can
+be supported by using Browserify, webpack, Closure Compiler, etc. to
+resolve imports at compile time.
+
+To use Protocol Buffers with JavaScript, you need two main components:
+
+1. The protobuf runtime library.  You can install this with
+   `npm install google-protobuf`, or use the files in this directory.
+2. The Protocol Compiler `protoc`.  This translates `.proto` files
+   into `.js` files.  The compiler is not currently available via
+   npm, but you can download a pre-built binary
+   [on GitHub](https://github.com/google/protobuf/releases)
+   (look for the `protoc-*.zip` files under **Downloads**).
+
+
+Setup
+=====
+
+First, obtain the Protocol Compiler.  The easiest way is to download
+a pre-built binary from [https://github.com/google/protobuf/releases](https://github.com/google/protobuf/releases).
+
+If you want, you can compile `protoc` from source instead.  To do this
+follow the instructions in [the top-level
+README](https://github.com/google/protobuf/blob/master/src/README.md).
+
+Once you have `protoc` compiled, you can run the tests by typing:
+
+    $ cd js
+    $ npm install
+    $ npm test
+
+    # If your protoc is somewhere else than ../src/protoc, instead do this.
+    # But make sure your protoc is the same version as this (or compatible)!
+    $ PROTOC=/usr/local/bin/protoc npm test
+
+This will run two separate copies of the tests: one that uses
+Closure Compiler style imports and one that uses CommonJS imports.
+You can see all the CommonJS files in `commonjs_out/`.
+If all of these tests pass, you know you have a working setup.
+
+
+Using Protocol Buffers in your own project
+==========================================
+
+To use Protocol Buffers in your own project, you need to integrate
+the Protocol Compiler into your build system.  The details are a
+little different depending on whether you are using Closure imports
+or CommonJS imports:
+
+Closure Imports
+---------------
+
+If you want to use Closure imports, your build should run a command
+like this:
+
+    $ protoc --js_out=library=myproto_libs,binary:. messages.proto base.proto
+
+For Closure imports, `protoc` will generate a single output file
+(`myproto_libs.js` in this example).  The generated file will `goog.provide()`
+all of the types defined in your .proto files.  For example, for the unit
+tests the generated files contain many `goog.provide` statements like:
+
+    goog.provide('proto.google.protobuf.DescriptorProto');
+    goog.provide('proto.google.protobuf.DescriptorProto.ExtensionRange');
+    goog.provide('proto.google.protobuf.DescriptorProto.ReservedRange');
+    goog.provide('proto.google.protobuf.EnumDescriptorProto');
+    goog.provide('proto.google.protobuf.EnumOptions');
+
+The generated code will also `goog.require()` many types in the core library,
+and they will require many types in the Google Closure library.  So make sure
+that your `goog.provide()` / `goog.require()` setup can find all of your
+generated code, the core library `.js` files in this directory, and the
+Google Closure library itself.
+
+Once you've done this, you should be able to import your types with
+statements like:
+
+    goog.require('proto.my.package.MyMessage');
+
+    var message = proto.my.package.MyMessage();
+
+CommonJS imports
+----------------
+
+If you want to use CommonJS imports, your build should run a command
+like this:
+
+    $ protoc --js_out=import_style=commonjs,binary:. messages.proto base.proto
+
+For CommonJS imports, `protoc` will spit out one file per input file
+(so `messages_pb.js` and `base_pb.js` in this example).  The generated
+code will depend on the core runtime, which should be in a file called
+`google-protobuf.js`.  If you are installing from `npm`, this file should
+already be built and available.  If you are running from GitHub, you need
+to build it first by running:
+
+    $ gulp dist
+
+Once you've done this, you should be able to import your types with
+statements like:
+
+    var messages = require('./messages_pb');
+
+    var message = new messages.MyMessage();
+
+The `--js_out` flag
+-------------------
+
+The syntax of the `--js_out` flag is:
+
+    --js_out=[OPTIONS:]output_dir
+
+Where `OPTIONS` are separated by commas.  Options are either `opt=val` or
+just `opt` (for options that don't take a value).  The available options
+are specified and documented in the `GeneratorOptions` struct in
+[src/google/protobuf/compiler/js/js_generator.h](https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/js/js_generator.h#L53).
+
+Some examples:
+
+- `--js_out=library=myprotos_lib.js,binary:.`: this contains the options
+  `library=myprotos.lib.js` and `binary` and outputs to the current directory.
+  The `import_style` option is left to the default, which is `closure`.
+- `--js_out=import_style=commonjs,binary:protos`: this contains the options
+  `import_style=commonjs` and `binary` and outputs to the directory `protos`.
+
+API
+===
+
+The API is not well-documented yet.  Here is a quick example to give you an
+idea of how the library generally works:
+
+    var message = new MyMessage();
+
+    message.setName("John Doe");
+    message.setAge(25);
+    message.setPhoneNumbers(["800-555-1212", "800-555-0000"]);
+
+    // Serializes to a UInt8Array.
+    bytes = message.serializeBinary();
+
+    var message2 = new MyMessage();
+    message2.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/binary/arith.js b/js/binary/arith.js
new file mode 100644
index 0000000..70257de
--- /dev/null
+++ b/js/binary/arith.js
@@ -0,0 +1,413 @@
+// 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.
+
+/**
+ * @fileoverview This file contains helper code used by jspb.utils to
+ * handle 64-bit integer conversion to/from strings.
+ *
+ * @author cfallin@google.com (Chris Fallin)
+ *
+ * TODO(haberman): move this to javascript/closure/math?
+ */
+
+goog.provide('jspb.arith.Int64');
+goog.provide('jspb.arith.UInt64');
+
+/**
+ * UInt64 implements some 64-bit arithmetic routines necessary for properly
+ * handling 64-bit integer fields. It implements lossless integer arithmetic on
+ * top of JavaScript's number type, which has only 53 bits of precision, by
+ * representing 64-bit integers as two 32-bit halves.
+ *
+ * @param {number} lo The low 32 bits.
+ * @param {number} hi The high 32 bits.
+ * @constructor
+ */
+jspb.arith.UInt64 = function(lo, hi) {
+  /**
+   * The low 32 bits.
+   * @public {number}
+   */
+  this.lo = lo;
+  /**
+   * The high 32 bits.
+   * @public {number}
+   */
+  this.hi = hi;
+};
+
+
+/**
+ * Compare two 64-bit numbers. Returns -1 if the first is
+ * less, +1 if the first is greater, or 0 if both are equal.
+ * @param {!jspb.arith.UInt64} other
+ * @return {number}
+ */
+jspb.arith.UInt64.prototype.cmp = function(other) {
+  if (this.hi < other.hi || (this.hi == other.hi && this.lo < other.lo)) {
+    return -1;
+  } else if (this.hi == other.hi && this.lo == other.lo) {
+    return 0;
+  } else {
+    return 1;
+  }
+};
+
+
+/**
+ * Right-shift this number by one bit.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.rightShift = function() {
+  var hi = this.hi >>> 1;
+  var lo = (this.lo >>> 1) | ((this.hi & 1) << 31);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Left-shift this number by one bit.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.leftShift = function() {
+  var lo = this.lo << 1;
+  var hi = (this.hi << 1) | (this.lo >>> 31);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Test the MSB.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.msb = function() {
+  return !!(this.hi & 0x80000000);
+};
+
+
+/**
+ * Test the LSB.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.lsb = function() {
+  return !!(this.lo & 1);
+};
+
+
+/**
+ * Test whether this number is zero.
+ * @return {boolean}
+ */
+jspb.arith.UInt64.prototype.zero = function() {
+  return this.lo == 0 && this.hi == 0;
+};
+
+
+/**
+ * Add two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.UInt64} other
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.add = function(other) {
+  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
+      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Subtract two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.UInt64} other
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.sub = function(other) {
+  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
+      (((this.lo - other.lo) < 0) ? 1 : 0);
+  return new jspb.arith.UInt64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Multiply two 32-bit numbers to produce a 64-bit number.
+ * @param {number} a The first integer:  must be in [0, 2^32-1).
+ * @param {number} b The second integer: must be in [0, 2^32-1).
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.mul32x32 = function(a, b) {
+  // Directly multiplying two 32-bit numbers may produce up to 64 bits of
+  // precision, thus losing precision because of the 53-bit mantissa of
+  // JavaScript numbers. So we multiply with 16-bit digits (radix 65536)
+  // instead.
+  var aLow = (a & 0xffff);
+  var aHigh = (a >>> 16);
+  var bLow = (b & 0xffff);
+  var bHigh = (b >>> 16);
+  var productLow =
+      // 32-bit result, result bits 0-31, take all 32 bits
+      (aLow * bLow) +
+      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
+      ((aLow * bHigh) & 0xffff) * 0x10000 +
+      // 32-bit result, result bits 16-47, take bottom 16 as our top 16
+      ((aHigh * bLow) & 0xffff) * 0x10000;
+  var productHigh =
+      // 32-bit result, result bits 32-63, take all 32 bits
+      (aHigh * bHigh) +
+      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
+      ((aLow * bHigh) >>> 16) +
+      // 32-bit result, result bits 16-47, take top 16 as our bottom 16
+      ((aHigh * bLow) >>> 16);
+
+  // Carry. Note that we actually have up to *two* carries due to addition of
+  // three terms.
+  while (productLow >= 0x100000000) {
+    productLow -= 0x100000000;
+    productHigh += 1;
+  }
+
+  return new jspb.arith.UInt64(productLow >>> 0, productHigh >>> 0);
+};
+
+
+/**
+ * Multiply this number by a 32-bit number, producing a 96-bit number, then
+ * truncate the top 32 bits.
+ * @param {number} a The multiplier.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.mul = function(a) {
+  // Produce two parts: at bits 0-63, and 32-95.
+  var lo = jspb.arith.UInt64.mul32x32(this.lo, a);
+  var hi = jspb.arith.UInt64.mul32x32(this.hi, a);
+  // Left-shift hi by 32 bits, truncating its top bits. The parts will then be
+  // aligned for addition.
+  hi.hi = hi.lo;
+  hi.lo = 0;
+  return lo.add(hi);
+};
+
+
+/**
+ * Divide a 64-bit number by a 32-bit number to produce a
+ * 64-bit quotient and a 32-bit remainder.
+ * @param {number} _divisor
+ * @return {Array.<jspb.arith.UInt64>} array of [quotient, remainder],
+ * unless divisor is 0, in which case an empty array is returned.
+ */
+jspb.arith.UInt64.prototype.div = function(_divisor) {
+  if (_divisor == 0) {
+    return [];
+  }
+
+  // We perform long division using a radix-2 algorithm, for simplicity (i.e.,
+  // one bit at a time). TODO: optimize to a radix-2^32 algorithm, taking care
+  // to get the variable shifts right.
+  var quotient = new jspb.arith.UInt64(0, 0);
+  var remainder = new jspb.arith.UInt64(this.lo, this.hi);
+  var divisor = new jspb.arith.UInt64(_divisor, 0);
+  var unit = new jspb.arith.UInt64(1, 0);
+
+  // Left-shift the divisor and unit until the high bit of divisor is set.
+  while (!divisor.msb()) {
+    divisor = divisor.leftShift();
+    unit = unit.leftShift();
+  }
+
+  // Perform long division one bit at a time.
+  while (!unit.zero()) {
+    // If divisor < remainder, add unit to quotient and subtract divisor from
+    // remainder.
+    if (divisor.cmp(remainder) <= 0) {
+      quotient = quotient.add(unit);
+      remainder = remainder.sub(divisor);
+    }
+    // Right-shift the divisor and unit.
+    divisor = divisor.rightShift();
+    unit = unit.rightShift();
+  }
+
+  return [quotient, remainder];
+};
+
+
+/**
+ * Convert a 64-bit number to a string.
+ * @return {string}
+ * @override
+ */
+jspb.arith.UInt64.prototype.toString = function() {
+  var result = '';
+  var num = this;
+  while (!num.zero()) {
+    var divResult = num.div(10);
+    var quotient = divResult[0], remainder = divResult[1];
+    result = remainder.lo + result;
+    num = quotient;
+  }
+  if (result == '') {
+    result = '0';
+  }
+  return result;
+};
+
+
+/**
+ * Parse a string into a 64-bit number. Returns `null` on a parse error.
+ * @param {string} s
+ * @return {?jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.fromString = function(s) {
+  var result = new jspb.arith.UInt64(0, 0);
+  // optimization: reuse this instance for each digit.
+  var digit64 = new jspb.arith.UInt64(0, 0);
+  for (var i = 0; i < s.length; i++) {
+    if (s[i] < '0' || s[i] > '9') {
+      return null;
+    }
+    var digit = parseInt(s[i], 10);
+    digit64.lo = digit;
+    result = result.mul(10).add(digit64);
+  }
+  return result;
+};
+
+
+/**
+ * Make a copy of the uint64.
+ * @return {!jspb.arith.UInt64}
+ */
+jspb.arith.UInt64.prototype.clone = function() {
+  return new jspb.arith.UInt64(this.lo, this.hi);
+};
+
+
+/**
+ * Int64 is like UInt64, but modifies string conversions to interpret the stored
+ * 64-bit value as a twos-complement-signed integer. It does *not* support the
+ * full range of operations that UInt64 does: only add, subtract, and string
+ * conversions.
+ *
+ * N.B. that multiply and divide routines are *NOT* supported. They will throw
+ * exceptions. (They are not necessary to implement string conversions, which
+ * are the only operations we really need in jspb.)
+ *
+ * @param {number} lo The low 32 bits.
+ * @param {number} hi The high 32 bits.
+ * @constructor
+ */
+jspb.arith.Int64 = function(lo, hi) {
+  /**
+   * The low 32 bits.
+   * @public {number}
+   */
+  this.lo = lo;
+  /**
+   * The high 32 bits.
+   * @public {number}
+   */
+  this.hi = hi;
+};
+
+
+/**
+ * Add two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.Int64} other
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.add = function(other) {
+  var lo = ((this.lo + other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi + other.hi) & 0xffffffff) >>> 0) +
+      (((this.lo + other.lo) >= 0x100000000) ? 1 : 0);
+  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Subtract two 64-bit numbers to produce a 64-bit number.
+ * @param {!jspb.arith.Int64} other
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.sub = function(other) {
+  var lo = ((this.lo - other.lo) & 0xffffffff) >>> 0;
+  var hi =
+      (((this.hi - other.hi) & 0xffffffff) >>> 0) -
+      (((this.lo - other.lo) < 0) ? 1 : 0);
+  return new jspb.arith.Int64(lo >>> 0, hi >>> 0);
+};
+
+
+/**
+ * Make a copy of the int64.
+ * @return {!jspb.arith.Int64}
+ */
+jspb.arith.Int64.prototype.clone = function() {
+  return new jspb.arith.Int64(this.lo, this.hi);
+};
+
+
+/**
+ * Convert a 64-bit number to a string.
+ * @return {string}
+ * @override
+ */
+jspb.arith.Int64.prototype.toString = function() {
+  // If the number is negative, find its twos-complement inverse.
+  var sign = (this.hi & 0x80000000) != 0;
+  var num = new jspb.arith.UInt64(this.lo, this.hi);
+  if (sign) {
+    num = new jspb.arith.UInt64(0, 0).sub(num);
+  }
+  return (sign ? '-' : '') + num.toString();
+};
+
+
+/**
+ * Parse a string into a 64-bit number. Returns `null` on a parse error.
+ * @param {string} s
+ * @return {?jspb.arith.Int64}
+ */
+jspb.arith.Int64.fromString = function(s) {
+  var hasNegative = (s.length > 0 && s[0] == '-');
+  if (hasNegative) {
+    s = s.substring(1);
+  }
+  var num = jspb.arith.UInt64.fromString(s);
+  if (num === null) {
+    return null;
+  }
+  if (hasNegative) {
+    num = new jspb.arith.UInt64(0, 0).sub(num);
+  }
+  return new jspb.arith.Int64(num.lo, num.hi);
+};
diff --git a/js/binary/arith_test.js b/js/binary/arith_test.js
new file mode 100644
index 0000000..89796bf
--- /dev/null
+++ b/js/binary/arith_test.js
@@ -0,0 +1,355 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for Int64-manipulation functions.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author cfallin@google.com (Chris Fallin)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.arith.Int64');
+goog.require('jspb.arith.UInt64');
+
+
+describe('binaryArithTest', function() {
+  /**
+   * Tests comparison operations.
+   */
+  it('testCompare', function() {
+    var a = new jspb.arith.UInt64(1234, 5678);
+    var b = new jspb.arith.UInt64(1234, 5678);
+    assertEquals(a.cmp(b), 0);
+    assertEquals(b.cmp(a), 0);
+    b.lo -= 1;
+    assertEquals(a.cmp(b), 1);
+    assertEquals(b.cmp(a), -1);
+    b.lo += 2;
+    assertEquals(a.cmp(b), -1);
+    assertEquals(b.cmp(a), 1);
+    b.lo = a.lo;
+    b.hi = a.hi - 1;
+    assertEquals(a.cmp(b), 1);
+    assertEquals(b.cmp(a), -1);
+
+    assertEquals(a.zero(), false);
+    assertEquals(a.msb(), false);
+    assertEquals(a.lsb(), false);
+    a.hi = 0;
+    a.lo = 0;
+    assertEquals(a.zero(), true);
+    a.hi = 0x80000000;
+    assertEquals(a.zero(), false);
+    assertEquals(a.msb(), true);
+    a.lo = 0x00000001;
+    assertEquals(a.lsb(), true);
+  });
+
+
+  /**
+   * Tests shifts.
+   */
+  it('testShifts', function() {
+    var a = new jspb.arith.UInt64(1, 0);
+    assertEquals(a.lo, 1);
+    assertEquals(a.hi, 0);
+    var orig = a;
+    a = a.leftShift();
+    assertEquals(orig.lo, 1);  // original unmodified.
+    assertEquals(orig.hi, 0);
+    assertEquals(a.lo, 2);
+    assertEquals(a.hi, 0);
+    a = a.leftShift();
+    assertEquals(a.lo, 4);
+    assertEquals(a.hi, 0);
+    for (var i = 0; i < 29; i++) {
+      a = a.leftShift();
+    }
+    assertEquals(a.lo, 0x80000000);
+    assertEquals(a.hi, 0);
+    a = a.leftShift();
+    assertEquals(a.lo, 0);
+    assertEquals(a.hi, 1);
+    a = a.leftShift();
+    assertEquals(a.lo, 0);
+    assertEquals(a.hi, 2);
+    a = a.rightShift();
+    a = a.rightShift();
+    assertEquals(a.lo, 0x80000000);
+    assertEquals(a.hi, 0);
+    a = a.rightShift();
+    assertEquals(a.lo, 0x40000000);
+    assertEquals(a.hi, 0);
+  });
+
+
+  /**
+   * Tests additions.
+   */
+  it('testAdd', function() {
+    var a = new jspb.arith.UInt64(/* lo = */ 0x89abcdef,
+                                         /* hi = */ 0x01234567);
+    var b = new jspb.arith.UInt64(/* lo = */ 0xff52ab91,
+                                         /* hi = */ 0x92fa2123);
+    // Addition with carry.
+    var c = a.add(b);
+    assertEquals(a.lo, 0x89abcdef);  // originals unmodified.
+    assertEquals(a.hi, 0x01234567);
+    assertEquals(b.lo, 0xff52ab91);
+    assertEquals(b.hi, 0x92fa2123);
+    assertEquals(c.lo, 0x88fe7980);
+    assertEquals(c.hi, 0x941d668b);
+
+    // Simple addition without carry.
+    a.lo = 2;
+    a.hi = 0;
+    b.lo = 3;
+    b.hi = 0;
+    c = a.add(b);
+    assertEquals(c.lo, 5);
+    assertEquals(c.hi, 0);
+  });
+
+
+  /**
+   * Test subtractions.
+   */
+  it('testSub', function() {
+    var kLength = 10;
+    var hiValues = [0x1682ef32,
+                    0x583902f7,
+                    0xb62f5955,
+                    0x6ea99bbf,
+                    0x25a39c20,
+                    0x0700a08b,
+                    0x00f7304d,
+                    0x91a5b5af,
+                    0x89077fd2,
+                    0xe09e347c];
+    var loValues = [0xe1538b18,
+                    0xbeacd556,
+                    0x74100758,
+                    0x96e3cb26,
+                    0x56c37c3f,
+                    0xe00b3f7d,
+                    0x859f25d7,
+                    0xc2ee614a,
+                    0xe1d21cd7,
+                    0x30aae6a4];
+    for (var i = 0; i < kLength; i++) {
+      for (var j = 0; j < kLength; j++) {
+        var a = new jspb.arith.UInt64(loValues[i], hiValues[j]);
+        var b = new jspb.arith.UInt64(loValues[j], hiValues[i]);
+        var c = a.add(b).sub(b);
+        assertEquals(c.hi, a.hi);
+        assertEquals(c.lo, a.lo);
+      }
+    }
+  });
+
+
+  /**
+   * Tests 32-by-32 multiplication.
+   */
+  it('testMul32x32', function() {
+    var testData = [
+      // a        b          low(a*b)   high(a*b)
+      [0xc0abe2f8, 0x1607898a, 0x5de711b0, 0x109471b8],
+      [0x915eb3cb, 0x4fb66d0e, 0xbd0d441a, 0x2d43d0bc],
+      [0xfe4efe70, 0x80b48c37, 0xbcddea10, 0x7fdada0c],
+      [0xe222fd4a, 0xe43d524a, 0xd5e0eb64, 0xc99d549c],
+      [0xd171f469, 0xb94ebd01, 0x4be17969, 0x979bc4fa],
+      [0x829cc1df, 0xe2598b38, 0xf4157dc8, 0x737c12ad],
+      [0xf10c3767, 0x8382881e, 0x942b3612, 0x7bd428b8],
+      [0xb0f6dd24, 0x232597e1, 0x079c98a4, 0x184bbce7],
+      [0xfcdb05a7, 0x902f55bc, 0x636199a4, 0x8e69f412],
+      [0x0dd0bfa9, 0x916e27b1, 0x6e2542d9, 0x07d92e65]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = testData[i][0] >>> 0;
+      var b = testData[i][1] >>> 0;
+      var cLow = testData[i][2] >>> 0;
+      var cHigh = testData[i][3] >>> 0;
+      var c = jspb.arith.UInt64.mul32x32(a, b);
+      assertEquals(c.lo, cLow);
+      assertEquals(c.hi, cHigh);
+    }
+  });
+
+
+  /**
+   * Tests 64-by-32 multiplication.
+   */
+  it('testMul', function() {
+    // 64x32 bits produces 96 bits of product. The multiplication function under
+    // test truncates the top 32 bits, so we compare against a 64-bit expected
+    // product.
+    var testData = [
+      // low(a)   high(a)               low(a*b)   high(a*b)
+      [0xec10955b, 0x360eb168, 0x4b7f3f5b, 0xbfcb7c59, 0x9517da5f],
+      [0x42b000fc, 0x9d101642, 0x6fa1ab72, 0x2584c438, 0x6a9e6d2b],
+      [0xf42d4fb4, 0xae366403, 0xa65a1000, 0x92434000, 0x1ff978df],
+      [0x17e2f56b, 0x25487693, 0xf13f98c7, 0x73794e2d, 0xa96b0c6a],
+      [0x492f241f, 0x76c0eb67, 0x7377ac44, 0xd4336c3c, 0xfc4b1ebe],
+      [0xd6b92321, 0xe184fa48, 0xd6e76904, 0x93141584, 0xcbf44da1],
+      [0x4bf007ea, 0x968c0a9e, 0xf5e4026a, 0x4fdb1ae4, 0x61b9fb7d],
+      [0x10a83be7, 0x2d685ba6, 0xc9e5fb7f, 0x2ad43499, 0x3742473d],
+      [0x2f261829, 0x1aca681a, 0x3d3494e3, 0x8213205b, 0x283719f8],
+      [0xe4f2ce21, 0x2e74b7bd, 0xd801b38b, 0xbc17feeb, 0xc6c44e0f]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var prod = a.mul(testData[i][2]);
+      assertEquals(prod.lo, testData[i][3]);
+      assertEquals(prod.hi, testData[i][4]);
+    }
+  });
+
+
+  /**
+   * Tests 64-div-by-32 division.
+   */
+  it('testDiv', function() {
+    // Compute a/b, yielding quot = a/b and rem = a%b.
+    var testData = [
+      // --- divisors in (0, 2^32-1) to test full divisor range
+      // low(a)   high(a)    b          low(quot)  high(quot) rem
+      [0x712443f1, 0xe85cefcc, 0xc1a7050b, 0x332c79ad, 0x00000001, 0x92ffa882],
+      [0x11912915, 0xb2699eb5, 0x30467cbe, 0xb21b4be4, 0x00000003, 0x283465dd],
+      [0x0d917982, 0x201f2a6e, 0x3f35bf03, 0x8217c8e4, 0x00000000, 0x153402d6],
+      [0xa072c108, 0x74020c96, 0xc60568fd, 0x95f9613e, 0x00000000, 0x3f4676c2],
+      [0xd845d5d8, 0xcdd235c4, 0x20426475, 0x6154e78b, 0x00000006, 0x202fb751],
+      [0xa4dbf71f, 0x9e90465e, 0xf08e022f, 0xa8be947f, 0x00000000, 0xbe43b5ce],
+      [0x3dbe627f, 0xa791f4b9, 0x28a5bd89, 0x1f5dfe93, 0x00000004, 0x02bf9ed4],
+      [0x5c1c53ee, 0xccf5102e, 0x198576e7, 0x07e3ae31, 0x00000008, 0x02ea8fb7],
+      [0xfef1e581, 0x04714067, 0xca6540c1, 0x059e73ec, 0x00000000, 0x31658095],
+      [0x1e2dd90c, 0x13dd6667, 0x8b2184c3, 0x248d1a42, 0x00000000, 0x4ca6d0c6],
+      // --- divisors in (0, 2^16-1) to test larger quotient high-words
+      // low(a)   high(a)    b          low(quot)  high(quot) rem
+      [0x86722b47, 0x2cd57c9a, 0x00003123, 0x2ae41b7a, 0x0000e995, 0x00000f99],
+      [0x1dd7884c, 0xf5e839bc, 0x00009eeb, 0x5c886242, 0x00018c21, 0x000099b6],
+      [0x5c53d625, 0x899fc7e5, 0x000087d7, 0xd625007a, 0x0001035c, 0x000019af],
+      [0x6932d932, 0x9d0a5488, 0x000051fb, 0x9d976143, 0x0001ea63, 0x00004981],
+      [0x4d18bb85, 0x0c92fb31, 0x00001d9f, 0x03265ab4, 0x00006cac, 0x000001b9],
+      [0xbe756768, 0xdea67ccb, 0x00008a03, 0x58add442, 0x00019cff, 0x000056a2],
+      [0xe2466f9a, 0x2521f114, 0x0000c350, 0xa0c0860d, 0x000030ab, 0x0000a48a],
+      [0xf00ddad1, 0xe2f5446a, 0x00002cfc, 0x762697a6, 0x00050b96, 0x00000b69],
+      [0xa879152a, 0x0a70e0a5, 0x00007cdf, 0xb44151b3, 0x00001567, 0x0000363d],
+      [0x7179a74c, 0x46083fff, 0x0000253c, 0x4d39ba6e, 0x0001e17f, 0x00000f84]
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var result = a.div(testData[i][2]);
+      var quotient = result[0];
+      var remainder = result[1];
+      assertEquals(quotient.lo, testData[i][3]);
+      assertEquals(quotient.hi, testData[i][4]);
+      assertEquals(remainder.lo, testData[i][5]);
+    }
+  });
+
+
+  /**
+   * Tests .toString() and .fromString().
+   */
+  it('testStrings', function() {
+    var testData = [
+        [0x5e84c935, 0xcae33d0e, '14619595947299359029'],
+        [0x62b3b8b8, 0x93480544, '10612738313170434232'],
+        [0x319bfb13, 0xc01c4172, '13843011313344445203'],
+        [0x5b8a65fb, 0xa5885b31, '11927883880638080507'],
+        [0x6bdb80f1, 0xb0d1b16b, '12741159895737008369'],
+        [0x4b82b442, 0x2e0d8c97, '3318463081876730946'],
+        [0x780d5208, 0x7d76752c, '9040542135845999112'],
+        [0x2e46800f, 0x0993778d, '690026616168284175'],
+        [0xf00a7e32, 0xcd8e3931, '14811839111111540274'],
+        [0x1baeccd6, 0x923048c4, '10533999535534820566'],
+        [0x03669d29, 0xbff3ab72, '13831587386756603177'],
+        [0x2526073e, 0x01affc81, '121593346566522686'],
+        [0xc24244e0, 0xd7f40d0e, '15561076969511732448'],
+        [0xc56a341e, 0xa68b66a7, '12000798502816461854'],
+        [0x8738d64d, 0xbfe78604, '13828168534871037517'],
+        [0x5baff03b, 0xd7572aea, '15516918227177304123'],
+        [0x4a843d8a, 0x864e132b, '9677693725920476554'],
+        [0x25b4e94d, 0x22b54dc6, '2500990681505655117'],
+        [0x6bbe664b, 0x55a5cc0e, '6171563226690381387'],
+        [0xee916c81, 0xb00aabb3, '12685140089732426881']
+    ];
+
+    for (var i = 0; i < testData.length; i++) {
+      var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]);
+      var roundtrip = jspb.arith.UInt64.fromString(a.toString());
+      assertEquals(roundtrip.lo, a.lo);
+      assertEquals(roundtrip.hi, a.hi);
+      assertEquals(a.toString(), testData[i][2]);
+    }
+  });
+
+
+  /**
+   * Tests signed Int64s. These are built on UInt64s, so we only need to test
+   * the explicit overrides: .toString() and .fromString().
+   */
+  it('testSignedInt64', function() {
+    var testStrings = [
+        '-7847499644178593666',
+        '3771946501229139523',
+        '2872856549054995060',
+        '-5780049594274350904',
+        '3383785956695105201',
+        '2973055184857072610',
+        '-3879428459215627206',
+        '4589812431064156631',
+        '8484075557333689940',
+        '1075325817098092407',
+        '-4346697501012292314',
+        '2488620459718316637',
+        '6112655187423520672',
+        '-3655278273928612104',
+        '3439154019435803196',
+        '1004112478843763757',
+        '-6587790776614368413',
+        '664320065099714586',
+        '4760412909973292912',
+        '-7911903989602274672'
+    ];
+
+    for (var i = 0; i < testStrings.length; i++) {
+      var roundtrip =
+          jspb.arith.Int64.fromString(testStrings[i]).toString();
+      assertEquals(roundtrip, testStrings[i]);
+    }
+  });
+});
diff --git a/js/binary/constants.js b/js/binary/constants.js
new file mode 100644
index 0000000..a976e0b
--- /dev/null
+++ b/js/binary/constants.js
@@ -0,0 +1,320 @@
+// 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.
+
+/**
+ * @fileoverview This file contains constants and typedefs used by
+ * jspb.BinaryReader and BinaryWriter.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.AnyFieldType');
+goog.provide('jspb.BinaryConstants');
+goog.provide('jspb.BinaryMessage');
+goog.provide('jspb.BuilderFunction');
+goog.provide('jspb.ByteSource');
+goog.provide('jspb.ClonerFunction');
+goog.provide('jspb.ConstBinaryMessage');
+goog.provide('jspb.ReaderFunction');
+goog.provide('jspb.RecyclerFunction');
+goog.provide('jspb.WriterFunction');
+
+goog.forwardDeclare('jspb.Message');
+goog.forwardDeclare('jsproto.BinaryExtension');
+
+
+
+/**
+ * Base interface class for all const messages. Does __not__ define any
+ * methods, as doing so on a widely-used interface defeats dead-code
+ * elimination.
+ * @interface
+ */
+jspb.ConstBinaryMessage = function() {};
+
+
+
+/**
+ * Base interface class for all messages. Does __not__ define any methods, as
+ * doing so on a widely-used interface defeats dead-code elimination.
+ * @interface
+ * @extends {jspb.ConstBinaryMessage}
+ */
+jspb.BinaryMessage = function() {};
+
+
+/**
+ * The types convertible to Uint8Arrays. Strings are assumed to be
+ * base64-encoded.
+ * @typedef {ArrayBuffer|Uint8Array|Array<number>|string}
+ */
+jspb.ByteSource;
+
+
+/**
+ * A field in jspb can be a scalar, a block of bytes, another proto, or an
+ * array of any of the above.
+ * @typedef {boolean|number|string|Uint8Array|
+             jspb.BinaryMessage|jsproto.BinaryExtension|
+             Array<jspb.AnyFieldType>}
+ */
+jspb.AnyFieldType;
+
+
+/**
+ * A builder function creates an instance of a message object.
+ * @typedef {function():!jspb.BinaryMessage}
+ */
+jspb.BuilderFunction;
+
+
+/**
+ * A cloner function creates a deep copy of a message object.
+ * @typedef {function(jspb.ConstBinaryMessage):jspb.BinaryMessage}
+ */
+jspb.ClonerFunction;
+
+
+/**
+ * A recycler function destroys an instance of a message object.
+ * @typedef {function(!jspb.BinaryMessage):void}
+ */
+jspb.RecyclerFunction;
+
+
+/**
+ * A reader function initializes a message using data from a BinaryReader.
+ * @typedef {function(!jspb.BinaryMessage, !jspb.BinaryReader):void}
+ */
+jspb.ReaderFunction;
+
+
+/**
+ * A writer function serializes a message to a BinaryWriter.
+ * @typedef {!function(!jspb.Message, !jspb.BinaryWriter):void |
+ *           !function(!jspb.ConstBinaryMessage, !jspb.BinaryWriter):void}
+ */
+jspb.WriterFunction;
+
+
+/**
+ * Field type codes, taken from proto2/public/wire_format_lite.h.
+ * @enum {number}
+ */
+jspb.BinaryConstants.FieldType = {
+  INVALID: -1,
+  DOUBLE: 1,
+  FLOAT: 2,
+  INT64: 3,
+  UINT64: 4,
+  INT32: 5,
+  FIXED64: 6,
+  FIXED32: 7,
+  BOOL: 8,
+  STRING: 9,
+  GROUP: 10,
+  MESSAGE: 11,
+  BYTES: 12,
+  UINT32: 13,
+  ENUM: 14,
+  SFIXED32: 15,
+  SFIXED64: 16,
+  SINT32: 17,
+  SINT64: 18,
+
+  // Extended types for Javascript
+
+  FHASH64: 30, // 64-bit hash string, fixed-length encoding.
+  VHASH64: 31  // 64-bit hash string, varint encoding.
+};
+
+
+/**
+ * Wire-format type codes, taken from proto2/public/wire_format_lite.h.
+ * @enum {number}
+ */
+jspb.BinaryConstants.WireType = {
+  INVALID: -1,
+  VARINT: 0,
+  FIXED64: 1,
+  DELIMITED: 2,
+  START_GROUP: 3,
+  END_GROUP: 4,
+  FIXED32: 5
+};
+
+
+/**
+ * Translates field type to wire type.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @return {jspb.BinaryConstants.WireType}
+ */
+jspb.BinaryConstants.FieldTypeToWireType = function(fieldType) {
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  var wireTypes = jspb.BinaryConstants.WireType;
+  switch (fieldType) {
+    case fieldTypes.INT32:
+    case fieldTypes.INT64:
+    case fieldTypes.UINT32:
+    case fieldTypes.UINT64:
+    case fieldTypes.SINT32:
+    case fieldTypes.SINT64:
+    case fieldTypes.BOOL:
+    case fieldTypes.ENUM:
+    case fieldTypes.VHASH64:
+      return wireTypes.VARINT;
+
+    case fieldTypes.DOUBLE:
+    case fieldTypes.FIXED64:
+    case fieldTypes.SFIXED64:
+    case fieldTypes.FHASH64:
+      return wireTypes.FIXED64;
+
+    case fieldTypes.STRING:
+    case fieldTypes.MESSAGE:
+    case fieldTypes.BYTES:
+      return wireTypes.DELIMITED;
+
+    case fieldTypes.FLOAT:
+    case fieldTypes.FIXED32:
+    case fieldTypes.SFIXED32:
+      return wireTypes.FIXED32;
+
+    case fieldTypes.INVALID:
+    case fieldTypes.GROUP:
+    default:
+      return wireTypes.INVALID;
+  }
+};
+
+
+/**
+ * Flag to indicate a missing field.
+ * @const {number}
+ */
+jspb.BinaryConstants.INVALID_FIELD_NUMBER = -1;
+
+
+/**
+ * The smallest denormal float32 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_EPS = 1.401298464324817e-45;
+
+
+/**
+ * The smallest normal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_MIN = 1.1754943508222875e-38;
+
+
+/**
+ * The largest finite float32 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT32_MAX = 3.4028234663852886e+38;
+
+
+/**
+ * The smallest denormal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_EPS = 5e-324;
+
+
+/**
+ * The smallest normal float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_MIN = 2.2250738585072014e-308;
+
+
+/**
+ * The largest finite float64 value.
+ * @const {number}
+ */
+jspb.BinaryConstants.FLOAT64_MAX = 1.7976931348623157e+308;
+
+
+/**
+ * Convenience constant equal to 2^20.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_20 = 1048576;
+
+
+/**
+ * Convenience constant equal to 2^23.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_23 = 8388608;
+
+
+/**
+ * Convenience constant equal to 2^31.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_31 = 2147483648;
+
+
+/**
+ * Convenience constant equal to 2^32.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_32 = 4294967296;
+
+
+/**
+ * Convenience constant equal to 2^52.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_52 = 4503599627370496;
+
+
+/**
+ * Convenience constant equal to 2^63.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_63 = 9223372036854775808;
+
+
+/**
+ * Convenience constant equal to 2^64.
+ * @const {number}
+ */
+jspb.BinaryConstants.TWO_TO_64 = 18446744073709551616;
+
+
+/**
+ * Eight-character string of zeros, used as the default 64-bit hash value.
+ * @const {string}
+ */
+jspb.BinaryConstants.ZERO_HASH = '\0\0\0\0\0\0\0\0';
diff --git a/js/binary/decoder.js b/js/binary/decoder.js
new file mode 100644
index 0000000..9004eff
--- /dev/null
+++ b/js/binary/decoder.js
@@ -0,0 +1,1005 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for decoding primitive values
+ * (signed and unsigned integers, varints, booleans, enums, hashes, strings,
+ * and raw bytes) embedded in Uint8Arrays into their corresponding Javascript
+ * types.
+ *
+ * Major caveat - Javascript is unable to accurately represent integers larger
+ * than 2^53 due to its use of a double-precision floating point format or all
+ * numbers. If you need to guarantee that 64-bit values survive with all bits
+ * intact, you _must_ read them using one of the Hash64 methods, which return
+ * an 8-character string.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryDecoder');
+goog.provide('jspb.BinaryIterator');
+
+goog.require('goog.asserts');
+goog.require('jspb.utils');
+
+
+
+/**
+ * Simple helper class for traversing the contents of repeated scalar fields.
+ * that may or may not have been packed into a wire-format blob.
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @constructor
+ * @struct
+ */
+jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
+  /** @private {jspb.BinaryDecoder} */
+  this.decoder_ = null;
+
+  /**
+   * The BinaryDecoder member function used when iterating over packed data.
+   * @private {?function(this:jspb.BinaryDecoder):(number|boolean|string)}
+   */
+  this.nextMethod_ = null;
+
+  /** @private {Array.<number>} */
+  this.elements_ = null;
+
+  /** @private {number} */
+  this.cursor_ = 0;
+
+  /** @private {number|boolean|string|null} */
+  this.nextValue_ = null;
+
+  /** @private {boolean} */
+  this.atEnd_ = true;
+
+  this.init_(opt_decoder, opt_next, opt_elements);
+};
+
+
+/**
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @private
+ */
+jspb.BinaryIterator.prototype.init_ =
+    function(opt_decoder, opt_next, opt_elements) {
+  if (opt_decoder && opt_next) {
+    this.decoder_ = opt_decoder;
+    this.nextMethod_ = opt_next;
+  }
+  this.elements_ = opt_elements ? opt_elements : null;
+  this.cursor_ = 0;
+  this.nextValue_ = null;
+  this.atEnd_ = !this.decoder_ && !this.elements_;
+
+  this.next();
+};
+
+
+/**
+ * Global pool of BinaryIterator instances.
+ * @private {!Array.<!jspb.BinaryIterator>}
+ */
+jspb.BinaryIterator.instanceCache_ = [];
+
+
+/**
+ * Allocates a BinaryIterator from the cache, creating a new one if the cache
+ * is empty.
+ * @param {?jspb.BinaryDecoder=} opt_decoder
+ * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
+ *     opt_next The decoder method to use for next().
+ * @param {?Array.<number|boolean|string>=} opt_elements
+ * @return {!jspb.BinaryIterator}
+ */
+jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
+  if (jspb.BinaryIterator.instanceCache_.length) {
+    var iterator = jspb.BinaryIterator.instanceCache_.pop();
+    iterator.init_(opt_decoder, opt_next, opt_elements);
+    return iterator;
+  } else {
+    return new jspb.BinaryIterator(opt_decoder, opt_next, opt_elements);
+  }
+};
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryIterator.prototype.free = function() {
+  this.clear();
+  if (jspb.BinaryIterator.instanceCache_.length < 100) {
+    jspb.BinaryIterator.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Clears the iterator.
+ */
+jspb.BinaryIterator.prototype.clear = function() {
+  if (this.decoder_) {
+    this.decoder_.free();
+  }
+  this.decoder_ = null;
+  this.nextMethod_ = null;
+  this.elements_ = null;
+  this.cursor_ = 0;
+  this.nextValue_ = null;
+  this.atEnd_ = true;
+};
+
+
+/**
+ * Returns the element at the iterator, or null if the iterator is invalid or
+ * past the end of the decoder/array.
+ * @return {number|boolean|string|null}
+ */
+jspb.BinaryIterator.prototype.get = function() {
+  return this.nextValue_;
+};
+
+
+/**
+ * Returns true if the iterator is at the end of the decoder/array.
+ * @return {boolean}
+ */
+jspb.BinaryIterator.prototype.atEnd = function() {
+  return this.atEnd_;
+};
+
+
+/**
+ * Returns the element at the iterator and steps to the next element,
+ * equivalent to '*pointer++' in C.
+ * @return {number|boolean|string|null}
+ */
+jspb.BinaryIterator.prototype.next = function() {
+  var lastValue = this.nextValue_;
+  if (this.decoder_) {
+    if (this.decoder_.atEnd()) {
+      this.nextValue_ = null;
+      this.atEnd_ = true;
+    } else {
+      this.nextValue_ = this.nextMethod_.call(this.decoder_);
+    }
+  } else if (this.elements_) {
+    if (this.cursor_ == this.elements_.length) {
+      this.nextValue_ = null;
+      this.atEnd_ = true;
+    } else {
+      this.nextValue_ = this.elements_[this.cursor_++];
+    }
+  }
+  return lastValue;
+};
+
+
+
+/**
+ * BinaryDecoder implements the decoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @constructor
+ * @struct
+ */
+jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
+  /**
+   * Typed byte-wise view of the source buffer.
+   * @private {Uint8Array}
+   */
+  this.bytes_ = null;
+
+  /**
+   * Start point of the block to read.
+   * @private {number}
+   */
+  this.start_ = 0;
+
+  /**
+   * End point of the block to read.
+   * @private {number}
+   */
+  this.end_ = 0;
+
+  /**
+   * Current read location in bytes_.
+   * @private {number}
+   */
+  this.cursor_ = 0;
+
+  /**
+   * Temporary storage for the low 32 bits of 64-bit data types that we're
+   * decoding.
+   * @private {number}
+   */
+  this.tempLow_ = 0;
+
+  /**
+   * Temporary storage for the high 32 bits of 64-bit data types that we're
+   * decoding.
+   * @private {number}
+   */
+  this.tempHigh_ = 0;
+
+  /**
+   * Set to true if this decoder encountered an error due to corrupt data.
+   * @private {boolean}
+   */
+  this.error_ = false;
+
+  if (opt_bytes) {
+    this.setBlock(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Global pool of BinaryDecoder instances.
+ * @private {!Array.<!jspb.BinaryDecoder>}
+ */
+jspb.BinaryDecoder.instanceCache_ = [];
+
+
+/**
+ * Pops an instance off the instance cache, or creates one if the cache is
+ * empty.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryDecoder.alloc = function(opt_bytes, opt_start, opt_length) {
+  if (jspb.BinaryDecoder.instanceCache_.length) {
+    var newDecoder = jspb.BinaryDecoder.instanceCache_.pop();
+    if (opt_bytes) {
+      newDecoder.setBlock(opt_bytes, opt_start, opt_length);
+    }
+    return newDecoder;
+  } else {
+    return new jspb.BinaryDecoder(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryDecoder.prototype.free = function() {
+  this.clear();
+  if (jspb.BinaryDecoder.instanceCache_.length < 100) {
+    jspb.BinaryDecoder.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Makes a copy of this decoder.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryDecoder.prototype.clone = function() {
+  return jspb.BinaryDecoder.alloc(this.bytes_,
+      this.start_, this.end_ - this.start_);
+};
+
+
+/**
+ * Clears the decoder.
+ */
+jspb.BinaryDecoder.prototype.clear = function() {
+  this.bytes_ = null;
+  this.start_ = 0;
+  this.end_ = 0;
+  this.cursor_ = 0;
+  this.error_ = false;
+};
+
+
+/**
+ * Returns the raw buffer.
+ * @return {Uint8Array} The raw buffer.
+ */
+jspb.BinaryDecoder.prototype.getBuffer = function() {
+  return this.bytes_;
+};
+
+
+/**
+ * Changes the block of bytes we're decoding.
+ * @param {!jspb.ByteSource} data The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ */
+jspb.BinaryDecoder.prototype.setBlock =
+    function(data, opt_start, opt_length) {
+  this.bytes_ = jspb.utils.byteSourceToUint8Array(data);
+  this.start_ = goog.isDef(opt_start) ? opt_start : 0;
+  this.end_ =
+      goog.isDef(opt_length) ? this.start_ + opt_length : this.bytes_.length;
+  this.cursor_ = this.start_;
+};
+
+
+/**
+ * @return {number}
+ */
+jspb.BinaryDecoder.prototype.getEnd = function() {
+  return this.end_;
+};
+
+
+/**
+ * @param {number} end
+ */
+jspb.BinaryDecoder.prototype.setEnd = function(end) {
+  this.end_ = end;
+};
+
+
+/**
+ * Moves the read cursor back to the start of the block.
+ */
+jspb.BinaryDecoder.prototype.reset = function() {
+  this.cursor_ = this.start_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryDecoder.prototype.getCursor = function() {
+  return this.cursor_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @param {number} cursor The new cursor.
+ */
+jspb.BinaryDecoder.prototype.setCursor = function(cursor) {
+  this.cursor_ = cursor;
+};
+
+
+/**
+ * Advances the stream cursor by the given number of bytes.
+ * @param {number} count The number of bytes to advance by.
+ */
+jspb.BinaryDecoder.prototype.advance = function(count) {
+  this.cursor_ += count;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+};
+
+
+/**
+ * Returns true if this decoder is at the end of the block.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.atEnd = function() {
+  return this.cursor_ == this.end_;
+};
+
+
+/**
+ * Returns true if this decoder is at the end of the block.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.pastEnd = function() {
+  return this.cursor_ > this.end_;
+};
+
+
+/**
+ * Returns true if this decoder encountered an error due to corrupt data.
+ * @return {boolean}
+ */
+jspb.BinaryDecoder.prototype.getError = function() {
+  return this.error_ ||
+         (this.cursor_ < 0) ||
+         (this.cursor_ > this.end_);
+};
+
+
+/**
+ * Reads an unsigned varint from the binary stream and stores it as a split
+ * 64-bit integer. Since this does not convert the value to a number, no
+ * precision is lost.
+ *
+ * It's possible for an unsigned varint to be incorrectly encoded - more than
+ * 64 bits' worth of data could be present. If this happens, this method will
+ * throw an error.
+ *
+ * Decoding varints requires doing some funny base-128 math - for more
+ * details on the format, see
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @private
+ */
+jspb.BinaryDecoder.prototype.readSplitVarint64_ = function() {
+  var temp;
+  var lowBits = 0;
+  var highBits = 0;
+
+  // Read the first four bytes of the varint, stopping at the terminator if we
+  // see it.
+  for (var i = 0; i < 4; i++) {
+    temp = this.bytes_[this.cursor_++];
+    lowBits |= (temp & 0x7F) << (i * 7);
+    if (temp < 128) {
+      this.tempLow_ = lowBits >>> 0;
+      this.tempHigh_ = 0;
+      return;
+    }
+  }
+
+  // Read the fifth byte, which straddles the low and high dwords.
+  temp = this.bytes_[this.cursor_++];
+  lowBits |= (temp & 0x7F) << 28;
+  highBits |= (temp & 0x7F) >> 4;
+  if (temp < 128) {
+    this.tempLow_ = lowBits >>> 0;
+    this.tempHigh_ = highBits >>> 0;
+    return;
+  }
+
+  // Read the sixth through tenth byte.
+  for (var i = 0; i < 5; i++) {
+    temp = this.bytes_[this.cursor_++];
+    highBits |= (temp & 0x7F) << (i * 7 + 3);
+    if (temp < 128) {
+      this.tempLow_ = lowBits >>> 0;
+      this.tempHigh_ = highBits >>> 0;
+      return;
+    }
+  }
+
+  // If we did not see the terminator, the encoding was invalid.
+  goog.asserts.fail('Failed to read varint, encoding is invalid.');
+  this.error_ = true;
+};
+
+
+/**
+ * Skips over a varint in the block without decoding it.
+ */
+jspb.BinaryDecoder.prototype.skipVarint = function() {
+  while (this.bytes_[this.cursor_] & 0x80) {
+    this.cursor_++;
+  }
+  this.cursor_++;
+};
+
+
+/**
+ * Skips backwards over a varint in the block - to do this correctly, we have
+ * to know the value we're skipping backwards over or things are ambiguous.
+ * @param {number} value The varint value to unskip.
+ */
+jspb.BinaryDecoder.prototype.unskipVarint = function(value) {
+  while (value > 128) {
+    this.cursor_--;
+    value = value >>> 7;
+  }
+  this.cursor_--;
+};
+
+
+/**
+ * Reads a 32-bit varint from the binary stream. Due to a quirk of the encoding
+ * format and Javascript's handling of bitwise math, this actually works
+ * correctly for both signed and unsigned 32-bit varints.
+ *
+ * This function is called vastly more frequently than any other in
+ * BinaryDecoder, so it has been unrolled and tweaked for performance.
+ *
+ * If there are more than 32 bits of data in the varint, it _must_ be due to
+ * sign-extension. If we're in debug mode and the high 32 bits don't match the
+ * expected sign extension, this method will throw an error.
+ *
+ * Decoding varints requires doing some funny base-128 math - for more
+ * details on the format, see
+ * https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded unsigned 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() {
+  var temp;
+  var bytes = this.bytes_;
+
+  temp = bytes[this.cursor_ + 0];
+  var x = (temp & 0x7F);
+  if (temp < 128) {
+    this.cursor_ += 1;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 1];
+  x |= (temp & 0x7F) << 7;
+  if (temp < 128) {
+    this.cursor_ += 2;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 2];
+  x |= (temp & 0x7F) << 14;
+  if (temp < 128) {
+    this.cursor_ += 3;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 3];
+  x |= (temp & 0x7F) << 21;
+  if (temp < 128) {
+    this.cursor_ += 4;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x;
+  }
+
+  temp = bytes[this.cursor_ + 4];
+  x |= (temp & 0x0F) << 28;
+  if (temp < 128) {
+    // We're reading the high bits of an unsigned varint. The byte we just read
+    // also contains bits 33 through 35, which we're going to discard. Those
+    // bits _must_ be zero, or the encoding is invalid.
+    goog.asserts.assert((temp & 0xF0) == 0);
+    this.cursor_ += 5;
+    goog.asserts.assert(this.cursor_ <= this.end_);
+    return x >>> 0;
+  }
+
+  // If we get here, we're reading the sign extension of a negative 32-bit int.
+  // We can skip these bytes, as we know in advance that they have to be all
+  // 1's if the varint is correctly encoded. Since we also know the value is
+  // negative, we don't have to coerce it to unsigned before we return it.
+
+  goog.asserts.assert((temp & 0xF0) == 0xF0);
+  goog.asserts.assert(bytes[this.cursor_ + 5] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 6] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 7] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 8] == 0xFF);
+  goog.asserts.assert(bytes[this.cursor_ + 9] == 0x01);
+
+  this.cursor_ += 10;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return x;
+};
+
+
+/**
+ * The readUnsignedVarint32 above deals with signed 32-bit varints correctly,
+ * so this is just an alias.
+ *
+ * @return {number} The decoded signed 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint32 =
+    jspb.BinaryDecoder.prototype.readUnsignedVarint32;
+
+
+/**
+ * Reads a 32-bit unsigned variant and returns its value as a string.
+ *
+ * @return {string} The decoded unsigned 32-bit varint as a string.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() {
+  // 32-bit integers fit in JavaScript numbers without loss of precision, so
+  // string variants of 32-bit varint readers can simply delegate then convert
+  // to string.
+  var value = this.readUnsignedVarint32();
+  return value.toString();
+};
+
+/**
+ * Reads a 32-bit signed variant and returns its value as a string.
+ *
+ * @return {string} The decoded signed 32-bit varint as a string.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
+  // 32-bit integers fit in JavaScript numbers without loss of precision, so
+  // string variants of 32-bit varint readers can simply delegate then convert
+  // to string.
+  var value = this.readSignedVarint32();
+  return value.toString();
+};
+
+
+/**
+ * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
+ *
+ * Zigzag encoding is a modification of varint encoding that reduces the
+ * storage overhead for small negative integers - for more details on the
+ * format, see https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
+ */
+jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
+  var result = this.readUnsignedVarint32();
+  return (result >>> 1) ^ - (result & 1);
+};
+
+
+/**
+ * Reads an unsigned 64-bit varint from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the varint is larger than 2^53.
+ *
+ * @return {number} The decoded unsigned varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads an unsigned 64-bit varint from the binary stream and returns the value
+ * as a decimal string.
+ *
+ * @return {string} The decoded unsigned varint as a decimal string.
+ */
+jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a signed 64-bit varint from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the varint is larger than 2^53.
+ *
+ * @return {number} The decoded signed varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads an signed 64-bit varint from the binary stream and returns the value
+ * as a decimal string.
+ *
+ * @return {string} The decoded signed varint as a decimal string.
+ */
+jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
+ * that since Javascript represents all numbers as double-precision floats,
+ * there will be precision lost if the absolute value of the varint is larger
+ * than 2^53.
+ *
+ * Zigzag encoding is a modification of varint encoding that reduces the
+ * storage overhead for small negative integers - for more details on the
+ * format, see https://developers.google.com/protocol-buffers/docs/encoding
+ *
+ * @return {number} The decoded zigzag varint. Precision will be lost if the
+ *     integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a raw unsigned 8-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 8-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint8 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  this.cursor_ += 1;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return a;
+};
+
+
+/**
+ * Reads a raw unsigned 16-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 16-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint16 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  this.cursor_ += 2;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 0) | (b << 8);
+};
+
+
+/**
+ * Reads a raw unsigned 32-bit integer from the binary stream.
+ *
+ * @return {number} The unsigned 32-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readUint32 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  var c = this.bytes_[this.cursor_ + 2];
+  var d = this.bytes_[this.cursor_ + 3];
+  this.cursor_ += 4;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
+};
+
+
+/**
+ * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute value of the integer is larger than 2^53.
+ *
+ * @return {number} The unsigned 64-bit integer read from the binary stream.
+ *     Precision will be lost if the integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readUint64 = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinUint64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a raw signed 8-bit integer from the binary stream.
+ *
+ * @return {number} The signed 8-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt8 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  this.cursor_ += 1;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 24) >> 24;
+};
+
+
+/**
+ * Reads a raw signed 16-bit integer from the binary stream.
+ *
+ * @return {number} The signed 16-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt16 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  this.cursor_ += 2;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (((a << 0) | (b << 8)) << 16) >> 16;
+};
+
+
+/**
+ * Reads a raw signed 32-bit integer from the binary stream.
+ *
+ * @return {number} The signed 32-bit integer read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readInt32 = function() {
+  var a = this.bytes_[this.cursor_ + 0];
+  var b = this.bytes_[this.cursor_ + 1];
+  var c = this.bytes_[this.cursor_ + 2];
+  var d = this.bytes_[this.cursor_ + 3];
+  this.cursor_ += 4;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return (a << 0) | (b << 8) | (c << 16) | (d << 24);
+};
+
+
+/**
+ * Reads a raw signed 64-bit integer from the binary stream. Note that since
+ * Javascript represents all numbers as double-precision floats, there will be
+ * precision lost if the absolute vlaue of the integer is larger than 2^53.
+ *
+ * @return {number} The signed 64-bit integer read from the binary stream.
+ *     Precision will be lost if the integer exceeds 2^53.
+ */
+jspb.BinaryDecoder.prototype.readInt64 = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinInt64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a 32-bit floating-point number from the binary stream, using the
+ * temporary buffer to realign the data.
+ *
+ * @return {number} The float read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readFloat = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = 0;
+  return jspb.utils.joinFloat32(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a 64-bit floating-point number from the binary stream, using the
+ * temporary buffer to realign the data.
+ *
+ * @return {number} The double read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readDouble = function() {
+  var bitsLow = this.readUint32();
+  var bitsHigh = this.readUint32();
+  return jspb.utils.joinFloat64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Reads a boolean value from the binary stream.
+ * @return {boolean} The boolean read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readBool = function() {
+  return !!this.bytes_[this.cursor_++];
+};
+
+
+/**
+ * Reads an enum value from the binary stream, which are always encoded as
+ * signed varints.
+ * @return {number} The enum value read from the binary stream.
+ */
+jspb.BinaryDecoder.prototype.readEnum = function() {
+  return this.readSignedVarint32();
+};
+
+
+/**
+ * Reads and parses a UTF-8 encoded unicode string from the stream.
+ * The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with
+ * the exception that the implementation here does not get confused if it
+ * encounters characters longer than three bytes. These characters are ignored
+ * though, as they are extremely rare: three UTF-8 bytes cover virtually all
+ * characters in common use (http://en.wikipedia.org/wiki/UTF-8).
+ * @param {number} length The length of the string to read.
+ * @return {string} The decoded string.
+ */
+jspb.BinaryDecoder.prototype.readString = function(length) {
+  var bytes = this.bytes_;
+  var cursor = this.cursor_;
+  var end = cursor + length;
+  var chars = [];
+
+  while (cursor < end) {
+    var c = bytes[cursor++];
+    if (c < 128) { // Regular 7-bit ASCII.
+      chars.push(c);
+    } else if (c < 192) {
+      // UTF-8 continuation mark. We are out of sync. This
+      // might happen if we attempted to read a character
+      // with more than three bytes.
+      continue;
+    } else if (c < 224) { // UTF-8 with two bytes.
+      var c2 = bytes[cursor++];
+      chars.push(((c & 31) << 6) | (c2 & 63));
+    } else if (c < 240) { // UTF-8 with three bytes.
+      var c2 = bytes[cursor++];
+      var c3 = bytes[cursor++];
+      chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+    }
+  }
+
+  // String.fromCharCode.apply is faster than manually appending characters on
+  // Chrome 25+, and generates no additional cons string garbage.
+  var result = String.fromCharCode.apply(null, chars);
+  this.cursor_ = cursor;
+  return result;
+};
+
+
+/**
+ * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
+ * the stream.
+ * @return {string} The decoded string.
+ */
+jspb.BinaryDecoder.prototype.readStringWithLength = function() {
+  var length = this.readUnsignedVarint32();
+  return this.readString(length);
+};
+
+
+/**
+ * Reads a block of raw bytes from the binary stream.
+ *
+ * @param {number} length The number of bytes to read.
+ * @return {Uint8Array} The decoded block of bytes, or null if the length was
+ *     invalid.
+ */
+jspb.BinaryDecoder.prototype.readBytes = function(length) {
+  if (length < 0 ||
+      this.cursor_ + length > this.bytes_.length) {
+    this.error_ = true;
+    return null;
+  }
+
+  var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
+
+  this.cursor_ += length;
+  goog.asserts.assert(this.cursor_ <= this.end_);
+  return result;
+};
+
+
+/**
+ * Reads a 64-bit varint from the stream and returns it as an 8-character
+ * Unicode string for use as a hash table key.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
+  this.readSplitVarint64_();
+  return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
+};
+
+
+/**
+ * Reads a 64-bit fixed-width value from the stream and returns it as an
+ * 8-character Unicode string for use as a hash table key.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
+  var bytes = this.bytes_;
+  var cursor = this.cursor_;
+
+  var a = bytes[cursor + 0];
+  var b = bytes[cursor + 1];
+  var c = bytes[cursor + 2];
+  var d = bytes[cursor + 3];
+  var e = bytes[cursor + 4];
+  var f = bytes[cursor + 5];
+  var g = bytes[cursor + 6];
+  var h = bytes[cursor + 7];
+
+  this.cursor_ += 8;
+
+  return String.fromCharCode(a, b, c, d, e, f, g, h);
+};
diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js
new file mode 100644
index 0000000..27342e4
--- /dev/null
+++ b/js/binary/decoder_test.js
@@ -0,0 +1,327 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer decoder.
+ *
+ * There are two particular magic numbers that need to be pointed out -
+ * 2^64-1025 is the largest number representable as both a double and an
+ * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
+ * both a double and a signed 64-bit integer.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+goog.require('jspb.BinaryWriter');
+
+
+/**
+ * Tests raw encoding and decoding of unsigned types.
+ * @param {Function} readValue
+ * @param {Function} writeValue
+ * @param {number} epsilon
+ * @param {number} upperLimit
+ * @param {Function} filter
+ * @suppress {missingProperties|visibility}
+ */
+function doTestUnsignedValue(readValue,
+    writeValue, epsilon, upperLimit, filter) {
+  var writer = new jspb.BinaryWriter();
+
+  // Encode zero and limits.
+  writeValue.call(writer, filter(0));
+  writeValue.call(writer, filter(epsilon));
+  writeValue.call(writer, filter(upperLimit));
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    writeValue.call(writer, filter(cursor));
+  }
+
+  var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+  // Check zero and limits.
+  assertEquals(filter(0), readValue.call(reader));
+  assertEquals(filter(epsilon), readValue.call(reader));
+  assertEquals(filter(upperLimit), readValue.call(reader));
+
+  // Check positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    if (filter(cursor) != readValue.call(reader)) throw 'fail!';
+  }
+}
+
+
+/**
+ * Tests raw encoding and decoding of signed types.
+ * @param {Function} readValue
+ * @param {Function} writeValue
+ * @param {number} epsilon
+ * @param {number} lowerLimit
+ * @param {number} upperLimit
+ * @param {Function} filter
+ * @suppress {missingProperties}
+ */
+function doTestSignedValue(readValue,
+    writeValue, epsilon, lowerLimit, upperLimit, filter) {
+  var writer = new jspb.BinaryWriter();
+
+  // Encode zero and limits.
+  writeValue.call(writer, filter(lowerLimit));
+  writeValue.call(writer, filter(-epsilon));
+  writeValue.call(writer, filter(0));
+  writeValue.call(writer, filter(epsilon));
+  writeValue.call(writer, filter(upperLimit));
+
+  var inputValues = [];
+
+  // Encode negative values.
+  for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(writer, val);
+    inputValues.push(val);
+  }
+
+  // Encode positive values.
+  for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+    var val = filter(cursor);
+    writeValue.call(writer, val);
+    inputValues.push(val);
+  }
+
+  var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+  // Check zero and limits.
+  assertEquals(filter(lowerLimit), readValue.call(reader));
+  assertEquals(filter(-epsilon), readValue.call(reader));
+  assertEquals(filter(0), readValue.call(reader));
+  assertEquals(filter(epsilon), readValue.call(reader));
+  assertEquals(filter(upperLimit), readValue.call(reader));
+
+  // Verify decoded values.
+  for (var i = 0; i < inputValues.length; i++) {
+    assertEquals(inputValues[i], readValue.call(reader));
+  }
+}
+
+describe('binaryDecoderTest', function() {
+  /**
+   * Tests the decoder instance cache.
+   * @suppress {visibility}
+   */
+  it('testInstanceCache', function() {
+    // Empty the instance caches.
+    jspb.BinaryDecoder.instanceCache_ = [];
+
+    // Allocating and then freeing a decoder should put it in the instance
+    // cache.
+    jspb.BinaryDecoder.alloc().free();
+
+    assertEquals(1, jspb.BinaryDecoder.instanceCache_.length);
+
+    // Allocating and then freeing three decoders should leave us with three in
+    // the cache.
+
+    var decoder1 = jspb.BinaryDecoder.alloc();
+    var decoder2 = jspb.BinaryDecoder.alloc();
+    var decoder3 = jspb.BinaryDecoder.alloc();
+    decoder1.free();
+    decoder2.free();
+    decoder3.free();
+
+    assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
+  });
+
+
+  /**
+   * Tests reading 64-bit integers as hash strings.
+   */
+  it('testHashStrings', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var hashA = String.fromCharCode(0x00, 0x00, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00);
+    var hashB = String.fromCharCode(0x12, 0x34, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00);
+    var hashC = String.fromCharCode(0x12, 0x34, 0x56, 0x78,
+                                    0x87, 0x65, 0x43, 0x21);
+    var hashD = String.fromCharCode(0xFF, 0xFF, 0xFF, 0xFF,
+                                    0xFF, 0xFF, 0xFF, 0xFF);
+
+    writer.rawWriteVarintHash64(hashA);
+    writer.rawWriteVarintHash64(hashB);
+    writer.rawWriteVarintHash64(hashC);
+    writer.rawWriteVarintHash64(hashD);
+
+    writer.rawWriteFixedHash64(hashA);
+    writer.rawWriteFixedHash64(hashB);
+    writer.rawWriteFixedHash64(hashC);
+    writer.rawWriteFixedHash64(hashD);
+
+    var decoder = jspb.BinaryDecoder.alloc(writer.getResultBuffer());
+
+    assertEquals(hashA, decoder.readVarintHash64());
+    assertEquals(hashB, decoder.readVarintHash64());
+    assertEquals(hashC, decoder.readVarintHash64());
+    assertEquals(hashD, decoder.readVarintHash64());
+
+    assertEquals(hashA, decoder.readFixedHash64());
+    assertEquals(hashB, decoder.readFixedHash64());
+    assertEquals(hashC, decoder.readFixedHash64());
+    assertEquals(hashD, decoder.readFixedHash64());
+  });
+
+
+  /**
+   * Verifies that misuse of the decoder class triggers assertions.
+   * @suppress {checkTypes|visibility}
+   */
+  it('testDecodeErrors', function() {
+    // Reading a value past the end of the stream should trigger an assertion.
+    var decoder = jspb.BinaryDecoder.alloc([0, 1, 2]);
+    assertThrows(function() {decoder.readUint64()});
+
+    // Overlong varints should trigger assertions.
+    decoder.setBlock(
+        [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0]);
+    assertThrows(function() {decoder.readUnsignedVarint64()});
+    decoder.reset();
+    assertThrows(function() {decoder.readSignedVarint64()});
+    decoder.reset();
+    assertThrows(function() {decoder.readZigzagVarint64()});
+
+    // Positive 32-bit varints encoded with 1 bits in positions 33 through 35
+    // should trigger assertions.
+    decoder.setBlock([255, 255, 255, 255, 0x1F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 0x2F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 0x4F]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    // Negative 32-bit varints encoded with non-1 bits in the high dword should
+    // trigger assertions.
+    decoder.setBlock([255, 255, 255, 255, 255, 255, 0, 255, 255, 1]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+
+    decoder.setBlock([255, 255, 255, 255, 255, 255, 255, 255, 255, 0]);
+    assertThrows(function() {decoder.readUnsignedVarint32()});
+  });
+
+
+  /**
+   * Tests raw encoding and decoding of unsigned integers.
+   */
+  it('testRawUnsigned', function() {
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint8,
+        jspb.BinaryWriter.prototype.rawWriteUint8,
+        1, 0xFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint16,
+        jspb.BinaryWriter.prototype.rawWriteUint16,
+        1, 0xFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint32,
+        jspb.BinaryWriter.prototype.rawWriteUint32,
+        1, 0xFFFFFFFF, Math.round);
+
+    doTestUnsignedValue(
+        jspb.BinaryDecoder.prototype.readUint64,
+        jspb.BinaryWriter.prototype.rawWriteUint64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+  });
+
+
+  /**
+   * Tests raw encoding and decoding of signed integers.
+   */
+  it('testRawSigned', function() {
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt8,
+        jspb.BinaryWriter.prototype.rawWriteInt8,
+        1, -0x80, 0x7F, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt16,
+        jspb.BinaryWriter.prototype.rawWriteInt16,
+        1, -0x8000, 0x7FFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt32,
+        jspb.BinaryWriter.prototype.rawWriteInt32,
+        1, -0x80000000, 0x7FFFFFFF, Math.round);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readInt64,
+        jspb.BinaryWriter.prototype.rawWriteInt64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests raw encoding and decoding of floats.
+   */
+  it('testRawFloats', function() {
+    /**
+     * @param {number} x
+     * @return {number}
+     */
+    function truncate(x) {
+      var temp = new Float32Array(1);
+      temp[0] = x;
+      return temp[0];
+    }
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readFloat,
+        jspb.BinaryWriter.prototype.rawWriteFloat,
+        jspb.BinaryConstants.FLOAT32_EPS,
+        -jspb.BinaryConstants.FLOAT32_MAX,
+        jspb.BinaryConstants.FLOAT32_MAX,
+        truncate);
+
+    doTestSignedValue(
+        jspb.BinaryDecoder.prototype.readDouble,
+        jspb.BinaryWriter.prototype.rawWriteDouble,
+        jspb.BinaryConstants.FLOAT64_EPS * 10,
+        -jspb.BinaryConstants.FLOAT64_MAX,
+        jspb.BinaryConstants.FLOAT64_MAX,
+        function(x) { return x; });
+  });
+});
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
new file mode 100644
index 0000000..817f8a7
--- /dev/null
+++ b/js/binary/proto_test.js
@@ -0,0 +1,489 @@
+// 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.
+
+// Test suite is written using Jasmine -- see http://jasmine.github.io/
+
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
+goog.require('proto.jspb.test.ExtendsWithMessage');
+goog.require('proto.jspb.test.ForeignEnum');
+goog.require('proto.jspb.test.ForeignMessage');
+goog.require('proto.jspb.test.TestAllTypes');
+goog.require('proto.jspb.test.TestExtendable');
+
+var suite = {};
+
+/**
+ * Helper: fill all fields on a TestAllTypes message.
+ * @param {proto.jspb.test.TestAllTypes} msg
+ */
+function fillAllFields(msg) {
+  msg.setOptionalInt32(-42);
+  // can be exactly represented by JS number (64-bit double, i.e., 52-bit
+  // mantissa).
+  msg.setOptionalInt64(-0x7fffffff00000000);
+  msg.setOptionalUint32(0x80000000);
+  msg.setOptionalUint64(0xf000000000000000);
+  msg.setOptionalSint32(-100);
+  msg.setOptionalSint64(-0x8000000000000000);
+  msg.setOptionalFixed32(1234);
+  msg.setOptionalFixed64(0x1234567800000000);
+  msg.setOptionalSfixed32(-1234);
+  msg.setOptionalSfixed64(-0x1234567800000000);
+  msg.setOptionalFloat(1.5);
+  msg.setOptionalDouble(-1.5);
+  msg.setOptionalBool(true);
+  msg.setOptionalString('hello world');
+  msg.setOptionalBytes('bytes');
+  msg.setOptionalGroup(new proto.jspb.test.TestAllTypes.OptionalGroup());
+  msg.getOptionalGroup().setA(100);
+  var submsg = new proto.jspb.test.ForeignMessage();
+  submsg.setC(16);
+  msg.setOptionalForeignMessage(submsg);
+  msg.setOptionalForeignEnum(proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+  msg.setOneofString('oneof');
+
+  msg.setRepeatedInt32List([-42]);
+  msg.setRepeatedInt64List([-0x7fffffff00000000]);
+  msg.setRepeatedUint32List([0x80000000]);
+  msg.setRepeatedUint64List([0xf000000000000000]);
+  msg.setRepeatedSint32List([-100]);
+  msg.setRepeatedSint64List([-0x8000000000000000]);
+  msg.setRepeatedFixed32List([1234]);
+  msg.setRepeatedFixed64List([0x1234567800000000]);
+  msg.setRepeatedSfixed32List([-1234]);
+  msg.setRepeatedSfixed64List([-0x1234567800000000]);
+  msg.setRepeatedFloatList([1.5]);
+  msg.setRepeatedDoubleList([-1.5]);
+  msg.setRepeatedBoolList([true]);
+  msg.setRepeatedStringList(['hello world']);
+  msg.setRepeatedBytesList(['bytes']);
+  msg.setRepeatedGroupList([new proto.jspb.test.TestAllTypes.RepeatedGroup()]);
+  msg.getRepeatedGroupList()[0].setA(100);
+  submsg = new proto.jspb.test.ForeignMessage();
+  submsg.setC(1000);
+  msg.setRepeatedForeignMessageList([submsg]);
+  msg.setRepeatedForeignEnumList([proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  msg.setPackedRepeatedInt32List([-42]);
+  msg.setPackedRepeatedInt64List([-0x7fffffff00000000]);
+  msg.setPackedRepeatedUint32List([0x80000000]);
+  msg.setPackedRepeatedUint64List([0xf000000000000000]);
+  msg.setPackedRepeatedSint32List([-100]);
+  msg.setPackedRepeatedSint64List([-0x8000000000000000]);
+  msg.setPackedRepeatedFixed32List([1234]);
+  msg.setPackedRepeatedFixed64List([0x1234567800000000]);
+  msg.setPackedRepeatedSfixed32List([-1234]);
+  msg.setPackedRepeatedSfixed64List([-0x1234567800000000]);
+  msg.setPackedRepeatedFloatList([1.5]);
+  msg.setPackedRepeatedDoubleList([-1.5]);
+  msg.setPackedRepeatedBoolList([true]);
+}
+
+
+/**
+ * Helper: compare a bytes field to a string with codepoints 0--255.
+ * @param {Uint8Array|string} arr
+ * @param {string} str
+ * @return {boolean}
+ */
+function bytesCompare(arr, str) {
+  if (arr.length != str.length) {
+    return false;
+  }
+  if (typeof arr == 'string') {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr.charCodeAt(i) != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr[i] != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+
+/**
+ * Helper: verify contents of given TestAllTypes message as set by
+ * fillAllFields().
+ * @param {proto.jspb.test.TestAllTypes} msg
+ */
+function checkAllFields(msg) {
+  assertEquals(msg.getOptionalInt32(), -42);
+  assertEquals(msg.getOptionalInt64(), -0x7fffffff00000000);
+  assertEquals(msg.getOptionalUint32(), 0x80000000);
+  assertEquals(msg.getOptionalUint64(), 0xf000000000000000);
+  assertEquals(msg.getOptionalSint32(), -100);
+  assertEquals(msg.getOptionalSint64(), -0x8000000000000000);
+  assertEquals(msg.getOptionalFixed32(), 1234);
+  assertEquals(msg.getOptionalFixed64(), 0x1234567800000000);
+  assertEquals(msg.getOptionalSfixed32(), -1234);
+  assertEquals(msg.getOptionalSfixed64(), -0x1234567800000000);
+  assertEquals(msg.getOptionalFloat(), 1.5);
+  assertEquals(msg.getOptionalDouble(), -1.5);
+  assertEquals(msg.getOptionalBool(), true);
+  assertEquals(msg.getOptionalString(), 'hello world');
+  assertEquals(true, bytesCompare(msg.getOptionalBytes(), 'bytes'));
+  assertEquals(msg.getOptionalGroup().getA(), 100);
+  assertEquals(msg.getOptionalForeignMessage().getC(), 16);
+  assertEquals(msg.getOptionalForeignEnum(),
+      proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+  assertEquals(msg.getOneofString(), 'oneof');
+  assertEquals(msg.getOneofFieldCase(),
+      proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING);
+
+  assertElementsEquals(msg.getRepeatedInt32List(), [-42]);
+  assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]);
+  assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]);
+  assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]);
+  assertElementsEquals(msg.getRepeatedSint32List(), [-100]);
+  assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]);
+  assertElementsEquals(msg.getRepeatedFixed32List(), [1234]);
+  assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]);
+  assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]);
+  assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]);
+  assertElementsEquals(msg.getRepeatedFloatList(), [1.5]);
+  assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]);
+  assertElementsEquals(msg.getRepeatedBoolList(), [true]);
+  assertElementsEquals(msg.getRepeatedStringList(), ['hello world']);
+  assertEquals(msg.getRepeatedBytesList().length, 1);
+  assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], 'bytes'));
+  assertEquals(msg.getRepeatedGroupList().length, 1);
+  assertEquals(msg.getRepeatedGroupList()[0].getA(), 100);
+  assertEquals(msg.getRepeatedForeignMessageList().length, 1);
+  assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
+  assertElementsEquals(msg.getRepeatedForeignEnumList(),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  assertElementsEquals(msg.getPackedRepeatedInt32List(), [-42]);
+  assertElementsEquals(msg.getPackedRepeatedInt64List(),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(msg.getPackedRepeatedUint32List(), [0x80000000]);
+  assertElementsEquals(msg.getPackedRepeatedUint64List(), [0xf000000000000000]);
+  assertElementsEquals(msg.getPackedRepeatedSint32List(), [-100]);
+  assertElementsEquals(msg.getPackedRepeatedSint64List(),
+      [-0x8000000000000000]);
+  assertElementsEquals(msg.getPackedRepeatedFixed32List(), [1234]);
+  assertElementsEquals(msg.getPackedRepeatedFixed64List(),
+      [0x1234567800000000]);
+  assertElementsEquals(msg.getPackedRepeatedSfixed32List(), [-1234]);
+  assertElementsEquals(msg.getPackedRepeatedSfixed64List(),
+      [-0x1234567800000000]);
+  assertElementsEquals(msg.getPackedRepeatedFloatList(), [1.5]);
+  assertElementsEquals(msg.getPackedRepeatedDoubleList(), [-1.5]);
+  assertElementsEquals(msg.getPackedRepeatedBoolList(), [true]);
+}
+
+
+/**
+ * Helper: verify that all expected extensions are present.
+ * @param {!proto.jspb.test.TestExtendable} msg
+ */
+function checkExtensions(msg) {
+  assertEquals(-42,
+      msg.getExtension(proto.jspb.test.extendOptionalInt32));
+  assertEquals(-0x7fffffff00000000,
+      msg.getExtension(proto.jspb.test.extendOptionalInt64));
+  assertEquals(0x80000000,
+      msg.getExtension(proto.jspb.test.extendOptionalUint32));
+  assertEquals(0xf000000000000000,
+      msg.getExtension(proto.jspb.test.extendOptionalUint64));
+  assertEquals(-100,
+      msg.getExtension(proto.jspb.test.extendOptionalSint32));
+  assertEquals(-0x8000000000000000,
+      msg.getExtension(proto.jspb.test.extendOptionalSint64));
+  assertEquals(1234,
+      msg.getExtension(proto.jspb.test.extendOptionalFixed32));
+  assertEquals(0x1234567800000000,
+      msg.getExtension(proto.jspb.test.extendOptionalFixed64));
+  assertEquals(-1234,
+      msg.getExtension(proto.jspb.test.extendOptionalSfixed32));
+  assertEquals(-0x1234567800000000,
+      msg.getExtension(proto.jspb.test.extendOptionalSfixed64));
+  assertEquals(1.5,
+      msg.getExtension(proto.jspb.test.extendOptionalFloat));
+  assertEquals(-1.5,
+      msg.getExtension(proto.jspb.test.extendOptionalDouble));
+  assertEquals(true,
+      msg.getExtension(proto.jspb.test.extendOptionalBool));
+  assertEquals('hello world',
+      msg.getExtension(proto.jspb.test.extendOptionalString));
+  assertEquals(true,
+      bytesCompare(msg.getExtension(proto.jspb.test.extendOptionalBytes),
+        'bytes'));
+  assertEquals(16,
+      msg.getExtension(
+          proto.jspb.test.ExtendsWithMessage.optionalExtension).getFoo());
+  assertEquals(proto.jspb.test.ForeignEnum.FOREIGN_FOO,
+      msg.getExtension(proto.jspb.test.extendOptionalForeignEnum));
+
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedInt32List),
+      [-42]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedInt64List),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedUint32List),
+      [0x80000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedUint64List),
+      [0xf000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSint32List),
+      [-100]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSint64List),
+      [-0x8000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFixed32List),
+      [1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFixed64List),
+      [0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSfixed32List),
+      [-1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedSfixed64List),
+      [-0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedFloatList),
+      [1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedDoubleList),
+      [-1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedBoolList),
+      [true]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedStringList),
+      ['hello world']);
+  assertEquals(true,
+      bytesCompare(
+          msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0],
+          'bytes'));
+  assertEquals(1000,
+      msg.getExtension(
+          proto.jspb.test.ExtendsWithMessage.repeatedExtensionList)[0]
+      .getFoo());
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendRepeatedForeignEnumList),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedInt32List),
+      [-42]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedInt64List),
+      [-0x7fffffff00000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedUint32List),
+      [0x80000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedUint64List),
+      [0xf000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSint32List),
+      [-100]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSint64List),
+      [-0x8000000000000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed32List),
+      [1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFixed64List),
+      [0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed32List),
+      [-1234]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedSfixed64List),
+      [-0x1234567800000000]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedFloatList),
+      [1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedDoubleList),
+      [-1.5]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedBoolList),
+      [true]);
+  assertElementsEquals(
+      msg.getExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList),
+      [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+}
+
+
+describe('protoBinaryTest', function() {
+  /**
+   * Tests a basic serialization-deserializaton round-trip with all supported
+   * field types (on the TestAllTypes message type).
+   */
+  it('testRoundTrip', function() {
+    var msg = new proto.jspb.test.TestAllTypes();
+    fillAllFields(msg);
+    var encoded = msg.serializeBinary();
+    var decoded = proto.jspb.test.TestAllTypes.deserializeBinary(encoded);
+    checkAllFields(decoded);
+  });
+
+
+  /**
+   * Helper: fill all extension values.
+   * @param {proto.jspb.test.TestExtendable} msg
+   */
+  function fillExtensions(msg) {
+    msg.setExtension(
+        proto.jspb.test.extendOptionalInt32, -42);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalUint32, 0x80000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalUint64, 0xf000000000000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSint32, -100);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSint64, -0x8000000000000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFixed32, 1234);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFixed64, 0x1234567800000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSfixed32, -1234);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalSfixed64, -0x1234567800000000);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalFloat, 1.5);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalDouble, -1.5);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalBool, true);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalString, 'hello world');
+    msg.setExtension(
+        proto.jspb.test.extendOptionalBytes, 'bytes');
+    var submsg = new proto.jspb.test.ExtendsWithMessage();
+    submsg.setFoo(16);
+    msg.setExtension(
+        proto.jspb.test.ExtendsWithMessage.optionalExtension, submsg);
+    msg.setExtension(
+        proto.jspb.test.extendOptionalForeignEnum,
+        proto.jspb.test.ForeignEnum.FOREIGN_FOO);
+
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedInt32List, [-42]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedInt64List, [-0x7fffffff00000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedUint32List, [0x80000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedUint64List, [0xf000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSint32List, [-100]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSint64List, [-0x8000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFixed32List, [1234]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFixed64List, [0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSfixed32List, [-1234]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedSfixed64List, [-0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedFloatList, [1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedDoubleList, [-1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedBoolList, [true]);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedStringList, ['hello world']);
+    msg.setExtension(
+        proto.jspb.test.extendRepeatedBytesList, ['bytes']);
+    submsg = new proto.jspb.test.ExtendsWithMessage();
+    submsg.setFoo(1000);
+    msg.setExtension(
+        proto.jspb.test.ExtendsWithMessage.repeatedExtensionList, [submsg]);
+    msg.setExtension(proto.jspb.test.extendRepeatedForeignEnumList,
+        [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedInt32List, [-42]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedInt64List, [-0x7fffffff00000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedUint32List, [0x80000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedUint64List, [0xf000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSint32List, [-100]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSint64List, [-0x8000000000000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFixed32List, [1234]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFixed64List, [0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSfixed32List, [-1234]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedSfixed64List,
+        [-0x1234567800000000]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedFloatList, [1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedDoubleList, [-1.5]);
+    msg.setExtension(
+        proto.jspb.test.extendPackedRepeatedBoolList, [true]);
+    msg.setExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList,
+        [proto.jspb.test.ForeignEnum.FOREIGN_FOO]);
+  }
+
+
+  /**
+   * Tests extension serialization and deserialization.
+   */
+  it('testExtensions', function() {
+    var msg = new proto.jspb.test.TestExtendable();
+    fillExtensions(msg);
+    var encoded = msg.serializeBinary();
+    var decoded = proto.jspb.test.TestExtendable.deserializeBinary(encoded);
+    checkExtensions(decoded);
+  });
+});
diff --git a/js/binary/reader.js b/js/binary/reader.js
new file mode 100644
index 0000000..abcd166
--- /dev/null
+++ b/js/binary/reader.js
@@ -0,0 +1,1127 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for converting binary,
+ * wire-format protocol buffers into Javascript data structures.
+ *
+ * jspb's BinaryReader class wraps the BinaryDecoder class to add methods
+ * that understand the protocol buffer syntax and can do the type checking and
+ * bookkeeping necessary to parse trees of nested messages.
+ *
+ * Major caveat - Users of this library _must_ keep their Javascript proto
+ * parsing code in sync with the original .proto file - presumably you'll be
+ * using the typed jspb code generator, but if you bypass that you'll need
+ * to keep things in sync by hand.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryReader');
+
+goog.require('goog.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+
+
+
+/**
+ * BinaryReader implements the decoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @constructor
+ * @struct
+ */
+jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
+  /**
+   * Wire-format decoder.
+   * @private {!jspb.BinaryDecoder}
+   */
+  this.decoder_ = jspb.BinaryDecoder.alloc(opt_bytes, opt_start, opt_length);
+
+  /**
+   * Cursor immediately before the field tag.
+   * @private {number}
+   */
+  this.fieldCursor_ = this.decoder_.getCursor();
+
+  /**
+   * Field number of the next field in the buffer, filled in by nextField().
+   * @private {number}
+   */
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+
+  /**
+   * Wire type of the next proto field in the buffer, filled in by
+   * nextField().
+   * @private {jspb.BinaryConstants.WireType}
+   */
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+
+  /**
+   * Set to true if this reader encountered an error due to corrupt data.
+   * @private {boolean}
+   */
+  this.error_ = false;
+
+  /**
+   * User-defined reader callbacks.
+   * @private {Object.<string, function(!jspb.BinaryReader):*>}
+   */
+  this.readCallbacks_ = null;
+};
+
+
+/**
+ * Global pool of BinaryReader instances.
+ * @private {!Array.<!jspb.BinaryReader>}
+ */
+jspb.BinaryReader.instanceCache_ = [];
+
+
+/**
+ * Pops an instance off the instance cache, or creates one if the cache is
+ * empty.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryReader}
+ */
+jspb.BinaryReader.alloc =
+    function(opt_bytes, opt_start, opt_length) {
+  if (jspb.BinaryReader.instanceCache_.length) {
+    var newReader = jspb.BinaryReader.instanceCache_.pop();
+    if (opt_bytes) {
+      newReader.decoder_.setBlock(opt_bytes, opt_start, opt_length);
+    }
+    return newReader;
+  } else {
+    return new jspb.BinaryReader(opt_bytes, opt_start, opt_length);
+  }
+};
+
+
+/**
+ * Alias for the above method.
+ * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
+ * @param {number=} opt_start The optional offset to start reading at.
+ * @param {number=} opt_length The optional length of the block to read -
+ *     we'll throw an assertion if we go off the end of the block.
+ * @return {!jspb.BinaryReader}
+ */
+jspb.BinaryReader.prototype.alloc = jspb.BinaryReader.alloc;
+
+
+/**
+ * Puts this instance back in the instance cache.
+ */
+jspb.BinaryReader.prototype.free = function() {
+  this.decoder_.clear();
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+  this.error_ = false;
+  this.readCallbacks_ = null;
+
+  if (jspb.BinaryReader.instanceCache_.length < 100) {
+    jspb.BinaryReader.instanceCache_.push(this);
+  }
+};
+
+
+/**
+ * Returns the cursor immediately before the current field's tag.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryReader.prototype.getFieldCursor = function() {
+  return this.fieldCursor_;
+};
+
+
+/**
+ * Returns the internal read cursor.
+ * @return {number} The internal read cursor.
+ */
+jspb.BinaryReader.prototype.getCursor = function() {
+  return this.decoder_.getCursor();
+};
+
+
+/**
+ * Returns the raw buffer.
+ * @return {Uint8Array} The raw buffer.
+ */
+jspb.BinaryReader.prototype.getBuffer = function() {
+  return this.decoder_.getBuffer();
+};
+
+
+/**
+ * @return {number} The field number of the next field in the buffer, or
+ *     INVALID_FIELD_NUMBER if there is no next field.
+ */
+jspb.BinaryReader.prototype.getFieldNumber = function() {
+  return this.nextField_;
+};
+
+
+/**
+ * @return {jspb.BinaryConstants.WireType} The wire type of the next field
+ *     in the stream, or WireType.INVALID if there is no next field.
+ */
+jspb.BinaryReader.prototype.getWireType = function() {
+  return this.nextWireType_;
+};
+
+
+/**
+ * @return {boolean} Whether the current wire type is an end-group tag. Used as
+ * an exit condition in decoder loops in generated code.
+ */
+jspb.BinaryReader.prototype.isEndGroup = function() {
+  return this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP;
+};
+
+
+/**
+ * Returns true if this reader hit an error due to corrupt data.
+ * @return {boolean}
+ */
+jspb.BinaryReader.prototype.getError = function() {
+  return this.error_ || this.decoder_.getError();
+};
+
+
+/**
+ * Points this reader at a new block of bytes.
+ * @param {!Uint8Array} bytes The block of bytes we're reading from.
+ * @param {number} start The offset to start reading at.
+ * @param {number} length The length of the block to read.
+ */
+jspb.BinaryReader.prototype.setBlock = function(bytes, start, length) {
+  this.decoder_.setBlock(bytes, start, length);
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+};
+
+
+/**
+ * Rewinds the stream cursor to the beginning of the buffer and resets all
+ * internal state.
+ */
+jspb.BinaryReader.prototype.reset = function() {
+  this.decoder_.reset();
+  this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
+  this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
+};
+
+
+/**
+ * Advances the stream cursor by the given number of bytes.
+ * @param {number} count The number of bytes to advance by.
+ */
+jspb.BinaryReader.prototype.advance = function(count) {
+  this.decoder_.advance(count);
+};
+
+
+/**
+ * Reads the next field header in the stream if there is one, returns true if
+ * we saw a valid field header or false if we've read the whole stream.
+ * Throws an error if we encountered a deprecated START_GROUP/END_GROUP field.
+ * @return {boolean} True if the stream contains more fields.
+ */
+jspb.BinaryReader.prototype.nextField = function() {
+  // If we're at the end of the block, there are no more fields.
+  if (this.decoder_.atEnd()) {
+    return false;
+  }
+
+  // If we hit an error decoding the previous field, stop now before we
+  // try to decode anything else
+  if (this.getError()) {
+    goog.asserts.fail('Decoder hit an error');
+    return false;
+  }
+
+  // Otherwise just read the header of the next field.
+  this.fieldCursor_ = this.decoder_.getCursor();
+  var header = this.decoder_.readUnsignedVarint32();
+
+  var nextField = header >>> 3;
+  var nextWireType = /** @type {jspb.BinaryConstants.WireType} */
+      (header & 0x7);
+
+  // If the wire type isn't one of the valid ones, something's broken.
+  if (nextWireType != jspb.BinaryConstants.WireType.VARINT &&
+      nextWireType != jspb.BinaryConstants.WireType.FIXED32 &&
+      nextWireType != jspb.BinaryConstants.WireType.FIXED64 &&
+      nextWireType != jspb.BinaryConstants.WireType.DELIMITED &&
+      nextWireType != jspb.BinaryConstants.WireType.START_GROUP &&
+      nextWireType != jspb.BinaryConstants.WireType.END_GROUP) {
+    goog.asserts.fail('Invalid wire type');
+    this.error_ = true;
+    return false;
+  }
+
+  this.nextField_ = nextField;
+  this.nextWireType_ = nextWireType;
+
+  return true;
+};
+
+
+/**
+ * Winds the reader back to just before this field's header.
+ */
+jspb.BinaryReader.prototype.unskipHeader = function() {
+  this.decoder_.unskipVarint((this.nextField_ << 3) | this.nextWireType_);
+};
+
+
+/**
+ * Skips all contiguous fields whose header matches the one we just read.
+ */
+jspb.BinaryReader.prototype.skipMatchingFields = function() {
+  var field = this.nextField_;
+  this.unskipHeader();
+
+  while (this.nextField() && (this.getFieldNumber() == field)) {
+    this.skipField();
+  }
+
+  if (!this.decoder_.atEnd()) {
+    this.unskipHeader();
+  }
+};
+
+
+/**
+ * Skips over the next varint field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipVarintField = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.VARINT) {
+    goog.asserts.fail('Invalid wire type for skipVarintField');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.skipVarint();
+};
+
+
+/**
+ * Skips over the next delimited field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipDelimitedField = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.DELIMITED) {
+    goog.asserts.fail('Invalid wire type for skipDelimitedField');
+    this.skipField();
+    return;
+  }
+
+  var length = this.decoder_.readUnsignedVarint32();
+  this.decoder_.advance(length);
+};
+
+
+/**
+ * Skips over the next fixed32 field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipFixed32Field = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED32) {
+    goog.asserts.fail('Invalid wire type for skipFixed32Field');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.advance(4);
+};
+
+
+/**
+ * Skips over the next fixed64 field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipFixed64Field = function() {
+  if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED64) {
+    goog.asserts.fail('Invalid wire type for skipFixed64Field');
+    this.skipField();
+    return;
+  }
+
+  this.decoder_.advance(8);
+};
+
+
+/**
+ * Skips over the next group field in the binary stream.
+ */
+jspb.BinaryReader.prototype.skipGroup = function() {
+  // Keep a stack of start-group tags that must be matched by end-group tags.
+  var nestedGroups = [this.nextField_];
+  do {
+    if (!this.nextField()) {
+      goog.asserts.fail('Unmatched start-group tag: stream EOF');
+      this.error_ = true;
+      return;
+    }
+    if (this.nextWireType_ ==
+        jspb.BinaryConstants.WireType.START_GROUP) {
+      // Nested group start.
+      nestedGroups.push(this.nextField_);
+    } else if (this.nextWireType_ ==
+               jspb.BinaryConstants.WireType.END_GROUP) {
+      // Group end: check that it matches top-of-stack.
+      if (this.nextField_ != nestedGroups.pop()) {
+        goog.asserts.fail('Unmatched end-group tag');
+        this.error_ = true;
+        return;
+      }
+    }
+  } while (nestedGroups.length > 0);
+};
+
+
+/**
+ * Skips over the next field in the binary stream - this is useful if we're
+ * decoding a message that contain unknown fields.
+ */
+jspb.BinaryReader.prototype.skipField = function() {
+  switch (this.nextWireType_) {
+    case jspb.BinaryConstants.WireType.VARINT:
+      this.skipVarintField();
+      break;
+    case jspb.BinaryConstants.WireType.FIXED64:
+      this.skipFixed64Field();
+      break;
+    case jspb.BinaryConstants.WireType.DELIMITED:
+      this.skipDelimitedField();
+      break;
+    case jspb.BinaryConstants.WireType.FIXED32:
+      this.skipFixed32Field();
+      break;
+    case jspb.BinaryConstants.WireType.START_GROUP:
+      this.skipGroup();
+      break;
+    default:
+      goog.asserts.fail('Invalid wire encoding for field.');
+  }
+};
+
+
+/**
+ * Registers a user-defined read callback.
+ * @param {string} callbackName
+ * @param {function(!jspb.BinaryReader):*} callback
+ */
+jspb.BinaryReader.prototype.registerReadCallback =
+    function(callbackName, callback) {
+  if (goog.isNull(this.readCallbacks_)) {
+    this.readCallbacks_ = {};
+  }
+  goog.asserts.assert(!this.readCallbacks_[callbackName]);
+  this.readCallbacks_[callbackName] = callback;
+};
+
+
+/**
+ * Runs a registered read callback.
+ * @param {string} callbackName The name the callback is registered under.
+ * @return {*} The value returned by the callback.
+ */
+jspb.BinaryReader.prototype.runReadCallback = function(callbackName) {
+  goog.asserts.assert(!goog.isNull(this.readCallbacks_));
+  var callback = this.readCallbacks_[callbackName];
+  goog.asserts.assert(callback);
+  return callback(this);
+};
+
+
+/**
+ * Reads a field of any valid non-message type from the binary stream.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @return {jspb.AnyFieldType}
+ */
+jspb.BinaryReader.prototype.readAny = function(fieldType) {
+  this.nextWireType_ = jspb.BinaryConstants.FieldTypeToWireType(fieldType);
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  switch (fieldType) {
+    case fieldTypes.DOUBLE:
+      return this.readDouble();
+    case fieldTypes.FLOAT:
+      return this.readFloat();
+    case fieldTypes.INT64:
+      return this.readInt64();
+    case fieldTypes.UINT64:
+      return this.readUint64();
+    case fieldTypes.INT32:
+      return this.readInt32();
+    case fieldTypes.FIXED64:
+      return this.readFixed64();
+    case fieldTypes.FIXED32:
+      return this.readFixed32();
+    case fieldTypes.BOOL:
+      return this.readBool();
+    case fieldTypes.STRING:
+      return this.readString();
+    case fieldTypes.GROUP:
+      goog.asserts.fail('Group field type not supported in readAny()');
+    case fieldTypes.MESSAGE:
+      goog.asserts.fail('Message field type not supported in readAny()');
+    case fieldTypes.BYTES:
+      return this.readBytes();
+    case fieldTypes.UINT32:
+      return this.readUint32();
+    case fieldTypes.ENUM:
+      return this.readEnum();
+    case fieldTypes.SFIXED32:
+      return this.readSfixed32();
+    case fieldTypes.SFIXED64:
+      return this.readSfixed64();
+    case fieldTypes.SINT32:
+      return this.readSint32();
+    case fieldTypes.SINT64:
+      return this.readSint64();
+    case fieldTypes.FHASH64:
+      return this.readFixedHash64();
+    case fieldTypes.VHASH64:
+      return this.readVarintHash64();
+    default:
+      goog.asserts.fail('Invalid field type in readAny()');
+  }
+  return 0;
+};
+
+
+/**
+ * Deserialize a proto into the provided message object using the provided
+ * reader function. This function is templated as we currently have one client
+ * who is using manual deserialization instead of the code-generated versions.
+ * @template T
+ * @param {T} message
+ * @param {function(T, !jspb.BinaryReader)} reader
+ */
+jspb.BinaryReader.prototype.readMessage = function(message, reader) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+
+  // Save the current endpoint of the decoder and move it to the end of the
+  // embedded message.
+  var oldEnd = this.decoder_.getEnd();
+  var length = this.decoder_.readUnsignedVarint32();
+  var newEnd = this.decoder_.getCursor() + length;
+  this.decoder_.setEnd(newEnd);
+
+  // Deserialize the embedded message.
+  reader(message, this);
+
+  // Advance the decoder past the embedded message and restore the endpoint.
+  this.decoder_.setCursor(newEnd);
+  this.decoder_.setEnd(oldEnd);
+};
+
+
+/**
+ * Deserialize a proto into the provided message object using the provided
+ * reader function, assuming that the message is serialized as a group
+ * with the given tag.
+ * @template T
+ * @param {number} field
+ * @param {T} message
+ * @param {function(T, !jspb.BinaryReader)} reader
+ */
+jspb.BinaryReader.prototype.readGroup =
+    function(field, message, reader) {
+  // Ensure that the wire type is correct.
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.START_GROUP);
+  // Ensure that the field number is correct.
+  goog.asserts.assert(this.nextField_ == field);
+
+  // Deserialize the message. The deserialization will stop at an END_GROUP tag.
+  reader(message, this);
+
+  if (!this.error_ &&
+      this.nextWireType_ != jspb.BinaryConstants.WireType.END_GROUP) {
+    goog.asserts.fail('Group submessage did not end with an END_GROUP tag');
+    this.error_ = true;
+  }
+};
+
+
+/**
+ * Return a decoder that wraps the current delimited field.
+ * @return {!jspb.BinaryDecoder}
+ */
+jspb.BinaryReader.prototype.getFieldDecoder = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+
+  var length = this.decoder_.readUnsignedVarint32();
+  var start = this.decoder_.getCursor();
+  var end = start + length;
+
+  var innerDecoder = jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(),
+                                                 start, length);
+  this.decoder_.setCursor(end);
+  return innerDecoder;
+};
+
+
+/**
+ * Reads a signed 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the signed 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readInt32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint32();
+};
+
+
+/**
+ * Reads a signed 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the signed 32-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readInt32String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint32String();
+};
+
+
+/**
+ * Reads a signed 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the signed 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readInt64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64();
+};
+
+
+/**
+ * Reads a signed 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the signed 64-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readInt64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64String();
+};
+
+
+/**
+ * Reads an unsigned 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the unsigned 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readUint32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint32();
+};
+
+
+/**
+ * Reads an unsigned 32-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the unsigned 32-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readUint32String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint32String();
+};
+
+
+/**
+ * Reads an unsigned 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the unsigned 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readUint64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint64();
+};
+
+
+/**
+ * Reads an unsigned 64-bit integer field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * Returns the value as a string.
+ *
+ * @return {string} The value of the unsigned 64-bit integer field as a decimal
+ * string.
+ */
+jspb.BinaryReader.prototype.readUint64String = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readUnsignedVarint64String();
+};
+
+
+/**
+ * Reads a signed zigzag-encoded 32-bit integer field from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the signed 32-bit integer field.
+ */
+jspb.BinaryReader.prototype.readSint32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readZigzagVarint32();
+};
+
+
+/**
+ * Reads a signed zigzag-encoded 64-bit integer field from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the signed 64-bit integer field.
+ */
+jspb.BinaryReader.prototype.readSint64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readZigzagVarint64();
+};
+
+
+/**
+ * Reads an unsigned 32-bit fixed-length integer fiield from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readFixed32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readUint32();
+};
+
+
+/**
+ * Reads an unsigned 64-bit fixed-length integer fiield from the binary stream,
+ * or throws an error if the next field in the stream is not of the correct
+ * wire type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readFixed64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readUint64();
+};
+
+
+/**
+ * Reads a signed 32-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readSfixed32 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readInt32();
+};
+
+
+/**
+ * Reads a signed 64-bit fixed-length integer fiield from the binary stream, or
+ * throws an error if the next field in the stream is not of the correct wire
+ * type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readSfixed64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readInt64();
+};
+
+
+/**
+ * Reads a 32-bit floating-point field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the float field.
+ */
+jspb.BinaryReader.prototype.readFloat = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
+  return this.decoder_.readFloat();
+};
+
+
+/**
+ * Reads a 64-bit floating-point field from the binary stream, or throws an
+ * error if the next field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the double field.
+ */
+jspb.BinaryReader.prototype.readDouble = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readDouble();
+};
+
+
+/**
+ * Reads a boolean field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {boolean} The value of the boolean field.
+ */
+jspb.BinaryReader.prototype.readBool = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return !!this.decoder_.readUnsignedVarint32();
+};
+
+
+/**
+ * Reads an enum field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {number} The value of the enum field.
+ */
+jspb.BinaryReader.prototype.readEnum = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readSignedVarint64();
+};
+
+
+/**
+ * Reads a string field from the binary stream, or throws an error if the next
+ * field in the stream is not of the correct wire type.
+ *
+ * @return {string} The value of the string field.
+ */
+jspb.BinaryReader.prototype.readString = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  return this.decoder_.readString(length);
+};
+
+
+/**
+ * Reads a length-prefixed block of bytes from the binary stream, or returns
+ * null if the next field in the stream has an invalid length value.
+ *
+ * @return {Uint8Array} The block of bytes.
+ */
+jspb.BinaryReader.prototype.readBytes = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  return this.decoder_.readBytes(length);
+};
+
+
+/**
+ * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
+ * 8-character Unicode string for use as a hash table key, or throws an error
+ * if the next field in the stream is not of the correct wire type.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryReader.prototype.readVarintHash64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
+  return this.decoder_.readVarintHash64();
+};
+
+
+/**
+ * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
+ * 8-character Unicode string for use as a hash table key, or throws an error
+ * if the next field in the stream is not of the correct wire type.
+ *
+ * @return {string} The hash value.
+ */
+jspb.BinaryReader.prototype.readFixedHash64 = function() {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
+  return this.decoder_.readFixedHash64();
+};
+
+
+/**
+ * Reads a packed scalar field using the supplied raw reader function.
+ * @param {function()} decodeMethod
+ * @return {!Array}
+ * @private
+ */
+jspb.BinaryReader.prototype.readPackedField_ = function(decodeMethod) {
+  goog.asserts.assert(
+      this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
+  var length = this.decoder_.readUnsignedVarint32();
+  var end = this.decoder_.getCursor() + length;
+  var result = [];
+  while (this.decoder_.getCursor() < end) {
+    // TODO(aappleby): .call is slow
+    result.push(decodeMethod.call(this.decoder_));
+  }
+  return result;
+};
+
+
+/**
+ * Reads a packed int32 field, which consists of a length header and a list of
+ * signed varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedInt32 = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint32);
+};
+
+
+/**
+ * Reads a packed int32 field, which consists of a length header and a list of
+ * signed varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedInt32String = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint32String);
+};
+
+
+/**
+ * Reads a packed int64 field, which consists of a length header and a list of
+ * signed varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedInt64 = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint64);
+};
+
+
+/**
+ * Reads a packed int64 field, which consists of a length header and a list of
+ * signed varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedInt64String = function() {
+  return this.readPackedField_(this.decoder_.readSignedVarint64String);
+};
+
+
+/**
+ * Reads a packed uint32 field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedUint32 = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint32);
+};
+
+
+/**
+ * Reads a packed uint32 field, which consists of a length header and a list of
+ * unsigned varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedUint32String = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint32String);
+};
+
+
+/**
+ * Reads a packed uint64 field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedUint64 = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint64);
+};
+
+
+/**
+ * Reads a packed uint64 field, which consists of a length header and a list of
+ * unsigned varints. Returns a list of strings.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedUint64String = function() {
+  return this.readPackedField_(this.decoder_.readUnsignedVarint64String);
+};
+
+
+/**
+ * Reads a packed sint32 field, which consists of a length header and a list of
+ * zigzag varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSint32 = function() {
+  return this.readPackedField_(this.decoder_.readZigzagVarint32);
+};
+
+
+/**
+ * Reads a packed sint64 field, which consists of a length header and a list of
+ * zigzag varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSint64 = function() {
+  return this.readPackedField_(this.decoder_.readZigzagVarint64);
+};
+
+
+/**
+ * Reads a packed fixed32 field, which consists of a length header and a list
+ * of unsigned 32-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFixed32 = function() {
+  return this.readPackedField_(this.decoder_.readUint32);
+};
+
+
+/**
+ * Reads a packed fixed64 field, which consists of a length header and a list
+ * of unsigned 64-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFixed64 = function() {
+  return this.readPackedField_(this.decoder_.readUint64);
+};
+
+
+/**
+ * Reads a packed sfixed32 field, which consists of a length header and a list
+ * of 32-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
+  return this.readPackedField_(this.decoder_.readInt32);
+};
+
+
+/**
+ * Reads a packed sfixed64 field, which consists of a length header and a list
+ * of 64-bit ints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
+  return this.readPackedField_(this.decoder_.readInt64);
+};
+
+
+/**
+ * Reads a packed float field, which consists of a length header and a list of
+ * floats.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedFloat = function() {
+  return this.readPackedField_(this.decoder_.readFloat);
+};
+
+
+/**
+ * Reads a packed double field, which consists of a length header and a list of
+ * doubles.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedDouble = function() {
+  return this.readPackedField_(this.decoder_.readDouble);
+};
+
+
+/**
+ * Reads a packed bool field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<boolean>}
+ */
+jspb.BinaryReader.prototype.readPackedBool = function() {
+  return this.readPackedField_(this.decoder_.readBool);
+};
+
+
+/**
+ * Reads a packed enum field, which consists of a length header and a list of
+ * unsigned varints.
+ * @return {!Array.<number>}
+ */
+jspb.BinaryReader.prototype.readPackedEnum = function() {
+  return this.readPackedField_(this.decoder_.readEnum);
+};
+
+
+/**
+ * Reads a packed varint hash64 field, which consists of a length header and a
+ * list of varint hash64s.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
+  return this.readPackedField_(this.decoder_.readVarintHash64);
+};
+
+
+/**
+ * Reads a packed fixed hash64 field, which consists of a length header and a
+ * list of fixed hash64s.
+ * @return {!Array.<string>}
+ */
+jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
+  return this.readPackedField_(this.decoder_.readFixedHash64);
+};
diff --git a/js/binary/reader_test.js b/js/binary/reader_test.js
new file mode 100644
index 0000000..a648261
--- /dev/null
+++ b/js/binary/reader_test.js
@@ -0,0 +1,889 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer reader.
+ *
+ * There are two particular magic numbers that need to be pointed out -
+ * 2^64-1025 is the largest number representable as both a double and an
+ * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
+ * both a double and a signed 64-bit integer.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryDecoder');
+goog.require('jspb.BinaryReader');
+goog.require('jspb.BinaryWriter');
+
+
+
+describe('binaryReaderTest', function() {
+  /**
+   * Tests the reader instance cache.
+   * @suppress {visibility}
+   */
+  it('testInstanceCaches', function() {
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+    writer.writeMessage(1, dummyMessage, goog.nullFunction);
+    writer.writeMessage(2, dummyMessage, goog.nullFunction);
+
+    var buffer = writer.getResultBuffer();
+
+    // Empty the instance caches.
+    jspb.BinaryReader.instanceCache_ = [];
+
+    // Allocating and then freeing three decoders should leave us with three in
+    // the cache.
+
+    var decoder1 = jspb.BinaryDecoder.alloc();
+    var decoder2 = jspb.BinaryDecoder.alloc();
+    var decoder3 = jspb.BinaryDecoder.alloc();
+    decoder1.free();
+    decoder2.free();
+    decoder3.free();
+
+    assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Allocating and then freeing a reader should remove one decoder from its
+    // cache, but it should stay stuck to the reader afterwards since we can't
+    // have a reader without a decoder.
+    jspb.BinaryReader.alloc().free();
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(1, jspb.BinaryReader.instanceCache_.length);
+
+    // Allocating a reader should remove a reader from the cache.
+    var reader = jspb.BinaryReader.alloc(buffer);
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Processing the message reuses the current reader.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+    });
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+    });
+
+    assertEquals(false, reader.nextField());
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(0, jspb.BinaryReader.instanceCache_.length);
+
+    // Freeing the reader should put it back into the cache.
+    reader.free();
+
+    assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
+    assertEquals(1, jspb.BinaryReader.instanceCache_.length);
+  });
+
+
+  /**
+   * @param {number} x
+   * @return {number}
+   */
+  function truncate(x) {
+    var temp = new Float32Array(1);
+    temp[0] = x;
+    return temp[0];
+  }
+
+
+  /**
+   * Verifies that misuse of the reader class triggers assertions.
+   * @suppress {checkTypes|visibility}
+   */
+  it('testReadErrors', function() {
+    // Calling readMessage on a non-delimited field should trigger an
+    // assertion.
+    var reader = jspb.BinaryReader.alloc([8, 1]);
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+    reader.nextField();
+    assertThrows(function() {
+      reader.readMessage(dummyMessage, goog.nullFunction);
+    });
+
+    // Reading past the end of the stream should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([9, 1]);
+    reader.nextField();
+    assertThrows(function() {reader.readFixed64()});
+
+    // Reading past the end of a submessage should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
+    reader.nextField();
+    reader.readMessage(dummyMessage, function() {
+      reader.nextField();
+      assertThrows(function() {reader.readFixed32()});
+    });
+
+    // Skipping an invalid field should trigger an assertion.
+    reader = jspb.BinaryReader.alloc([12, 1]);
+    reader.nextWireType_ = 1000;
+    assertThrows(function() {reader.skipField()});
+
+    // Reading fields with the wrong wire type should assert.
+    reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
+    reader.nextField();
+    assertThrows(function() {reader.readInt32()});
+    assertThrows(function() {reader.readInt32String()});
+    assertThrows(function() {reader.readInt64()});
+    assertThrows(function() {reader.readInt64String()});
+    assertThrows(function() {reader.readUint32()});
+    assertThrows(function() {reader.readUint32String()});
+    assertThrows(function() {reader.readUint64()});
+    assertThrows(function() {reader.readUint64String()});
+    assertThrows(function() {reader.readSint32()});
+    assertThrows(function() {reader.readBool()});
+    assertThrows(function() {reader.readEnum()});
+
+    reader = jspb.BinaryReader.alloc([8, 1]);
+    reader.nextField();
+    assertThrows(function() {reader.readFixed32()});
+    assertThrows(function() {reader.readFixed64()});
+    assertThrows(function() {reader.readSfixed32()});
+    assertThrows(function() {reader.readSfixed64()});
+    assertThrows(function() {reader.readFloat()});
+    assertThrows(function() {reader.readDouble()});
+
+    assertThrows(function() {reader.readString()});
+    assertThrows(function() {reader.readBytes()});
+  });
+
+
+  /**
+   * Tests encoding and decoding of unsigned field types.
+   * @param {Function} readField
+   * @param {Function} writeField
+   * @param {number} epsilon
+   * @param {number} upperLimit
+   * @param {Function} filter
+   * @private
+   * @suppress {missingProperties}
+   */
+  function doTestUnsignedField_(readField,
+      writeField, epsilon, upperLimit, filter) {
+    assertNotNull(readField);
+    assertNotNull(writeField);
+
+    var writer = new jspb.BinaryWriter();
+
+    // Encode zero and limits.
+    writeField.call(writer, 1, filter(0));
+    writeField.call(writer, 2, filter(epsilon));
+    writeField.call(writer, 3, filter(upperLimit));
+
+    // Encode positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      writeField.call(writer, 4, filter(cursor));
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Check zero and limits.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(filter(0), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(filter(epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(filter(upperLimit), readField.call(reader));
+
+    // Check positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      reader.nextField();
+      if (4 != reader.getFieldNumber()) throw 'fail!';
+      if (filter(cursor) != readField.call(reader)) throw 'fail!';
+    }
+  };
+
+
+  /**
+   * Tests encoding and decoding of signed field types.
+   * @param {Function} readField
+   * @param {Function} writeField
+   * @param {number} epsilon
+   * @param {number} lowerLimit
+   * @param {number} upperLimit
+   * @param {Function} filter
+   * @private
+   * @suppress {missingProperties}
+   */
+  function doTestSignedField_(readField,
+      writeField, epsilon, lowerLimit, upperLimit, filter) {
+    var writer = new jspb.BinaryWriter();
+
+    // Encode zero and limits.
+    writeField.call(writer, 1, filter(lowerLimit));
+    writeField.call(writer, 2, filter(-epsilon));
+    writeField.call(writer, 3, filter(0));
+    writeField.call(writer, 4, filter(epsilon));
+    writeField.call(writer, 5, filter(upperLimit));
+
+    var inputValues = [];
+
+    // Encode negative values.
+    for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
+      var val = filter(cursor);
+      writeField.call(writer, 6, val);
+      inputValues.push({
+        fieldNumber: 6,
+        value: val
+      });
+    }
+
+    // Encode positive values.
+    for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
+      var val = filter(cursor);
+      writeField.call(writer, 7, val);
+      inputValues.push({
+        fieldNumber: 7,
+        value: val
+      });
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Check zero and limits.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(filter(lowerLimit), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(filter(-epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(filter(0), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(4, reader.getFieldNumber());
+    assertEquals(filter(epsilon), readField.call(reader));
+
+    reader.nextField();
+    assertEquals(5, reader.getFieldNumber());
+    assertEquals(filter(upperLimit), readField.call(reader));
+
+    for (var i = 0; i < inputValues.length; i++) {
+      var expected = inputValues[i];
+      reader.nextField();
+      assertEquals(expected.fieldNumber, reader.getFieldNumber());
+      assertEquals(expected.value, readField.call(reader));
+    }
+  };
+
+
+  /**
+   * Tests fields that use varint encoding.
+   */
+  it('testVarintFields', function() {
+    assertNotNull(jspb.BinaryReader.prototype.readUint32);
+    assertNotNull(jspb.BinaryReader.prototype.writeUint32);
+    assertNotNull(jspb.BinaryReader.prototype.readUint64);
+    assertNotNull(jspb.BinaryReader.prototype.writeUint64);
+    assertNotNull(jspb.BinaryReader.prototype.readBool);
+    assertNotNull(jspb.BinaryReader.prototype.writeBool);
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readUint32,
+        jspb.BinaryWriter.prototype.writeUint32,
+        1, Math.pow(2, 32) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readUint64,
+        jspb.BinaryWriter.prototype.writeUint64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readInt32,
+        jspb.BinaryWriter.prototype.writeInt32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readInt64,
+        jspb.BinaryWriter.prototype.writeInt64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readEnum,
+        jspb.BinaryWriter.prototype.writeEnum,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readBool,
+        jspb.BinaryWriter.prototype.writeBool,
+        1, 1, function(x) { return !!x; });
+  });
+
+
+  /**
+   * Tests 64-bit fields that are handled as strings.
+   */
+  it('testStringInt64Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var testSignedData = [
+        '2730538252207801776',
+        '-2688470994844604560',
+        '3398529779486536359',
+        '3568577411627971000',
+        '272477188847484900',
+        '-6649058714086158188',
+        '-7695254765712060806',
+        '-4525541438037104029',
+        '-4993706538836508568',
+        '4990160321893729138'
+    ];
+    var testUnsignedData = [
+        '7822732630241694882',
+        '6753602971916687352',
+        '2399935075244442116',
+        '8724292567325338867',
+        '16948784802625696584',
+        '4136275908516066934',
+        '3575388346793700364',
+        '5167142028379259461',
+        '1557573948689737699',
+        '17100725280812548567'
+    ];
+
+    for (var i = 0; i < testSignedData.length; i++) {
+      writer.writeInt64String(2 * i + 1, testSignedData[i]);
+      writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    for (var i = 0; i < testSignedData.length; i++) {
+      reader.nextField();
+      assertEquals(2 * i + 1, reader.getFieldNumber());
+      assertEquals(testSignedData[i], reader.readInt64String());
+      reader.nextField();
+      assertEquals(2 * i + 2, reader.getFieldNumber());
+      assertEquals(testUnsignedData[i], reader.readUint64String());
+    }
+  });
+
+
+  /**
+   * Tests fields that use zigzag encoding.
+   */
+  it('testZigzagFields', function() {
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSint32,
+        jspb.BinaryWriter.prototype.writeSint32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSint64,
+        jspb.BinaryWriter.prototype.writeSint64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests fields that use fixed-length encoding.
+   */
+  it('testFixedFields', function() {
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readFixed32,
+        jspb.BinaryWriter.prototype.writeFixed32,
+        1, Math.pow(2, 32) - 1, Math.round);
+
+    doTestUnsignedField_(
+        jspb.BinaryReader.prototype.readFixed64,
+        jspb.BinaryWriter.prototype.writeFixed64,
+        1, Math.pow(2, 64) - 1025, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSfixed32,
+        jspb.BinaryWriter.prototype.writeSfixed32,
+        1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readSfixed64,
+        jspb.BinaryWriter.prototype.writeSfixed64,
+        1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
+  });
+
+
+  /**
+   * Tests floating point fields.
+   */
+  it('testFloatFields', function() {
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readFloat,
+        jspb.BinaryWriter.prototype.writeFloat,
+        jspb.BinaryConstants.FLOAT32_MIN,
+        -jspb.BinaryConstants.FLOAT32_MAX,
+        jspb.BinaryConstants.FLOAT32_MAX,
+        truncate);
+
+    doTestSignedField_(
+        jspb.BinaryReader.prototype.readDouble,
+        jspb.BinaryWriter.prototype.writeDouble,
+        jspb.BinaryConstants.FLOAT64_EPS * 10,
+        -jspb.BinaryConstants.FLOAT64_MIN,
+        jspb.BinaryConstants.FLOAT64_MIN,
+        function(x) { return x; });
+  });
+
+
+  /**
+   * Tests length-delimited string fields.
+   */
+  it('testStringFields', function() {
+    var s1 = 'The quick brown fox jumps over the lazy dog.';
+    var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
+
+    var writer = new jspb.BinaryWriter();
+
+    writer.writeString(1, s1);
+    writer.writeString(2, s2);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(s1, reader.readString());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(s2, reader.readString());
+  });
+
+
+  /**
+   * Tests length-delimited byte fields.
+   */
+  it('testByteFields', function() {
+    var message = [];
+    var lowerLimit = 1;
+    var upperLimit = 256;
+    var scale = 1.1;
+
+    var writer = new jspb.BinaryWriter();
+
+    for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
+      var len = Math.round(cursor);
+      var bytes = [];
+      for (var i = 0; i < len; i++) bytes.push(i % 256);
+
+      writer.writeBytes(len, bytes);
+    }
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
+      var len = Math.round(cursor);
+      if (len != reader.getFieldNumber()) throw 'fail!';
+
+      var bytes = reader.readBytes();
+      if (len != bytes.length) throw 'fail!';
+      for (var i = 0; i < bytes.length; i++) {
+        if (i % 256 != bytes[i]) throw 'fail!';
+      }
+    }
+  });
+
+
+  /**
+   * Tests nested messages.
+   */
+  it('testNesting', function() {
+    var writer = new jspb.BinaryWriter();
+  var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    writer.writeInt32(1, 100);
+
+    // Add one message with 3 int fields.
+    writer.writeMessage(2, dummyMessage, function() {
+      writer.writeInt32(3, 300);
+      writer.writeInt32(4, 400);
+      writer.writeInt32(5, 500);
+    });
+
+    // Add one empty message.
+    writer.writeMessage(6, dummyMessage, goog.nullFunction);
+
+    writer.writeInt32(7, 700);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    // Validate outermost message.
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(100, reader.readInt32());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Validate embedded message 1.
+      reader.nextField();
+      assertEquals(3, reader.getFieldNumber());
+      assertEquals(300, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(4, reader.getFieldNumber());
+      assertEquals(400, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(5, reader.getFieldNumber());
+      assertEquals(500, reader.readInt32());
+
+      assertEquals(false, reader.nextField());
+    });
+
+    reader.nextField();
+    assertEquals(6, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Validate embedded message 2.
+
+      assertEquals(false, reader.nextField());
+    });
+
+    reader.nextField();
+    assertEquals(7, reader.getFieldNumber());
+    assertEquals(700, reader.readInt32());
+
+    assertEquals(false, reader.nextField());
+  });
+
+  /**
+   * Tests skipping fields of each type by interleaving them with sentinel
+   * values and skipping everything that's not a sentinel.
+   */
+  it('testSkipField', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var sentinel = 123456789;
+
+    // Write varint fields of different sizes.
+    writer.writeInt32(1, sentinel);
+    writer.writeInt32(1, 1);
+    writer.writeInt32(1, 1000);
+    writer.writeInt32(1, 1000000);
+    writer.writeInt32(1, 1000000000);
+
+    // Write fixed 64-bit encoded fields.
+    writer.writeInt32(2, sentinel);
+    writer.writeDouble(2, 1);
+    writer.writeFixed64(2, 1);
+    writer.writeSfixed64(2, 1);
+
+    // Write fixed 32-bit encoded fields.
+    writer.writeInt32(3, sentinel);
+    writer.writeFloat(3, 1);
+    writer.writeFixed32(3, 1);
+    writer.writeSfixed32(3, 1);
+
+    // Write delimited fields.
+    writer.writeInt32(4, sentinel);
+    writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
+
+    // Write a group with a nested group inside. We use the internal
+    // .rawWriteVarint() to ensure the tested wire data is what we want,
+    // independently of any serialization logic.
+    writer.writeInt32(5, sentinel);
+    // Start group, field 5.
+    writer.rawWriteVarint(
+        (5 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
+    // Varint, field 42.
+    writer.rawWriteVarint(
+        (42 << 3) + jspb.BinaryConstants.WireType.VARINT);
+    // Varint data.
+    writer.rawWriteVarint(42);
+    // Start group, field 6.
+    writer.rawWriteVarint(
+        (6 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
+    // Varint, field 84.
+    writer.rawWriteVarint(
+        (84 << 3) + jspb.BinaryConstants.WireType.VARINT);
+    writer.rawWriteVarint(42);
+    // End group, field 6.
+    writer.rawWriteVarint(
+        (6 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
+    // End group, field 5.
+    writer.rawWriteVarint(
+        (5 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
+
+    // Write final sentinel.
+    writer.writeInt32(6, sentinel);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    function skip(field, count) {
+      for (var i = 0; i < count; i++) {
+        reader.nextField();
+        if (field != reader.getFieldNumber()) throw 'fail!';
+        reader.skipField();
+      }
+    }
+
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(1, 4);
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(2, 3);
+
+    reader.nextField();
+    assertEquals(3, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(3, 3);
+
+    reader.nextField();
+    assertEquals(4, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(4, 2);
+
+    reader.nextField();
+    assertEquals(5, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+    skip(5, 1);
+
+    reader.nextField();
+    assertEquals(6, reader.getFieldNumber());
+    assertEquals(sentinel, reader.readInt32());
+  });
+
+
+  /**
+   * Tests packed fields.
+   */
+  it('testPackedFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var sentinel = 123456789;
+
+    var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
+    var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
+    var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
+    var boolData = [true, false, true, true, false, false, true, false];
+
+    for (var i = 0; i < floatData.length; i++) {
+      floatData[i] = truncate(floatData[i]);
+    }
+
+    writer.writeInt32(1, sentinel);
+
+    writer.writePackedInt32(2, signedData);
+    writer.writePackedInt64(2, signedData);
+    writer.writePackedUint32(2, unsignedData);
+    writer.writePackedUint64(2, unsignedData);
+    writer.writePackedSint32(2, signedData);
+    writer.writePackedSint64(2, signedData);
+    writer.writePackedFixed32(2, unsignedData);
+    writer.writePackedFixed64(2, unsignedData);
+    writer.writePackedSfixed32(2, signedData);
+    writer.writePackedSfixed64(2, signedData);
+    writer.writePackedFloat(2, floatData);
+    writer.writePackedDouble(2, doubleData);
+    writer.writePackedBool(2, boolData);
+    writer.writePackedEnum(2, unsignedData);
+
+    writer.writeInt32(3, sentinel);
+
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    reader.nextField();
+    assertEquals(sentinel, reader.readInt32());
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedInt32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedInt64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedUint32(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedUint64(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSint32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSint64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFixed32(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFixed64(), unsignedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSfixed32(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedSfixed64(), signedData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedFloat(), floatData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedDouble(), doubleData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedBool(), boolData);
+
+    reader.nextField();
+    assertElementsEquals(reader.readPackedEnum(), unsignedData);
+
+    reader.nextField();
+    assertEquals(sentinel, reader.readInt32());
+  });
+
+
+  /**
+   * Byte blobs inside nested messages should always have their byte offset set
+   * relative to the start of the outermost blob, not the start of their parent
+   * blob.
+   */
+  it('testNestedBlobs', function() {
+    // Create a proto consisting of two nested messages, with the inner one
+    // containing a blob of bytes.
+
+    var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
+    var blob = [1, 2, 3, 4, 5];
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    writer.writeMessage(1, dummyMessage, function() {
+      writer.writeMessage(1, dummyMessage, function() {
+        writer.writeBytes(1, blob);
+      });
+    });
+
+    // Peel off the outer two message layers. Each layer should have two bytes
+    // of overhead, one for the field tag and one for the length of the inner
+    // blob.
+
+    var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
+    assertEquals(fieldTag, decoder1.readUnsignedVarint32());
+    assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
+
+    var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
+    assertEquals(fieldTag, decoder2.readUnsignedVarint32());
+    assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
+
+    assertEquals(fieldTag, decoder2.readUnsignedVarint32());
+    assertEquals(blob.length, decoder2.readUnsignedVarint32());
+    var bytes = decoder2.readBytes(blob.length);
+
+    assertElementsEquals(bytes, blob);
+  });
+
+
+  /**
+   * Tests read callbacks.
+   */
+  it('testReadCallbacks', function() {
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    // Add an int, a submessage, and another int.
+    writer.writeInt32(1, 100);
+
+    writer.writeMessage(2, dummyMessage, function() {
+      writer.writeInt32(3, 300);
+      writer.writeInt32(4, 400);
+      writer.writeInt32(5, 500);
+    });
+
+    writer.writeInt32(7, 700);
+
+    // Create the reader and register a custom read callback.
+    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
+
+    /**
+     * @param {!jspb.BinaryReader} reader
+     * @return {*}
+     */
+    function readCallback(reader) {
+      reader.nextField();
+      assertEquals(3, reader.getFieldNumber());
+      assertEquals(300, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(4, reader.getFieldNumber());
+      assertEquals(400, reader.readInt32());
+
+      reader.nextField();
+      assertEquals(5, reader.getFieldNumber());
+      assertEquals(500, reader.readInt32());
+
+      assertEquals(false, reader.nextField());
+    };
+
+    reader.registerReadCallback('readCallback', readCallback);
+
+    // Read the container message.
+    reader.nextField();
+    assertEquals(1, reader.getFieldNumber());
+    assertEquals(100, reader.readInt32());
+
+    reader.nextField();
+    assertEquals(2, reader.getFieldNumber());
+    reader.readMessage(dummyMessage, function() {
+      // Decode the embedded message using the registered callback.
+      reader.runReadCallback('readCallback');
+    });
+
+    reader.nextField();
+    assertEquals(7, reader.getFieldNumber());
+    assertEquals(700, reader.readInt32());
+
+    assertEquals(false, reader.nextField());
+  });
+});
diff --git a/js/binary/utils.js b/js/binary/utils.js
new file mode 100644
index 0000000..9260038
--- /dev/null
+++ b/js/binary/utils.js
@@ -0,0 +1,979 @@
+// 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.
+
+/**
+ * @fileoverview This file contains helper code used by jspb.BinaryReader
+ * and BinaryWriter.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.utils');
+
+goog.require('goog.asserts');
+goog.require('goog.crypt.base64');
+goog.require('goog.string');
+goog.require('jspb.BinaryConstants');
+
+
+/**
+ * Javascript can't natively handle 64-bit data types, so to manipulate them we
+ * have to split them into two 32-bit halves and do the math manually.
+ *
+ * Instead of instantiating and passing small structures around to do this, we
+ * instead just use two global temporary values. This one stores the low 32
+ * bits of a split value - for example, if the original value was a 64-bit
+ * integer, this temporary value will contain the low 32 bits of that integer.
+ * If the original value was a double, this temporary value will contain the
+ * low 32 bits of the binary representation of that double, etcetera.
+ * @type {number}
+ */
+jspb.utils.split64Low = 0;
+
+
+/**
+ * And correspondingly, this temporary variable will contain the high 32 bits
+ * of whatever value was split.
+ * @type {number}
+ */
+jspb.utils.split64High = 0;
+
+
+/**
+ * Splits an unsigned Javascript integer into two 32-bit halves and stores it
+ * in the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitUint64 = function(value) {
+  // Extract low 32 bits and high 32 bits as unsigned integers.
+  var lowBits = value >>> 0;
+  var highBits = Math.floor((value - lowBits) /
+                            jspb.BinaryConstants.TWO_TO_32) >>> 0;
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Splits a signed Javascript integer into two 32-bit halves and stores it in
+ * the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitInt64 = function(value) {
+  // Convert to sign-magnitude representation.
+  var sign = (value < 0);
+  value = Math.abs(value);
+
+  // Extract low 32 bits and high 32 bits as unsigned integers.
+  var lowBits = value >>> 0;
+  var highBits = Math.floor((value - lowBits) /
+                            jspb.BinaryConstants.TWO_TO_32);
+  highBits = highBits >>> 0;
+
+  // Perform two's complement conversion if the sign bit was set.
+  if (sign) {
+    highBits = ~highBits >>> 0;
+    lowBits = ~lowBits >>> 0;
+    lowBits += 1;
+    if (lowBits > 0xFFFFFFFF) {
+      lowBits = 0;
+      highBits++;
+      if (highBits > 0xFFFFFFFF) highBits = 0;
+    }
+  }
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Convers a signed Javascript integer into zigzag format, splits it into two
+ * 32-bit halves, and stores it in the temp values above.
+ * @param {number} value The number to split.
+ */
+jspb.utils.splitZigzag64 = function(value) {
+  // Convert to sign-magnitude and scale by 2 before we split the value.
+  var sign = (value < 0);
+  value = Math.abs(value) * 2;
+
+  jspb.utils.splitUint64(value);
+  var lowBits = jspb.utils.split64Low;
+  var highBits = jspb.utils.split64High;
+
+  // If the value is negative, subtract 1 from the split representation so we
+  // don't lose the sign bit due to precision issues.
+  if (sign) {
+    if (lowBits == 0) {
+      if (highBits == 0) {
+        lowBits = 0xFFFFFFFF;
+        highBits = 0xFFFFFFFF;
+      } else {
+        highBits--;
+        lowBits = 0xFFFFFFFF;
+      }
+    } else {
+      lowBits--;
+    }
+  }
+
+  jspb.utils.split64Low = lowBits;
+  jspb.utils.split64High = highBits;
+};
+
+
+/**
+ * Converts a floating-point number into 32-bit IEEE representation and stores
+ * it in the temp values above.
+ * @param {number} value
+ */
+jspb.utils.splitFloat32 = function(value) {
+  var sign = (value < 0) ? 1 : 0;
+  value = sign ? -value : value;
+  var exp;
+  var mant;
+
+  // Handle zeros.
+  if (value === 0) {
+    if ((1 / value) > 0) {
+      // Positive zero.
+      jspb.utils.split64High = 0;
+      jspb.utils.split64Low = 0x00000000;
+    } else {
+      // Negative zero.
+      jspb.utils.split64High = 0;
+      jspb.utils.split64Low = 0x80000000;
+    }
+    return;
+  }
+
+  // Handle nans.
+  if (isNaN(value)) {
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = 0x7FFFFFFF;
+    return;
+  }
+
+  // Handle infinities.
+  if (value > jspb.BinaryConstants.FLOAT32_MAX) {
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = ((sign << 31) | (0x7F800000)) >>> 0;
+    return;
+  }
+
+  // Handle denormals.
+  if (value < jspb.BinaryConstants.FLOAT32_MIN) {
+    // Number is a denormal.
+    mant = Math.round(value / Math.pow(2, -149));
+    jspb.utils.split64High = 0;
+    jspb.utils.split64Low = ((sign << 31) | mant) >>> 0;
+    return;
+  }
+
+  exp = Math.floor(Math.log(value) / Math.LN2);
+  mant = value * Math.pow(2, -exp);
+  mant = Math.round(mant * jspb.BinaryConstants.TWO_TO_23) & 0x7FFFFF;
+
+  jspb.utils.split64High = 0;
+  jspb.utils.split64Low = ((sign << 31) | ((exp + 127) << 23) | mant) >>> 0;
+};
+
+
+/**
+ * Converts a floating-point number into 64-bit IEEE representation and stores
+ * it in the temp values above.
+ * @param {number} value
+ */
+jspb.utils.splitFloat64 = function(value) {
+  var sign = (value < 0) ? 1 : 0;
+  value = sign ? -value : value;
+
+  // Handle zeros.
+  if (value === 0) {
+    if ((1 / value) > 0) {
+      // Positive zero.
+      jspb.utils.split64High = 0x00000000;
+      jspb.utils.split64Low = 0x00000000;
+    } else {
+      // Negative zero.
+      jspb.utils.split64High = 0x80000000;
+      jspb.utils.split64Low = 0x00000000;
+    }
+    return;
+  }
+
+  // Handle nans.
+  if (isNaN(value)) {
+    jspb.utils.split64High = 0x7FFFFFFF;
+    jspb.utils.split64Low = 0xFFFFFFFF;
+    return;
+  }
+
+  // Handle infinities.
+  if (value > jspb.BinaryConstants.FLOAT64_MAX) {
+    jspb.utils.split64High = ((sign << 31) | (0x7FF00000)) >>> 0;
+    jspb.utils.split64Low = 0;
+    return;
+  }
+
+  // Handle denormals.
+  if (value < jspb.BinaryConstants.FLOAT64_MIN) {
+    // Number is a denormal.
+    var mant = value / Math.pow(2, -1074);
+    var mantHigh = (mant / jspb.BinaryConstants.TWO_TO_32);
+    jspb.utils.split64High = ((sign << 31) | mantHigh) >>> 0;
+    jspb.utils.split64Low = (mant >>> 0);
+    return;
+  }
+
+  var exp = Math.floor(Math.log(value) / Math.LN2);
+  if (exp == 1024) exp = 1023;
+  var mant = value * Math.pow(2, -exp);
+
+  var mantHigh = (mant * jspb.BinaryConstants.TWO_TO_20) & 0xFFFFF;
+  var mantLow = (mant * jspb.BinaryConstants.TWO_TO_52) >>> 0;
+
+  jspb.utils.split64High =
+      ((sign << 31) | ((exp + 1023) << 20) | mantHigh) >>> 0;
+  jspb.utils.split64Low = mantLow;
+};
+
+
+/**
+ * Converts an 8-character hash string into two 32-bit numbers and stores them
+ * in the temp values above.
+ * @param {string} hash
+ */
+jspb.utils.splitHash64 = function(hash) {
+  var a = hash.charCodeAt(0);
+  var b = hash.charCodeAt(1);
+  var c = hash.charCodeAt(2);
+  var d = hash.charCodeAt(3);
+  var e = hash.charCodeAt(4);
+  var f = hash.charCodeAt(5);
+  var g = hash.charCodeAt(6);
+  var h = hash.charCodeAt(7);
+
+  jspb.utils.split64Low = (a + (b << 8) + (c << 16) + (d << 24)) >>> 0;
+  jspb.utils.split64High = (e + (f << 8) + (g << 16) + (h << 24)) >>> 0;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit unsigned integer. Precision will be
+ * lost if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinUint64 = function(bitsLow, bitsHigh) {
+  return bitsHigh * jspb.BinaryConstants.TWO_TO_32 + bitsLow;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit signed integer. Precision will be lost
+ * if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinInt64 = function(bitsLow, bitsHigh) {
+  // If the high bit is set, do a manual two's complement conversion.
+  var sign = (bitsHigh & 0x80000000);
+  if (sign) {
+    bitsLow = (~bitsLow + 1) >>> 0;
+    bitsHigh = ~bitsHigh >>> 0;
+    if (bitsLow == 0) {
+      bitsHigh = (bitsHigh + 1) >>> 0;
+    }
+  }
+
+  var result = jspb.utils.joinUint64(bitsLow, bitsHigh);
+  return sign ? -result : result;
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit unsigned integer and applies zigzag
+ * decoding. Precision will be lost if the result is greater than 2^52.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {number}
+ */
+jspb.utils.joinZigzag64 = function(bitsLow, bitsHigh) {
+  // Extract the sign bit and shift right by one.
+  var sign = bitsLow & 1;
+  bitsLow = ((bitsLow >>> 1) | (bitsHigh << 31)) >>> 0;
+  bitsHigh = bitsHigh >>> 1;
+
+  // Increment the split value if the sign bit was set.
+  if (sign) {
+    bitsLow = (bitsLow + 1) >>> 0;
+    if (bitsLow == 0) {
+      bitsHigh = (bitsHigh + 1) >>> 0;
+    }
+  }
+
+  var result = jspb.utils.joinUint64(bitsLow, bitsHigh);
+  return sign ? -result : result;
+};
+
+
+/**
+ * Joins two 32-bit values into a 32-bit IEEE floating point number and
+ * converts it back into a Javascript number.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {number}
+ */
+jspb.utils.joinFloat32 = function(bitsLow, bitsHigh) {
+  var sign = ((bitsLow >> 31) * 2 + 1);
+  var exp = (bitsLow >>> 23) & 0xFF;
+  var mant = bitsLow & 0x7FFFFF;
+
+  if (exp == 0xFF) {
+    if (mant) {
+      return NaN;
+    } else {
+      return sign * Infinity;
+    }
+  }
+
+  if (exp == 0) {
+    // Denormal.
+    return sign * Math.pow(2, -149) * mant;
+  } else {
+    return sign * Math.pow(2, exp - 150) *
+           (mant + Math.pow(2, 23));
+  }
+};
+
+
+/**
+ * Joins two 32-bit values into a 64-bit IEEE floating point number and
+ * converts it back into a Javascript number.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {number}
+ */
+jspb.utils.joinFloat64 = function(bitsLow, bitsHigh) {
+  var sign = ((bitsHigh >> 31) * 2 + 1);
+  var exp = (bitsHigh >>> 20) & 0x7FF;
+  var mant = jspb.BinaryConstants.TWO_TO_32 * (bitsHigh & 0xFFFFF) + bitsLow;
+
+  if (exp == 0x7FF) {
+    if (mant) {
+      return NaN;
+    } else {
+      return sign * Infinity;
+    }
+  }
+
+  if (exp == 0) {
+    // Denormal.
+    return sign * Math.pow(2, -1074) * mant;
+  } else {
+    return sign * Math.pow(2, exp - 1075) *
+           (mant + jspb.BinaryConstants.TWO_TO_52);
+  }
+};
+
+
+/**
+ * Joins two 32-bit values into an 8-character hash string.
+ * @param {number} bitsLow
+ * @param {number} bitsHigh
+ * @return {string}
+ */
+jspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
+  var a = (bitsLow >>> 0) & 0xFF;
+  var b = (bitsLow >>> 8) & 0xFF;
+  var c = (bitsLow >>> 16) & 0xFF;
+  var d = (bitsLow >>> 24) & 0xFF;
+  var e = (bitsHigh >>> 0) & 0xFF;
+  var f = (bitsHigh >>> 8) & 0xFF;
+  var g = (bitsHigh >>> 16) & 0xFF;
+  var h = (bitsHigh >>> 24) & 0xFF;
+
+  return String.fromCharCode(a, b, c, d, e, f, g, h);
+};
+
+
+/**
+ * Individual digits for number->string conversion.
+ * @const {!Array.<number>}
+ */
+jspb.utils.DIGITS = [
+  '0', '1', '2', '3', '4', '5', '6', '7',
+  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+];
+
+
+/**
+ * Losslessly converts a 64-bit unsigned integer in 32:32 split representation
+ * into a decimal string.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {string} The binary number represented as a string.
+ */
+jspb.utils.joinUnsignedDecimalString = function(bitsLow, bitsHigh) {
+  // Skip the expensive conversion if the number is small enough to use the
+  // built-in conversions.
+  if (bitsHigh <= 0x1FFFFF) {
+    return '' + (jspb.BinaryConstants.TWO_TO_32 * bitsHigh + bitsLow);
+  }
+
+  // What this code is doing is essentially converting the input number from
+  // base-2 to base-1e7, which allows us to represent the 64-bit range with
+  // only 3 (very large) digits. Those digits are then trivial to convert to
+  // a base-10 string.
+
+  // The magic numbers used here are -
+  // 2^24 = 16777216 = (1,6777216) in base-1e7.
+  // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
+
+  // Split 32:32 representation into 16:24:24 representation so our
+  // intermediate digits don't overflow.
+  var low = bitsLow & 0xFFFFFF;
+  var mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF;
+  var high = (bitsHigh >> 16) & 0xFFFF;
+
+  // Assemble our three base-1e7 digits, ignoring carries. The maximum
+  // value in a digit at this step is representable as a 48-bit integer, which
+  // can be stored in a 64-bit floating point number.
+  var digitA = low + (mid * 6777216) + (high * 6710656);
+  var digitB = mid + (high * 8147497);
+  var digitC = (high * 2);
+
+  // Apply carries from A to B and from B to C.
+  var base = 10000000;
+  if (digitA >= base) {
+    digitB += Math.floor(digitA / base);
+    digitA %= base;
+  }
+
+  if (digitB >= base) {
+    digitC += Math.floor(digitB / base);
+    digitB %= base;
+  }
+
+  // Convert base-1e7 digits to base-10, omitting leading zeroes.
+  var table = jspb.utils.DIGITS;
+  var start = false;
+  var result = '';
+
+  function emit(digit) {
+    var temp = base;
+    for (var i = 0; i < 7; i++) {
+      temp /= 10;
+      var decimalDigit = ((digit / temp) % 10) >>> 0;
+      if ((decimalDigit == 0) && !start) continue;
+      start = true;
+      result += table[decimalDigit];
+    }
+  }
+
+  if (digitC || start) emit(digitC);
+  if (digitB || start) emit(digitB);
+  if (digitA || start) emit(digitA);
+
+  return result;
+};
+
+
+/**
+ * Losslessly converts a 64-bit signed integer in 32:32 split representation
+ * into a decimal string.
+ * @param {number} bitsLow The low 32 bits of the binary number;
+ * @param {number} bitsHigh The high 32 bits of the binary number.
+ * @return {string} The binary number represented as a string.
+ */
+jspb.utils.joinSignedDecimalString = function(bitsLow, bitsHigh) {
+  // If we're treating the input as a signed value and the high bit is set, do
+  // a manual two's complement conversion before the decimal conversion.
+  var negative = (bitsHigh & 0x80000000);
+  if (negative) {
+    bitsLow = (~bitsLow + 1) >>> 0;
+    var carry = (bitsLow == 0) ? 1 : 0;
+    bitsHigh = (~bitsHigh + carry) >>> 0;
+  }
+
+  var result = jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
+  return negative ? '-' + result : result;
+};
+
+
+/**
+ * Convert an 8-character hash string representing either a signed or unsigned
+ * 64-bit integer into its decimal representation without losing accuracy.
+ * @param {string} hash The hash string to convert.
+ * @param {boolean} signed True if we should treat the hash string as encoding
+ *     a signed integer.
+ * @return {string}
+ */
+jspb.utils.hash64ToDecimalString = function(hash, signed) {
+  jspb.utils.splitHash64(hash);
+  var bitsLow = jspb.utils.split64Low;
+  var bitsHigh = jspb.utils.split64High;
+  return signed ?
+      jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh) :
+      jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Converts an array of 8-character hash strings into their decimal
+ * representations.
+ * @param {!Array.<string>} hashes The array of hash strings to convert.
+ * @param {boolean} signed True if we should treat the hash string as encoding
+ *     a signed integer.
+ * @return {!Array.<string>}
+ */
+jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) {
+  var result = new Array(hashes.length);
+  for (var i = 0; i < hashes.length; i++) {
+    result[i] = jspb.utils.hash64ToDecimalString(hashes[i], signed);
+  }
+  return result;
+};
+
+
+/**
+ * Converts an 8-character hash string into its hexadecimal representation.
+ * @param {string} hash
+ * @return {string}
+ */
+jspb.utils.hash64ToHexString = function(hash) {
+  var temp = new Array(18);
+  temp[0] = '0';
+  temp[1] = 'x';
+
+  for (var i = 0; i < 8; i++) {
+    var c = hash.charCodeAt(7 - i);
+    temp[i * 2 + 2] = jspb.utils.DIGITS[c >> 4];
+    temp[i * 2 + 3] = jspb.utils.DIGITS[c & 0xF];
+  }
+
+  var result = temp.join('');
+  return result;
+};
+
+
+/**
+ * Converts a '0x<16 digits>' hex string into its hash string representation.
+ * @param {string} hex
+ * @return {string}
+ */
+jspb.utils.hexStringToHash64 = function(hex) {
+  hex = hex.toLowerCase();
+  goog.asserts.assert(hex.length == 18);
+  goog.asserts.assert(hex[0] == '0');
+  goog.asserts.assert(hex[1] == 'x');
+
+  var result = '';
+  for (var i = 0; i < 8; i++) {
+    var hi = jspb.utils.DIGITS.indexOf(hex[i * 2 + 2]);
+    var lo = jspb.utils.DIGITS.indexOf(hex[i * 2 + 3]);
+    result = String.fromCharCode(hi * 16 + lo) + result;
+  }
+
+  return result;
+};
+
+
+/**
+ * Convert an 8-character hash string representing either a signed or unsigned
+ * 64-bit integer into a Javascript number. Will lose accuracy if the result is
+ * larger than 2^52.
+ * @param {string} hash The hash string to convert.
+ * @param {boolean} signed True if the has should be interpreted as a signed
+ *     number.
+ * @return {number}
+ */
+jspb.utils.hash64ToNumber = function(hash, signed) {
+  jspb.utils.splitHash64(hash);
+  var bitsLow = jspb.utils.split64Low;
+  var bitsHigh = jspb.utils.split64High;
+  return signed ? jspb.utils.joinInt64(bitsLow, bitsHigh) :
+                  jspb.utils.joinUint64(bitsLow, bitsHigh);
+};
+
+
+/**
+ * Convert a Javascript number into an 8-character hash string. Will lose
+ * precision if the value is non-integral or greater than 2^64.
+ * @param {number} value The integer to convert.
+ * @return {string}
+ */
+jspb.utils.numberToHash64 = function(value) {
+  jspb.utils.splitInt64(value);
+  return jspb.utils.joinHash64(jspb.utils.split64Low,
+                                  jspb.utils.split64High);
+};
+
+
+/**
+ * Counts the number of contiguous varints in a buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @return {number} The number of varints in the buffer.
+ */
+jspb.utils.countVarints = function(buffer, start, end) {
+  // Count how many high bits of each byte were set in the buffer.
+  var count = 0;
+  for (var i = start; i < end; i++) {
+    count += buffer[i] >> 7;
+  }
+
+  // The number of varints in the buffer equals the size of the buffer minus
+  // the number of non-terminal bytes in the buffer (those with the high bit
+  // set).
+  return (end - start) - count;
+};
+
+
+/**
+ * Counts the number of contiguous varint fields with the given field number in
+ * the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countVarintFields = function(buffer, start, end, field) {
+  var count = 0;
+  var cursor = start;
+  var tag = field * 8 + jspb.BinaryConstants.WireType.VARINT;
+
+  if (tag < 128) {
+    // Single-byte field tag, we can use a slightly quicker count.
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      if (buffer[cursor++] != tag) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the varint.
+      while (1) {
+        var x = buffer[cursor++];
+        if ((x & 0x80) == 0) break;
+      }
+    }
+  } else {
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      var temp = tag;
+      while (temp > 128) {
+        if (buffer[cursor] != ((temp & 0x7F) | 0x80)) return count;
+        cursor++;
+        temp >>= 7;
+      }
+      if (buffer[cursor++] != temp) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the varint.
+      while (1) {
+        var x = buffer[cursor++];
+        if ((x & 0x80) == 0) break;
+      }
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Counts the number of contiguous fixed32 fields with the given tag in the
+ * buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} tag The tag value to count.
+ * @param {number} stride The number of bytes to skip per field.
+ * @return {number} The number of fields with a matching tag in the buffer.
+ * @private
+ */
+jspb.utils.countFixedFields_ =
+    function(buffer, start, end, tag, stride) {
+  var count = 0;
+  var cursor = start;
+
+  if (tag < 128) {
+    // Single-byte field tag, we can use a slightly quicker count.
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      if (buffer[cursor++] != tag) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the value.
+      cursor += stride;
+    }
+  } else {
+    while (cursor < end) {
+      // Skip the field tag, or exit if we find a non-matching tag.
+      var temp = tag;
+      while (temp > 128) {
+        if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
+        temp >>= 7;
+      }
+      if (buffer[cursor++] != temp) return count;
+
+      // Field tag matches, we've found a valid field.
+      count++;
+
+      // Skip the value.
+      cursor += stride;
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Counts the number of contiguous fixed32 fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countFixed32Fields = function(buffer, start, end, field) {
+  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED32;
+  return jspb.utils.countFixedFields_(buffer, start, end, tag, 4);
+};
+
+
+/**
+ * Counts the number of contiguous fixed64 fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countFixed64Fields = function(buffer, start, end, field) {
+  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED64;
+  return jspb.utils.countFixedFields_(buffer, start, end, tag, 8);
+};
+
+
+/**
+ * Counts the number of contiguous delimited fields with the given field number
+ * in the buffer.
+ * @param {!Uint8Array} buffer The buffer to scan.
+ * @param {number} start The starting point in the buffer to scan.
+ * @param {number} end The end point in the buffer to scan.
+ * @param {number} field The field number to count.
+ * @return {number} The number of matching fields in the buffer.
+ */
+jspb.utils.countDelimitedFields = function(buffer, start, end, field) {
+  var count = 0;
+  var cursor = start;
+  var tag = field * 8 + jspb.BinaryConstants.WireType.DELIMITED;
+
+  while (cursor < end) {
+    // Skip the field tag, or exit if we find a non-matching tag.
+    var temp = tag;
+    while (temp > 128) {
+      if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
+      temp >>= 7;
+    }
+    if (buffer[cursor++] != temp) return count;
+
+    // Field tag matches, we've found a valid field.
+    count++;
+
+    // Decode the length prefix.
+    var length = 0;
+    var shift = 1;
+    while (1) {
+      temp = buffer[cursor++];
+      length += (temp & 0x7f) * shift;
+      shift *= 128;
+      if ((temp & 0x80) == 0) break;
+    }
+
+    // Advance the cursor past the blob.
+    cursor += length;
+  }
+  return count;
+};
+
+
+/**
+ * Clones a scalar field. Pulling this out to a helper method saves us a few
+ * bytes of generated code.
+ * @param {Array} array
+ * @return {Array}
+ */
+jspb.utils.cloneRepeatedScalarField = function(array) {
+  return array ? array.slice() : null;
+};
+
+
+/**
+ * Clones an array of messages using the provided cloner function.
+ * @param {Array.<jspb.BinaryMessage>} messages
+ * @param {jspb.ClonerFunction} cloner
+ * @return {Array.<jspb.BinaryMessage>}
+ */
+jspb.utils.cloneRepeatedMessageField = function(messages, cloner) {
+  if (messages === null) return null;
+  var result = [];
+  for (var i = 0; i < messages.length; i++) {
+    result.push(cloner(messages[i]));
+  }
+  return result;
+};
+
+
+/**
+ * Clones an array of byte blobs.
+ * @param {Array.<Uint8Array>} blobs
+ * @return {Array.<Uint8Array>}
+ */
+jspb.utils.cloneRepeatedBlobField = function(blobs) {
+  if (blobs === null) return null;
+  var result = [];
+  for (var i = 0; i < blobs.length; i++) {
+    result.push(new Uint8Array(blobs[i]));
+  }
+  return result;
+};
+
+
+/**
+ * String-ify bytes for text format. Should be optimized away in non-debug.
+ * The returned string uses \xXX escapes for all values and is itself quoted.
+ * [1, 31] serializes to '"\x01\x1f"'.
+ * @param {jspb.ByteSource} byteSource The bytes to serialize.
+ * @param {boolean=} opt_stringIsRawBytes The string is interpreted as a series
+ * of raw bytes rather than base64 data.
+ * @return {string} Stringified bytes for text format.
+ */
+jspb.utils.debugBytesToTextFormat = function(byteSource,
+                                                opt_stringIsRawBytes) {
+  var s = '"';
+  if (byteSource) {
+    var bytes =
+        jspb.utils.byteSourceToUint8Array(byteSource, opt_stringIsRawBytes);
+    for (var i = 0; i < bytes.length; i++) {
+      s += '\\x';
+      if (bytes[i] < 16) s += '0';
+      s += bytes[i].toString(16);
+    }
+  }
+  return s + '"';
+};
+
+
+/**
+ * String-ify a scalar for text format. Should be optimized away in non-debug.
+ * @param {string|number|boolean} scalar The scalar to stringify.
+ * @return {string} Stringified scalar for text format.
+ */
+jspb.utils.debugScalarToTextFormat = function(scalar) {
+  if (goog.isString(scalar)) {
+    return goog.string.quote(scalar);
+  } else {
+    return scalar.toString();
+  }
+};
+
+
+/**
+ * Utility function: convert a string with codepoints 0--255 inclusive to a
+ * Uint8Array. If any codepoints greater than 255 exist in the string, throws an
+ * exception.
+ * @param {string} str
+ * @return {!Uint8Array}
+ * @private
+ */
+jspb.utils.stringToByteArray_ = function(str) {
+  var arr = new Uint8Array(str.length);
+  for (var i = 0; i < str.length; i++) {
+    var codepoint = str.charCodeAt(i);
+    if (codepoint > 255) {
+      throw new Error('Conversion error: string contains codepoint ' +
+                      'outside of byte range');
+    }
+    arr[i] = codepoint;
+  }
+  return arr;
+};
+
+
+/**
+ * Converts any type defined in jspb.ByteSource into a Uint8Array.
+ * @param {!jspb.ByteSource} data
+ * @param {boolean=} opt_stringIsRawBytes Interpret a string as a series of raw
+ * bytes (encoded as codepoints 0--255 inclusive) rather than base64 data
+ * (default behavior).
+ * @return {!Uint8Array}
+ * @suppress {invalidCasts}
+ */
+jspb.utils.byteSourceToUint8Array = function(data, opt_stringIsRawBytes) {
+  if (data.constructor === Uint8Array) {
+    return /** @type {!Uint8Array} */(data);
+  }
+
+  if (data.constructor === ArrayBuffer) {
+    data = /** @type {!ArrayBuffer} */(data);
+    return /** @type {!Uint8Array} */(new Uint8Array(data));
+  }
+
+  if (data.constructor === Array) {
+    data = /** @type {!Array.<number>} */(data);
+    return /** @type {!Uint8Array} */(new Uint8Array(data));
+  }
+
+  if (data.constructor === String) {
+    data = /** @type {string} */(data);
+    if (opt_stringIsRawBytes) {
+      return jspb.utils.stringToByteArray_(data);
+    } else {
+      return goog.crypt.base64.decodeStringToUint8Array(data);
+    }
+  }
+
+  goog.asserts.fail('Type not convertible to Uint8Array.');
+  return /** @type {!Uint8Array} */(new Uint8Array(0));
+};
diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js
new file mode 100644
index 0000000..5c33079
--- /dev/null
+++ b/js/binary/utils_test.js
@@ -0,0 +1,632 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's helper functions.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.crypt.base64');
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.BinaryWriter');
+goog.require('jspb.utils');
+
+
+/**
+ * @param {number} x
+ * @return {number}
+ */
+function truncate(x) {
+  var temp = new Float32Array(1);
+  temp[0] = x;
+  return temp[0];
+}
+
+
+/**
+ * Converts an 64-bit integer in split representation to a 64-bit hash string
+ * (8 bits encoded per character).
+ * @param {number} bitsLow The low 32 bits of the split 64-bit integer.
+ * @param {number} bitsHigh The high 32 bits of the split 64-bit integer.
+ * @return {string} The encoded hash string, 8 bits per character.
+ */
+function toHashString(bitsLow, bitsHigh) {
+  return String.fromCharCode((bitsLow >>> 0) & 0xFF,
+                             (bitsLow >>> 8) & 0xFF,
+                             (bitsLow >>> 16) & 0xFF,
+                             (bitsLow >>> 24) & 0xFF,
+                             (bitsHigh >>> 0) & 0xFF,
+                             (bitsHigh >>> 8) & 0xFF,
+                             (bitsHigh >>> 16) & 0xFF,
+                             (bitsHigh >>> 24) & 0xFF);
+}
+
+
+describe('binaryUtilsTest', function() {
+  /**
+   * Tests lossless binary-to-decimal conversion.
+   */
+  it('testDecimalConversion', function() {
+    // Check some magic numbers.
+    var result =
+        jspb.utils.joinUnsignedDecimalString(0x89e80001, 0x8ac72304);
+    assertEquals('10000000000000000001', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xacd05f15, 0x1b69b4b);
+    assertEquals('123456789123456789', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xeb1f0ad2, 0xab54a98c);
+    assertEquals('12345678901234567890', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xe3b70cb1, 0x891087b8);
+    assertEquals('9876543210987654321', result);
+
+    // Check limits.
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00000000);
+    assertEquals('0', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0xFFFFFFFF, 0xFFFFFFFF);
+    assertEquals('18446744073709551615', result);
+
+    // Check each bit of the low dword.
+    for (var i = 0; i < 32; i++) {
+      var low = (1 << i) >>> 0;
+      result = jspb.utils.joinUnsignedDecimalString(low, 0);
+      assertEquals('' + Math.pow(2, i), result);
+    }
+
+    // Check the first 20 bits of the high dword.
+    for (var i = 0; i < 20; i++) {
+      var high = (1 << i) >>> 0;
+      result = jspb.utils.joinUnsignedDecimalString(0, high);
+      assertEquals('' + Math.pow(2, 32 + i), result);
+    }
+
+    // V8's internal double-to-string conversion is inaccurate for values above
+    // 2^52, even if they're representable integers - check the rest of the bits
+    // manually against the correct string representations of 2^N.
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00100000);
+    assertEquals('4503599627370496', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00200000);
+    assertEquals('9007199254740992', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00400000);
+    assertEquals('18014398509481984', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x00800000);
+    assertEquals('36028797018963968', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x01000000);
+    assertEquals('72057594037927936', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x02000000);
+    assertEquals('144115188075855872', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x04000000);
+    assertEquals('288230376151711744', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x08000000);
+    assertEquals('576460752303423488', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x10000000);
+    assertEquals('1152921504606846976', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x20000000);
+    assertEquals('2305843009213693952', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x40000000);
+    assertEquals('4611686018427387904', result);
+
+    result = jspb.utils.joinUnsignedDecimalString(0x00000000, 0x80000000);
+    assertEquals('9223372036854775808', result);
+  });
+
+
+  /**
+   * Going from hash strings to decimal strings should also be lossless.
+   */
+  it('testHashToDecimalConversion', function() {
+    var result;
+    var convert = jspb.utils.hash64ToDecimalString;
+
+    result = convert(toHashString(0x00000000, 0x00000000), false);
+    assertEquals('0', result);
+
+    result = convert(toHashString(0x00000000, 0x00000000), true);
+    assertEquals('0', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), false);
+    assertEquals('18446744073709551615', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF), true);
+    assertEquals('-1', result);
+
+    result = convert(toHashString(0x00000000, 0x80000000), false);
+    assertEquals('9223372036854775808', result);
+
+    result = convert(toHashString(0x00000000, 0x80000000), true);
+    assertEquals('-9223372036854775808', result);
+
+    result = convert(toHashString(0xacd05f15, 0x01b69b4b), false);
+    assertEquals('123456789123456789', result);
+
+    result = convert(toHashString(~0xacd05f15 + 1, ~0x01b69b4b), true);
+    assertEquals('-123456789123456789', result);
+
+    // And converting arrays of hashes should work the same way.
+    result = jspb.utils.hash64ArrayToDecimalStrings([
+      toHashString(0xFFFFFFFF, 0xFFFFFFFF),
+      toHashString(0x00000000, 0x80000000),
+      toHashString(0xacd05f15, 0x01b69b4b)], false);
+    assertEquals(3, result.length);
+    assertEquals('18446744073709551615', result[0]);
+    assertEquals('9223372036854775808', result[1]);
+    assertEquals('123456789123456789', result[2]);
+  });
+
+
+  /**
+   * Going from hash strings to hex strings should be lossless.
+   */
+  it('testHashToHexConversion', function() {
+    var result;
+    var convert = jspb.utils.hash64ToHexString;
+
+    result = convert(toHashString(0x00000000, 0x00000000));
+    assertEquals('0x0000000000000000', result);
+
+    result = convert(toHashString(0xFFFFFFFF, 0xFFFFFFFF));
+    assertEquals('0xffffffffffffffff', result);
+
+    result = convert(toHashString(0x12345678, 0x9ABCDEF0));
+    assertEquals('0x9abcdef012345678', result);
+  });
+
+
+  /**
+   * Going from hex strings to hash strings should be lossless.
+   */
+  it('testHexToHashConversion', function() {
+    var result;
+    var convert = jspb.utils.hexStringToHash64;
+
+    result = convert('0x0000000000000000');
+    assertEquals(String.fromCharCode.apply(null,
+        [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result);
+
+    result = convert('0xffffffffffffffff');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result);
+
+    // Hex string is big-endian, hash string is little-endian.
+    result = convert('0x123456789ABCDEF0');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xF0, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12]), result);
+
+    // Capitalization should not matter.
+    result = convert('0x0000abcdefABCDEF');
+    assertEquals(String.fromCharCode.apply(null,
+        [0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB, 0x00, 0x00]), result);
+  });
+
+
+  /**
+   * Going from numbers to hash strings should be lossless for up to 53 bits of
+   * precision.
+   */
+  it('testNumberToHashConversion', function() {
+    var result;
+    var convert = jspb.utils.numberToHash64;
+
+    result = convert(0x0000000000000);
+    assertEquals('0x0000000000000000', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0xFFFFFFFFFFFFF);
+    assertEquals('0x000fffffffffffff', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0x123456789ABCD);
+    assertEquals('0x000123456789abcd', jspb.utils.hash64ToHexString(result));
+
+    result = convert(0xDCBA987654321);
+    assertEquals('0x000dcba987654321', jspb.utils.hash64ToHexString(result));
+
+    // 53 bits of precision should not be truncated.
+    result = convert(0x10000000000001);
+    assertEquals('0x0010000000000001', jspb.utils.hash64ToHexString(result));
+
+    // 54 bits of precision should be truncated.
+    result = convert(0x20000000000001);
+    assertNotEquals(
+        '0x0020000000000001', jspb.utils.hash64ToHexString(result));
+  });
+
+
+  /**
+   * Sanity check the behavior of Javascript's strings when doing funny things
+   * with unicode characters.
+   */
+  it('sanityCheckUnicodeStrings', function() {
+    var strings = new Array(65536);
+
+    // All possible unsigned 16-bit values should be storable in a string, they
+    // shouldn't do weird things with the length of the string, and they should
+    // come back out of the string unchanged.
+    for (var i = 0; i < 65536; i++) {
+      strings[i] = 'a' + String.fromCharCode(i) + 'a';
+      if (3 != strings[i].length) throw 'fail!';
+      if (i != strings[i].charCodeAt(1)) throw 'fail!';
+    }
+
+    // Each unicode character should compare equal to itself and not equal to a
+    // different unicode character.
+    for (var i = 0; i < 65536; i++) {
+      if (strings[i] != strings[i]) throw 'fail!';
+      if (strings[i] == strings[(i + 1) % 65536]) throw 'fail!';
+    }
+  });
+
+
+  /**
+   * Tests conversion from 32-bit floating point numbers to split64 numbers.
+   */
+  it('testFloat32ToSplit64', function() {
+    var f32_eps = jspb.BinaryConstants.FLOAT32_EPS;
+    var f32_min = jspb.BinaryConstants.FLOAT32_MIN;
+    var f32_max = jspb.BinaryConstants.FLOAT32_MAX;
+
+    // NaN.
+    jspb.utils.splitFloat32(NaN);
+    if (!isNaN(jspb.utils.joinFloat32(jspb.utils.split64Low,
+                                         jspb.utils.split64High))) {
+      throw 'fail!';
+    }
+
+    /**
+     * @param {number} x
+     * @param {number=} opt_bits
+     */
+    function test(x, opt_bits) {
+      jspb.utils.splitFloat32(x);
+      if (goog.isDef(opt_bits)) {
+        if (opt_bits != jspb.utils.split64Low) throw 'fail!';
+      }
+      if (truncate(x) != jspb.utils.joinFloat32(jspb.utils.split64Low,
+                                                   jspb.utils.split64High)) {
+        throw 'fail!';
+      }
+    }
+
+    // Positive and negative infinity.
+    test(Infinity, 0x7f800000);
+    test(-Infinity, 0xff800000);
+
+    // Positive and negative zero.
+    test(0, 0x00000000);
+    test(-0, 0x80000000);
+
+    // Positive and negative epsilon.
+    test(f32_eps, 0x00000001);
+    test(-f32_eps, 0x80000001);
+
+    // Positive and negative min.
+    test(f32_min, 0x00800000);
+    test(-f32_min, 0x80800000);
+
+    // Positive and negative max.
+    test(f32_max, 0x7F7FFFFF);
+    test(-f32_max, 0xFF7FFFFF);
+
+    // Various positive values.
+    var cursor = f32_eps * 10;
+    while (cursor != Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+
+    // Various negative values.
+    cursor = -f32_eps * 10;
+    while (cursor != -Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+  });
+
+
+  /**
+   * Tests conversion from 64-bit floating point numbers to split64 numbers.
+   */
+  it('testFloat64ToSplit64', function() {
+    var f64_eps = jspb.BinaryConstants.FLOAT64_EPS;
+    var f64_min = jspb.BinaryConstants.FLOAT64_MIN;
+    var f64_max = jspb.BinaryConstants.FLOAT64_MAX;
+
+    // NaN.
+    jspb.utils.splitFloat64(NaN);
+    if (!isNaN(jspb.utils.joinFloat64(jspb.utils.split64Low,
+                                         jspb.utils.split64High))) {
+      throw 'fail!';
+    }
+
+    /**
+     * @param {number} x
+     * @param {number=} opt_highBits
+     * @param {number=} opt_lowBits
+     */
+    function test(x, opt_highBits, opt_lowBits) {
+      jspb.utils.splitFloat64(x);
+      if (goog.isDef(opt_highBits)) {
+        if (opt_highBits != jspb.utils.split64High) throw 'fail!';
+      }
+      if (goog.isDef(opt_lowBits)) {
+        if (opt_lowBits != jspb.utils.split64Low) throw 'fail!';
+      }
+      if (x != jspb.utils.joinFloat64(jspb.utils.split64Low,
+                                         jspb.utils.split64High)) {
+        throw 'fail!';
+      }
+    }
+
+    // Positive and negative infinity.
+    test(Infinity, 0x7ff00000, 0x00000000);
+    test(-Infinity, 0xfff00000, 0x00000000);
+
+    // Positive and negative zero.
+    test(0, 0x00000000, 0x00000000);
+    test(-0, 0x80000000, 0x00000000);
+
+    // Positive and negative epsilon.
+    test(f64_eps, 0x00000000, 0x00000001);
+    test(-f64_eps, 0x80000000, 0x00000001);
+
+    // Positive and negative min.
+    test(f64_min, 0x00100000, 0x00000000);
+    test(-f64_min, 0x80100000, 0x00000000);
+
+    // Positive and negative max.
+    test(f64_max, 0x7FEFFFFF, 0xFFFFFFFF);
+    test(-f64_max, 0xFFEFFFFF, 0xFFFFFFFF);
+
+    // Various positive values.
+    var cursor = f64_eps * 10;
+    while (cursor != Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+
+    // Various negative values.
+    cursor = -f64_eps * 10;
+    while (cursor != -Infinity) {
+      test(cursor);
+      cursor *= 1.1;
+    }
+  });
+
+
+  /**
+   * Tests counting packed varints.
+   */
+  it('testCountVarints', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.rawWriteVarint(Math.floor(i));
+      count++;
+    }
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count, jspb.utils.countVarints(buffer, 0, buffer.length));
+  });
+
+
+  /**
+   * Tests counting matching varint fields.
+   */
+  it('testCountVarintFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeUint64(1, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countVarintFields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeUint64(123456789, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countVarintFields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching fixed32 fields.
+   */
+  it('testCountFixed32Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeFixed32(1, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeFixed32(123456789, Math.floor(i));
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed32Fields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching fixed64 fields.
+   */
+  it('testCountFixed64Fields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeDouble(1, i);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000000000; i *= 1.1) {
+      writer.writeDouble(123456789, i);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countFixed64Fields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests counting matching delimited fields.
+   */
+  it('testCountDelimitedFields', function() {
+    var writer = new jspb.BinaryWriter();
+
+    var count = 0;
+    for (var i = 1; i < 1000; i *= 1.1) {
+      writer.writeBytes(1, [Math.floor(i)]);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    var buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 1));
+
+    writer = new jspb.BinaryWriter();
+
+    count = 0;
+    for (var i = 1; i < 1000; i *= 1.1) {
+      writer.writeBytes(123456789, [Math.floor(i)]);
+      count++;
+    }
+    writer.writeString(2, 'terminator');
+
+    buffer = new Uint8Array(writer.getResultBuffer());
+    assertEquals(count,
+        jspb.utils.countDelimitedFields(buffer, 0, buffer.length, 123456789));
+  });
+
+
+  /**
+   * Tests byte format for debug strings.
+   */
+  it('testDebugBytesToTextFormat', function() {
+    assertEquals('""', jspb.utils.debugBytesToTextFormat(null));
+    assertEquals('"\\x00\\x10\\xff"',
+        jspb.utils.debugBytesToTextFormat([0, 16, 255]));
+  });
+
+
+  /**
+   * Tests converting byte blob sources into byte blobs.
+   */
+  it('testByteSourceToUint8Array', function() {
+    var convert = jspb.utils.byteSourceToUint8Array;
+
+    var sourceData = [];
+    for (var i = 0; i < 256; i++) {
+      sourceData.push(i);
+    }
+
+    var sourceBytes = new Uint8Array(sourceData);
+    var sourceBuffer = sourceBytes.buffer;
+    var sourceBase64 = goog.crypt.base64.encodeByteArray(sourceData);
+    var sourceString = String.fromCharCode.apply(null, sourceData);
+
+    function check(result) {
+      assertEquals(Uint8Array, result.constructor);
+      assertEquals(sourceData.length, result.length);
+      for (var i = 0; i < result.length; i++) {
+        assertEquals(sourceData[i], result[i]);
+      }
+    }
+
+    // Converting Uint8Arrays into Uint8Arrays should be a no-op.
+    assertEquals(sourceBytes, convert(sourceBytes));
+
+    // Converting Array.<numbers> into Uint8Arrays should work.
+    check(convert(sourceData));
+
+    // Converting ArrayBuffers into Uint8Arrays should work.
+    check(convert(sourceBuffer));
+
+    // Converting base64-encoded strings into Uint8Arrays should work.
+    check(convert(sourceBase64));
+
+    // Converting binary-data strings into Uint8Arrays should work.
+    check(convert(sourceString, /* opt_stringIsRawBytes = */ true));
+  });
+});
diff --git a/js/binary/writer.js b/js/binary/writer.js
new file mode 100644
index 0000000..a184945
--- /dev/null
+++ b/js/binary/writer.js
@@ -0,0 +1,2124 @@
+// 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.
+
+/**
+ * @fileoverview This file contains utilities for encoding Javascript objects
+ * into binary, wire-format protocol buffers (in the form of Uint8Arrays) that
+ * a server can consume directly.
+ *
+ * jspb's BinaryWriter class defines methods for efficiently encoding
+ * Javascript objects into binary, wire-format protocol buffers and supports
+ * all the fundamental field types used in protocol buffers.
+ *
+ * Major caveat 1 - Users of this library _must_ keep their Javascript proto
+ * parsing code in sync with the original .proto file - presumably you'll be
+ * using the typed jspb code generator, but if you bypass that you'll need
+ * to keep things in sync by hand.
+ *
+ * Major caveat 2 - Javascript is unable to accurately represent integers
+ * larger than 2^53 due to its use of a double-precision floating point format
+ * for all numbers. BinaryWriter does not make any special effort to preserve
+ * precision for values above this limit - if you need to pass 64-bit integers
+ * (hash codes, for example) between the client and server without precision
+ * loss, do _not_ use this library.
+ *
+ * Major caveat 3 - This class uses typed arrays and must not be used on older
+ * browsers that do not support them.
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.provide('jspb.BinaryWriter');
+
+goog.require('goog.asserts');
+goog.require('goog.crypt.base64');
+goog.require('jspb.BinaryConstants');
+goog.require('jspb.arith.Int64');
+goog.require('jspb.arith.UInt64');
+goog.require('jspb.utils');
+
+goog.forwardDeclare('jspb.Message');
+
+
+
+/**
+ * BinaryWriter implements encoders for all the wire types specified in
+ * https://developers.google.com/protocol-buffers/docs/encoding.
+ *
+ * @constructor
+ * @struct
+ */
+jspb.BinaryWriter = function() {
+  /**
+   * Blocks of serialized data that will be concatenated once all messages have
+   * been written.
+   * @private {!Array<!Uint8Array|!Array<number>>}
+   */
+  this.blocks_ = [];
+
+  /**
+   * Total number of bytes in the blocks_ array. Does _not_ include the temp
+   * buffer.
+   * @private {number}
+   */
+  this.totalLength_ = 0;
+
+  /**
+   * Temporary buffer holding a message that we're still serializing. When we
+   * get to a stopping point (either the start of a new submessage, or when we
+   * need to append a raw Uint8Array), the temp buffer will be added to the
+   * block array above and a new temp buffer will be created.
+   * @private {!Array.<number>}
+   */
+  this.temp_ = [];
+
+  /**
+   * A stack of bookmarks containing the parent blocks for each message started
+   * via beginSubMessage(), needed as bookkeeping for endSubMessage().
+   * TODO(aappleby): Deprecated, users should be calling writeMessage().
+   * @private {!Array.<!jspb.BinaryWriter.Bookmark_>}
+   */
+  this.bookmarks_ = [];
+};
+
+
+/**
+ * @typedef {{block: !Array.<number>, length: number}}
+ * @private
+ */
+jspb.BinaryWriter.Bookmark_;
+
+
+/**
+ * Saves the current temp buffer in the blocks_ array and starts a new one.
+ * @return {!Array.<number>} Returns a reference to the old temp buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.saveTempBuffer_ = function() {
+  var oldTemp = this.temp_;
+  this.blocks_.push(this.temp_);
+  this.totalLength_ += this.temp_.length;
+  this.temp_ = [];
+  return oldTemp;
+};
+
+
+/**
+ * Append a typed array of bytes onto the buffer.
+ *
+ * @param {!Uint8Array} arr The byte array to append.
+ * @private
+ */
+jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
+  if (this.temp_.length) {
+    this.saveTempBuffer_();
+  }
+  this.blocks_.push(arr);
+  this.totalLength_ += arr.length;
+};
+
+
+/**
+ * Append an untyped array of bytes onto the buffer.
+ *
+ * @param {!Array.<number>} arr The byte array to append.
+ * @private
+ */
+jspb.BinaryWriter.prototype.appendArray_ = function(arr) {
+  if (this.temp_.length) {
+    this.saveTempBuffer_();
+  }
+  this.temp_ = arr;
+};
+
+
+/**
+ * Begins a length-delimited section by writing the field header to the current
+ * temp buffer and then saving it in the block array. Returns the saved block,
+ * which we will append the length to in endDelimited_ below.
+ * @param {number} field
+ * @return {!jspb.BinaryWriter.Bookmark_}
+ * @private
+ */
+jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+  return {block: this.saveTempBuffer_(), length: this.totalLength_};
+};
+
+
+/**
+ * Ends a length-delimited block by encoding the _change_ in length of the
+ * buffer to the parent block and adds the number of bytes needed to encode
+ * that length to the total byte length. Note that 'parentLength' _must_ be the
+ * total length _after_ the field header was written in beginDelimited_ above.
+ * @param {!jspb.BinaryWriter.Bookmark_} bookmark
+ * @private
+ */
+jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
+  var messageLength = this.totalLength_ + this.temp_.length - bookmark.length;
+  goog.asserts.assert(messageLength >= 0);
+
+  var bytes = 1;
+  while (messageLength > 127) {
+    bookmark.block.push((messageLength & 0x7f) | 0x80);
+    messageLength = messageLength >>> 7;
+    bytes++;
+  }
+
+  bookmark.block.push(messageLength);
+  this.totalLength_ += bytes;
+};
+
+
+/**
+ * Resets the writer, throwing away any accumulated buffers.
+ */
+jspb.BinaryWriter.prototype.reset = function() {
+  this.blocks_ = [];
+  this.temp_ = [];
+  this.totalLength_ = 0;
+  this.bookmarks_ = [];
+};
+
+
+/**
+ * Converts the encoded data into a Uint8Array.
+ * @return {!Uint8Array}
+ */
+jspb.BinaryWriter.prototype.getResultBuffer = function() {
+  goog.asserts.assert(this.bookmarks_.length == 0);
+
+  var flat = new Uint8Array(this.totalLength_ + this.temp_.length);
+
+  var blocks = this.blocks_;
+  var blockCount = blocks.length;
+  var offset = 0;
+
+  for (var i = 0; i < blockCount; i++) {
+    var block = blocks[i];
+    flat.set(block, offset);
+    offset += block.length;
+  }
+
+  flat.set(this.temp_, offset);
+  offset += this.temp_.length;
+
+  // Post condition: `flattened` must have had every byte written.
+  goog.asserts.assert(offset == flat.length);
+
+  // Replace our block list with the flattened block, which lets GC reclaim
+  // the temp blocks sooner.
+  this.blocks_ = [flat];
+  this.temp_ = [];
+
+  return flat;
+};
+
+
+/**
+ * Converts the encoded data into a bas64-encoded string.
+ * @return {string}
+ */
+jspb.BinaryWriter.prototype.getResultBase64String = function() {
+  return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
+};
+
+
+/**
+ * Begins a new sub-message. The client must call endSubMessage() when they're
+ * done.
+ * TODO(aappleby): Deprecated. Move callers to writeMessage().
+ * @param {number} field The field number of the sub-message.
+ */
+jspb.BinaryWriter.prototype.beginSubMessage = function(field) {
+  this.bookmarks_.push(this.beginDelimited_(field));
+};
+
+
+/**
+ * Finishes a sub-message and packs it into the parent messages' buffer.
+ * TODO(aappleby): Deprecated. Move callers to writeMessage().
+ */
+jspb.BinaryWriter.prototype.endSubMessage = function() {
+  goog.asserts.assert(this.bookmarks_.length >= 0);
+  this.endDelimited_(this.bookmarks_.pop());
+};
+
+
+/**
+ * Encodes a 32-bit unsigned integer into its wire-format varint representation
+ * and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteUnsignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+
+  while (value > 127) {
+    this.temp_.push((value & 0x7f) | 0x80);
+    value = value >>> 7;
+  }
+
+  this.temp_.push(value);
+};
+
+
+/**
+ * Encodes a 32-bit signed integer into its wire-format varint representation
+ * and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteSignedVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  if (value >= 0) {
+    this.rawWriteUnsignedVarint32(value);
+    return;
+  }
+
+  // Write nine bytes with a _signed_ right shift so we preserve the sign bit.
+  for (var i = 0; i < 9; i++) {
+    this.temp_.push((value & 0x7f) | 0x80);
+    value = value >> 7;
+  }
+
+  // The above loop writes out 63 bits, so the last byte is always the sign bit
+  // which is always set for negative numbers.
+  this.temp_.push(1);
+};
+
+
+/**
+ * Encodes an unsigned 64-bit integer in 32:32 split representation into its
+ * wire-format varint representation and stores it in the buffer.
+ * @param {number} lowBits The low 32 bits of the int.
+ * @param {number} highBits The high 32 bits of the int.
+ */
+jspb.BinaryWriter.prototype.rawWriteSplitVarint =
+    function(lowBits, highBits) {
+  // Break the binary representation into chunks of 7 bits, set the 8th bit
+  // in each chunk if it's not the final chunk, and append to the result.
+  while (highBits > 0 || lowBits > 127) {
+    this.temp_.push((lowBits & 0x7f) | 0x80);
+    lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0;
+    highBits = highBits >>> 7;
+  }
+  this.temp_.push(lowBits);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format varint representation and
+ * stores it in the buffer. Due to the way the varint encoding works this
+ * behaves correctly for both signed and unsigned integers, though integers
+ * that are not representable in 64 bits will still be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteVarint = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  jspb.utils.splitInt64(value);
+  this.rawWriteSplitVarint(jspb.utils.split64Low,
+                           jspb.utils.split64High);
+};
+
+
+/**
+ * Encodes a jspb.arith.{Int64,UInt64} instance into its wire-format
+ * varint representation and stores it in the buffer. Due to the way the varint
+ * encoding works this behaves correctly for both signed and unsigned integers,
+ * though integers that are not representable in 64 bits will still be
+ * truncated.
+ * @param {jspb.arith.Int64|jspb.arith.UInt64} value
+ */
+jspb.BinaryWriter.prototype.rawWriteVarintFromNum = function(value) {
+  this.rawWriteSplitVarint(value.lo, value.hi);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
+ * representation and stores it in the buffer.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteZigzagVarint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  this.rawWriteUnsignedVarint32(((value << 1) ^ (value >> 31)) >>> 0);
+};
+
+
+/**
+ * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint
+ * representation and stores it in the buffer. Integers not representable in 64
+ * bits will be truncated.
+ * @param {number} value The integer to convert.
+ */
+jspb.BinaryWriter.prototype.rawWriteZigzagVarint = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  jspb.utils.splitZigzag64(value);
+  this.rawWriteSplitVarint(jspb.utils.split64Low,
+                           jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw 8-bit unsigned integer to the buffer. Numbers outside the range
+ * [0,2^8) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUint8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 256));
+  this.temp_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 16-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^16) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUint16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) && (value < 65536));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 32-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^32) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUint32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+  this.temp_.push((value >>> 16) & 0xFF);
+  this.temp_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 64-bit unsigned integer to the buffer. Numbers outside the
+ * range [0,2^64) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUint64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  jspb.utils.splitUint64(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw 8-bit integer to the buffer. Numbers outside the range
+ * [-2^7,2^7) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteInt8 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -128) && (value < 128));
+  this.temp_.push((value >>> 0) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 16-bit integer to the buffer. Numbers outside the range
+ * [-2^15,2^15) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteInt16 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -32768) && (value < 32768));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 32-bit integer to the buffer. Numbers outside the range
+ * [-2^31,2^31) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteInt32 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.temp_.push((value >>> 0) & 0xFF);
+  this.temp_.push((value >>> 8) & 0xFF);
+  this.temp_.push((value >>> 16) & 0xFF);
+  this.temp_.push((value >>> 24) & 0xFF);
+};
+
+
+/**
+ * Writes a raw 64-bit integer to the buffer. Numbers outside the range
+ * [-2^63,2^63) will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteInt64 = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  jspb.utils.splitInt64(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw single-precision floating point value to the buffer. Numbers
+ * requiring more than 32 bits of precision will be truncated.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteFloat = function(value) {
+  jspb.utils.splitFloat32(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+};
+
+
+/**
+ * Writes a raw double-precision floating point value to the buffer. As this is
+ * the native format used by JavaScript, no precision will be lost.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteDouble = function(value) {
+  jspb.utils.splitFloat64(value);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a raw boolean value to the buffer as a varint.
+ * @param {boolean} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteBool = function(value) {
+  goog.asserts.assert(goog.isBoolean(value));
+  this.temp_.push(~~value);
+};
+
+
+/**
+ * Writes an raw enum value to the buffer as a varint.
+ * @param {number} value The value to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteEnum = function(value) {
+  goog.asserts.assert(value == Math.floor(value));
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.rawWriteSignedVarint32(value);
+};
+
+
+/**
+ * Writes a raw string value to the buffer.
+ * @param {string} string The string to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteUtf8String = function(string) {
+  for (var i = 0; i < string.length; i++) {
+    this.temp_.push(string.charCodeAt(i));
+  }
+};
+
+
+/**
+ * Writes an arbitrary raw byte array to the buffer.
+ * @param {!Uint8Array} bytes The array of bytes to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteBytes = function(bytes) {
+  this.appendUint8Array_(bytes);
+};
+
+
+/**
+ * Writes an arbitrary raw byte array to the buffer.
+ * @param {!Uint8Array} bytes The array of bytes to write.
+ * @param {number} start The start of the range to write.
+ * @param {number} end The end of the range to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteByteRange = function(bytes, start, end) {
+  this.appendUint8Array_(bytes.subarray(start, end));
+};
+
+
+/**
+ * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
+ * buffer as a varint.
+ * @param {string} hash The hash to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteVarintHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.rawWriteSplitVarint(jspb.utils.split64Low,
+                           jspb.utils.split64High);
+};
+
+
+/**
+ * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the
+ * buffer as a fixed64.
+ * @param {string} hash The hash to write.
+ */
+jspb.BinaryWriter.prototype.rawWriteFixedHash64 = function(hash) {
+  jspb.utils.splitHash64(hash);
+  this.rawWriteUint32(jspb.utils.split64Low);
+  this.rawWriteUint32(jspb.utils.split64High);
+};
+
+
+/**
+ * Encodes a (field number, wire type) tuple into a wire-format field header
+ * and stores it in the buffer as a varint.
+ * @param {number} field The field number.
+ * @param {number} wireType The wire-type of the field, as specified in the
+ *     protocol buffer documentation.
+ * @private
+ */
+jspb.BinaryWriter.prototype.rawWriteFieldHeader_ =
+    function(field, wireType) {
+  goog.asserts.assert(field >= 1 && field == Math.floor(field));
+  var x = field * 8 + wireType;
+  this.rawWriteUnsignedVarint32(x);
+};
+
+
+/**
+ * Writes a field of any valid scalar type to the binary stream.
+ * @param {jspb.BinaryConstants.FieldType} fieldType
+ * @param {number} field
+ * @param {jspb.AnyFieldType} value
+ */
+jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) {
+  var fieldTypes = jspb.BinaryConstants.FieldType;
+  switch (fieldType) {
+    case fieldTypes.DOUBLE:
+      this.writeDouble(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FLOAT:
+      this.writeFloat(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.INT64:
+      this.writeInt64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.UINT64:
+      this.writeUint64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.INT32:
+      this.writeInt32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FIXED64:
+      this.writeFixed64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FIXED32:
+      this.writeFixed32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.BOOL:
+      this.writeBool(field, /** @type {boolean} */(value));
+      return;
+    case fieldTypes.STRING:
+      this.writeString(field, /** @type {string} */(value));
+      return;
+    case fieldTypes.GROUP:
+      goog.asserts.fail('Group field type not supported in writeAny()');
+      return;
+    case fieldTypes.MESSAGE:
+      goog.asserts.fail('Message field type not supported in writeAny()');
+      return;
+    case fieldTypes.BYTES:
+      this.writeBytes(field, /** @type {?Uint8Array} */(value));
+      return;
+    case fieldTypes.UINT32:
+      this.writeUint32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.ENUM:
+      this.writeEnum(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SFIXED32:
+      this.writeSfixed32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SFIXED64:
+      this.writeSfixed64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SINT32:
+      this.writeSint32(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.SINT64:
+      this.writeSint64(field, /** @type {number} */(value));
+      return;
+    case fieldTypes.FHASH64:
+      this.writeFixedHash64(field, /** @type {string} */(value));
+      return;
+    case fieldTypes.VHASH64:
+      this.writeVarintHash64(field, /** @type {string} */(value));
+      return;
+    default:
+      goog.asserts.fail('Invalid field type in writeAny()');
+      return;
+  }
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(value);
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(value);
+};
+
+
+/**
+ * Writes a varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeVarint_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarint(value);
+};
+
+
+/**
+ * Writes a zigzag varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteZigzagVarint32(value);
+};
+
+
+/**
+ * Writes a zigzag varint field to the buffer without range checking.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeZigzagVarint_ = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteZigzagVarint(value);
+};
+
+
+/**
+ * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeSignedVarint32_(field, value);
+};
+
+
+/**
+ * Writes an int32 field represented as a string to the buffer. Numbers outside
+ * the range [-2^31,2^31) will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
+  if (value == null) return;
+  var intValue = /** {number} */ parseInt(value, 10);
+  goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (intValue < jspb.BinaryConstants.TWO_TO_31));
+  this.writeSignedVarint32_(field, intValue);
+};
+
+
+/**
+ * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeVarint_(field, value);
+};
+
+
+/**
+ * Writes a int64 field (with value as a string) to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.Int64.fromString(value);
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintFromNum(num);
+};
+
+
+/**
+ * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.writeUnsignedVarint32_(field, value);
+};
+
+
+/**
+ * Writes a uint32 field represented as a string to the buffer. Numbers outside
+ * the range [0,2^32) will be truncated.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
+  if (value == null) return;
+  var intValue = /** {number} */ parseInt(value, 10);
+  goog.asserts.assert((intValue >= 0) &&
+                      (intValue < jspb.BinaryConstants.TWO_TO_32));
+  this.writeUnsignedVarint32_(field, intValue);
+};
+
+
+/**
+ * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  this.writeVarint_(field, value);
+};
+
+
+/**
+ * Writes a uint64 field (with value as a string) to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
+  if (value == null) return;
+  var num = jspb.arith.UInt64.fromString(value);
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintFromNum(num);
+};
+
+
+/**
+ * Writes a sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.writeZigzagVarint32_(field, value);
+};
+
+
+/**
+ * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.writeZigzagVarint_(field, value);
+};
+
+
+/**
+ * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_32));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteUint32(value);
+};
+
+
+/**
+ * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
+ * will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= 0) &&
+                      (value < jspb.BinaryConstants.TWO_TO_64));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteUint64(value);
+};
+
+
+/**
+ * Writes a sfixed32 field to the buffer. Numbers outside the range
+ * [-2^31,2^31) will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteInt32(value);
+};
+
+
+/**
+ * Writes a sfixed64 field to the buffer. Numbers outside the range
+ * [-2^63,2^63) will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
+                      (value < jspb.BinaryConstants.TWO_TO_63));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteInt64(value);
+};
+
+
+/**
+ * Writes a single-precision floating point field to the buffer. Numbers
+ * requiring more than 32 bits of precision will be truncated.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
+  this.rawWriteFloat(value);
+};
+
+
+/**
+ * Writes a double-precision floating point field to the buffer. As this is the
+ * native format used by JavaScript, no precision will be lost.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteDouble(value);
+};
+
+
+/**
+ * Writes a boolean field to the buffer.
+ * @param {number} field The field number.
+ * @param {boolean?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeBool = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(goog.isBoolean(value));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.temp_.push(~~value);
+};
+
+
+/**
+ * Writes an enum field to the buffer.
+ * @param {number} field The field number.
+ * @param {number?} value The value to write.
+ */
+jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
+                      (value < jspb.BinaryConstants.TWO_TO_31));
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteSignedVarint32(value);
+};
+
+
+/**
+ * Writes a string field to the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The string to write.
+ */
+jspb.BinaryWriter.prototype.writeString = function(field, value) {
+  if (value == null) return;
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+
+  // Conversion loop swiped from goog.crypt.stringToUtf8ByteArray. Note that
+  // 'bytes' will be at least as long as 'value', but could be longer if we
+  // need to unpack unicode characters.
+  var bytes = [];
+  for (var i = 0; i < value.length; i++) {
+    var c = value.charCodeAt(i);
+    if (c < 128) {
+      bytes.push(c);
+    } else if (c < 2048) {
+      bytes.push((c >> 6) | 192);
+      bytes.push((c & 63) | 128);
+    } else {
+      bytes.push((c >> 12) | 224);
+      bytes.push(((c >> 6) & 63) | 128);
+      bytes.push((c & 63) | 128);
+    }
+  }
+
+  this.rawWriteUnsignedVarint32(bytes.length);
+  this.appendArray_(bytes);
+};
+
+
+/**
+ * Writes an arbitrary byte field to the buffer. Note - to match the behavior
+ * of the C++ implementation, empty byte arrays _are_ serialized.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {jspb.ByteSource} value The array of bytes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @param {boolean=} opt_stringIsRawBytes If `value` is a string, interpret it
+ * as a series of raw bytes (codepoints 0--255 inclusive) rather than base64
+ * data.
+ */
+jspb.BinaryWriter.prototype.writeBytes =
+    function(field, value, opt_buffer, opt_start, opt_end,
+             opt_stringIsRawBytes) {
+  if (value != null) {
+    this.rawWriteFieldHeader_(field,
+        jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length);
+    this.rawWriteBytes(
+        jspb.utils.byteSourceToUint8Array(value, opt_stringIsRawBytes));
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an arbitrary byte field to the buffer, with `opt_stringIsRawBytes`
+ * flag implicitly true.
+ * @param {number} field
+ * @param {jspb.ByteSource} value The array of bytes to write.
+ */
+jspb.BinaryWriter.prototype.writeBytesRawString = function(field, value) {
+  this.writeBytes(field, value, null, null, null, true);
+};
+
+
+/**
+ * Writes a message to the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?MessageType} value The message to write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writeMessage =
+    function(field, value, writerCallback, opt_buffer, opt_start, opt_end) {
+  if (value !== null) {
+    var bookmark = this.beginDelimited_(field);
+
+    writerCallback(value, this);
+
+    this.endDelimited_(bookmark);
+  } else if (opt_buffer && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes a group message to the buffer.
+ *
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?MessageType} value The message to write, wrapped with START_GROUP /
+ *     END_GROUP tags. Will be a no-op if 'value' is null.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeGroup =
+    function(field, value, writerCallback) {
+  if (value) {
+    this.rawWriteFieldHeader_(
+        field, jspb.BinaryConstants.WireType.START_GROUP);
+    writerCallback(value, this);
+    this.rawWriteFieldHeader_(
+        field, jspb.BinaryConstants.WireType.END_GROUP);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The hash string.
+ */
+jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(value.length == 8);
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
+  this.rawWriteFixedHash64(value);
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {string?} value The hash string.
+ */
+jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
+  if (value == null) return;
+  goog.asserts.assert(value.length == 8);
+  this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
+  this.rawWriteVarintHash64(value);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUnsignedVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSignedVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated varint field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedVarint_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeVarint_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint32_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated zigzag field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeZigzagVarint_(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt32 =
+    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt32String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeInt32String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt64 =
+    jspb.BinaryWriter.prototype.writeRepeatedVarint_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedInt64String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeInt64String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
+ *     field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint32 =
+    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * unsigned 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint32String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUint32String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
+ *     field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint64 =
+    jspb.BinaryWriter.prototype.writeRepeatedVarint_;
+
+
+/**
+ * Writes an array of numbers formatted as strings to the buffer as a repeated
+ * unsigned 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedUint64String =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeUint64String(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSint32 =
+    jspb.BinaryWriter.prototype.writeRepeatedZigzag32_;
+
+
+/**
+ * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSint64 =
+    jspb.BinaryWriter.prototype.writeRepeatedZigzag_;
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated fixed32 field. This
+ * works for both signed and unsigned fixed32s.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixed32(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated fixed64 field. This
+ * works for both signed and unsigned fixed64s.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixed64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated sfixed32 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSfixed32(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated sfixed64 field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeSfixed64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated float field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFloat(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a repeated double field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeDouble(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of booleans to the buffer as a repeated bool field.
+ * @param {number} field The field number.
+ * @param {?Array.<boolean>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeBool(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of enums to the buffer as a repeated enum field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeEnum(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of strings to the buffer as a repeated string field.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of strings to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeString(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of arbitrary byte fields to the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<!Uint8Array|string>} value
+ *     The arrays of arrays of bytes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @param {boolean=} opt_stringIsRawBytes Any values that are strings are
+ * interpreted as raw bytes rather than base64 data.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBytes =
+    function(field, value, opt_buffer, opt_start, opt_end,
+             opt_stringIsRawBytes) {
+  if (value != null) {
+    for (var i = 0; i < value.length; i++) {
+      this.writeBytes(field, value[i], null, null, null, opt_stringIsRawBytes);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of arbitrary byte fields to the buffer, with
+ * `opt_stringIsRawBytes` implicitly true.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writeRepeatedBytesRawString =
+    function(field, value) {
+  this.writeRepeatedBytes(field, value, null, null, null, true);
+};
+
+
+/**
+ * Writes an array of messages to the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?Array.<!MessageType>} value The array of messages to
+ *    write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedMessage =
+    function(field, value, writerCallback, opt_buffer, opt_start, opt_end) {
+  if (value) {
+    for (var i = 0; i < value.length; i++) {
+      var bookmark = this.beginDelimited_(field);
+
+      writerCallback(value[i], this);
+
+      this.endDelimited_(bookmark);
+    }
+  } else if (opt_buffer && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of group messages to the buffer.
+ *
+ * @template MessageType
+ * @param {number} field The field number.
+ * @param {?Array.<!MessageType>} value The array of messages to
+ *    write.
+ * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
+ *     to write and the writer to write it with.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedGroup =
+    function(field, value, writerCallback) {
+  if (value) {
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFieldHeader_(
+          field, jspb.BinaryConstants.WireType.START_GROUP);
+      writerCallback(value[i], this);
+      this.rawWriteFieldHeader_(
+          field, jspb.BinaryConstants.WireType.END_GROUP);
+    }
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeFixedHash64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
+ * each) to the buffer.
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ */
+jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
+    function(field, value) {
+  if (value == null) return;
+  for (var i = 0; i < value.length; i++) {
+    this.writeVarintHash64(field, value[i]);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUnsignedVarint32(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedSignedVarint32_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteSignedVarint32(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed varint field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedVarint_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteVarint(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed zigzag field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ * @private
+ */
+jspb.BinaryWriter.prototype.writePackedZigzag_ =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteZigzagVarint(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedInt32 =
+    jspb.BinaryWriter.prototype.writePackedSignedVarint32_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.rawWriteSignedVarint32(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed 64-bit int field.
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedInt64 =
+    jspb.BinaryWriter.prototype.writePackedVarint_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * 64-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedInt64String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    var num = jspb.arith.Int64.fromString(value[i]);
+    this.rawWriteVarintFromNum(num);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedUint32 =
+    jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * unsigned 32-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedUint32String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    this.rawWriteUnsignedVarint32(parseInt(value[i], 10));
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedUint64 =
+    jspb.BinaryWriter.prototype.writePackedVarint_;
+
+
+/**
+ * Writes an array of numbers represented as strings to the buffer as a packed
+ * unsigned 64-bit int field.
+ * @param {number} field
+ * @param {?Array.<string>} value
+ */
+jspb.BinaryWriter.prototype.writePackedUint64String =
+    function(field, value) {
+  if (value == null || !value.length) return;
+  var bookmark = this.beginDelimited_(field);
+  for (var i = 0; i < value.length; i++) {
+    var num = jspb.arith.UInt64.fromString(value[i]);
+    this.rawWriteVarintFromNum(num);
+  }
+  this.endDelimited_(bookmark);
+};
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 32-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSint32 =
+    jspb.BinaryWriter.prototype.writePackedZigzag_;
+
+
+/**
+ * Writes an array numbers to the buffer as a packed signed 64-bit int field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSint64 =
+    jspb.BinaryWriter.prototype.writePackedZigzag_;
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed32 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed32 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUint32(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed fixed64 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixed64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteUint64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed32 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed32 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteInt32(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed sfixed64 field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedSfixed64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteInt64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed float field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFloat =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 4);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFloat(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of numbers to the buffer as a packed double field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedDouble =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteDouble(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of booleans to the buffer as a packed bool field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<boolean>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedBool =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteBool(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes an array of enums to the buffer as a packed enum field.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedEnum =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteEnum(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedFixedHash64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
+    this.rawWriteUnsignedVarint32(value.length * 8);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteFixedHash64(value[i]);
+    }
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
+
+
+/**
+ * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
+ * the buffer.
+ *
+ * If 'value' is null, this method will try and copy the pre-serialized value
+ * in 'opt_buffer' if present.
+ *
+ * @param {number} field The field number.
+ * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values.
+ * @param {?number=} opt_start The starting point in the above buffer.
+ * @param {?number=} opt_end The ending point in the above buffer.
+ */
+jspb.BinaryWriter.prototype.writePackedVarintHash64 =
+    function(field, value, opt_buffer, opt_start, opt_end) {
+  if (value != null && value.length) {
+    var bookmark = this.beginDelimited_(field);
+    for (var i = 0; i < value.length; i++) {
+      this.rawWriteVarintHash64(value[i]);
+    }
+    this.endDelimited_(bookmark);
+  } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) {
+    this.rawWriteByteRange(opt_buffer, opt_start, opt_end);
+  }
+};
diff --git a/js/binary/writer_test.js b/js/binary/writer_test.js
new file mode 100644
index 0000000..54d37a2
--- /dev/null
+++ b/js/binary/writer_test.js
@@ -0,0 +1,123 @@
+// 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.
+
+/**
+ * @fileoverview Test cases for jspb's binary protocol buffer writer. In
+ * practice BinaryWriter is used to drive the Decoder and Reader test cases,
+ * so only writer-specific tests are here.
+ *
+ * Test suite is written using Jasmine -- see http://jasmine.github.io/
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ */
+
+goog.require('goog.crypt');
+goog.require('goog.testing.asserts');
+goog.require('jspb.BinaryWriter');
+
+
+/**
+ * @param {function()} func This function should throw an error when run.
+ */
+function assertFails(func) {
+  var e = assertThrows(func);
+  console.log(e);
+  //assertNotNull(e.toString().match(/Error/));
+}
+
+
+describe('binaryWriterTest', function() {
+  /**
+   * Verifies that misuse of the writer class triggers assertions.
+   */
+  it('testWriteErrors', function() {
+    // Submessages with invalid field indices should assert.
+    var writer = new jspb.BinaryWriter();
+    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
+
+    assertFails(function() {
+      writer.writeMessage(-1, dummyMessage, goog.nullFunction);
+    });
+
+    // Writing invalid field indices should assert.
+    writer = new jspb.BinaryWriter();
+    assertFails(function() {writer.writeUint64(-1, 1);});
+
+    // Writing out-of-range field values should assert.
+    writer = new jspb.BinaryWriter();
+
+    assertFails(function() {writer.writeInt32(1, -Infinity);});
+    assertFails(function() {writer.writeInt32(1, Infinity);});
+
+    assertFails(function() {writer.writeInt64(1, -Infinity);});
+    assertFails(function() {writer.writeInt64(1, Infinity);});
+
+    assertFails(function() {writer.writeUint32(1, -1);});
+    assertFails(function() {writer.writeUint32(1, Infinity);});
+
+    assertFails(function() {writer.writeUint64(1, -1);});
+    assertFails(function() {writer.writeUint64(1, Infinity);});
+
+    assertFails(function() {writer.writeSint32(1, -Infinity);});
+    assertFails(function() {writer.writeSint32(1, Infinity);});
+
+    assertFails(function() {writer.writeSint64(1, -Infinity);});
+    assertFails(function() {writer.writeSint64(1, Infinity);});
+
+    assertFails(function() {writer.writeFixed32(1, -1);});
+    assertFails(function() {writer.writeFixed32(1, Infinity);});
+
+    assertFails(function() {writer.writeFixed64(1, -1);});
+    assertFails(function() {writer.writeFixed64(1, Infinity);});
+
+    assertFails(function() {writer.writeSfixed32(1, -Infinity);});
+    assertFails(function() {writer.writeSfixed32(1, Infinity);});
+
+    assertFails(function() {writer.writeSfixed64(1, -Infinity);});
+    assertFails(function() {writer.writeSfixed64(1, Infinity);});
+  });
+
+
+  /**
+   * Basic test of retrieving the result as a Uint8Array buffer
+   */
+  it('testGetResultBuffer', function() {
+    var expected = '0864120b48656c6c6f20776f726c641a0301020320c801';
+
+    var writer = new jspb.BinaryWriter();
+    writer.writeUint32(1, 100);
+    writer.writeString(2, 'Hello world');
+    writer.writeBytes(3, new Uint8Array([1, 2, 3]));
+    writer.writeUint32(4, 200);
+
+    var buffer = writer.getResultBuffer();
+    assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
+  });
+});
diff --git a/js/commonjs/export.js b/js/commonjs/export.js
new file mode 100644
index 0000000..a3cfbd6
--- /dev/null
+++ b/js/commonjs/export.js
@@ -0,0 +1,22 @@
+/**
+ * @fileoverview Export symbols needed by generated code in CommonJS style.
+ *
+ * This effectively is our canonical list of what we publicly export from
+ * the google-protobuf.js file that we build at distribution time.
+ */
+
+goog.require('goog.object');
+goog.require('jspb.BinaryReader');
+goog.require('jspb.BinaryWriter');
+goog.require('jspb.ExtensionFieldInfo');
+goog.require('jspb.Message');
+
+exports.Message = jspb.Message;
+exports.BinaryReader = jspb.BinaryReader;
+exports.BinaryWriter = jspb.BinaryWriter;
+exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
+
+// These are used by generated code but should not be used directly by clients.
+exports.exportSymbol = goog.exportSymbol;
+exports.inherits = goog.inherits;
+exports.object = {extend: goog.object.extend};
diff --git a/js/commonjs/export_asserts.js b/js/commonjs/export_asserts.js
new file mode 100644
index 0000000..5219d12
--- /dev/null
+++ b/js/commonjs/export_asserts.js
@@ -0,0 +1,37 @@
+/**
+ * @fileoverview Exports symbols needed only by tests.
+ *
+ * This file exports several Closure Library symbols that are only
+ * used by tests.  It is used to generate a file
+ * closure_asserts_commonjs.js that is only used at testing time.
+ */
+
+goog.require('goog.testing.asserts');
+
+var global = Function('return this')();
+
+// All of the closure "assert" functions are exported at the global level.
+//
+// The Google Closure assert functions start with assert, eg.
+//   assertThrows
+//   assertNotThrows
+//   assertTrue
+//   ...
+//
+// The one exception is the "fail" function.
+function shouldExport(str) {
+  return str.lastIndexOf('assert') === 0 || str == 'fail';
+}
+
+for (var key in global) {
+  if ((typeof key == "string") && global.hasOwnProperty(key) &&
+      shouldExport(key)) {
+    exports[key] = global[key];
+  }
+}
+
+// The COMPILED variable is set by Closure compiler to "true" when it compiles
+// JavaScript, so in practice this is equivalent to "exports.COMPILED = true".
+// This will disable some debugging functionality in debug.js.  We could
+// investigate whether this can/should be enabled in CommonJS builds.
+exports.COMPILED = COMPILED
diff --git a/js/commonjs/jasmine.json b/js/commonjs/jasmine.json
new file mode 100644
index 0000000..666b8ed
--- /dev/null
+++ b/js/commonjs/jasmine.json
@@ -0,0 +1,9 @@
+{
+    "spec_dir": "",
+    "spec_files": [
+        "*_test.js",
+        "binary/proto_test.js"
+    ],
+    "helpers": [
+    ]
+}
diff --git a/js/commonjs/rewrite_tests_for_commonjs.js b/js/commonjs/rewrite_tests_for_commonjs.js
new file mode 100644
index 0000000..dc5effe
--- /dev/null
+++ b/js/commonjs/rewrite_tests_for_commonjs.js
@@ -0,0 +1,92 @@
+/**
+ * @fileoverview Utility to translate test files to CommonJS imports.
+ *
+ * This is a somewhat hacky tool designed to do one very specific thing.
+ * All of the test files in *_test.js are written with Closure-style
+ * imports (goog.require()).  This works great for running the tests
+ * against Closure-style generated code, but we also want to run the
+ * tests against CommonJS-style generated code without having to fork
+ * the tests.
+ *
+ * Closure-style imports import each individual type by name.  This is
+ * very different than CommonJS imports which are by file.  So we put
+ * special comments in these tests like:
+ *
+ * // CommonJS-LoadFromFile: test_pb
+ * goog.require('proto.jspb.test.CloneExtension');
+ * goog.require('proto.jspb.test.Complex');
+ * goog.require('proto.jspb.test.DefaultValues');
+ *
+ * This script parses that special comment and uses it to generate proper
+ * CommonJS require() statements so that the tests can run and pass using
+ * CommonJS imports.  The script will change the above statements into:
+ *
+ *   var test_pb = require('test_pb');
+ *   googleProtobuf.exportSymbol('proto.jspb.test.CloneExtension', test_pb.CloneExtension, global);
+ *   googleProtobuf.exportSymbol('proto.jspb.test.Complex', test_pb.Complex, global);
+ *   googleProtobuf.exportSymbol('proto.jspb.test.DefaultValues', test_pb.DefaultValues, global);
+ *
+ * (The "exportSymbol" function will define the given names in the global
+ * namespace, taking care not to overwrite any previous value for
+ * "proto.jspb.test").
+ */
+
+var lineReader = require('readline').createInterface({
+  input: process.stdin,
+  output: process.stdout
+});
+
+function tryStripPrefix(str, prefix) {
+  if (str.lastIndexOf(prefix) !== 0) {
+    throw "String: " + str + " didn't start with: " + prefix;
+  }
+  return str.substr(prefix.length);
+}
+
+function camelCase(str) {
+  var ret = '';
+  var ucaseNext = false;
+  for (var i = 0; i < str.length; i++) {
+    if (str[i] == '-') {
+      ucaseNext = true;
+    } else if (ucaseNext) {
+      ret += str[i].toUpperCase();
+      ucaseNext = false;
+    } else {
+      ret += str[i];
+    }
+  }
+  return ret;
+}
+
+var module = null;
+var pkg = null;
+lineReader.on('line', function(line) {
+  var isRequire = line.match(/goog\.require\('([^']*)'\)/);
+  var isLoadFromFile = line.match(/CommonJS-LoadFromFile: (\S*) (.*)/);
+  var isSetTestOnly = line.match(/goog.setTestOnly()/);
+  if (isRequire) {
+    if (module) {  // Skip goog.require() lines before the first directive.
+      var fullSym = isRequire[1];
+      var sym = tryStripPrefix(fullSym, pkg);
+      console.log("googleProtobuf.exportSymbol('" + fullSym + "', " + module + sym + ', global);');
+    }
+  } else if (isLoadFromFile) {
+    if (!module) {
+      console.log("var googleProtobuf = require('google-protobuf');");
+      console.log("var asserts = require('closure_asserts_commonjs');");
+      console.log("var global = Function('return this')();");
+      console.log("");
+      console.log("// Bring asserts into the global namespace.");
+      console.log("googleProtobuf.object.extend(global, asserts);");
+    }
+    module = camelCase(isLoadFromFile[1])
+    pkg = isLoadFromFile[2];
+
+    if (module != "googleProtobuf") {  // We unconditionally require this in the header.
+      console.log("var " + module + " = require('" + isLoadFromFile[1] + "');");
+    }
+  } else if (!isSetTestOnly) {  // Remove goog.setTestOnly() lines.
+    console.log(line);
+  }
+});
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/data.proto
similarity index 82%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/data.proto
index cb6ca1b..74a8a99 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/data.proto
@@ -28,16 +28,24 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
+// Author: mwr@google.com (Mark Rawling)
+
 syntax = "proto2";
 
-package protobuf_unittest;
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
+package jspb.test;
+
+// legacy data, must be nested
+message data {
+  message NestedData {
+    required string str = 1;
   }
 }
+
+// new data, does not require nesting
+message UnnestedData {
+  required string str = 1;
+}
+
diff --git a/js/debug.js b/js/debug.js
new file mode 100644
index 0000000..4838911
--- /dev/null
+++ b/js/debug.js
@@ -0,0 +1,140 @@
+// 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.
+
+/**
+ * @fileoverview Utilities to debug JSPB based proto objects.
+ */
+
+goog.provide('jspb.debug');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.object');
+goog.require('jspb.Message');
+
+
+/**
+ * Turns a proto into a human readable object that can i.e. be written to the
+ * console: {@code console.log(jspb.debug.dump(myProto))}.
+ * This function makes a best effort and may not work in all cases. It will not
+ * work in obfuscated and or optimized code.
+ * Use this in environments where {@see jspb.Message.prototype.toObject} is
+ * not available for code size reasons.
+ * @param {jspb.Message} message A jspb.Message.
+ * @return {Object}
+ */
+jspb.debug.dump = function(message) {
+  if (!goog.DEBUG) {
+    return null;
+  }
+  goog.asserts.assert(message instanceof jspb.Message,
+      'jspb.Message instance expected');
+  /** @type {Object} */
+  var object = message;
+  goog.asserts.assert(object['getExtension'],
+      'Only unobfuscated and unoptimized compilation modes supported.');
+  return /** @type {Object} */ (jspb.debug.dump_(message));
+};
+
+
+/**
+ * Recursively introspects a message and the values its getters return to
+ * make a best effort in creating a human readable representation of the
+ * message.
+ * @param {*} thing A jspb.Message, Array or primitive type to dump.
+ * @return {*}
+ * @private
+ */
+jspb.debug.dump_ = function(thing) {
+  var type = goog.typeOf(thing);
+  if (type == 'number' || type == 'string' || type == 'boolean' ||
+      type == 'null' || type == 'undefined') {
+    return thing;
+  }
+  if (type == 'array') {
+    goog.asserts.assertArray(thing);
+    return goog.array.map(thing, jspb.debug.dump_);
+  }
+  var message = thing;  // Copy because we don't want type inference on thing.
+  goog.asserts.assert(message instanceof jspb.Message,
+      'Only messages expected: ' + thing);
+  var ctor = message.constructor;
+  var messageName = ctor.name || ctor.displayName;
+  var object = {
+    '$name': messageName
+  };
+  for (var name in ctor.prototype) {
+    var match = /^get([A-Z]\w*)/.exec(name);
+    if (match && name != 'getExtension' &&
+        name != 'getJsPbMessageId') {
+      var val = thing[name]();
+      if (val != null) {
+        object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val);
+      }
+    }
+  }
+  if (COMPILED && thing['extensionObject_']) {
+    object['$extensions'] = 'Recursive dumping of extensions not supported ' +
+        'in compiled code. Switch to uncompiled or dump extension object ' +
+        'directly';
+    return object;
+  }
+  var extensionsObject;
+  for (var id in ctor['extensions']) {
+    if (/^\d+$/.test(id)) {
+      var ext = ctor['extensions'][id];
+      var extVal = thing.getExtension(ext);
+      var fieldName = goog.object.getKeys(ext.fieldName)[0];
+      if (extVal != null) {
+        if (!extensionsObject) {
+          extensionsObject = object['$extensions'] = {};
+        }
+        extensionsObject[jspb.debug.formatFieldName_(fieldName)] =
+            jspb.debug.dump_(extVal);
+      }
+    }
+  }
+  return object;
+};
+
+
+/**
+ * Formats a field name for output as camelCase.
+ *
+ * @param {string} name Name of the field.
+ * @return {string}
+ * @private
+ */
+jspb.debug.formatFieldName_ = function(name) {
+  // Name may be in TitleCase.
+  return name.replace(/^[A-Z]/, function(c) {
+    return c.toLowerCase();
+  });
+};
diff --git a/js/debug_test.js b/js/debug_test.js
new file mode 100644
index 0000000..d7bf376
--- /dev/null
+++ b/js/debug_test.js
@@ -0,0 +1,104 @@
+// 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.
+
+goog.setTestOnly();
+
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: google-protobuf
+goog.require('jspb.debug');
+
+// CommonJS-LoadFromFile: test_pb
+goog.require('proto.jspb.test.HasExtensions');
+goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.Simple1');
+
+
+describe('debugTest', function() {
+  it('testSimple1', function() {
+    if (COMPILED) {
+      return;
+    }
+    var message = new proto.jspb.test.Simple1();
+    message.setAString('foo');
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aString': 'foo',
+      'aRepeatedStringList': []
+    }, jspb.debug.dump(message));
+
+    message.setABoolean(true);
+    message.setARepeatedStringList(['1', '2']);
+
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aString': 'foo',
+      'aRepeatedStringList': ['1', '2'],
+      'aBoolean': true
+    }, jspb.debug.dump(message));
+
+    message.setAString(undefined);
+
+    assertObjectEquals({
+      $name: 'proto.jspb.test.Simple1',
+      'aRepeatedStringList': ['1', '2'],
+      'aBoolean': true
+    }, jspb.debug.dump(message));
+  });
+
+
+  it('testExtensions', function() {
+    if (COMPILED) {
+      return;
+    }
+    var extension = new proto.jspb.test.IsExtension();
+    extension.setExt1('ext1field');
+    var extendable = new proto.jspb.test.HasExtensions();
+    extendable.setStr1('v1');
+    extendable.setStr2('v2');
+    extendable.setStr3('v3');
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension);
+
+    assertObjectEquals({
+      '$name': 'proto.jspb.test.HasExtensions',
+      'str1': 'v1',
+      'str2': 'v2',
+      'str3': 'v3',
+      '$extensions': {
+        'extField': {
+          '$name': 'proto.jspb.test.IsExtension',
+          'ext1': 'ext1field'
+        },
+        'repeatedSimpleList': []
+      }
+    }, jspb.debug.dump(extendable));
+  });
+
+});
diff --git a/js/gulpfile.js b/js/gulpfile.js
new file mode 100644
index 0000000..b0faed0
--- /dev/null
+++ b/js/gulpfile.js
@@ -0,0 +1,96 @@
+var gulp = require('gulp');
+var exec = require('child_process').exec;
+var glob = require('glob');
+
+var protoc = process.env.PROTOC || '../src/protoc';
+
+gulp.task('genproto_closure', function (cb) {
+  exec(protoc + ' --js_out=library=testproto_libs,binary:. -I ../src -I . *.proto ../src/google/protobuf/descriptor.proto',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('genproto_commonjs', function (cb) {
+  exec('mkdir -p commonjs_out && ' + protoc + ' --js_out=import_style=commonjs,binary:commonjs_out -I ../src -I . *.proto ../src/google/protobuf/descriptor.proto',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('dist', function (cb) {
+  // TODO(haberman): minify this more aggressively.
+  // Will require proper externs/exports.
+  exec('./node_modules/google-closure-library/closure/bin/calcdeps.py -i message.js -i binary/reader.js -i binary/writer.js -i commonjs/export.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > google-protobuf.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('commonjs_asserts', function (cb) {
+  exec('mkdir -p commonjs_out && ./node_modules/google-closure-library/closure/bin/calcdeps.py -i commonjs/export_asserts.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > commonjs_out/closure_asserts_commonjs.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('make_commonjs_out', ['dist', 'genproto_commonjs', 'commonjs_asserts'], function (cb) {
+  // TODO(haberman): minify this more aggressively.
+  // Will require proper externs/exports.
+  var cmd = "mkdir -p commonjs_out/binary && ";
+  function addTestFile(file) {
+    cmd += 'node commonjs/rewrite_tests_for_commonjs.js < ' + file +
+           ' > commonjs_out/' + file + '&& ';
+  }
+
+  glob.sync('*_test.js').forEach(addTestFile);
+  glob.sync('binary/*_test.js').forEach(addTestFile);
+
+  exec(cmd +
+       'cp commonjs/jasmine.json commonjs_out/jasmine.json && ' +
+       'cp google-protobuf.js commonjs_out',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('deps', ['genproto_closure'], function (cb) {
+  exec('./node_modules/google-closure-library/closure/bin/build/depswriter.py *.js binary/*.js > deps.js',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test_closure', ['genproto_closure', 'deps'], function (cb) {
+  exec('JASMINE_CONFIG_PATH=jasmine.json ./node_modules/.bin/jasmine',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test_commonjs', ['make_commonjs_out'], function (cb) {
+  exec('cd commonjs_out && JASMINE_CONFIG_PATH=jasmine.json NODE_PATH=. ../node_modules/.bin/jasmine',
+       function (err, stdout, stderr) {
+    console.log(stdout);
+    console.log(stderr);
+    cb(err);
+  });
+});
+
+gulp.task('test', ['test_closure', 'test_commonjs'], function(cb) {
+  cb();
+});
diff --git a/js/jasmine.json b/js/jasmine.json
new file mode 100644
index 0000000..f83c54c
--- /dev/null
+++ b/js/jasmine.json
@@ -0,0 +1,12 @@
+{
+    "spec_dir": "",
+    "spec_files": [
+        "*_test.js",
+        "binary/*_test.js"
+    ],
+    "helpers": [
+        "node_modules/google-closure-library/closure/goog/bootstrap/nodejs.js",
+        "node_loader.js",
+        "deps.js"
+    ]
+}
diff --git a/js/message.js b/js/message.js
new file mode 100644
index 0000000..cef9aef
--- /dev/null
+++ b/js/message.js
@@ -0,0 +1,1125 @@
+// 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.
+
+/**
+ * @fileoverview Definition of jspb.Message.
+ *
+ * @author mwr@google.com (Mark Rawling)
+ */
+
+goog.provide('jspb.ExtensionFieldInfo');
+goog.provide('jspb.Message');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.json');
+goog.require('goog.object');
+
+// Not needed in compilation units that have no protos with xids.
+goog.forwardDeclare('xid.String');
+
+
+
+/**
+ * Stores information for a single extension field.
+ *
+ * For example, an extension field defined like so:
+ *
+ *     extend BaseMessage {
+ *       optional MyMessage my_field = 123;
+ *     }
+ *
+ * will result in an ExtensionFieldInfo object with these properties:
+ *
+ *     {
+ *       fieldIndex: 123,
+ *       fieldName: {my_field_renamed: 0},
+ *       ctor: proto.example.MyMessage,
+ *       toObjectFn: proto.example.MyMessage.toObject,
+ *       isRepeated: 0
+ *     }
+ *
+ * We include `toObjectFn` to allow the JSCompiler to perform dead-code removal
+ * on unused toObject() methods.
+ *
+ * If an extension field is primitive, ctor and toObjectFn will be null.
+ * isRepeated should be 0 or 1.
+ *
+ * binary{Reader,Writer}Fn and (if message type) binaryMessageSerializeFn are
+ * always provided. binaryReaderFn and binaryWriterFn are references to the
+ * appropriate methods on BinaryReader/BinaryWriter to read/write the value of
+ * this extension, and binaryMessageSerializeFn is a reference to the message
+ * class's .serializeBinary method, if available.
+ *
+ * @param {number} fieldNumber
+ * @param {Object} fieldName This has the extension field name as a property.
+ * @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) {
+  /** @const */
+  this.fieldIndex = fieldNumber;
+  /** @const */
+  this.fieldName = fieldName;
+  /** @const */
+  this.ctor = ctor;
+  /** @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;
+};
+
+
+/**
+ * Base class for all JsPb messages.
+ * @constructor
+ * @struct
+ */
+jspb.Message = function() {
+};
+
+
+/**
+ * @define {boolean} Whether to generate toObject methods for objects. Turn
+ *     this off, if you do not want toObject to be ever used in your project.
+ *     When turning off this flag, consider adding a conformance test that bans
+ *     calling toObject. Enabling this will disable the JSCompiler's ability to
+ *     dead code eliminate fields used in protocol buffers that are never used
+ *     in an application.
+ */
+goog.define('jspb.Message.GENERATE_TO_OBJECT', true);
+
+
+/**
+ * @define {boolean} Whether to generate fromObject methods for objects. Turn
+ *     this off, if you do not want fromObject to be ever used in your project.
+ *     When turning off this flag, consider adding a conformance test that bans
+ *     calling fromObject. Enabling this might disable the JSCompiler's ability
+ *     to dead code eliminate fields used in protocol buffers that are never
+ *     used in an application.
+ *     NOTE: By default no protos actually have a fromObject method. You need to
+ *     add the jspb.generate_from_object options to the proto definition to
+ *     activate the feature.
+ *     By default this is enabled for test code only.
+ */
+goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
+
+
+/**
+ * @define {boolean} Turning on this flag does NOT change the behavior of JSPB
+ *     and only affects private internal state. It may, however, break some
+ *     tests that use naive deeply-equals algorithms, because using a proto
+ *     mutates its internal state.
+ *     Projects are advised to turn this flag always on.
+ */
+goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', COMPILED);
+// TODO(b/19419436) Turn this on by default.
+
+
+/**
+ * The internal data array.
+ * @type {!Array}
+ * @protected
+ */
+jspb.Message.prototype.array;
+
+
+/**
+ * Wrappers are the constructed instances of message-type fields. They are built
+ * on demand from the raw array data. Includes message fields, repeated message
+ * fields and extension message fields. Indexed by field number.
+ * @type {Object}
+ * @private
+ */
+jspb.Message.prototype.wrappers_;
+
+
+/**
+ * The object that contains extension fields, if any. This is an object that
+ * maps from a proto field number to the field's value.
+ * @type {Object}
+ * @private
+ */
+jspb.Message.prototype.extensionObject_;
+
+
+/**
+ * Non-extension fields with a field number at or above the pivot are
+ * stored in the extension object (in addition to all extension fields).
+ * @type {number}
+ * @private
+ */
+jspb.Message.prototype.pivot_;
+
+
+/**
+ * The JsPb message_id of this proto.
+ * @type {string|undefined} the message id or undefined if this message
+ *     has no id.
+ * @private
+ */
+jspb.Message.prototype.messageId_;
+
+
+/**
+ * The xid of this proto type (The same for all instances of a proto). Provides
+ * a way to identify a proto by stable obfuscated name.
+ * @see {xid}.
+ * Available if {@link jspb.generate_xid} is added as a Message option to
+ * a protocol buffer.
+ * @const {!xid.String|undefined} The xid or undefined if message is
+ *     annotated to generate the xid.
+ */
+jspb.Message.prototype.messageXid;
+
+
+
+/**
+ * Returns the JsPb message_id of this proto.
+ * @return {string|undefined} the message id or undefined if this message
+ *     has no id.
+ */
+jspb.Message.prototype.getJsPbMessageId = function() {
+  return this.messageId_;
+};
+
+
+/**
+ * An offset applied to lookups into this.array to account for the presence or
+ * absence of a messageId at position 0. For response messages, this will be 0.
+ * Otherwise, it will be -1 so that the first array position is not wasted.
+ * @type {number}
+ * @private
+ */
+jspb.Message.prototype.arrayIndexOffset_;
+
+
+/**
+ * Returns the index into msg.array at which the proto field with tag number
+ * fieldNumber will be located.
+ * @param {!jspb.Message} msg Message for which we're calculating an index.
+ * @param {number} fieldNumber The field number.
+ * @return {number} The index.
+ * @private
+ */
+jspb.Message.getIndex_ = function(msg, fieldNumber) {
+  return fieldNumber + msg.arrayIndexOffset_;
+};
+
+
+/**
+ * Initializes a JsPb Message.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @param {Array|undefined} data An initial data array.
+ * @param {string|number} messageId For response messages, the message id or ''
+ *     if no message id is specified. For non-response messages, 0.
+ * @param {number} suggestedPivot The field number at which to start putting
+ *     fields into the extension object. This is only used if data does not
+ *     contain an extension object already. -1 if no extension object is
+ *     required for this message type.
+ * @param {Array<number>} repeatedFields The message's repeated fields.
+ * @param {Array<!Array<number>>=} opt_oneofFields The fields belonging to
+ *     each of the message's oneof unions.
+ * @protected
+ */
+jspb.Message.initialize = function(
+    msg, data, messageId, suggestedPivot, repeatedFields, opt_oneofFields) {
+  msg.wrappers_ = jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ? null : {};
+  if (!data) {
+    data = messageId ? [messageId] : [];
+  }
+  msg.messageId_ = messageId ? String(messageId) : undefined;
+  // If the messageId is 0, this message is not a response message, so we shift
+  // array indices down by 1 so as not to waste the first position in the array,
+  // which would otherwise go unused.
+  msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0;
+  msg.array = data;
+  jspb.Message.materializeExtensionObject_(msg, suggestedPivot);
+  if (repeatedFields) {
+    for (var i = 0; i < repeatedFields.length; i++) {
+      var fieldNumber = repeatedFields[i];
+      if (fieldNumber < msg.pivot_) {
+        var index = jspb.Message.getIndex_(msg, fieldNumber);
+        msg.array[index] = msg.array[index] ||
+            (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
+                jspb.Message.EMPTY_LIST_SENTINEL_ :
+                []);
+      } else {
+        msg.extensionObject_[fieldNumber] =
+            msg.extensionObject_[fieldNumber] ||
+            (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
+                jspb.Message.EMPTY_LIST_SENTINEL_ :
+                []);
+      }
+    }
+  }
+
+  if (opt_oneofFields && opt_oneofFields.length) {
+    // Compute the oneof case for each union. This ensures only one value is
+    // set in the union.
+    goog.array.forEach(
+        opt_oneofFields, goog.partial(jspb.Message.computeOneofCase, msg));
+  }
+};
+
+
+/**
+ * Used to mark empty repeated fields. Serializes to null when serialized
+ * to JSON.
+ * When reading a repeated field readers must check the return value against
+ * this value and return and replace it with a new empty array if it is
+ * present.
+ * @private @const {!Object}
+ */
+jspb.Message.EMPTY_LIST_SENTINEL_ = goog.DEBUG && Object.freeze ?
+    Object.freeze([]) :
+    [];
+
+
+/**
+ * Ensures that the array contains an extension object if necessary.
+ * If the array contains an extension object in its last position, then the
+ * object is kept in place and its position is used as the pivot.  If not, then
+ * create an extension object using suggestedPivot.  If suggestedPivot is -1,
+ * we don't have an extension object at all, in which case all fields are stored
+ * in the array.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @param {number} suggestedPivot See description for initialize().
+ * @private
+ */
+jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) {
+  if (msg.array.length) {
+    var foundIndex = msg.array.length - 1;
+    var obj = msg.array[foundIndex];
+    // Normal fields are never objects, so we can be sure that if we find an
+    // object here, then it's the extension object. However, we must ensure that
+    // the object is not an array, since arrays are valid field values.
+    // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
+    // in Safari on iOS 8. See the description of CL/86511464 for details.
+    if (obj && typeof obj == 'object' && !goog.isArray(obj)) {
+      msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
+      msg.extensionObject_ = obj;
+      return;
+    }
+  }
+  // This complexity exists because we keep all extension fields in the
+  // extensionObject_ regardless of proto field number. Changing this would
+  // simplify the code here, but it would require changing the serialization
+  // format from the server, which is not backwards compatible.
+  // TODO(jshneier): Should we just treat extension fields the same as
+  // non-extension fields, and select whether they appear in the object or in
+  // the array purely based on tag number? This would allow simplifying all the
+  // get/setExtension logic, but it would require the breaking change described
+  // above.
+  if (suggestedPivot > -1) {
+    msg.pivot_ = suggestedPivot;
+    var pivotIndex = jspb.Message.getIndex_(msg, suggestedPivot);
+    if (!jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) {
+      msg.extensionObject_ = msg.array[pivotIndex] = {};
+    } else {
+      // Initialize to null to avoid changing the shape of the proto when it
+      // gets eventually set.
+      msg.extensionObject_ = null;
+    }
+  } else {
+    msg.pivot_ = Number.MAX_VALUE;
+  }
+};
+
+
+/**
+ * Creates an empty extensionObject_ if non exists.
+ * @param {!jspb.Message} msg The JsPb proto to modify.
+ * @private
+ */
+jspb.Message.maybeInitEmptyExtensionObject_ = function(msg) {
+  var pivotIndex = jspb.Message.getIndex_(msg, msg.pivot_);
+  if (!msg.array[pivotIndex]) {
+    msg.extensionObject_ = msg.array[pivotIndex] = {};
+  }
+};
+
+
+/**
+ * Converts a JsPb repeated message field into an object list.
+ * @param {!Array<T>} field The repeated message field to be
+ *     converted.
+ * @param {?function(boolean=): Object|
+ *     function((boolean|undefined),T): Object} toObjectFn The toObject
+ *     function for this field.  We need to pass this for effective dead code
+ *     removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Array<Object>} An array of converted message objects.
+ * @template T
+ */
+jspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) {
+  // Not using goog.array.map in the generated code to keep it small.
+  // And not using it here to avoid a function call.
+  var result = [];
+  for (var i = 0; i < field.length; i++) {
+    result[i] = toObjectFn.call(field[i], opt_includeInstance,
+      /** @type {!jspb.Message} */ (field[i]));
+  }
+  return result;
+};
+
+
+/**
+ * Adds a proto's extension data to a Soy rendering object.
+ * @param {!jspb.Message} proto The proto whose extensions to convert.
+ * @param {!Object} obj The Soy object to add converted extension data to.
+ * @param {!Object} extensions The proto class' registered extensions.
+ * @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
+ *     class' getExtension function. Passed for effective dead code removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ */
+jspb.Message.toObjectExtension = function(proto, obj, extensions,
+    getExtensionFn, opt_includeInstance) {
+  for (var fieldNumber in extensions) {
+    var fieldInfo = extensions[fieldNumber];
+    var value = getExtensionFn.call(proto, fieldInfo);
+    if (value) {
+      for (var name in fieldInfo.fieldName) {
+        if (fieldInfo.fieldName.hasOwnProperty(name)) {
+          break; // the compiled field name
+        }
+      }
+      if (!fieldInfo.toObjectFn) {
+        obj[name] = value;
+      } else {
+        if (fieldInfo.isRepeated) {
+          obj[name] = jspb.Message.toObjectList(
+              /** @type {!Array<jspb.Message>} */ (value),
+              fieldInfo.toObjectFn, opt_includeInstance);
+        } else {
+          obj[name] = fieldInfo.toObjectFn(opt_includeInstance, value);
+        }
+      }
+    }
+  }
+};
+
+
+/**
+ * Writes a proto's extension data to a binary-format output stream.
+ * @param {!jspb.Message} proto The proto whose extensions to convert.
+ * @param {*} writer The binary-format writer to write to.
+ * @param {!Object} extensions The proto class' registered extensions.
+ * @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
+ *     class' getExtension function. Passed for effective dead code removal.
+ */
+jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
+    getExtensionFn) {
+  for (var fieldNumber in extensions) {
+    var fieldInfo = extensions[fieldNumber];
+    // 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) {
+      throw new Error('Message extension present that was generated ' +
+                      'without binary serialization support');
+    }
+    var value = getExtensionFn.call(proto, fieldInfo);
+    if (value) {
+      if (fieldInfo.ctor) {  // is this a message type?
+        // If the message type of the extension was generated without binary
+        // support, there may not be a binary message serializer function, and
+        // we can't know when we codegen the extending message that the extended
+        // 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);
+        } 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);
+      }
+    }
+  }
+};
+
+
+/**
+ * Reads an extension field from the given reader and, if a valid extension,
+ * sets the extension value.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {{skipField:function(),getFieldNumber:function():number}} reader
+ * @param {!Object} extensions The extensions object.
+ * @param {function(jspb.ExtensionFieldInfo)} getExtensionFn
+ * @param {function(jspb.ExtensionFieldInfo, ?)} setExtensionFn
+ */
+jspb.Message.readBinaryExtension = function(msg, reader, extensions,
+    getExtensionFn, setExtensionFn) {
+  var fieldInfo = extensions[reader.getFieldNumber()];
+  if (!fieldInfo) {
+    reader.skipField();
+    return;
+  }
+  if (!fieldInfo.binaryReaderFn) {
+    throw new Error('Deserializing extension whose generated code does not ' +
+                    'support binary format');
+  }
+
+  var value;
+  if (fieldInfo.ctor) {
+    // Message type.
+    value = new fieldInfo.ctor();
+    fieldInfo.binaryReaderFn.call(
+        reader, value, fieldInfo.binaryMessageDeserializeFn);
+  } else {
+    // All other types.
+    value = fieldInfo.binaryReaderFn.call(reader);
+  }
+
+  if (fieldInfo.isRepeated && !fieldInfo.isPacked) {
+    var currentList = getExtensionFn.call(msg, fieldInfo);
+    if (!currentList) {
+      setExtensionFn.call(msg, fieldInfo, [value]);
+    } else {
+      currentList.push(value);
+    }
+  } else {
+    setExtensionFn.call(msg, fieldInfo, value);
+  }
+};
+
+
+/**
+ * Gets the value of a non-extension field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {string|number|boolean|Uint8Array|Array|null|undefined}
+ * The field's value.
+ * @protected
+ */
+jspb.Message.getField = function(msg, fieldNumber) {
+  if (fieldNumber < msg.pivot_) {
+    var index = jspb.Message.getIndex_(msg, fieldNumber);
+    var val = msg.array[index];
+    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
+      return msg.array[index] = [];
+    }
+    return val;
+  } else {
+    var val = msg.extensionObject_[fieldNumber];
+    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
+      return msg.extensionObject_[fieldNumber] = [];
+    }
+    return val;
+  }
+};
+
+
+/**
+ * Gets the value of a non-extension primitive field, with proto3 (non-nullable
+ * primitives) semantics. Returns `defaultValue` if the field is not otherwise
+ * set.
+ * @template T
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {T} defaultValue The default value.
+ * @return {T} The field's value.
+ * @protected
+ */
+jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
+  var value = jspb.Message.getField(msg, fieldNumber);
+  if (value == null) {
+    return defaultValue;
+  } else {
+    return value;
+  }
+};
+
+
+/**
+ * Sets the value of a non-extension field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @protected
+ */
+jspb.Message.setField = function(msg, fieldNumber, value) {
+  if (fieldNumber < msg.pivot_) {
+    msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value;
+  } else {
+    msg.extensionObject_[fieldNumber] = value;
+  }
+};
+
+
+/**
+ * Sets the value of a field in a oneof union and clears all other fields in
+ * the union.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {!Array<number>} oneof The fields belonging to the union.
+ * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
+ * @protected
+ */
+jspb.Message.setOneofField = function(msg, fieldNumber, oneof, value) {
+  var currentCase = jspb.Message.computeOneofCase(msg, oneof);
+  if (currentCase && currentCase !== fieldNumber && value !== undefined) {
+    if (msg.wrappers_ && currentCase in msg.wrappers_) {
+      msg.wrappers_[currentCase] = undefined;
+    }
+    jspb.Message.setField(msg, currentCase, undefined);
+  }
+  jspb.Message.setField(msg, fieldNumber, value);
+};
+
+
+/**
+ * Computes the selection in a oneof group for the given message, ensuring
+ * only one field is set in the process.
+ *
+ * According to the protobuf language guide (
+ * https://developers.google.com/protocol-buffers/docs/proto#oneof), "if the
+ * parser encounters multiple members of the same oneof on the wire, only the
+ * last member seen is used in the parsed message." Since JSPB serializes
+ * messages to a JSON array, the "last member seen" will always be the field
+ * with the greatest field number (directly corresponding to the greatest
+ * array index).
+ *
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {!Array<number>} oneof The field numbers belonging to the union.
+ * @return {number} The field number currently set in the union, or 0 if none.
+ * @protected
+ */
+jspb.Message.computeOneofCase = function(msg, oneof) {
+  var oneofField;
+  var oneofValue;
+
+  goog.array.forEach(oneof, function(fieldNumber) {
+    var value = jspb.Message.getField(msg, fieldNumber);
+    if (goog.isDefAndNotNull(value)) {
+      oneofField = fieldNumber;
+      oneofValue = value;
+      jspb.Message.setField(msg, fieldNumber, undefined);
+    }
+  });
+
+  if (oneofField) {
+    // NB: We know the value is unique, so we can call jspb.Message.setField
+    // directly instead of jpsb.Message.setOneofField. Also, setOneofField
+    // calls this function.
+    jspb.Message.setField(msg, oneofField, oneofValue);
+    return oneofField;
+  }
+
+  return 0;
+};
+
+
+/**
+ * Gets and wraps a proto field on access.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
+ * @param {number} fieldNumber The field number.
+ * @param {number=} opt_required True (1) if this is a required field.
+ * @return {jspb.Message} The field as a jspb proto.
+ * @protected
+ */
+jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
+  // TODO(mwr): Consider copying data and/or arrays.
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  if (!msg.wrappers_[fieldNumber]) {
+    var data = /** @type {Array} */ (jspb.Message.getField(msg, fieldNumber));
+    if (opt_required || data) {
+      // TODO(mwr): Remove existence test for always valid default protos.
+      msg.wrappers_[fieldNumber] = new ctor(data);
+    }
+  }
+  return /** @type {jspb.Message} */ (msg.wrappers_[fieldNumber]);
+};
+
+
+/**
+ * Gets and wraps a repeated proto field on access.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
+ * @param {number} fieldNumber The field number.
+ * @return {Array<!jspb.Message>} The repeated field as an array of protos.
+ * @protected
+ */
+jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  if (!msg.wrappers_[fieldNumber]) {
+    var data = jspb.Message.getField(msg, fieldNumber);
+    for (var wrappers = [], i = 0; i < data.length; i++) {
+      wrappers[i] = new ctor(data[i]);
+    }
+    msg.wrappers_[fieldNumber] = wrappers;
+  }
+  var val = msg.wrappers_[fieldNumber];
+  if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
+    val = msg.wrappers_[fieldNumber] = [];
+  }
+  return /** @type {Array<!jspb.Message>} */ (val);
+};
+
+
+/**
+ * Sets a proto field and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @protected
+ */
+jspb.Message.setWrapperField = function(msg, fieldNumber, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  var data = value ? value.toArray() : value;
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setField(msg, fieldNumber, data);
+};
+
+
+/**
+ * Sets a proto field in a oneof union and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {!Array<number>} oneof The fields belonging to the union.
+ * @param {jspb.Message|undefined} value A new value for this proto field.
+ * @protected
+ */
+jspb.Message.setOneofWrapperField = function(msg, fieldNumber, oneof, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  var data = value ? value.toArray() : value;
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setOneofField(msg, fieldNumber, oneof, data);
+};
+
+
+/**
+ * Sets a repeated proto field and syncs it to the backing array.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {Array<!jspb.Message>|undefined} value An array of protos.
+ * @protected
+ */
+jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  value = value || [];
+  for (var data = [], i = 0; i < value.length; i++) {
+    data[i] = value[i].toArray();
+  }
+  msg.wrappers_[fieldNumber] = value;
+  jspb.Message.setField(msg, fieldNumber, data);
+};
+
+
+/**
+ * Converts a JsPb repeated message field into a map. The map will contain
+ * protos unless an optional toObject function is given, in which case it will
+ * contain objects suitable for Soy rendering.
+ * @param {!Array<T>} field The repeated message field to be
+ *     converted.
+ * @param {function() : string?} mapKeyGetterFn The function to get the key of
+ *     the map.
+ * @param {?function(boolean=): Object|
+ *     function((boolean|undefined),T): Object} opt_toObjectFn The
+ *     toObject function for this field. We need to pass this for effective
+ *     dead code removal.
+ * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
+ *     for transitional soy proto support: http://goto/soy-param-migration
+ * @return {!Object.<string, Object>} A map of proto or Soy objects.
+ * @template T
+ */
+jspb.Message.toMap = function(
+    field, mapKeyGetterFn, opt_toObjectFn, opt_includeInstance) {
+  var result = {};
+  for (var i = 0; i < field.length; i++) {
+    result[mapKeyGetterFn.call(field[i])] = opt_toObjectFn ?
+        opt_toObjectFn.call(field[i], opt_includeInstance,
+            /** @type {!jspb.Message} */ (field[i])) : field[i];
+  }
+  return result;
+};
+
+
+/**
+ * Returns the internal array of this proto.
+ * <p>Note: If you use this array to construct a second proto, the content
+ * would then be partially shared between the two protos.
+ * @return {!Array} The proto represented as an array.
+ */
+jspb.Message.prototype.toArray = function() {
+  return this.array;
+};
+
+
+
+
+/**
+ * Creates a string representation of the internal data array of this proto.
+ * <p>NOTE: This string is *not* suitable for use in server requests.
+ * @return {string} A string representation of this proto.
+ * @override
+ */
+jspb.Message.prototype.toString = function() {
+  return this.array.toString();
+};
+
+
+/**
+ * Gets the value of the extension field from the extended object.
+ * @param {jspb.ExtensionFieldInfo.<T>} fieldInfo Specifies the field to get.
+ * @return {T} The value of the field.
+ * @template T
+ */
+jspb.Message.prototype.getExtension = function(fieldInfo) {
+  if (!this.extensionObject_) {
+    return undefined;
+  }
+  if (!this.wrappers_) {
+    this.wrappers_ = {};
+  }
+  var fieldNumber = fieldInfo.fieldIndex;
+  if (fieldInfo.isRepeated) {
+    if (fieldInfo.ctor) {
+      if (!this.wrappers_[fieldNumber]) {
+        this.wrappers_[fieldNumber] =
+            goog.array.map(this.extensionObject_[fieldNumber] || [],
+                function(arr) {
+                  return new fieldInfo.ctor(arr);
+                });
+      }
+      return this.wrappers_[fieldNumber];
+    } else {
+      return this.extensionObject_[fieldNumber];
+    }
+  } else {
+    if (fieldInfo.ctor) {
+      if (!this.wrappers_[fieldNumber] && this.extensionObject_[fieldNumber]) {
+        this.wrappers_[fieldNumber] = new fieldInfo.ctor(
+            /** @type {Array|undefined} */ (
+                this.extensionObject_[fieldNumber]));
+      }
+      return this.wrappers_[fieldNumber];
+    } else {
+      return this.extensionObject_[fieldNumber];
+    }
+  }
+};
+
+
+/**
+ * Sets the value of the extension field in the extended object.
+ * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set.
+ * @param {jspb.Message|string|number|boolean|Array} value The value to set.
+ */
+jspb.Message.prototype.setExtension = function(fieldInfo, value) {
+  if (!this.wrappers_) {
+    this.wrappers_ = {};
+  }
+  jspb.Message.maybeInitEmptyExtensionObject_(this);
+  var fieldNumber = fieldInfo.fieldIndex;
+  if (fieldInfo.isRepeated) {
+    value = value || [];
+    if (fieldInfo.ctor) {
+      this.wrappers_[fieldNumber] = value;
+      this.extensionObject_[fieldNumber] = goog.array.map(
+          /** @type {Array<jspb.Message>} */ (value), function(msg) {
+        return msg.toArray();
+      });
+    } else {
+      this.extensionObject_[fieldNumber] = value;
+    }
+  } else {
+    if (fieldInfo.ctor) {
+      this.wrappers_[fieldNumber] = value;
+      this.extensionObject_[fieldNumber] = value ? value.toArray() : value;
+    } else {
+      this.extensionObject_[fieldNumber] = value;
+    }
+  }
+};
+
+
+/**
+ * Creates a difference object between two messages.
+ *
+ * The result will contain the top-level fields of m2 that differ from those of
+ * m1 at any level of nesting. No data is cloned, the result object will
+ * share its top-level elements with m2 (but not with m1).
+ *
+ * Note that repeated fields should not have null/undefined elements, but if
+ * they do, this operation will treat repeated fields of different length as
+ * the same if the only difference between them is due to trailing
+ * null/undefined values.
+ *
+ * @param {!jspb.Message} m1 The first message object.
+ * @param {!jspb.Message} m2 The second message object.
+ * @return {!jspb.Message} The difference returned as a proto message.
+ *     Note that the returned message may be missing required fields. This is
+ *     currently tolerated in Js, but would cause an error if you tried to
+ *     send such a proto to the server. You can access the raw difference
+ *     array with result.toArray().
+ * @throws {Error} If the messages are responses with different types.
+ */
+jspb.Message.difference = function(m1, m2) {
+  if (!(m1 instanceof m2.constructor)) {
+    throw new Error('Messages have different types.');
+  }
+  var arr1 = m1.toArray();
+  var arr2 = m2.toArray();
+  var res = [];
+  var start = 0;
+  var length = arr1.length > arr2.length ? arr1.length : arr2.length;
+  if (m1.getJsPbMessageId()) {
+    res[0] = m1.getJsPbMessageId();
+    start = 1;
+  }
+  for (var i = start; i < length; i++) {
+    if (!jspb.Message.compareFields(arr1[i], arr2[i])) {
+      res[i] = arr2[i];
+    }
+  }
+  return new m1.constructor(res);
+};
+
+
+/**
+ * Tests whether two messages are equal.
+ * @param {jspb.Message|undefined} m1 The first message object.
+ * @param {jspb.Message|undefined} m2 The second message object.
+ * @return {boolean} true if both messages are null/undefined, or if both are
+ *     of the same type and have the same field values.
+ */
+jspb.Message.equals = function(m1, m2) {
+  return m1 == m2 || (!!(m1 && m2) && (m1 instanceof m2.constructor) &&
+      jspb.Message.compareFields(m1.toArray(), m2.toArray()));
+};
+
+
+/**
+ * Compares two message fields recursively.
+ * @param {*} field1 The first field.
+ * @param {*} field2 The second field.
+ * @return {boolean} true if the fields are null/undefined, or otherwise equal.
+ */
+jspb.Message.compareFields = function(field1, field2) {
+  if (goog.isObject(field1) && goog.isObject(field2)) {
+    var keys = {}, name, extensionObject1, extensionObject2;
+    for (name in field1) {
+      field1.hasOwnProperty(name) && (keys[name] = 0);
+    }
+    for (name in field2) {
+      field2.hasOwnProperty(name) && (keys[name] = 0);
+    }
+    for (name in keys) {
+      var val1 = field1[name], val2 = field2[name];
+      if (goog.isObject(val1) && !goog.isArray(val1)) {
+        if (extensionObject1 !== undefined) {
+          throw new Error('invalid jspb state');
+        }
+        extensionObject1 = goog.object.isEmpty(val1) ? undefined : val1;
+        val1 = undefined;
+      }
+      if (goog.isObject(val2) && !goog.isArray(val2)) {
+        if (extensionObject2 !== undefined) {
+          throw new Error('invalid jspb state');
+        }
+        extensionObject2 = goog.object.isEmpty(val2) ? undefined : val2;
+        val2 = undefined;
+      }
+      if (!jspb.Message.compareFields(val1, val2)) {
+        return false;
+      }
+    }
+    if (extensionObject1 || extensionObject2) {
+      return jspb.Message.compareFields(extensionObject1, extensionObject2);
+    }
+    return true;
+  }
+  // Primitive fields, null and undefined compare as equal.
+  // This also forces booleans and 0/1 to compare as equal to ensure
+  // compatibility with the jspb serializer.
+  return field1 == field2;
+};
+
+
+/**
+ * Static clone function. NOTE: A type-safe method called "cloneMessage" exists
+ * on each generated JsPb class. Do not call this function directly.
+ * @param {!jspb.Message} msg A message to clone.
+ * @return {!jspb.Message} A deep clone of the given message.
+ */
+jspb.Message.clone = function(msg) {
+  // Although we could include the wrappers, we leave them out here.
+  return jspb.Message.cloneMessage(msg);
+};
+
+
+/**
+ * @param {!jspb.Message} msg A message to clone.
+ * @return {!jspb.Message} A deep clone of the given message.
+ * @protected
+ */
+jspb.Message.cloneMessage = function(msg) {
+  // Although we could include the wrappers, we leave them out here.
+  return new msg.constructor(jspb.Message.clone_(msg.toArray()));
+};
+
+
+/**
+ * Takes 2 messages of the same type and copies the contents of the first
+ * message into the second. After this the 2 messages will equals in terms of
+ * value semantics but share no state. All data in the destination message will
+ * be overridden.
+ *
+ * @param {MESSAGE} fromMessage Message that will be copied into toMessage.
+ * @param {MESSAGE} toMessage Message which will receive a copy of fromMessage
+ *     as its contents.
+ * @template MESSAGE
+ */
+jspb.Message.copyInto = function(fromMessage, toMessage) {
+  goog.asserts.assertInstanceof(fromMessage, jspb.Message);
+  goog.asserts.assertInstanceof(toMessage, jspb.Message);
+  goog.asserts.assert(fromMessage.constructor == toMessage.constructor,
+      'Copy source and target message should have the same type.');
+  var copyOfFrom = jspb.Message.clone(fromMessage);
+
+  var to = toMessage.toArray();
+  var from = copyOfFrom.toArray();
+
+  // Empty destination in case it has more values at the end of the array.
+  to.length = 0;
+  // and then copy everything from the new to the existing message.
+  for (var i = 0; i < from.length; i++) {
+    to[i] = from[i];
+  }
+
+  // This is either null or empty for a fresh copy.
+  toMessage.wrappers_ = copyOfFrom.wrappers_;
+  // Just a reference into the shared array.
+  toMessage.extensionObject_ = copyOfFrom.extensionObject_;
+};
+
+
+/**
+ * Helper for cloning an internal JsPb object.
+ * @param {!Object} obj A JsPb object, eg, a field, to be cloned.
+ * @return {!Object} A clone of the input object.
+ * @private
+ */
+jspb.Message.clone_ = function(obj) {
+  var o;
+  if (goog.isArray(obj)) {
+    // Allocate array of correct size.
+    var clonedArray = new Array(obj.length);
+    // Use array iteration where possible because it is faster than for-in.
+    for (var i = 0; i < obj.length; i++) {
+      if ((o = obj[i]) != null) {
+        clonedArray[i] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+      }
+    }
+    return clonedArray;
+  }
+  var clone = {};
+  for (var key in obj) {
+    if ((o = obj[key]) != null) {
+      clone[key] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
+    }
+  }
+  return clone;
+};
+
+
+/**
+ * Registers a JsPb message type id with its constructor.
+ * @param {string} id The id for this type of message.
+ * @param {Function} constructor The message constructor.
+ */
+jspb.Message.registerMessageType = function(id, constructor) {
+  jspb.Message.registry_[id] = constructor;
+  // This is needed so we can later access messageId directly on the contructor,
+  // otherwise it is not available due to 'property collapsing' by the compiler.
+  constructor.messageId = id;
+};
+
+
+/**
+ * The registry of message ids to message constructors.
+ * @private
+ */
+jspb.Message.registry_ = {};
+
+
+/**
+ * The extensions registered on MessageSet. This is a map of extension
+ * field number to field info object. This should be considered as a
+ * private API.
+ *
+ * This is similar to [jspb class name].extensions object for
+ * non-MessageSet. We special case MessageSet so that we do not need
+ * to goog.require MessageSet from classes that extends MessageSet.
+ *
+ * @type {!Object.<number, jspb.ExtensionFieldInfo>}
+ */
+jspb.Message.messageSetExtensions = {};
diff --git a/js/message_test.js b/js/message_test.js
new file mode 100644
index 0000000..f572188
--- /dev/null
+++ b/js/message_test.js
@@ -0,0 +1,992 @@
+// 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.
+
+// Test suite is written using Jasmine -- see http://jasmine.github.io/
+
+goog.setTestOnly();
+
+goog.require('goog.json');
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: google-protobuf jspb
+goog.require('jspb.Message');
+
+// CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta
+goog.require('proto.jspb.exttest.beta.floatingStrField');
+
+// CommonJS-LoadFromFile: test3_pb proto.jspb.exttest
+goog.require('proto.jspb.exttest.floatingMsgField');
+
+// CommonJS-LoadFromFile: test4_pb proto.jspb.exttest
+goog.require('proto.jspb.exttest.floatingMsgFieldTwo');
+
+// CommonJS-LoadFromFile: test_pb proto.jspb.test
+goog.require('proto.jspb.test.CloneExtension');
+goog.require('proto.jspb.test.Complex');
+goog.require('proto.jspb.test.DefaultValues');
+goog.require('proto.jspb.test.Empty');
+goog.require('proto.jspb.test.EnumContainer');
+goog.require('proto.jspb.test.floatingStrField');
+goog.require('proto.jspb.test.HasExtensions');
+goog.require('proto.jspb.test.IndirectExtension');
+goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.OptionalFields');
+goog.require('proto.jspb.test.OuterEnum');
+goog.require('proto.jspb.test.OuterMessage.Complex');
+goog.require('proto.jspb.test.simple1');
+goog.require('proto.jspb.test.Simple1');
+goog.require('proto.jspb.test.Simple2');
+goog.require('proto.jspb.test.SpecialCases');
+goog.require('proto.jspb.test.TestClone');
+goog.require('proto.jspb.test.TestGroup');
+goog.require('proto.jspb.test.TestGroup1');
+goog.require('proto.jspb.test.TestMessageWithOneof');
+goog.require('proto.jspb.test.TestReservedNames');
+goog.require('proto.jspb.test.TestReservedNamesExtension');
+
+// CommonJS-LoadFromFile: test2_pb proto.jspb.test
+goog.require('proto.jspb.test.ExtensionMessage');
+goog.require('proto.jspb.test.TestExtensionsMessage');
+goog.require('proto.jspb.test.floatingMsgField');
+
+
+
+describe('Message test suite', function() {
+  it('testEmptyProto', function() {
+    var empty1 = new proto.jspb.test.Empty([]);
+    var empty2 = new proto.jspb.test.Empty([]);
+    assertObjectEquals({}, empty1.toObject());
+    assertObjectEquals('Message should not be corrupted:', empty2, empty1);
+  });
+
+  it('testTopLevelEnum', function() {
+    var response = new proto.jspb.test.EnumContainer([]);
+    response.setOuterEnum(proto.jspb.test.OuterEnum.FOO);
+    assertEquals(proto.jspb.test.OuterEnum.FOO, response.getOuterEnum());
+  });
+
+  it('testByteStrings', function() {
+    var data = new proto.jspb.test.DefaultValues([]);
+    data.setBytesField('some_bytes');
+    assertEquals('some_bytes', data.getBytesField());
+  });
+
+  it('testNestedMessage', function() {
+    var msg = new proto.jspb.test.OuterMessage.Complex();
+    msg.setInnerComplexField(5);
+    assertObjectEquals({innerComplexField: 5}, msg.toObject());
+  });
+
+  it('testComplexConversion', function() {
+    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var data2 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var foo = new proto.jspb.test.Complex(data1);
+    var bar = new proto.jspb.test.Complex(data2);
+    var result = foo.toObject();
+    assertObjectEquals({
+      aString: 'a',
+      anOutOfOrderBool: 1,
+      aNestedMessage: {
+        anInt: 11
+      },
+      aRepeatedMessageList: [{anInt: 22}, {anInt: 33}],
+      aRepeatedStringList: ['s1', 's2']
+    }, result);
+
+    // Now test with the jspb instances included.
+    result = foo.toObject(true /* opt_includeInstance */);
+    assertObjectEquals({
+      aString: 'a',
+      anOutOfOrderBool: 1,
+      aNestedMessage: {
+        anInt: 11,
+        $jspbMessageInstance: foo.getANestedMessage()
+      },
+      aRepeatedMessageList: [
+        {anInt: 22, $jspbMessageInstance: foo.getARepeatedMessageList()[0]},
+        {anInt: 33, $jspbMessageInstance: foo.getARepeatedMessageList()[1]}
+      ],
+      aRepeatedStringList: ['s1', 's2'],
+      $jspbMessageInstance: foo
+    }, result);
+
+  });
+
+  it('testMissingFields', function() {
+    var foo = new proto.jspb.test.Complex([
+        undefined, undefined, undefined, [],
+        undefined, undefined, undefined, undefined]);
+    var bar = new proto.jspb.test.Complex([
+        undefined, undefined, undefined, [],
+        undefined, undefined, undefined, undefined]);
+    var result = foo.toObject();
+    assertObjectEquals({
+      aString: undefined,
+      anOutOfOrderBool: undefined,
+      aNestedMessage: {
+        anInt: undefined
+      },
+      // Note: JsPb converts undefined repeated fields to empty arrays.
+      aRepeatedMessageList: [],
+      aRepeatedStringList: []
+    }, result);
+
+  });
+
+  it('testSpecialCases', function() {
+    // Note: Some property names are reserved in JavaScript.
+    // These names are converted to the Js property named pb_<reserved_name>.
+    var special =
+        new proto.jspb.test.SpecialCases(['normal', 'default', 'function',
+        'var']);
+    var result = special.toObject();
+    assertObjectEquals({
+      normal: 'normal',
+      pb_default: 'default',
+      pb_function: 'function',
+      pb_var: 'var'
+    }, result);
+  });
+
+  it('testDefaultValues', function() {
+    var defaultString = "default<>\'\"abc";
+    var response = new proto.jspb.test.DefaultValues();
+
+    // Test toObject
+    var expectedObject = {
+      stringField: defaultString,
+      boolField: true,
+      intField: 11,
+      enumField: 13,
+      emptyField: '',
+      bytesField: 'bW9v'
+    };
+    assertObjectEquals(expectedObject, response.toObject());
+
+
+    // Test getters
+    response = new proto.jspb.test.DefaultValues();
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+    assertEquals('', response.getEmptyField());
+    assertEquals('bW9v', response.getBytesField());
+
+    function makeDefault(values) {
+      return new proto.jspb.test.DefaultValues(values);
+    }
+
+    // Test with undefined values,
+    // Use push to workaround IE treating undefined array elements as holes.
+    response = makeDefault([undefined, undefined, undefined, undefined]);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test with null values, as would be returned by a JSON serializer.
+    response = makeDefault([null, null, null, null]);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test with false-like values.
+    response = makeDefault(['', false, 0, 0]);
+    assertEquals('', response.getStringField());
+    assertEquals(false, response.getBoolField());
+    assertEquals(true, response.getIntField() == 0);
+    assertEquals(true, response.getEnumField() == 0);
+
+    // Test that clearing the values reverts them to the default state.
+    response = makeDefault(['blah', false, 111, 77]);
+    response.clearStringField(); response.clearBoolField();
+    response.clearIntField(); response.clearEnumField();
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+
+    // Test that setFoo(null) clears the values.
+    response = makeDefault(['blah', false, 111, 77]);
+    response.setStringField(null); response.setBoolField(null);
+    response.setIntField(undefined); response.setEnumField(undefined);
+    assertEquals(defaultString, response.getStringField());
+    assertEquals(true, response.getBoolField());
+    assertEquals(11, response.getIntField());
+    assertEquals(13, response.getEnumField());
+  });
+
+  it('testMessageRegistration', function() {
+    // goog.require(SomeResponse) will include its library, which will in
+    // turn add SomeResponse to the message registry.
+    assertEquals(jspb.Message.registry_['res'], proto.jspb.test.SomeResponse);
+  });
+
+  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();
+    foo.clearABool();
+    foo.clearANestedMessage();
+    foo.clearARepeatedMessageList();
+    foo.clearARepeatedStringList();
+    assertUndefined(foo.getAString());
+    assertUndefined(foo.getABool());
+    assertUndefined(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    // NOTE: We want the missing fields in 'expected' to be undefined,
+    // but we actually get a sparse array instead. We could use something
+    // like [1,undefined,2] to avoid this, except that this is still
+    // sparse on IE. No comment...
+    var expected = [,,, [], []];
+    expected[0] = expected[1] = expected[2] = undefined;
+    assertObjectEquals(expected, foo.toArray());
+
+    // Test set(null). We could deprecated this in favor of clear(), but
+    // it's also convenient to have.
+    data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
+    foo = new proto.jspb.test.OptionalFields(data);
+    foo.setAString(null);
+    foo.setABool(null);
+    foo.setANestedMessage(null);
+    foo.setARepeatedMessageList(null);
+    foo.setARepeatedStringList(null);
+    assertNull(foo.getAString());
+    assertNull(foo.getABool());
+    assertNull(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    assertObjectEquals([null, null, null, [], []], foo.toArray());
+
+    // Test set(undefined). Again, not something we really need, and not
+    // supported directly by our typing, but it should 'do the right thing'.
+    data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
+    foo = new proto.jspb.test.OptionalFields(data);
+    foo.setAString(undefined);
+    foo.setABool(undefined);
+    foo.setANestedMessage(undefined);
+    foo.setARepeatedMessageList(undefined);
+    foo.setARepeatedStringList(undefined);
+    assertUndefined(foo.getAString());
+    assertUndefined(foo.getABool());
+    assertUndefined(foo.getANestedMessage());
+    assertObjectEquals([], foo.getARepeatedMessageList());
+    assertObjectEquals([], foo.getARepeatedStringList());
+    expected = [,,, [], []];
+    expected[0] = expected[1] = expected[2] = undefined;
+    assertObjectEquals(expected, foo.toArray());
+  });
+
+  it('testDifferenceRawObject', function() {
+    var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
+    var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
+                                               {1000: 'unique'}]);
+    var diff = /** @type {proto.jspb.test.HasExtensions} */
+        (jspb.Message.difference(p1, p2));
+    assertUndefined(diff.getStr1());
+    assertEquals('what', diff.getStr2());
+    assertUndefined(diff.getStr3());
+    assertEquals('unique', diff.extensionObject_[1000]);
+  });
+
+  it('testEqualsSimple', function() {
+    var s1 = new proto.jspb.test.Simple1(['hi']);
+    assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
+    assertFalse(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['bye'])));
+    var s1b = new proto.jspb.test.Simple1(['hi', ['hello']]);
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', ['hello']])));
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', ['hello', undefined,
+                                            undefined, undefined]])));
+    assertFalse(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['no', ['hello']])));
+    // Test with messages of different types
+    var s2 = new proto.jspb.test.Simple2(['hi']);
+    assertFalse(jspb.Message.equals(s1, s2));
+  });
+
+  it('testEquals_softComparison', function() {
+    var s1 = new proto.jspb.test.Simple1(['hi', [], null]);
+    assertTrue(jspb.Message.equals(s1,
+        new proto.jspb.test.Simple1(['hi', []])));
+
+    var s1b = new proto.jspb.test.Simple1(['hi', [], true]);
+    assertTrue(jspb.Message.equals(s1b,
+        new proto.jspb.test.Simple1(['hi', [], 1])));
+  });
+
+  it('testEqualsComplex', function() {
+    var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1];
+    var data2 = ['a',,, [, 11], [[, 22], [, 34]],, ['s1', 's2'],, 1];
+    var data3 = ['a',,, [, 11], [[, 22]],, ['s1', 's2'],, 1];
+    var data4 = ['hi'];
+    var c1a = new proto.jspb.test.Complex(data1);
+    var c1b = new proto.jspb.test.Complex(data1);
+    var c2 = new proto.jspb.test.Complex(data2);
+    var c3 = new proto.jspb.test.Complex(data3);
+    var s1 = new proto.jspb.test.Simple1(data4);
+
+    assertTrue(jspb.Message.equals(c1a, c1b));
+    assertFalse(jspb.Message.equals(c1a, c2));
+    assertFalse(jspb.Message.equals(c2, c3));
+    assertFalse(jspb.Message.equals(c1a, s1));
+  });
+
+  it('testEqualsExtensionsConstructed', function() {
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([]),
+        new proto.jspb.test.HasExtensions([{}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
+    ));
+    assertFalse(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'b'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions([,,, {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions([{100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}])
+    ));
+    assertTrue(jspb.Message.equals(
+        new proto.jspb.test.HasExtensions(['hi',,, {100: [{200: 'a'}]}]),
+        new proto.jspb.test.HasExtensions(['hi', {100: [{200: 'a'}]}])
+    ));
+  });
+
+  it('testEqualsExtensionsUnconstructed', function() {
+    assertTrue(jspb.Message.compareFields([], [{}]));
+    assertTrue(jspb.Message.compareFields([,,, {}], []));
+    assertTrue(jspb.Message.compareFields([,,, {}], [,, {}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
+    assertFalse(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi', {100: [{200: 'b'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [{100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [{100: [{200: 'a'}]}], [,,, {100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        [,,, {100: [{200: 'a'}]}], [{100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi', {100: [{200: 'a'}]}], ['hi',,, {100: [{200: 'a'}]}]));
+    assertTrue(jspb.Message.compareFields(
+        ['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
+  });
+
+  it('testToMap', function() {
+    var p1 = new proto.jspb.test.Simple1(['k', ['v']]);
+    var p2 = new proto.jspb.test.Simple1(['k1', ['v1', 'v2']]);
+    var soymap = jspb.Message.toMap([p1, p2],
+        proto.jspb.test.Simple1.prototype.getAString,
+        proto.jspb.test.Simple1.prototype.toObject);
+    assertEquals('k', soymap['k'].aString);
+    assertArrayEquals(['v'], soymap['k'].aRepeatedStringList);
+    var protomap = jspb.Message.toMap([p1, p2],
+        proto.jspb.test.Simple1.prototype.getAString);
+    assertEquals('k', protomap['k'].getAString());
+    assertArrayEquals(['v'], protomap['k'].getARepeatedStringList());
+  });
+
+  it('testClone', function() {
+    var original = new proto.jspb.test.TestClone();
+    original.setStr('v1');
+    var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
+    var simple2 = new proto.jspb.test.Simple1(['x2', ['y2', 'z2']]);
+    var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
+    original.setSimple1(simple1);
+    original.setSimple2List([simple2, simple3]);
+    var extension = new proto.jspb.test.CloneExtension();
+    extension.setExt('e1');
+    original.setExtension(proto.jspb.test.IsExtension.extField, extension);
+    var clone = original.cloneMessage();
+    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+        clone.toArray());
+    clone.setStr('v2');
+    var simple4 = new proto.jspb.test.Simple1(['a1', ['b1', 'c1']]);
+    var simple5 = new proto.jspb.test.Simple1(['a2', ['b2', 'c2']]);
+    var simple6 = new proto.jspb.test.Simple1(['a3', ['b3', 'c3']]);
+    clone.setSimple1(simple4);
+    clone.setSimple2List([simple5, simple6]);
+    var newExtension = new proto.jspb.test.CloneExtension();
+    newExtension.setExt('e2');
+    clone.setExtension(proto.jspb.test.CloneExtension.extField, newExtension);
+    assertArrayEquals(['v2',, ['a1', ['b1', 'c1']],,
+      [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]],,, { 100: [, 'e2'] }],
+        clone.toArray());
+    assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+        original.toArray());
+  });
+
+  it('testCopyInto', function() {
+    var original = new proto.jspb.test.TestClone();
+    original.setStr('v1');
+    var dest = new proto.jspb.test.TestClone();
+    dest.setStr('override');
+    var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
+    var simple2 = new proto.jspb.test.Simple1(['x2', ['y2', 'z2']]);
+    var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
+    var destSimple1 = new proto.jspb.test.Simple1(['ox1', ['oy1', 'oz1']]);
+    var destSimple2 = new proto.jspb.test.Simple1(['ox2', ['oy2', 'oz2']]);
+    var destSimple3 = new proto.jspb.test.Simple1(['ox3', ['oy3', 'oz3']]);
+    original.setSimple1(simple1);
+    original.setSimple2List([simple2, simple3]);
+    dest.setSimple1(destSimple1);
+    dest.setSimple2List([destSimple2, destSimple3]);
+    var extension = new proto.jspb.test.CloneExtension();
+    extension.setExt('e1');
+    original.setExtension(proto.jspb.test.CloneExtension.extField, extension);
+
+    jspb.Message.copyInto(original, dest);
+    assertArrayEquals(original.toArray(), dest.toArray());
+    assertEquals('x1', dest.getSimple1().getAString());
+    assertEquals('e1',
+        dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt());
+    dest.getSimple1().setAString('new value');
+    assertNotEquals(dest.getSimple1().getAString(),
+        original.getSimple1().getAString());
+    dest.getExtension(proto.jspb.test.CloneExtension.extField).
+        setExt('new value');
+    assertNotEquals(
+        dest.getExtension(proto.jspb.test.CloneExtension.extField).getExt(),
+        original.getExtension(
+            proto.jspb.test.CloneExtension.extField).getExt());
+  });
+
+  it('testCopyInto_notSameType', function() {
+    var a = new proto.jspb.test.TestClone();
+    var b = new proto.jspb.test.Simple1(['str', ['s1', 's2']]);
+
+    var e = assertThrows(function() {
+      jspb.Message.copyInto(a, b);
+    });
+    assertContains('should have the same type', e.message);
+  });
+
+  it('testExtensions', function() {
+    var extension1 = new proto.jspb.test.IsExtension(['ext1field']);
+    var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2']]);
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
+                            extension2);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
+    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
+        ['a', 'b']);
+    var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
+    var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2']]);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList,
+        [s1, s2]);
+    assertObjectEquals(extension1,
+        extendable.getExtension(proto.jspb.test.IsExtension.extField));
+    assertObjectEquals(extension2,
+        extendable.getExtension(proto.jspb.test.IndirectExtension.simple));
+    assertObjectEquals('xyzzy',
+        extendable.getExtension(proto.jspb.test.IndirectExtension.str));
+    assertObjectEquals(['a', 'b'], extendable.getExtension(
+        proto.jspb.test.IndirectExtension.repeatedStrList));
+    assertObjectEquals([s1, s2], extendable.getExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList));
+    // Not supported yet, but it should work...
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple, null);
+    assertNull(
+        extendable.getExtension(proto.jspb.test.IndirectExtension.simple));
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, null);
+    assertNull(extendable.getExtension(proto.jspb.test.IndirectExtension.str));
+
+    // These assertions will only work properly in uncompiled mode.
+    // Extension fields defined on proto2 Descriptor messages are filtered out.
+
+    // TODO(haberman): codegen changes to properly ignore descriptor.proto
+    // extensions need to be merged from google3.
+    // assertUndefined(proto.jspb.test.IsExtension['simpleOption']);
+
+    // Extension fields with jspb.ignore = true are ignored.
+    assertUndefined(proto.jspb.test.IndirectExtension['ignored']);
+    assertUndefined(proto.jspb.test.HasExtensions['ignoredFloating']);
+  });
+
+  it('testFloatingExtensions', function() {
+    // From an autogenerated container.
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    var extension = new proto.jspb.test.Simple1(['foo', ['s1', 's2']]);
+    extendable.setExtension(proto.jspb.test.simple1, extension);
+    assertObjectEquals(extension,
+        extendable.getExtension(proto.jspb.test.simple1));
+
+    // From _lib mode.
+    extension = new proto.jspb.test.ExtensionMessage(['s1']);
+    extendable = new proto.jspb.test.TestExtensionsMessage([16]);
+    extendable.setExtension(proto.jspb.test.floatingMsgField, extension);
+    extendable.setExtension(proto.jspb.test.floatingStrField, 's2');
+    assertObjectEquals(extension,
+        extendable.getExtension(proto.jspb.test.floatingMsgField));
+    assertObjectEquals('s2',
+        extendable.getExtension(proto.jspb.test.floatingStrField));
+    assertNotUndefined(proto.jspb.exttest.floatingMsgField);
+    assertNotUndefined(proto.jspb.exttest.floatingMsgFieldTwo);
+    assertNotUndefined(proto.jspb.exttest.beta.floatingStrField);
+  });
+
+  it('testToObject_extendedObject', function() {
+    var extension1 = new proto.jspb.test.IsExtension(['ext1field']);
+    var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2'], true]);
+    var extendable = new proto.jspb.test.HasExtensions(['v1', 'v2', 'v3']);
+    extendable.setExtension(proto.jspb.test.IsExtension.extField, extension1);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.simple,
+                            extension2);
+    extendable.setExtension(proto.jspb.test.IndirectExtension.str, 'xyzzy');
+    extendable.setExtension(proto.jspb.test.IndirectExtension.repeatedStrList,
+        ['a', 'b']);
+    var s1 = new proto.jspb.test.Simple1(['foo', ['s1', 's2'], true]);
+    var s2 = new proto.jspb.test.Simple1(['bar', ['t1', 't2'], false]);
+    extendable.setExtension(
+        proto.jspb.test.IndirectExtension.repeatedSimpleList,
+        [s1, s2]);
+    assertObjectEquals({
+      str1: 'v1', str2: 'v2', str3: 'v3',
+      extField: { ext1: 'ext1field' },
+      simple: {
+        aString: 'str', aRepeatedStringList: ['s1', 's2'], aBoolean: true
+      },
+      str: 'xyzzy',
+      repeatedStrList: ['a', 'b'],
+      repeatedSimpleList: [
+        { aString: 'foo', aRepeatedStringList: ['s1', 's2'], aBoolean: true},
+        { aString: 'bar', aRepeatedStringList: ['t1', 't2'], aBoolean: false}
+      ]
+    }, extendable.toObject());
+
+    // Now, with instances included.
+    assertObjectEquals({
+      str1: 'v1', str2: 'v2', str3: 'v3',
+      extField: {
+        ext1: 'ext1field',
+        $jspbMessageInstance:
+            extendable.getExtension(proto.jspb.test.IsExtension.extField)
+      },
+      simple: {
+        aString: 'str',
+        aRepeatedStringList: ['s1', 's2'],
+        aBoolean: true,
+        $jspbMessageInstance:
+            extendable.getExtension(proto.jspb.test.IndirectExtension.simple)
+      },
+      str: 'xyzzy',
+      repeatedStrList: ['a', 'b'],
+      repeatedSimpleList: [{
+        aString: 'foo',
+        aRepeatedStringList: ['s1', 's2'],
+        aBoolean: true,
+        $jspbMessageInstance: s1
+      }, {
+        aString: 'bar',
+        aRepeatedStringList: ['t1', 't2'],
+        aBoolean: false,
+        $jspbMessageInstance: s2
+      }],
+      $jspbMessageInstance: extendable
+    }, extendable.toObject(true /* opt_includeInstance */));
+  });
+
+  it('testInitialization_emptyArray', function() {
+    var msg = new proto.jspb.test.HasExtensions([]);
+    if (jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS) {
+      assertArrayEquals([], msg.toArray());
+    } else {
+      // Extension object is created past all regular fields.
+      assertArrayEquals([,,, {}], msg.toArray());
+    }
+  });
+
+  it('testInitialization_justExtensionObject', function() {
+    var msg = new proto.jspb.test.Empty([{1: 'hi'}]);
+    // The extensionObject is not moved from its original location.
+    assertArrayEquals([{1: 'hi'}], msg.toArray());
+  });
+
+  it('testInitialization_incompleteList', function() {
+    var msg = new proto.jspb.test.Empty([1, {4: 'hi'}]);
+    // The extensionObject is not moved from its original location.
+    assertArrayEquals([1, {4: 'hi'}], msg.toArray());
+  });
+
+  it('testInitialization_forwardCompatible', function() {
+    var msg = new proto.jspb.test.Empty([1, 2, 3, {1: 'hi'}]);
+    assertArrayEquals([1, 2, 3, {1: 'hi'}], msg.toArray());
+  });
+
+  it('testExtendedMessageEnsureObject', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1',
+        {'a_key': 'an_object'}]);
+    assertEquals('an_object', data.extensionObject_['a_key']);
+  });
+
+  it('testToObject_hasExtensionField', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);
+    var obj = data.toObject();
+    assertEquals('str1', obj.str1);
+    assertEquals('ext1', obj.extField.ext1);
+  });
+
+  it('testGetExtension', function() {
+    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);
+    assertEquals('str1', data.getStr1());
+    var extension = data.getExtension(proto.jspb.test.IsExtension.extField);
+    assertNotNull(extension);
+    assertEquals('ext1', extension.getExt1());
+  });
+
+  it('testSetExtension', function() {
+    var data = new proto.jspb.test.HasExtensions();
+    var extensionMessage = new proto.jspb.test.IsExtension(['is_extension']);
+    data.setExtension(proto.jspb.test.IsExtension.extField, extensionMessage);
+    var obj = data.toObject();
+    assertNotNull(
+        data.getExtension(proto.jspb.test.IsExtension.extField));
+    assertEquals('is_extension', obj.extField.ext1);
+  });
+
+  /**
+   * Note that group is long deprecated, we only support it because JsPb has
+   * a goal of being able to generate JS classes for all proto descriptors.
+   */
+  it('testGroups', function() {
+    var group = new proto.jspb.test.TestGroup();
+    var someGroup = new proto.jspb.test.TestGroup.RepeatedGroup();
+    someGroup.setId('g1');
+    someGroup.setSomeBoolList([true, false]);
+    group.setRepeatedGroupList([someGroup]);
+    var groups = group.getRepeatedGroupList();
+    assertEquals('g1', groups[0].getId());
+    assertObjectEquals([true, false], groups[0].getSomeBoolList());
+    assertObjectEquals({id: 'g1', someBoolList: [true, false]},
+        groups[0].toObject());
+    assertObjectEquals({
+      repeatedGroupList: [{id: 'g1', someBoolList: [true, false]}],
+      requiredGroup: {id: undefined},
+      optionalGroup: undefined,
+      requiredSimple: {aRepeatedStringList: [], aString: undefined},
+      optionalSimple: undefined,
+      id: undefined
+    }, group.toObject());
+    var group1 = new proto.jspb.test.TestGroup1();
+    group1.setGroup(someGroup);
+    assertEquals(someGroup, group1.getGroup());
+  });
+
+  it('testNonExtensionFieldsAfterExtensionRange', function() {
+    var data = [{'1': 'a_string'}];
+    var message = new proto.jspb.test.Complex(data);
+    assertArrayEquals([], message.getARepeatedStringList());
+  });
+
+  it('testReservedGetterNames', function() {
+    var message = new proto.jspb.test.TestReservedNames();
+    message.setExtension$(11);
+    message.setExtension(proto.jspb.test.TestReservedNamesExtension.foo, 12);
+    assertEquals(11, message.getExtension$());
+    assertEquals(12, message.getExtension(
+        proto.jspb.test.TestReservedNamesExtension.foo));
+    assertObjectEquals({extension: 11, foo: 12}, message.toObject());
+  });
+
+  it('testInitializeMessageWithUnsetOneof', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([]);
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
+            RECURSIVE_ONEOF_NOT_SET,
+        message.getRecursiveOneofCase());
+  });
+
+  it('testInitializeMessageWithSingleValueSetInOneof', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
+
+    assertEquals('x', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+  });
+
+  it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
+
+    assertUndefined('x', message.getPone());
+    assertEquals('y', message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
+        message.getPartialOneofCase());
+  });
+
+  it('testSettingOneofFieldClearsOthers', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getPone());
+    assertUndefined(message.getPthree());
+
+    message.setPone('hi');
+    assertEquals('hi', message.getPone());
+    assertUndefined(message.getPthree());
+
+    message.setPthree('bye');
+    assertUndefined(message.getPone());
+    assertEquals('bye', message.getPthree());
+  });
+
+  it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
+    var other = new proto.jspb.test.TestMessageWithOneof;
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getPone());
+    assertUndefined(message.getPthree());
+    assertUndefined(message.getRone());
+
+    message.setPone('hi');
+    message.setRone(other);
+    assertEquals('hi', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(other, message.getRone());
+
+    message.setPthree('bye');
+    assertUndefined(message.getPone());
+    assertEquals('bye', message.getPthree());
+    assertEquals(other, message.getRone());
+  });
+
+  it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+
+    message.setPone('hi');
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+
+    message.clearPone();
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.
+            PARTIAL_ONEOF_NOT_SET,
+        message.getPartialOneofCase());
+  });
+
+  it('testMessageWithDefaultOneofValues', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(1234, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
+            .DEFAULT_ONEOF_A_NOT_SET,
+        message.getDefaultOneofACase());
+
+    message.setAone(567);
+    assertEquals(567, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
+        message.getDefaultOneofACase());
+
+    message.setAtwo(890);
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+
+    message.clearAtwo();
+    assertEquals(1234, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
+            .DEFAULT_ONEOF_A_NOT_SET,
+        message.getDefaultOneofACase());
+  });
+
+  it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertUndefined(message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
+            .DEFAULT_ONEOF_B_NOT_SET,
+        message.getDefaultOneofBCase());
+
+    message.setBone(2);
+    assertEquals(2, message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
+        message.getDefaultOneofBCase());
+
+    message.setBtwo(3);
+    assertUndefined(message.getBone());
+    assertEquals(3, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+        message.getDefaultOneofBCase());
+
+    message.clearBtwo();
+    assertUndefined(message.getBone());
+    assertEquals(1234, message.getBtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
+            .DEFAULT_ONEOF_B_NOT_SET,
+        message.getDefaultOneofBCase());
+  });
+
+  it('testInitializeMessageWithOneofDefaults', function() {
+    var message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567));
+    assertEquals(567, message.getAone());
+    assertUndefined(message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
+        message.getDefaultOneofACase());
+
+    message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(10).concat(890));
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+
+    message =
+        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567,890));
+    assertEquals(1234, message.getAone());
+    assertEquals(890, message.getAtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
+        message.getDefaultOneofACase());
+  });
+
+  it('testInitializeMessageWithOneofDefaults_defaultNotSetOnFirstField',
+      function() {
+        var message;
+
+        message =
+            new proto.jspb.test.TestMessageWithOneof(new Array(11).concat(567));
+        assertEquals(567, message.getBone());
+        assertEquals(1234, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
+            message.getDefaultOneofBCase());
+
+        message =
+            new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890));
+        assertUndefined(message.getBone());
+        assertEquals(890, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+            message.getDefaultOneofBCase());
+
+        message = new proto.jspb.test.TestMessageWithOneof(
+            new Array(11).concat(567,890));
+        assertUndefined(message.getBone());
+        assertEquals(890, message.getBtwo());
+        assertEquals(
+            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
+            message.getDefaultOneofBCase());
+      });
+
+  it('testOneofContainingAnotherMessage', function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
+            RECURSIVE_ONEOF_NOT_SET,
+        message.getRecursiveOneofCase());
+
+    var other = new proto.jspb.test.TestMessageWithOneof;
+    message.setRone(other);
+    assertEquals(other, message.getRone());
+    assertUndefined(message.getRtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
+        message.getRecursiveOneofCase());
+
+    message.setRtwo('hi');
+    assertUndefined(message.getRone());
+    assertEquals('hi', message.getRtwo());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RTWO,
+        message.getRecursiveOneofCase());
+  });
+
+  it('testQueryingOneofCaseEnsuresOnlyOneFieldIsSetInUnderlyingArray',
+     function() {
+    var message = new proto.jspb.test.TestMessageWithOneof;
+    message.setPone('x');
+    assertEquals('x', message.getPone());
+    assertUndefined(message.getPthree());
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
+        message.getPartialOneofCase());
+
+    var array = message.toArray();
+    assertEquals('x', array[2]);
+    assertUndefined(array[4]);
+    array[4] = 'y';
+
+    assertEquals(
+        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
+        message.getPartialOneofCase());
+    assertUndefined(array[2]);
+    assertEquals('y', array[4]);
+  });
+
+});
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/node_loader.js
similarity index 78%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/node_loader.js
index cb6ca1b..79211ad 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/node_loader.js
@@ -28,16 +28,22 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
+/**
+ * @fileoverview Loader that handles goog.require() for Node.JS.
+ */
 
-package protobuf_unittest;
+var oldLoader = goog.global.CLOSURE_IMPORT_SCRIPT;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
+goog.global.CLOSURE_IMPORT_SCRIPT = function(src, opt_sourceText) {
+  if (opt_sourceText === undefined) {
+    try {
+      // Load from the current directory.
+      require("./" + src);
+      return true;
+    } catch (e) {
+      // Fall back to the Closure loader.
+    }
   }
-}
+
+  return oldLoader(src, opt_sourceText);
+};
diff --git a/js/package.json b/js/package.json
new file mode 100644
index 0000000..6418e50
--- /dev/null
+++ b/js/package.json
@@ -0,0 +1,24 @@
+{
+  "name": "google-protobuf",
+  "version": "3.0.0-alpha.5",
+  "description": "Protocol Buffers for JavaScript",
+  "main": "google-protobuf.js",
+  "dependencies": {
+    "google-closure-library": "~20160125.0.0",
+    "gulp": "~3.9.0",
+    "jasmine": "~2.4.1"
+  },
+  "devDependencies": {
+    "google-closure-compiler": "~20151216.2.0",
+    "glob": "~6.0.4"
+  },
+  "scripts": {
+    "test": "./node_modules/gulp/bin/gulp.js test"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/google/protobuf/tree/master/js"
+  },
+  "author": "",
+  "license": "Apache-2.0"
+}
diff --git a/js/proto3_test.js b/js/proto3_test.js
new file mode 100644
index 0000000..f886871
--- /dev/null
+++ b/js/proto3_test.js
@@ -0,0 +1,283 @@
+// 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.
+
+goog.require('goog.testing.asserts');
+
+// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
+goog.require('proto.jspb.test.ForeignMessage');
+
+// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
+goog.require('proto.jspb.test.Proto3Enum');
+goog.require('proto.jspb.test.TestProto3');
+
+/**
+ * Helper: compare a bytes field to a string with codepoints 0--255.
+ * @param {Uint8Array|string} arr
+ * @param {string} str
+ * @return {boolean}
+ */
+function bytesCompare(arr, str) {
+  if (arr.length != str.length) {
+    return false;
+  }
+  if (typeof arr == 'string') {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr.charCodeAt(i) != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    for (var i = 0; i < arr.length; i++) {
+      if (arr[i] != str.charCodeAt(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+
+describe('proto3Test', function() {
+  /**
+   * Test defaults for proto3 message fields.
+   */
+  it('testProto3FieldDefaults', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    assertEquals(msg.getOptionalInt32(), 0);
+    assertEquals(msg.getOptionalInt64(), 0);
+    assertEquals(msg.getOptionalUint32(), 0);
+    assertEquals(msg.getOptionalUint64(), 0);
+    assertEquals(msg.getOptionalSint32(), 0);
+    assertEquals(msg.getOptionalSint64(), 0);
+    assertEquals(msg.getOptionalFixed32(), 0);
+    assertEquals(msg.getOptionalFixed64(), 0);
+    assertEquals(msg.getOptionalSfixed32(), 0);
+    assertEquals(msg.getOptionalSfixed64(), 0);
+    assertEquals(msg.getOptionalFloat(), 0);
+    assertEquals(msg.getOptionalDouble(), 0);
+    assertEquals(msg.getOptionalString(), '');
+
+    // If/when we change bytes fields to return Uint8Array, we'll want to switch
+    // to this assertion instead:
+    //assertEquals(msg.getOptionalBytes() instanceof Uint8Array, true);
+    assertEquals(typeof msg.getOptionalBytes(), 'string');
+
+    assertEquals(msg.getOptionalBytes().length, 0);
+    assertEquals(msg.getOptionalForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_FOO);
+    assertEquals(msg.getOptionalForeignMessage(), undefined);
+    assertEquals(msg.getOptionalForeignMessage(), undefined);
+
+    assertEquals(msg.getRepeatedInt32List().length, 0);
+    assertEquals(msg.getRepeatedInt64List().length, 0);
+    assertEquals(msg.getRepeatedUint32List().length, 0);
+    assertEquals(msg.getRepeatedUint64List().length, 0);
+    assertEquals(msg.getRepeatedSint32List().length, 0);
+    assertEquals(msg.getRepeatedSint64List().length, 0);
+    assertEquals(msg.getRepeatedFixed32List().length, 0);
+    assertEquals(msg.getRepeatedFixed64List().length, 0);
+    assertEquals(msg.getRepeatedSfixed32List().length, 0);
+    assertEquals(msg.getRepeatedSfixed64List().length, 0);
+    assertEquals(msg.getRepeatedFloatList().length, 0);
+    assertEquals(msg.getRepeatedDoubleList().length, 0);
+    assertEquals(msg.getRepeatedStringList().length, 0);
+    assertEquals(msg.getRepeatedBytesList().length, 0);
+    assertEquals(msg.getRepeatedForeignEnumList().length, 0);
+    assertEquals(msg.getRepeatedForeignMessageList().length, 0);
+
+  });
+
+
+  /**
+   * Test that all fields can be set and read via a serialization roundtrip.
+   */
+  it('testProto3FieldSetGet', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    msg.setOptionalInt32(-42);
+    msg.setOptionalInt64(-0x7fffffff00000000);
+    msg.setOptionalUint32(0x80000000);
+    msg.setOptionalUint64(0xf000000000000000);
+    msg.setOptionalSint32(-100);
+    msg.setOptionalSint64(-0x8000000000000000);
+    msg.setOptionalFixed32(1234);
+    msg.setOptionalFixed64(0x1234567800000000);
+    msg.setOptionalSfixed32(-1234);
+    msg.setOptionalSfixed64(-0x1234567800000000);
+    msg.setOptionalFloat(1.5);
+    msg.setOptionalDouble(-1.5);
+    msg.setOptionalBool(true);
+    msg.setOptionalString('hello world');
+    msg.setOptionalBytes('bytes');
+    var submsg = new proto.jspb.test.ForeignMessage();
+    submsg.setC(16);
+    msg.setOptionalForeignMessage(submsg);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
+
+    msg.setRepeatedInt32List([-42]);
+    msg.setRepeatedInt64List([-0x7fffffff00000000]);
+    msg.setRepeatedUint32List([0x80000000]);
+    msg.setRepeatedUint64List([0xf000000000000000]);
+    msg.setRepeatedSint32List([-100]);
+    msg.setRepeatedSint64List([-0x8000000000000000]);
+    msg.setRepeatedFixed32List([1234]);
+    msg.setRepeatedFixed64List([0x1234567800000000]);
+    msg.setRepeatedSfixed32List([-1234]);
+    msg.setRepeatedSfixed64List([-0x1234567800000000]);
+    msg.setRepeatedFloatList([1.5]);
+    msg.setRepeatedDoubleList([-1.5]);
+    msg.setRepeatedBoolList([true]);
+    msg.setRepeatedStringList(['hello world']);
+    msg.setRepeatedBytesList(['bytes']);
+    submsg = new proto.jspb.test.ForeignMessage();
+    submsg.setC(1000);
+    msg.setRepeatedForeignMessageList([submsg]);
+    msg.setRepeatedForeignEnumList([proto.jspb.test.Proto3Enum.PROTO3_BAR]);
+
+    msg.setOneofString('asdf');
+
+    var serialized = msg.serializeBinary();
+    msg = proto.jspb.test.TestProto3.deserializeBinary(serialized);
+
+    assertEquals(msg.getOptionalInt32(), -42);
+    assertEquals(msg.getOptionalInt64(), -0x7fffffff00000000);
+    assertEquals(msg.getOptionalUint32(), 0x80000000);
+    assertEquals(msg.getOptionalUint64(), 0xf000000000000000);
+    assertEquals(msg.getOptionalSint32(), -100);
+    assertEquals(msg.getOptionalSint64(), -0x8000000000000000);
+    assertEquals(msg.getOptionalFixed32(), 1234);
+    assertEquals(msg.getOptionalFixed64(), 0x1234567800000000);
+    assertEquals(msg.getOptionalSfixed32(), -1234);
+    assertEquals(msg.getOptionalSfixed64(), -0x1234567800000000);
+    assertEquals(msg.getOptionalFloat(), 1.5);
+    assertEquals(msg.getOptionalDouble(), -1.5);
+    assertEquals(msg.getOptionalBool(), true);
+    assertEquals(msg.getOptionalString(), 'hello world');
+    assertEquals(true, bytesCompare(msg.getOptionalBytes(), 'bytes'));
+    assertEquals(msg.getOptionalForeignMessage().getC(), 16);
+    assertEquals(msg.getOptionalForeignEnum(),
+        proto.jspb.test.Proto3Enum.PROTO3_BAR);
+
+    assertElementsEquals(msg.getRepeatedInt32List(), [-42]);
+    assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]);
+    assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]);
+    assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]);
+    assertElementsEquals(msg.getRepeatedSint32List(), [-100]);
+    assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]);
+    assertElementsEquals(msg.getRepeatedFixed32List(), [1234]);
+    assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]);
+    assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]);
+    assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]);
+    assertElementsEquals(msg.getRepeatedFloatList(), [1.5]);
+    assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]);
+    assertElementsEquals(msg.getRepeatedBoolList(), [true]);
+    assertElementsEquals(msg.getRepeatedStringList(), ['hello world']);
+    assertEquals(msg.getRepeatedBytesList().length, 1);
+    assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], 'bytes'));
+    assertEquals(msg.getRepeatedForeignMessageList().length, 1);
+    assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
+    assertElementsEquals(msg.getRepeatedForeignEnumList(),
+        [proto.jspb.test.Proto3Enum.PROTO3_BAR]);
+
+    assertEquals(msg.getOneofString(), 'asdf');
+  });
+
+
+  /**
+   * Test that oneofs continue to have a notion of field presence.
+   */
+  it('testOneofs', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofUint32(42);
+    assertEquals(msg.getOneofUint32(), 42);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+
+    var submsg = new proto.jspb.test.ForeignMessage();
+    msg.setOneofForeignMessage(submsg);
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), submsg);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofString('hello');
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), 'hello');
+    assertEquals(msg.getOneofBytes(), undefined);
+
+    msg.setOneofBytes('\u00FF\u00FF');
+    assertEquals(msg.getOneofUint32(), undefined);
+    assertEquals(msg.getOneofForeignMessage(), undefined);
+    assertEquals(msg.getOneofString(), undefined);
+    assertEquals(msg.getOneofBytes(), '\u00FF\u00FF');
+  });
+
+
+  /**
+   * Test that "default"-valued primitive fields are not emitted on the wire.
+   */
+  it('testNoSerializeDefaults', function() {
+    var msg = new proto.jspb.test.TestProto3();
+
+    // Set each primitive to a non-default value, then back to its default, to
+    // ensure that the serialization is actually checking the value and not just
+    // whether it has ever been set.
+    msg.setOptionalInt32(42);
+    msg.setOptionalInt32(0);
+    msg.setOptionalDouble(3.14);
+    msg.setOptionalDouble(0.0);
+    msg.setOptionalBool(true);
+    msg.setOptionalBool(false);
+    msg.setOptionalString('hello world');
+    msg.setOptionalString('');
+    msg.setOptionalBytes('\u00FF\u00FF');
+    msg.setOptionalBytes('');
+    msg.setOptionalForeignMessage(new proto.jspb.test.ForeignMessage());
+    msg.setOptionalForeignMessage(null);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
+    msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO);
+    msg.setOneofUint32(32);
+    msg.setOneofUint32(null);
+
+
+    var serialized = msg.serializeBinary();
+    assertEquals(0, serialized.length);
+  });
+});
diff --git a/js/proto3_test.proto b/js/proto3_test.proto
new file mode 100644
index 0000000..acb6716
--- /dev/null
+++ b/js/proto3_test.proto
@@ -0,0 +1,89 @@
+// 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.
+
+syntax = "proto3";
+
+import "testbinary.proto";
+
+package jspb.test;
+
+message TestProto3 {
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
+
+  ForeignMessage optional_foreign_message = 19;
+  Proto3Enum     optional_foreign_enum    = 22;
+
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated Proto3Enum     repeated_foreign_enum    = 52;
+
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    ForeignMessage oneof_foreign_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+}
+
+enum Proto3Enum {
+  PROTO3_FOO = 0;
+  PROTO3_BAR = 1;
+  PROTO3_BAZ = 2;
+}
diff --git a/js/test.proto b/js/test.proto
new file mode 100644
index 0000000..3cea5f3
--- /dev/null
+++ b/js/test.proto
@@ -0,0 +1,219 @@
+// 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.
+
+// Author: mwr@google.com (Mark Rawling)
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+import "google/protobuf/descriptor.proto";
+
+package jspb.test;
+
+message Empty {
+}
+
+enum OuterEnum {
+  FOO = 1;
+  BAR = 2;
+}
+
+message EnumContainer {
+  optional OuterEnum outer_enum = 1;
+}
+
+message Simple1 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+  optional bool a_boolean = 3;
+}
+
+// A message that differs from Simple1 only by name
+message Simple2 {
+  required string a_string = 1;
+  repeated string a_repeated_string = 2;
+}
+
+message SpecialCases {
+  required string normal = 1;
+  // Examples of Js reserved names that are converted to pb_<name>.
+  required string default = 2;
+  required string function = 3;
+  required string var = 4;
+}
+
+message OptionalFields {
+  message Nested {
+    optional int32 an_int = 1;
+  }
+  optional string a_string = 1;
+  required bool a_bool = 2;
+  optional Nested a_nested_message = 3;
+  repeated Nested a_repeated_message = 4;
+  repeated string a_repeated_string = 5;
+}
+
+message HasExtensions {
+  optional string str1 = 1;
+  optional string str2 = 2;
+  optional string str3 = 3;
+  extensions 10 to max;
+}
+
+message Complex {
+  message Nested {
+    required int32 an_int = 2;
+  }
+  required string a_string = 1;
+  required bool an_out_of_order_bool = 9;
+  optional Nested a_nested_message = 4;
+  repeated Nested a_repeated_message = 5;
+  repeated string a_repeated_string = 7;
+}
+
+message OuterMessage {
+  // Make sure this doesn't conflict with the other Complex message.
+  message Complex {
+    optional int32 inner_complex_field = 1;
+  }
+}
+
+message IsExtension {
+  extend HasExtensions {
+    optional IsExtension ext_field = 100;
+  }
+  optional string ext1 = 1;
+
+  // Extensions of proto2 Descriptor messages will be ignored.
+  extend google.protobuf.EnumOptions {
+    optional string simple_option = 42113038;
+  }
+}
+
+message IndirectExtension {
+  extend HasExtensions {
+    optional Simple1 simple = 101;
+    optional string str = 102;
+    repeated string repeated_str = 103;
+    repeated Simple1 repeated_simple = 104;
+  }
+}
+
+extend HasExtensions {
+  optional Simple1 simple1 = 105;
+}
+
+message DefaultValues {
+  enum Enum {
+    E1 = 13;
+    E2 = 77;
+  }
+  optional string string_field = 1 [default="default<>\'\"abc"];
+  optional bool bool_field = 2 [default=true];
+  optional int64 int_field = 3 [default=11];
+  optional Enum enum_field = 4 [default=E1];
+  optional string empty_field = 6 [default=""];
+  optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v"
+}
+
+message TestClone {
+  optional string str = 1;
+  optional Simple1 simple1 = 3;
+  repeated Simple1 simple2 = 5;
+  optional string unused = 7;
+  extensions 10 to max;
+}
+
+message CloneExtension {
+  extend TestClone {
+    optional CloneExtension ext_field = 100;
+  }
+  optional string ext = 2;
+}
+
+message TestGroup {
+  repeated group RepeatedGroup = 1 {
+    required string id = 1;
+    repeated bool some_bool = 2;
+  }
+  required group RequiredGroup = 2 {
+    required string id = 1;
+  }
+  optional group OptionalGroup = 3 {
+    required string id = 1;
+  }
+  optional string id = 4;
+  required Simple2 required_simple = 5;
+  optional Simple2 optional_simple = 6;
+}
+
+message TestGroup1 {
+  optional TestGroup.RepeatedGroup group = 1;
+}
+
+message TestReservedNames {
+  optional int32 extension = 1;
+  extensions 10 to max;
+}
+
+message TestReservedNamesExtension {
+  extend TestReservedNames {
+    optional int32 foo = 10;
+  }
+}
+
+message TestMessageWithOneof {
+
+  oneof partial_oneof {
+    string pone = 3;
+    string pthree = 5;
+  }
+
+  oneof recursive_oneof {
+    TestMessageWithOneof rone = 6;
+    string rtwo = 7;
+  }
+
+  optional bool normal_field = 8;
+  repeated string repeated_field = 9;
+
+  oneof default_oneof_a {
+    int32 aone = 10 [default = 1234];
+    int32 atwo = 11;
+  }
+
+  oneof default_oneof_b {
+    int32 bone = 12;
+    int32 btwo = 13 [default = 1234];
+  }
+}
+
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/test2.proto
similarity index 75%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/test2.proto
index cb6ca1b..44e55ef 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/test2.proto
@@ -28,16 +28,27 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
 syntax = "proto2";
 
-package protobuf_unittest;
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
+package jspb.test;
+
+message TestExtensionsMessage {
+  optional int32 intfield = 1;
+  extensions 100 to max;
+}
+
+message ExtensionMessage {
+  extend TestExtensionsMessage {
+    optional ExtensionMessage ext_field = 100;
   }
+  optional string ext1 = 1;
+}
+
+// Floating extensions are only supported when generating a _lib.js library.
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field = 101;
+  optional string floating_str_field = 102;
 }
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/test3.proto
similarity index 77%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/test3.proto
index cb6ca1b..940a552 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/test3.proto
@@ -28,16 +28,26 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
 syntax = "proto2";
 
-package protobuf_unittest;
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
+package jspb.exttest;
+
+message TestExtensionsMessage {
+  optional int32 intfield = 1;
+  extensions 100 to max;
+}
+
+message ExtensionMessage {
+  extend TestExtensionsMessage {
+    optional ExtensionMessage ext_field = 100;
   }
+  optional string ext1 = 1;
+}
+
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field = 101;
+  optional string floating_str_field = 102;
 }
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/test4.proto
similarity index 83%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/test4.proto
index cb6ca1b..cf2451e 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/test4.proto
@@ -28,16 +28,15 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
 syntax = "proto2";
 
-package protobuf_unittest;
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
+package jspb.exttest;
+
+import "test3.proto";
+
+extend TestExtensionsMessage {
+  optional ExtensionMessage floating_msg_field_two = 103;
 }
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/test5.proto
similarity index 83%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/test5.proto
index cb6ca1b..3497951 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/test5.proto
@@ -28,16 +28,17 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
 syntax = "proto2";
 
-package protobuf_unittest;
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
+package jspb.exttest.beta;
+
+message TestBetaExtensionsMessage {
+  extensions 100 to max;
+}
+
+extend TestBetaExtensionsMessage {
+  optional string floating_str_field = 101;
 }
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/test_bootstrap.js
similarity index 82%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to js/test_bootstrap.js
index cb6ca1b..9d00a1c 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/test_bootstrap.js
@@ -28,16 +28,14 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
+/**
+ * @fileoverview Sets flags for uncompiled JSUnit tests.
+ */
 
-package protobuf_unittest;
-
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
-}
+/**
+ * Set uncompiled flags.
+ */
+var CLOSURE_DEFINES = {
+    // Enable the fromObject method on the message class.
+    'jspb.Message.GENERATE_FROM_OBJECT': true
+};
diff --git a/js/testbinary.proto b/js/testbinary.proto
new file mode 100644
index 0000000..60c7019
--- /dev/null
+++ b/js/testbinary.proto
@@ -0,0 +1,185 @@
+// 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.
+
+// LINT: ALLOW_GROUPS
+
+syntax = "proto2";
+
+
+package jspb.test;
+
+// These types are borrowed from `unittest.proto` in the protobuf tree. We want
+// to ensure that the binary-format support will handle all field types
+// properly.
+message TestAllTypes {
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional ForeignMessage                       optional_foreign_message = 19;
+  optional ForeignEnum                          optional_foreign_enum    = 22;
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated ForeignMessage                       repeated_foreign_message = 49;
+  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+
+  // Packed repeated
+  repeated    int32 packed_repeated_int32    = 61 [packed=true];
+  repeated    int64 packed_repeated_int64    = 62 [packed=true];
+  repeated   uint32 packed_repeated_uint32   = 63 [packed=true];
+  repeated   uint64 packed_repeated_uint64   = 64 [packed=true];
+  repeated   sint32 packed_repeated_sint32   = 65 [packed=true];
+  repeated   sint64 packed_repeated_sint64   = 66 [packed=true];
+  repeated  fixed32 packed_repeated_fixed32  = 67 [packed=true];
+  repeated  fixed64 packed_repeated_fixed64  = 68 [packed=true];
+  repeated sfixed32 packed_repeated_sfixed32 = 69 [packed=true];
+  repeated sfixed64 packed_repeated_sfixed64 = 70 [packed=true];
+  repeated    float packed_repeated_float    = 71 [packed=true];
+  repeated   double packed_repeated_double   = 72 [packed=true];
+  repeated     bool packed_repeated_bool     = 73 [packed=true];
+
+  oneof oneof_field {
+    uint32 oneof_uint32 = 111;
+    ForeignMessage oneof_foreign_message = 112;
+    string oneof_string = 113;
+    bytes oneof_bytes = 114;
+  }
+
+}
+
+message ForeignMessage {
+  optional int32 c = 1;
+}
+
+enum ForeignEnum {
+  FOREIGN_FOO = 4;
+  FOREIGN_BAR = 5;
+  FOREIGN_BAZ = 6;
+}
+
+message TestExtendable {
+  extensions 1 to max;
+}
+
+message ExtendsWithMessage {
+  extend TestExtendable {
+    optional ExtendsWithMessage optional_extension = 19;
+    repeated ExtendsWithMessage repeated_extension = 49;
+  }
+  optional int32 foo = 1;
+}
+
+extend TestExtendable {
+  optional    int32 extend_optional_int32    =  1;
+  optional    int64 extend_optional_int64    =  2;
+  optional   uint32 extend_optional_uint32   =  3;
+  optional   uint64 extend_optional_uint64   =  4;
+  optional   sint32 extend_optional_sint32   =  5;
+  optional   sint64 extend_optional_sint64   =  6;
+  optional  fixed32 extend_optional_fixed32  =  7;
+  optional  fixed64 extend_optional_fixed64  =  8;
+  optional sfixed32 extend_optional_sfixed32 =  9;
+  optional sfixed64 extend_optional_sfixed64 = 10;
+  optional    float extend_optional_float    = 11;
+  optional   double extend_optional_double   = 12;
+  optional     bool extend_optional_bool     = 13;
+  optional   string extend_optional_string   = 14;
+  optional    bytes extend_optional_bytes    = 15;
+  optional ForeignEnum extend_optional_foreign_enum    = 22;
+
+  repeated    int32 extend_repeated_int32    = 31;
+  repeated    int64 extend_repeated_int64    = 32;
+  repeated   uint32 extend_repeated_uint32   = 33;
+  repeated   uint64 extend_repeated_uint64   = 34;
+  repeated   sint32 extend_repeated_sint32   = 35;
+  repeated   sint64 extend_repeated_sint64   = 36;
+  repeated  fixed32 extend_repeated_fixed32  = 37;
+  repeated  fixed64 extend_repeated_fixed64  = 38;
+  repeated sfixed32 extend_repeated_sfixed32 = 39;
+  repeated sfixed64 extend_repeated_sfixed64 = 40;
+  repeated    float extend_repeated_float    = 41;
+  repeated   double extend_repeated_double   = 42;
+  repeated     bool extend_repeated_bool     = 43;
+  repeated   string extend_repeated_string   = 44;
+  repeated    bytes extend_repeated_bytes    = 45;
+  repeated ForeignEnum extend_repeated_foreign_enum    = 52;
+
+  repeated    int32 extend_packed_repeated_int32    = 61 [packed=true];
+  repeated    int64 extend_packed_repeated_int64    = 62 [packed=true];
+  repeated   uint32 extend_packed_repeated_uint32   = 63 [packed=true];
+  repeated   uint64 extend_packed_repeated_uint64   = 64 [packed=true];
+  repeated   sint32 extend_packed_repeated_sint32   = 65 [packed=true];
+  repeated   sint64 extend_packed_repeated_sint64   = 66 [packed=true];
+  repeated  fixed32 extend_packed_repeated_fixed32  = 67 [packed=true];
+  repeated  fixed64 extend_packed_repeated_fixed64  = 68 [packed=true];
+  repeated sfixed32 extend_packed_repeated_sfixed32 = 69 [packed=true];
+  repeated sfixed64 extend_packed_repeated_sfixed64 = 70 [packed=true];
+  repeated    float extend_packed_repeated_float    = 71 [packed=true];
+  repeated   double extend_packed_repeated_double   = 72 [packed=true];
+  repeated     bool extend_packed_repeated_bool     = 73 [packed=true];
+  repeated ForeignEnum extend_packed_repeated_foreign_enum    = 82
+      [packed=true];
+
+}
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/js/testempty.proto
similarity index 83%
rename from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
rename to js/testempty.proto
index cb6ca1b..960bce4 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/js/testempty.proto
@@ -28,16 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
 syntax = "proto2";
 
-package protobuf_unittest;
+package javatests.com.google.apps.jspb;
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
-}
diff --git a/m4/acx_check_suncc.m4 b/m4/acx_check_suncc.m4
index 8918593..8bc0a89 100644
--- a/m4/acx_check_suncc.m4
+++ b/m4/acx_check_suncc.m4
@@ -42,7 +42,6 @@
 
         AS_IF([test "x$ac_enable_64bit" = "xyes"],[
 
-          AC_DEFINE([SOLARIS_64BIT_ENABLED], [1], [64bit enabled])
           AS_IF([test "x$libdir" = "x\${exec_prefix}/lib"],[
            dnl The user hasn't overridden the default libdir, so we'll
            dnl the dir suffix to match solaris 32/64-bit policy
@@ -52,17 +51,13 @@
           dnl This should just be set in CPPFLAGS and in LDFLAGS, but libtool
           dnl does the wrong thing if you don't put it into CXXFLAGS. sigh.
           dnl (It also needs it in CFLAGS, or it does a different wrong thing!)
-          AS_IF([test "x${ac_cv_env_CXXFLAGS_set}" = "x"],[
-            CXXFLAGS="${CXXFLAGS} -m64"
-            ac_cv_env_CXXFLAGS_set=set
-            ac_cv_env_CXXFLAGS_value='-m64'
-          ])
+          CXXFLAGS="${CXXFLAGS} -m64"
+          ac_cv_env_CXXFLAGS_set=set
+          ac_cv_env_CXXFLAGS_value='-m64'
 
-          AS_IF([test "x${ac_cv_env_CFLAGS_set}" = "x"],[
-            CFLAGS="${CFLAGS} -m64"
-            ac_cv_env_CFLAGS_set=set
-            ac_cv_env_CFLAGS_value='-m64'
-          ])
+          CFLAGS="${CFLAGS} -m64"
+          ac_cv_env_CFLAGS_set=set
+          ac_cv_env_CFLAGS_value='-m64'
 
           AS_IF([test "$target_cpu" = "sparc" -a "x$SUNCC" = "xyes" ],[
             CXXFLAGS="-xmemalign=8s ${CXXFLAGS}"
diff --git a/m4/stl_hash.m4 b/m4/stl_hash.m4
index 0722b14..d7def1a 100644
--- a/m4/stl_hash.m4
+++ b/m4/stl_hash.m4
@@ -4,8 +4,7 @@
 # include AC_TRY_COMPILE for all the combinations we've seen in the
 # wild.  We define HASH_MAP_H to the location of the header file, and
 # HASH_NAMESPACE to the namespace the class (unordered_map or
-# hash_map) is in.  We define HAVE_UNORDERED_MAP if the class we found
-# is named unordered_map, or leave it undefined if not.
+# hash_map) is in.
 
 # This also checks if unordered map exists.
 AC_DEFUN([AC_CXX_STL_HASH],
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
index 2192b76..c8681e2 100755
--- a/objectivec/DevTools/full_mac_build.sh
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -26,16 +26,20 @@
          Issue a clean before the normal build.
    -a, --autogen
          Start by rerunning autogen & configure.
-   -r, --regenerate-descriptors
+   -r, --regenerate-cpp-descriptors
          The descriptor.proto is checked in generated, cause it to regenerate.
    -j #, --jobs #
          Force the number of parallel jobs (useful for debugging build issues).
+   --core-only
+         Skip some of the core protobuf build/checks to shorten the build time.
    --skip-xcode
          Skip the invoke of Xcode to test the runtime on both iOS and OS X.
    --skip-xcode-ios
          Skip the invoke of Xcode to test the runtime on iOS.
    --skip-xcode-osx
          Skip the invoke of Xcode to test the runtime on OS X.
+   --skip-objc-conformance
+         Skip the Objective C conformance tests (run on OS X).
 
 EOF
 }
@@ -68,8 +72,10 @@
 DO_AUTOGEN=no
 DO_CLEAN=no
 REGEN_CPP_DESCRIPTORS=no
+CORE_ONLY=no
 DO_XCODE_IOS_TESTS=yes
 DO_XCODE_OSX_TESTS=yes
+DO_OBJC_CONFORMANCE_TESTS=yes
 while [[ $# != 0 ]]; do
   case "${1}" in
     -h | --help )
@@ -89,6 +95,9 @@
       shift
       NUM_MAKE_JOBS="${1}"
       ;;
+    --core-only )
+      CORE_ONLY=yes
+      ;;
     --skip-xcode )
       DO_XCODE_IOS_TESTS=no
       DO_XCODE_OSX_TESTS=no
@@ -99,6 +108,9 @@
     --skip-xcode-osx )
       DO_XCODE_OSX_TESTS=no
       ;;
+    --skip-objc-conformance )
+      DO_OBJC_CONFORMANCE_TESTS=no
+      ;;
     -*)
       echo "ERROR: Unknown option: ${1}" 1>&2
       printUsage
@@ -114,7 +126,7 @@
 done
 
 # Into the proto dir.
-pushd "${ProtoRootDir}"
+cd "${ProtoRootDir}"
 
 # if no Makefile, force the autogen.
 if [[ ! -f Makefile ]] ; then
@@ -124,7 +136,9 @@
 if [[ "${DO_AUTOGEN}" == "yes" ]] ; then
   header "Running autogen & configure"
   ./autogen.sh
-  ./configure CXXFLAGS="-mmacosx-version-min=10.9 -Wnon-virtual-dtor -Woverloaded-virtual -Wunused-const-variable -Wunused-function"
+  ./configure \
+    CPPFLAGS="-mmacosx-version-min=10.9 -Wunused-const-variable -Wunused-function" \
+    CXXFLAGS="-Wnon-virtual-dtor -Woverloaded-virtual"
 fi
 
 if [[ "${DO_CLEAN}" == "yes" ]] ; then
@@ -155,11 +169,20 @@
   ./generate_descriptor_proto.sh -j "${NUM_MAKE_JOBS}"
 fi
 
-header "Building"
-# Can't issue these together, when fully parallel, something sometimes chokes
-# at random.
-wrapped_make -j "${NUM_MAKE_JOBS}" all
-wrapped_make -j "${NUM_MAKE_JOBS}" check
+if [[ "${CORE_ONLY}" == "yes" ]] ; then
+  header "Building core Only"
+  wrapped_make -j "${NUM_MAKE_JOBS}"
+else
+  header "Building"
+  # Can't issue these together, when fully parallel, something sometimes chokes
+  # at random.
+  wrapped_make -j "${NUM_MAKE_JOBS}" all
+  wrapped_make -j "${NUM_MAKE_JOBS}" check
+  # Fire off the conformance tests also.
+  cd conformance
+  wrapped_make -j "${NUM_MAKE_JOBS}" test_cpp
+  cd ..
+fi
 
 header "Ensuring the ObjC descriptors are current."
 # Find the newest input file (protos, compiler, and the generator script).
@@ -199,19 +222,45 @@
     xcodebuild
       -project objectivec/ProtocolBuffers_iOS.xcodeproj
       -scheme ProtocolBuffers
-      # Don't need to worry about form factors or retina/non retina;
-      # just pick a mix of OS Versions and 32/64 bit.
-      -destination "platform=iOS Simulator,name=iPhone 4s,OS=7.1" # 32bit
-      -destination "platform=iOS Simulator,name=iPhone 6,OS=8.3" # 64bit
-      -destination "platform=iOS Simulator,name=iPad 2,OS=7.1" # 32bit
-      -destination "platform=iOS Simulator,name=iPad Air,OS=8.3" # 64bit
   )
+  # Don't need to worry about form factors or retina/non retina;
+  # just pick a mix of OS Versions and 32/64 bit.
+  # NOTE: Different Xcode have different simulated hardware/os support.
+  readonly XCODE_VERSION_LINE="$(xcodebuild -version | grep Xcode\  )"
+  readonly XCODE_VERSION="${XCODE_VERSION_LINE/Xcode /}"  # drop the prefix.
+  IOS_SIMULATOR_NAME="Simulator"
+  case "${XCODE_VERSION}" in
+    6.* )
+      echo "ERROR: Xcode 6.3/6.4 no longer supported for building, please use 7.0 or higher." 1>&2
+      exit 10
+      ;;
+    7.1* )
+      XCODEBUILD_TEST_BASE_IOS+=(
+          -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPhone 6,OS=9.0" # 64bit
+          -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPad Air,OS=9.0" # 64bit
+      )
+      ;;
+    7.* )
+      XCODEBUILD_TEST_BASE_IOS+=(
+          -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
+          -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+          -destination "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
+      )
+      ;;
+    * )
+      echo "Time to update the simulator targets for Xcode ${XCODE_VERSION}"
+      exit 2
+      ;;
+  esac
   header "Doing Xcode iOS build/tests - Debug"
   "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Debug test
   header "Doing Xcode iOS build/tests - Release"
   "${XCODEBUILD_TEST_BASE_IOS[@]}" -configuration Release test
   # Don't leave the simulator in the developer's face.
-  killall "iOS Simulator"
+  killall "${IOS_SIMULATOR_NAME}"
 fi
 if [[ "${DO_XCODE_OSX_TESTS}" == "yes" ]] ; then
   XCODEBUILD_TEST_BASE_OSX=(
@@ -226,3 +275,9 @@
   header "Doing Xcode OS X build/tests - Release"
   "${XCODEBUILD_TEST_BASE_OSX[@]}" -configuration Release test
 fi
+
+if [[ "${DO_OBJC_CONFORMANCE_TESTS}" == "yes" ]] ; then
+  cd conformance
+  wrapped_make -j "${NUM_MAKE_JOBS}" test_objc
+  cd ..
+fi
diff --git a/objectivec/DevTools/pddm.py b/objectivec/DevTools/pddm.py
index d1b53f5..9a11fec 100755
--- a/objectivec/DevTools/pddm.py
+++ b/objectivec/DevTools/pddm.py
@@ -625,8 +625,7 @@
 def main(args):
   usage = '%prog [OPTIONS] PATH ...'
   description = (
-      'Processes PDDM directives in the the given paths and write them back'
-      ' out.'
+      'Processes PDDM directives in the given paths and write them back out.'
   )
   parser = optparse.OptionParser(usage=usage, description=description)
   parser.add_option('--dry-run',
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 3dd2de8..c49c7e2 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -46,12 +46,20 @@
 
 // Used in the generated code to give sizes to enums. int32_t was chosen based
 // on the fact that Protocol Buffers enums are limited to this range.
-// The complexity and double definition here are so we get the nice name
-// for objective C, but also define the name with a trailing underscore so
-// the Swift bridge will have one where the names line up to support short
-// names since they are scoped to the enum.
-// https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_11
-#define GPB_ENUM(X) NS_ENUM(int32_t, X)
+#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
+// doesn't allow us to forward declare. We work around this one case by
+// providing a local definition. The default case has to use NS_ENUM for the
+// magic that is Swift bridging of enums.
+#if (__cplusplus && __cplusplus < 201103L)
+ #define GPB_ENUM(X) enum X : int32_t X; enum X : int32_t
+#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;
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
index 71758ba..fd87783 100644
--- a/objectivec/GPBCodedInputStream.m
+++ b/objectivec/GPBCodedInputStream.m
@@ -216,7 +216,17 @@
     result = @"";
   } else {
     CheckSize(state, size);
-    result = GPBCreateGPBStringWithUTF8(&state->bytes[state->bufferPos], size);
+    result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
+                                      length:size
+                                    encoding:NSUTF8StringEncoding];
+    if (!result) {
+      result = @"";
+#ifdef DEBUG
+      // https://developers.google.com/protocol-buffers/docs/proto#scalar
+      NSLog(@"UTF8 failure, is some field type 'string' when it should be "
+            @"'bytes'?");
+#endif
+    }
     state->bufferPos += size;
   }
   return result;
@@ -264,10 +274,6 @@
 }
 
 size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) {
-  if (state->currentLimit == SIZE_T_MAX) {
-    return state->currentLimit;
-  }
-
   return state->currentLimit - state->bufferPos;
 }
 
@@ -299,7 +305,7 @@
     buffer_ = [data retain];
     state_.bytes = (const uint8_t *)[data bytes];
     state_.bufferSize = [data length];
-    state_.currentLimit = NSUIntegerMax;
+    state_.currentLimit = state_.bufferSize;
   }
   return self;
 }
@@ -482,320 +488,3 @@
 }
 
 @end
-
-@implementation GPBString {
- @package
-  CFStringRef string_;
-  unsigned char *utf8_;
-  NSUInteger utf8Len_;
-
-  // This lock is used to gate access to utf8_.  Once GPBStringInitStringValue()
-  // has been called, string_ will be filled in, and utf8_ will be NULL.
-  OSSpinLock lock_;
-
-  BOOL hasBOM_;
-  BOOL is7BitAscii_;
-}
-
-// Returns true if the passed in bytes are 7 bit ascii.
-// This routine needs to be fast.
-static bool AreBytesIn7BitASCII(const uint8_t *bytes, NSUInteger len) {
-// In the loops below, it's more efficient to collect rather than do
-// conditional at every step.
-#if __LP64__
-  // Align bytes. This is especially important in case of 3 byte BOM.
-  while (len > 0 && ((size_t)bytes & 0x07)) {
-    if (*bytes++ & 0x80) return false;
-    len--;
-  }
-  while (len >= 32) {
-    uint64_t val = *(const uint64_t *)bytes;
-    uint64_t hiBits = (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    hiBits |= (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    hiBits |= (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    if (hiBits | (val & 0x8080808080808080ULL)) return false;
-    bytes += 8;
-    len -= 32;
-  }
-
-  while (len >= 16) {
-    uint64_t val = *(const uint64_t *)bytes;
-    uint64_t hiBits = (val & 0x8080808080808080ULL);
-    bytes += 8;
-    val = *(const uint64_t *)bytes;
-    if (hiBits | (val & 0x8080808080808080ULL)) return false;
-    bytes += 8;
-    len -= 16;
-  }
-
-  while (len >= 8) {
-    uint64_t val = *(const uint64_t *)bytes;
-    if (val & 0x8080808080808080ULL) return false;
-    bytes += 8;
-    len -= 8;
-  }
-#else   // __LP64__
-  // Align bytes. This is especially important in case of 3 byte BOM.
-  while (len > 0 && ((size_t)bytes & 0x03)) {
-    if (*bytes++ & 0x80) return false;
-    len--;
-  }
-  while (len >= 16) {
-    uint32_t val = *(const uint32_t *)bytes;
-    uint32_t hiBits = (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    hiBits |= (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    hiBits |= (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    if (hiBits | (val & 0x80808080U)) return false;
-    bytes += 4;
-    len -= 16;
-  }
-
-  while (len >= 8) {
-    uint32_t val = *(const uint32_t *)bytes;
-    uint32_t hiBits = (val & 0x80808080U);
-    bytes += 4;
-    val = *(const uint32_t *)bytes;
-    if (hiBits | (val & 0x80808080U)) return false;
-    bytes += 4;
-    len -= 8;
-  }
-#endif  // __LP64__
-
-  while (len >= 4) {
-    uint32_t val = *(const uint32_t *)bytes;
-    if (val & 0x80808080U) return false;
-    bytes += 4;
-    len -= 4;
-  }
-
-  while (len--) {
-    if (*bytes++ & 0x80) return false;
-  }
-
-  return true;
-}
-
-static void GPBStringInitStringValue(GPBString *string) {
-  OSSpinLockLock(&string->lock_);
-  GPBStringInitStringValueAlreadyLocked(string);
-  OSSpinLockUnlock(&string->lock_);
-}
-
-static void GPBStringInitStringValueAlreadyLocked(GPBString *string) {
-  if (string->string_ == NULL && string->utf8_ != NULL) {
-    // Using kCFAllocatorMalloc for contentsDeallocator, as buffer in
-    // string->utf8_ is being handed off.
-    string->string_ = CFStringCreateWithBytesNoCopy(
-        NULL, string->utf8_, string->utf8Len_, kCFStringEncodingUTF8, false,
-        kCFAllocatorMalloc);
-    if (!string->string_) {
-#ifdef DEBUG
-      // https://developers.google.com/protocol-buffers/docs/proto#scalar
-      NSLog(@"UTF8 failure, is some field type 'string' when it should be "
-            @"'bytes'?");
-#endif
-      string->string_ = CFSTR("");
-      string->utf8Len_ = 0;
-      // On failure, we have to clean up the buffer.
-      free(string->utf8_);
-    }
-    string->utf8_ = NULL;
-  }
-}
-
-GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) {
-  GPBString *result = [[GPBString alloc] initWithBytes:bytes length:length];
-  return result;
-}
-
-- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)length {
-  self = [super init];
-  if (self) {
-    utf8_ = malloc(length);
-    memcpy(utf8_, bytes, length);
-    utf8Len_ = length;
-    lock_ = OS_SPINLOCK_INIT;
-    is7BitAscii_ = AreBytesIn7BitASCII(bytes, length);
-    if (length >= 3 && memcmp(utf8_, "\xef\xbb\xbf", 3) == 0) {
-      // We can't just remove the BOM from the string here, because in the case
-      // where we have > 1 BOM at the beginning of the string, we will remove one,
-      // and the internal NSString we create will remove the next one, and we will
-      // end up with a GPBString != NSString issue.
-      // We also just can't remove all the BOMs because then we would end up with
-      // potential cases where a GPBString and an NSString made with the same
-      // UTF8 buffer would in fact be different.
-      // We record the fact we have a BOM, and use it as necessary to simulate
-      // what NSString would return for various calls.
-      hasBOM_ = YES;
-#if DEBUG
-      // Sending BOMs across the line is just wasting bits.
-      NSLog(@"Bad data? String should not have BOM!");
-#endif  // DEBUG
-    }
-  }
-  return self;
-}
-
-- (void)dealloc {
-  if (string_ != NULL) {
-    CFRelease(string_);
-  }
-  if (utf8_ != NULL) {
-    free(utf8_);
-  }
-  [super dealloc];
-}
-
-// Required NSString overrides.
-- (NSUInteger)length {
-  if (is7BitAscii_) {
-    return utf8Len_;
-  } else {
-    GPBStringInitStringValue(self);
-    return CFStringGetLength(string_);
-  }
-}
-
-- (unichar)characterAtIndex:(NSUInteger)anIndex {
-  OSSpinLockLock(&lock_);
-  if (is7BitAscii_ && utf8_) {
-    unichar result = utf8_[anIndex];
-    OSSpinLockUnlock(&lock_);
-    return result;
-  } else {
-    GPBStringInitStringValueAlreadyLocked(self);
-    OSSpinLockUnlock(&lock_);
-    return CFStringGetCharacterAtIndex(string_, anIndex);
-  }
-}
-
-// Override a couple of methods that typically want high performance.
-
-- (id)copyWithZone:(NSZone *)zone {
-  GPBStringInitStringValue(self);
-  return [(NSString *)string_ copyWithZone:zone];
-}
-
-- (id)mutableCopyWithZone:(NSZone *)zone {
-  GPBStringInitStringValue(self);
-  return [(NSString *)string_ mutableCopyWithZone:zone];
-}
-
-- (NSUInteger)hash {
-  // Must convert to string here to make sure that the hash is always
-  // consistent no matter what state the GPBString is in.
-  GPBStringInitStringValue(self);
-  return CFHash(string_);
-}
-
-- (BOOL)isEqual:(id)object {
-  if (self == object) {
-    return YES;
-  }
-  if ([object isKindOfClass:[NSString class]]) {
-    GPBStringInitStringValue(self);
-    return CFStringCompare(string_, (CFStringRef)object, 0) ==
-           kCFCompareEqualTo;
-  }
-  return NO;
-}
-
-- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange {
-  OSSpinLockLock(&lock_);
-  if (is7BitAscii_ && utf8_) {
-    unsigned char *bytes = &(utf8_[aRange.location]);
-    for (NSUInteger i = 0; i < aRange.length; ++i) {
-      buffer[i] = bytes[i];
-    }
-    OSSpinLockUnlock(&lock_);
-  } else {
-    GPBStringInitStringValueAlreadyLocked(self);
-    OSSpinLockUnlock(&lock_);
-    CFStringGetCharacters(string_, CFRangeMake(aRange.location, aRange.length),
-                          buffer);
-  }
-}
-
-- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)encoding {
-  if ((encoding == NSUTF8StringEncoding) ||
-      (encoding == NSASCIIStringEncoding && is7BitAscii_)) {
-    return utf8Len_ - (hasBOM_ ? 3 : 0);
-  } else {
-    GPBStringInitStringValue(self);
-    return [(NSString *)string_ lengthOfBytesUsingEncoding:encoding];
-  }
-}
-
-- (BOOL)getBytes:(void *)buffer
-         maxLength:(NSUInteger)maxLength
-        usedLength:(NSUInteger *)usedLength
-          encoding:(NSStringEncoding)encoding
-           options:(NSStringEncodingConversionOptions)options
-             range:(NSRange)range
-    remainingRange:(NSRangePointer)remainingRange {
-  // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-  // does not return reliable results if the maxLength argument is 0
-  // (Radar 16385183). Therefore we have special cased it as a slow case so
-  // that it behaves however Apple intends it to behave. It should be a rare
-  // case.
-  //
-  // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-  // does not return reliable results if the range is outside of the strings
-  // length (Radar 16396177). Therefore we have special cased it as a slow
-  // case so that it behaves however Apple intends it to behave.  It should
-  // be a rare case.
-  //
-  // We can optimize the UTF8StringEncoding and NSASCIIStringEncoding with no
-  // options cases.
-  if ((options == 0) &&
-      (encoding == NSUTF8StringEncoding || encoding == NSASCIIStringEncoding) &&
-      (maxLength != 0) &&
-      (NSMaxRange(range) <= utf8Len_)) {
-    // Might be able to optimize it.
-    OSSpinLockLock(&lock_);
-    if (is7BitAscii_ && utf8_) {
-      NSUInteger length = range.length;
-      length = (length < maxLength) ? length : maxLength;
-      memcpy(buffer, utf8_ + range.location, length);
-      if (usedLength) {
-        *usedLength = length;
-      }
-      if (remainingRange) {
-        remainingRange->location = range.location + length;
-        remainingRange->length = range.length - length;
-      }
-      OSSpinLockUnlock(&lock_);
-      if (length > 0) {
-        return YES;
-      } else {
-        return NO;
-      }
-    } else {
-      GPBStringInitStringValueAlreadyLocked(self);
-      OSSpinLockUnlock(&lock_);
-    }
-  } else {
-    GPBStringInitStringValue(self);
-  }
-  return [(NSString *)string_ getBytes:buffer
-                             maxLength:maxLength
-                            usedLength:usedLength
-                              encoding:encoding
-                               options:options
-                                 range:range
-                        remainingRange:remainingRange];
-}
-
-@end
diff --git a/objectivec/GPBCodedInputStream_PackagePrivate.h b/objectivec/GPBCodedInputStream_PackagePrivate.h
index e482b4c..90bd0c9 100644
--- a/objectivec/GPBCodedInputStream_PackagePrivate.h
+++ b/objectivec/GPBCodedInputStream_PackagePrivate.h
@@ -39,19 +39,6 @@
 @class GPBUnknownFieldSet;
 @class GPBFieldDescriptor;
 
-// GPBString is a string subclass that avoids the overhead of initializing
-// a full NSString until it is actually needed. Lots of protocol buffers contain
-// strings, and instantiating all of those strings and having them parsed to
-// verify correctness when the message was being read was expensive, when many
-// of the strings were never being used.
-//
-// Note for future-self. I tried implementing this using a NSProxy.
-// Turned out the performance was horrible in client apps because folks
-// like to use libraries like SBJSON that grab characters one at a time.
-// The proxy overhead was a killer.
-@interface GPBString : NSString
-@end
-
 typedef struct GPBCodedInputStreamState {
   const uint8_t *bytes;
   size_t bufferSize;
@@ -92,10 +79,6 @@
 
 CF_EXTERN_C_BEGIN
 
-// Returns a GPBString with a +1 retain count.
-GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length)
-    __attribute__((ns_returns_retained));
-
 int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state);
 
 double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state);
diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h
index a5aef17..0a47f1c 100644
--- a/objectivec/GPBCodedOutputStream.h
+++ b/objectivec/GPBCodedOutputStream.h
@@ -168,26 +168,26 @@
 - (void)writeEnumNoTag:(int32_t)value;
 
 - (void)writeString:(int32_t)fieldNumber value:(NSString *)value;
-- (void)writeStringArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeStringArray:(int32_t)fieldNumber values:(NSArray<NSString*> *)values;
 - (void)writeStringNoTag:(NSString *)value;
 
 - (void)writeMessage:(int32_t)fieldNumber value:(GPBMessage *)value;
-- (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeMessageArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
 - (void)writeMessageNoTag:(GPBMessage *)value;
 
 - (void)writeBytes:(int32_t)fieldNumber value:(NSData *)value;
-- (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeBytesArray:(int32_t)fieldNumber values:(NSArray<NSData*> *)values;
 - (void)writeBytesNoTag:(NSData *)value;
 
 - (void)writeGroup:(int32_t)fieldNumber
              value:(GPBMessage *)value;
-- (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeGroupArray:(int32_t)fieldNumber values:(NSArray<GPBMessage*> *)values;
 - (void)writeGroupNoTag:(int32_t)fieldNumber
                   value:(GPBMessage *)value;
 
 - (void)writeUnknownGroup:(int32_t)fieldNumber
                     value:(GPBUnknownFieldSet *)value;
-- (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray *)values;
+- (void)writeUnknownGroupArray:(int32_t)fieldNumber values:(NSArray<GPBUnknownFieldSet*> *)values;
 - (void)writeUnknownGroupNoTag:(int32_t)fieldNumber
                          value:(GPBUnknownFieldSet *)value;
 
@@ -306,17 +306,17 @@
 //%
 // Write methods for types that aren't in packed arrays.
 //%PDDM-DEFINE _WRITE_UNPACKABLE_DECLS(NAME, TYPE)
-//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value;
-//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray *)values;
-//%- (void)write##NAME##NoTag:(TYPE)value;
+//%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE *)value;
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
+//%- (void)write##NAME##NoTag:(TYPE *)value;
 //%
 // Special write methods for Groups.
 //%PDDM-DEFINE _WRITE_GROUP_DECLS(NAME, TYPE)
 //%- (void)write##NAME:(int32_t)fieldNumber
-//%       NAME$S value:(TYPE)value;
-//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray *)values;
+//%       NAME$S value:(TYPE *)value;
+//%- (void)write##NAME##Array:(int32_t)fieldNumber values:(NSArray<##TYPE##*> *)values;
 //%- (void)write##NAME##NoTag:(int32_t)fieldNumber
-//%            NAME$S value:(TYPE)value;
+//%            NAME$S value:(TYPE *)value;
 //%
 
 // One macro to hide it all up above.
@@ -335,8 +335,8 @@
 //%_WRITE_PACKABLE_DECLS(SFixed32, Int32, int32_t)
 //%_WRITE_PACKABLE_DECLS(Bool, Bool, BOOL)
 //%_WRITE_PACKABLE_DECLS(Enum, Enum, int32_t)
-//%_WRITE_UNPACKABLE_DECLS(String, NSString *)
-//%_WRITE_UNPACKABLE_DECLS(Message, GPBMessage *)
-//%_WRITE_UNPACKABLE_DECLS(Bytes, NSData *)
-//%_WRITE_GROUP_DECLS(Group, GPBMessage *)
-//%_WRITE_GROUP_DECLS(UnknownGroup, GPBUnknownFieldSet *)
+//%_WRITE_UNPACKABLE_DECLS(String, NSString)
+//%_WRITE_UNPACKABLE_DECLS(Message, GPBMessage)
+//%_WRITE_UNPACKABLE_DECLS(Bytes, NSData)
+//%_WRITE_GROUP_DECLS(Group, GPBMessage)
+//%_WRITE_GROUP_DECLS(UnknownGroup, GPBUnknownFieldSet)
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index 360afe9..8d8e975 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -55,9 +55,9 @@
 @interface GPBDescriptor : NSObject<NSCopying>
 
 @property(nonatomic, readonly, copy) NSString *name;
-@property(nonatomic, readonly, strong, nullable) NSArray *fields;
-@property(nonatomic, readonly, strong, nullable) NSArray *oneofs;
-@property(nonatomic, readonly, strong, nullable) NSArray *enums;
+@property(nonatomic, readonly, strong, nullable) NSArray<GPBFieldDescriptor*> *fields;
+@property(nonatomic, readonly, strong, nullable) NSArray<GPBOneofDescriptor*> *oneofs;
+@property(nonatomic, readonly, strong, nullable) NSArray<GPBEnumDescriptor*> *enums;
 @property(nonatomic, readonly, nullable) const GPBExtensionRange *extensionRanges;
 @property(nonatomic, readonly) NSUInteger extensionRangesCount;
 @property(nonatomic, readonly, assign) GPBFileDescriptor *file;
@@ -81,7 +81,7 @@
 
 @interface GPBOneofDescriptor : NSObject
 @property(nonatomic, readonly) NSString *name;
-@property(nonatomic, readonly) NSArray *fields;
+@property(nonatomic, readonly) NSArray<GPBFieldDescriptor*> *fields;
 
 - (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber;
 - (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name;
diff --git a/objectivec/GPBDictionary.h b/objectivec/GPBDictionary.h
index cc4a698..3120814 100644
--- a/objectivec/GPBDictionary.h
+++ b/objectivec/GPBDictionary.h
@@ -355,35 +355,35 @@
 
 #pragma mark - UInt32 -> Object
 
-@interface GPBUInt32ObjectDictionary : NSObject <NSCopying>
+@interface GPBUInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
 @property(nonatomic, readonly) NSUInteger count;
 
 + (instancetype)dictionary;
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(uint32_t)key;
-+ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                             forKeys:(const uint32_t [])keys
-                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(uint32_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint32_t [])keys
+                                count:(NSUInteger)count;
 + (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
-- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                       forKeys:(const uint32_t [])keys
-                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary;
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-- (id)valueForKey:(uint32_t)key;
+- (ObjectType)objectForKey:(uint32_t)key;
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(uint32_t key, id value, BOOL *stop))block;
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint32_t key, ObjectType object, BOOL *stop))block;
 
 - (void)addEntriesFromDictionary:(GPBUInt32ObjectDictionary *)otherDictionary;
 
-- (void)setValue:(id)value forKey:(uint32_t)key;
+- (void)setObject:(ObjectType)object forKey:(uint32_t)key;
 
-- (void)removeValueForKey:(uint32_t)aKey;
+- (void)removeObjectForKey:(uint32_t)aKey;
 - (void)removeAll;
 
 @end
@@ -701,35 +701,35 @@
 
 #pragma mark - Int32 -> Object
 
-@interface GPBInt32ObjectDictionary : NSObject <NSCopying>
+@interface GPBInt32ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
 @property(nonatomic, readonly) NSUInteger count;
 
 + (instancetype)dictionary;
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(int32_t)key;
-+ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                             forKeys:(const int32_t [])keys
-                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(int32_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int32_t [])keys
+                                count:(NSUInteger)count;
 + (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
-- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                       forKeys:(const int32_t [])keys
-                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int32_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary;
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-- (id)valueForKey:(int32_t)key;
+- (ObjectType)objectForKey:(int32_t)key;
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(int32_t key, id value, BOOL *stop))block;
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int32_t key, ObjectType object, BOOL *stop))block;
 
 - (void)addEntriesFromDictionary:(GPBInt32ObjectDictionary *)otherDictionary;
 
-- (void)setValue:(id)value forKey:(int32_t)key;
+- (void)setObject:(ObjectType)object forKey:(int32_t)key;
 
-- (void)removeValueForKey:(int32_t)aKey;
+- (void)removeObjectForKey:(int32_t)aKey;
 - (void)removeAll;
 
 @end
@@ -1047,35 +1047,35 @@
 
 #pragma mark - UInt64 -> Object
 
-@interface GPBUInt64ObjectDictionary : NSObject <NSCopying>
+@interface GPBUInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
 @property(nonatomic, readonly) NSUInteger count;
 
 + (instancetype)dictionary;
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(uint64_t)key;
-+ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                             forKeys:(const uint64_t [])keys
-                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(uint64_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const uint64_t [])keys
+                                count:(NSUInteger)count;
 + (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
-- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                       forKeys:(const uint64_t [])keys
-                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const uint64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary;
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-- (id)valueForKey:(uint64_t)key;
+- (ObjectType)objectForKey:(uint64_t)key;
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(uint64_t key, id value, BOOL *stop))block;
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint64_t key, ObjectType object, BOOL *stop))block;
 
 - (void)addEntriesFromDictionary:(GPBUInt64ObjectDictionary *)otherDictionary;
 
-- (void)setValue:(id)value forKey:(uint64_t)key;
+- (void)setObject:(ObjectType)object forKey:(uint64_t)key;
 
-- (void)removeValueForKey:(uint64_t)aKey;
+- (void)removeObjectForKey:(uint64_t)aKey;
 - (void)removeAll;
 
 @end
@@ -1393,35 +1393,35 @@
 
 #pragma mark - Int64 -> Object
 
-@interface GPBInt64ObjectDictionary : NSObject <NSCopying>
+@interface GPBInt64ObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
 @property(nonatomic, readonly) NSUInteger count;
 
 + (instancetype)dictionary;
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(int64_t)key;
-+ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                             forKeys:(const int64_t [])keys
-                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(int64_t)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const int64_t [])keys
+                                count:(NSUInteger)count;
 + (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
-- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                       forKeys:(const int64_t [])keys
-                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const int64_t [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary;
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-- (id)valueForKey:(int64_t)key;
+- (ObjectType)objectForKey:(int64_t)key;
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(int64_t key, id value, BOOL *stop))block;
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int64_t key, ObjectType object, BOOL *stop))block;
 
 - (void)addEntriesFromDictionary:(GPBInt64ObjectDictionary *)otherDictionary;
 
-- (void)setValue:(id)value forKey:(int64_t)key;
+- (void)setObject:(ObjectType)object forKey:(int64_t)key;
 
-- (void)removeValueForKey:(int64_t)aKey;
+- (void)removeObjectForKey:(int64_t)aKey;
 - (void)removeAll;
 
 @end
@@ -1739,35 +1739,35 @@
 
 #pragma mark - Bool -> Object
 
-@interface GPBBoolObjectDictionary : NSObject <NSCopying>
+@interface GPBBoolObjectDictionary<__covariant ObjectType> : NSObject <NSCopying>
 
 @property(nonatomic, readonly) NSUInteger count;
 
 + (instancetype)dictionary;
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(BOOL)key;
-+ (instancetype)dictionaryWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                             forKeys:(const BOOL [])keys
-                               count:(NSUInteger)count;
++ (instancetype)dictionaryWithObject:(ObjectType)object
+                              forKey:(BOOL)key;
++ (instancetype)dictionaryWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                              forKeys:(const BOOL [])keys
+                                count:(NSUInteger)count;
 + (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary;
 + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 
-- (instancetype)initWithValues:(const id GPB_UNSAFE_UNRETAINED [])values
-                       forKeys:(const BOOL [])keys
-                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithObjects:(const ObjectType GPB_UNSAFE_UNRETAINED [])objects
+                        forKeys:(const BOOL [])keys
+                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary;
 - (instancetype)initWithCapacity:(NSUInteger)numItems;
 
-- (id)valueForKey:(BOOL)key;
+- (ObjectType)objectForKey:(BOOL)key;
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(BOOL key, id value, BOOL *stop))block;
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(BOOL key, ObjectType object, BOOL *stop))block;
 
 - (void)addEntriesFromDictionary:(GPBBoolObjectDictionary *)otherDictionary;
 
-- (void)setValue:(id)value forKey:(BOOL)key;
+- (void)setObject:(ObjectType)object forKey:(BOOL)key;
 
-- (void)removeValueForKey:(BOOL)aKey;
+- (void)removeObjectForKey:(BOOL)aKey;
 - (void)removeAll;
 
 @end
@@ -2096,7 +2096,7 @@
 //%DICTIONARY_POD_INTERFACES_FOR_KEY(String, NSString, *, OBJECT)
 //%PDDM-DEFINE DICTIONARY_INTERFACES_FOR_POD_KEY(KEY_NAME, KEY_TYPE)
 //%DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, , POD)
-//%DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, Object, id)
+//%DICTIONARY_POD_KEY_TO_OBJECT_INTERFACE(KEY_NAME, KEY_TYPE, Object, ObjectType)
 //%PDDM-DEFINE DICTIONARY_POD_INTERFACES_FOR_KEY(KEY_NAME, KEY_TYPE, KisP, KHELPER)
 //%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, UInt32, uint32_t)
 //%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Int32, int32_t)
@@ -2107,13 +2107,13 @@
 //%DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Double, double)
 //%DICTIONARY_KEY_TO_ENUM_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, Enum, int32_t)
 //%PDDM-DEFINE DICTIONARY_KEY_TO_POD_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE)
-//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, POD)
+//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, POD, value)
 //%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)
+//%DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, , POD, VALUE_NAME, VALUE_TYPE, OBJECT, object)
 //%PDDM-DEFINE VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE)
 //%- (BOOL)valueForKey:(KEY_TYPE)key value:(nullable VALUE_TYPE *)value;
 //%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_TYPE)
-//%- (VALUE_TYPE)valueForKey:(KEY_TYPE)key;
+//%- (VALUE_TYPE)objectForKey:(KEY_TYPE)key;
 //%PDDM-DEFINE VALUE_FOR_KEY_Enum(KEY_TYPE, VALUE_TYPE)
 //%VALUE_FOR_KEY_POD(KEY_TYPE, VALUE_TYPE)
 //%PDDM-DEFINE ARRAY_ARG_MODIFIERPOD()
@@ -2122,33 +2122,39 @@
 // Nothing
 //%PDDM-DEFINE ARRAY_ARG_MODIFIEROBJECT()
 //%GPB_UNSAFE_UNRETAINED ##
-//%PDDM-DEFINE DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLPOD(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLEnum(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLOBJECT(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary<__covariant VALUE_TYPE>
+//%PDDM-DEFINE DICTIONARY_COMMON_INTERFACE(KEY_NAME, KEY_TYPE, KisP, KHELPER, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
-//%@interface GPB##KEY_NAME##VALUE_NAME##Dictionary : NSObject <NSCopying>
+//%@interface DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) : NSObject <NSCopying>
 //%
 //%@property(nonatomic, readonly) NSUInteger count;
 //%
 //%+ (instancetype)dictionary;
-//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value
-//%                             forKey:(KEY_TYPE##KisP$S##KisP)key;
-//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])values
-//%                             forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
-//%                               count:(NSUInteger)count;
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)##VNAME
+//%                       ##VNAME$S## forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count;
 //%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
 //%+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;
 //%
-//%- (instancetype)initWithValues:(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;
+//%- (instancetype)initWith##VNAME$u##s:(const VALUE_TYPE ARRAY_ARG_MODIFIER##VHELPER()[])##VNAME##s
+//%                ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP ARRAY_ARG_MODIFIER##KHELPER()[])keys
+//%                ##VNAME$S##    count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
 //%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary;
 //%- (instancetype)initWithCapacity:(NSUInteger)numItems;
 //%
-//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
 //%
 //%- (void)addEntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary;
 //%
-//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
 //%
 //%@end
 //%
@@ -2189,7 +2195,7 @@
 //%// is not a valid enumerator as defined by validationFunc. If the actual value is
 //%// desired, use "raw" version of the method.
 //%
-//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, value)
 //%
 //%// These methods bypass the validationFunc to provide access to values that were not
 //%// known at the time the binary was compiled.
@@ -2206,21 +2212,21 @@
 //%// to the default value. Use the rawValue methods below to assign non enumerator
 //%// values.
 //%
-//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, value)
 //%
 //%@end
 //%
 
-//%PDDM-DEFINE DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
+//%PDDM-DEFINE DICTIONARY_IMMUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
 //%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_TYPE)
 //%
-//%- (void)enumerateKeysAndValuesUsingBlock:
-//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block;
+//%- (void)enumerateKeysAnd##VNAME$u##sUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop))block;
 
-//%PDDM-DEFINE DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER)
-//%- (void)setValue:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key;
+//%PDDM-DEFINE DICTIONARY_MUTABLE_INTERFACE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, VHELPER, VNAME)
+//%- (void)set##VNAME$u##:(VALUE_TYPE)##VNAME forKey:(KEY_TYPE##KisP$S##KisP)key;
 //%DICTIONARY_EXTRA_MUTABLE_METHODS_##VHELPER(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
-//%- (void)removeValueForKey:(KEY_TYPE##KisP$S##KisP)aKey;
+//%- (void)remove##VNAME$u##ForKey:(KEY_TYPE##KisP$S##KisP)aKey;
 //%- (void)removeAll;
 
 //%PDDM-DEFINE DICTIONARY_EXTRA_MUTABLE_METHODS_POD(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE)
diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m
index df63427..6baa2a1 100644
--- a/objectivec/GPBDictionary.m
+++ b/objectivec/GPBDictionary.m
@@ -45,6 +45,18 @@
 // directly.
 // ------------------------------------------------------------------
 
+// Used to include code only visible to specific versions of the static
+// analyzer. Useful for wrapping code that only exists to silence the analyzer.
+// Determine the values you want to use for BEGIN_APPLE_BUILD_VERSION,
+// END_APPLE_BUILD_VERSION using:
+//   xcrun clang -dM -E -x c /dev/null | grep __apple_build_version__
+// Example usage:
+//  #if GPB_STATIC_ANALYZER_ONLY(5621, 5623) ... #endif
+#define GPB_STATIC_ANALYZER_ONLY(BEGIN_APPLE_BUILD_VERSION, END_APPLE_BUILD_VERSION) \
+    (defined(__clang_analyzer__) && \
+     (__apple_build_version__ >= BEGIN_APPLE_BUILD_VERSION && \
+      __apple_build_version__ <= END_APPLE_BUILD_VERSION))
+
 enum {
   kMapKeyFieldNumber = 1,
   kMapValueFieldNumber = 2,
@@ -479,6 +491,12 @@
         case GPBDataTypeBytes:
           value.valueData = [GPBEmptyNSData() retain];
           break;
+#if defined(__clang_analyzer__)
+        case GPBDataTypeGroup:
+          // Maps can't really have Groups as the value type, but this case is needed
+          // so the analyzer won't report the posibility of send nil in for the value
+          // in the NSMutableDictionary case below.
+#endif
         case GPBDataTypeMessage: {
           value.valueMessage = [[field.msgClass alloc] init];
           break;
@@ -490,8 +508,22 @@
     }
 
     if ((keyDataType == GPBDataTypeString) && GPBDataTypeIsObject(valueDataType)) {
+#if GPB_STATIC_ANALYZER_ONLY(6020053, 7000181)
+     // Limited to Xcode 6.4 - 7.2, are known to fail here. The upper end can
+     // be raised as needed for new Xcodes.
+     //
+     // This is only needed on a "shallow" analyze; on a "deep" analyze, the
+     // existing code path gets this correct. In shallow, the analyzer decides
+     // GPBDataTypeIsObject(valueDataType) is both false and true on a single
+     // path through this function, allowing nil to be used for the
+     // setObject:forKey:.
+     if (value.valueString == nil) {
+       value.valueString = [@"" retain];
+     }
+#endif
       // mapDictionary is an NSMutableDictionary
-      [mapDictionary setObject:value.valueString forKey:key.valueString];
+      [(NSMutableDictionary *)mapDictionary setObject:value.valueString
+                                               forKey:key.valueString];
     } else {
       if (valueDataType == GPBDataTypeEnum) {
         if (GPBHasPreservingUnknownEnumSemantics([parentMessage descriptor].file.syntax) ||
@@ -536,12 +568,12 @@
 //%DICTIONARY_KEY_TO_ENUM_IMPL(KEY_NAME, KEY_TYPE, KisP, Enum, int32_t, KHELPER)
 
 //%PDDM-DEFINE DICTIONARY_KEY_TO_POD_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER)
-//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD)
+//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, POD, value)
 
 //%PDDM-DEFINE DICTIONARY_POD_KEY_TO_OBJECT_IMPL(KEY_NAME, KEY_TYPE, VALUE_NAME, VALUE_TYPE)
-//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, , VALUE_NAME, VALUE_TYPE, POD, OBJECT)
+//%DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, , VALUE_NAME, VALUE_TYPE, POD, OBJECT, object)
 
-//%PDDM-DEFINE DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER)
+//%PDDM-DEFINE DICTIONARY_COMMON_IMPL(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
 //%@implementation GPB##KEY_NAME##VALUE_NAME##Dictionary {
@@ -550,30 +582,30 @@
 //%}
 //%
 //%+ (instancetype)dictionary {
-//%  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+//%  return [[[self alloc] initWith##VNAME$u##s:NULL forKeys:NULL count:0] autorelease];
 //%}
 //%
-//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value
-//%                             forKey:(KEY_TYPE##KisP$S##KisP)key {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)##VNAME
+//%                      ##VNAME$S##  forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
 //%  // on to get the type correct.
-//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValues:&value
-//%               KEY_NAME$S VALUE_NAME$S                               forKeys:&key
-//%               KEY_NAME$S VALUE_NAME$S                                 count:1] autorelease];
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:&##VNAME
+//%               KEY_NAME$S VALUE_NAME$S                        ##VNAME$S##  forKeys:&key
+//%               KEY_NAME$S VALUE_NAME$S                        ##VNAME$S##    count:1] autorelease];
 //%}
 //%
-//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE [])values
-//%                             forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
-//%                               count:(NSUInteger)count {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
 //%  // on to get the type correct.
-//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithValues:values
+//%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:##VNAME##s
 //%               KEY_NAME$S VALUE_NAME$S                               forKeys:keys
 //%               KEY_NAME$S VALUE_NAME$S                                 count:count] autorelease];
 //%}
 //%
 //%+ (instancetype)dictionaryWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
 //%  // on to get the type correct.
 //%  return [[(GPB##KEY_NAME##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 //%}
@@ -583,18 +615,18 @@
 //%}
 //%
 //%- (instancetype)init {
-//%  return [self initWithValues:NULL forKeys:NULL count:0];
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
 //%}
 //%
-//%- (instancetype)initWithValues:(const VALUE_TYPE [])values
-//%                       forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
-//%                         count:(NSUInteger)count {
+//%- (instancetype)initWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                ##VNAME$S##  forKeys:(const KEY_TYPE##KisP$S##KisP [])keys
+//%                ##VNAME$S##    count:(NSUInteger)count {
 //%  self = [super init];
 //%  if (self) {
 //%    _dictionary = [[NSMutableDictionary alloc] init];
-//%    if (count && values && keys) {
+//%    if (count && VNAME##s && keys) {
 //%      for (NSUInteger i = 0; i < count; ++i) {
-//%        [_dictionary setObject:WRAPPED##VHELPER(values[i]) forKey:WRAPPED##KHELPER(keys[i])];
+//%DICTIONARY_VALIDATE_VALUE_##VHELPER(VNAME##s[i], ______)##DICTIONARY_VALIDATE_KEY_##KHELPER(keys[i], ______)        [_dictionary setObject:WRAPPED##VHELPER(VNAME##s[i]) forKey:WRAPPED##KHELPER(keys[i])];
 //%      }
 //%    }
 //%  }
@@ -602,7 +634,7 @@
 //%}
 //%
 //%- (instancetype)initWithDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)dictionary {
-//%  self = [self initWithValues:NULL forKeys:NULL count:0];
+//%  self = [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
 //%  if (self) {
 //%    if (dictionary) {
 //%      [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
@@ -613,14 +645,14 @@
 //%
 //%- (instancetype)initWithCapacity:(NSUInteger)numItems {
 //%  #pragma unused(numItems)
-//%  return [self initWithValues:NULL forKeys:NULL count:0];
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
 //%}
 //%
-//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, )
+//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, )
 //%
 //%VALUE_FOR_KEY_##VHELPER(KEY_TYPE##KisP$S##KisP, VALUE_NAME, VALUE_TYPE, KHELPER)
 //%
-//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, )
+//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, )
 //%
 //%@end
 //%
@@ -704,7 +736,7 @@
 //%    _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
 //%    if (count && rawValues && keys) {
 //%      for (NSUInteger i = 0; i < count; ++i) {
-//%        [_dictionary setObject:WRAPPED##VHELPER(rawValues[i]) forKey:WRAPPED##KHELPER(keys[i])];
+//%DICTIONARY_VALIDATE_KEY_##KHELPER(keys[i], ______)        [_dictionary setObject:WRAPPED##VHELPER(rawValues[i]) forKey:WRAPPED##KHELPER(keys[i])];
 //%      }
 //%    }
 //%  }
@@ -730,7 +762,7 @@
 //%  return [self initWithValidationFunction:func rawValues:NULL forKeys:NULL count:0];
 //%}
 //%
-//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, Raw)
+//%DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, value, Raw)
 //%
 //%- (BOOL)valueForKey:(KEY_TYPE##KisP$S##KisP)key value:(VALUE_TYPE *)value {
 //%  NSNumber *wrapped = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
@@ -766,10 +798,10 @@
 //%  }];
 //%}
 //%
-//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, Raw)
+//%DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, value, Raw)
 //%
 //%- (void)setValue:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key {
-//%  if (!_validationFunc(value)) {
+//%DICTIONARY_VALIDATE_KEY_##KHELPER(key, )  if (!_validationFunc(value)) {
 //%    [NSException raise:NSInvalidArgumentException
 //%                format:@"GPB##KEY_NAME##VALUE_NAME##Dictionary: Attempt to set an unknown enum value (%d)",
 //%                       value];
@@ -784,7 +816,7 @@
 //%@end
 //%
 
-//%PDDM-DEFINE DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ACCESSOR_NAME)
+//%PDDM-DEFINE DICTIONARY_IMMUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, ACCESSOR_NAME)
 //%- (void)dealloc {
 //%  NSAssert(!_autocreator,
 //%           @"%@: Autocreator must be cleared before release, autocreator: %@",
@@ -819,12 +851,12 @@
 //%  return _dictionary.count;
 //%}
 //%
-//%- (void)enumerateKeysAnd##ACCESSOR_NAME##ValuesUsingBlock:
-//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop))block {
+//%- (void)enumerateKeysAnd##ACCESSOR_NAME##VNAME$u##sUsingBlock:
+//%    (void (^)(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop))block {
 //%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
-//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u,
 //%                                                   BOOL *stop) {
-//%      block(UNWRAP##KEY_NAME(aKey), UNWRAP##VALUE_NAME(aValue), stop);
+//%      block(UNWRAP##KEY_NAME(aKey), UNWRAP##VALUE_NAME(a##VNAME$u), stop);
 //%  }];
 //%}
 //%
@@ -838,11 +870,11 @@
 //%  GPBDataType keyDataType = field.mapKeyDataType;
 //%  __block size_t result = 0;
 //%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
-//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u##,
 //%                                                   BOOL *stop) {
 //%    #pragma unused(stop)
 //%    size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
-//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueDataType);
+//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
 //%    result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
 //%  }];
 //%  size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
@@ -856,18 +888,18 @@
 //%  GPBDataType keyDataType = field.mapKeyDataType;
 //%  uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
 //%  [_dictionary enumerateKeysAndObjectsUsingBlock:^(ENUM_TYPE##KHELPER(KEY_TYPE)##aKey,
-//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##aValue,
+//%                                                   ENUM_TYPE##VHELPER(VALUE_TYPE)##a##VNAME$u,
 //%                                                   BOOL *stop) {
 //%    #pragma unused(stop)
 //%    // Write the tag.
 //%    [outputStream writeInt32NoTag:tag];
 //%    // Write the size of the message.
 //%    size_t msgSize = ComputeDict##KEY_NAME##FieldSize(UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
-//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueDataType);
+//%    msgSize += ComputeDict##VALUE_NAME##FieldSize(UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
 //%    [outputStream writeInt32NoTag:(int32_t)msgSize];
 //%    // Write the fields.
 //%    WriteDict##KEY_NAME##Field(outputStream, UNWRAP##KEY_NAME(aKey), kMapKeyFieldNumber, keyDataType);
-//%    WriteDict##VALUE_NAME##Field(outputStream, UNWRAP##VALUE_NAME(aValue), kMapValueFieldNumber, valueDataType);
+//%    WriteDict##VALUE_NAME##Field(outputStream, UNWRAP##VALUE_NAME(a##VNAME$u), kMapValueFieldNumber, valueDataType);
 //%  }];
 //%}
 //%
@@ -877,12 +909,12 @@
 //%}
 //%
 //%- (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
-//%  [self enumerateKeysAnd##ACCESSOR_NAME##ValuesUsingBlock:^(KEY_TYPE KisP##key, VALUE_TYPE value, BOOL *stop) {
+//%  [self enumerateKeysAnd##ACCESSOR_NAME##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##key, VALUE_TYPE VNAME, BOOL *stop) {
 //%      #pragma unused(stop)
-//%      block(TEXT_FORMAT_OBJ##KEY_NAME(key), TEXT_FORMAT_OBJ##VALUE_NAME(value));
+//%      block(TEXT_FORMAT_OBJ##KEY_NAME(key), TEXT_FORMAT_OBJ##VALUE_NAME(VNAME));
 //%  }];
 //%}
-//%PDDM-DEFINE DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, ACCESSOR_NAME)
+//%PDDM-DEFINE DICTIONARY_MUTABLE_CORE(KEY_NAME, KEY_TYPE, KisP, VALUE_NAME, VALUE_TYPE, KHELPER, VHELPER, VNAME, ACCESSOR_NAME)
 //%- (void)add##ACCESSOR_NAME##EntriesFromDictionary:(GPB##KEY_NAME##VALUE_NAME##Dictionary *)otherDictionary {
 //%  if (otherDictionary) {
 //%    [_dictionary addEntriesFromDictionary:otherDictionary->_dictionary];
@@ -892,14 +924,14 @@
 //%  }
 //%}
 //%
-//%- (void)set##ACCESSOR_NAME##Value:(VALUE_TYPE)value forKey:(KEY_TYPE##KisP$S##KisP)key {
-//%  [_dictionary setObject:WRAPPED##VHELPER(value) forKey:WRAPPED##KHELPER(key)];
+//%- (void)set##ACCESSOR_NAME##VNAME$u##:(VALUE_TYPE)VNAME forKey:(KEY_TYPE##KisP$S##KisP)key {
+//%DICTIONARY_VALIDATE_VALUE_##VHELPER(VNAME, )##DICTIONARY_VALIDATE_KEY_##KHELPER(key, )  [_dictionary setObject:WRAPPED##VHELPER(VNAME) forKey:WRAPPED##KHELPER(key)];
 //%  if (_autocreator) {
 //%    GPBAutocreatedDictionaryModified(_autocreator, self);
 //%  }
 //%}
 //%
-//%- (void)removeValueForKey:(KEY_TYPE##KisP$S##KisP)aKey {
+//%- (void)remove##VNAME$u##ForKey:(KEY_TYPE##KisP$S##KisP)aKey {
 //%  [_dictionary removeObjectForKey:WRAPPED##KHELPER(aKey)];
 //%}
 //%
@@ -912,11 +944,11 @@
 //
 
 //%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_POD_IMPL(VALUE_NAME, VALUE_TYPE)
-//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, POD)
+//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, POD, value)
 //%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_OBJECT_IMPL(VALUE_NAME, VALUE_TYPE)
-//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, OBJECT)
+//%DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, OBJECT, object)
 
-//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, HELPER)
+//%PDDM-DEFINE DICTIONARY_BOOL_KEY_TO_VALUE_IMPL(VALUE_NAME, VALUE_TYPE, HELPER, VNAME)
 //%#pragma mark - Bool -> VALUE_NAME
 //%
 //%@implementation GPBBool##VALUE_NAME##Dictionary {
@@ -925,30 +957,30 @@
 //%BOOL_DICT_HAS_STORAGE_##HELPER()}
 //%
 //%+ (instancetype)dictionary {
-//%  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+//%  return [[[self alloc] initWith##VNAME$u##s:NULL forKeys:NULL count:0] autorelease];
 //%}
 //%
-//%+ (instancetype)dictionaryWithValue:(VALUE_TYPE)value
-//%                             forKey:(BOOL)key {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%+ (instancetype)dictionaryWith##VNAME$u##:(VALUE_TYPE)VNAME
+//%                      ##VNAME$S##  forKey:(BOOL)key {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
 //%  // on to get the type correct.
-//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithValues:&value
-//%                    VALUE_NAME$S                               forKeys:&key
-//%                    VALUE_NAME$S                                 count:1] autorelease];
+//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:&##VNAME
+//%                    VALUE_NAME$S                        ##VNAME$S##  forKeys:&key
+//%                    VALUE_NAME$S                        ##VNAME$S##    count:1] autorelease];
 //%}
 //%
-//%+ (instancetype)dictionaryWithValues:(const VALUE_TYPE [])values
-//%                             forKeys:(const BOOL [])keys
-//%                               count:(NSUInteger)count {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%+ (instancetype)dictionaryWith##VNAME$u##s:(const VALUE_TYPE [])##VNAME##s
+//%                      ##VNAME$S##  forKeys:(const BOOL [])keys
+//%                      ##VNAME$S##    count:(NSUInteger)count {
+//%  // Cast is needed so the compiler knows what class we are invoking initWith##VNAME$u##s:forKeys:count:
 //%  // on to get the type correct.
-//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithValues:values
-//%                    VALUE_NAME$S                               forKeys:keys
-//%                    VALUE_NAME$S                                 count:count] autorelease];
+//%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWith##VNAME$u##s:##VNAME##s
+//%                    VALUE_NAME$S                        ##VNAME$S##  forKeys:keys
+//%                    VALUE_NAME$S                        ##VNAME$S##    count:count] autorelease];
 //%}
 //%
 //%+ (instancetype)dictionaryWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary {
-//%  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+//%  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
 //%  // on to get the type correct.
 //%  return [[(GPBBool##VALUE_NAME##Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 //%}
@@ -958,14 +990,14 @@
 //%}
 //%
 //%- (instancetype)init {
-//%  return [self initWithValues:NULL forKeys:NULL count:0];
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
 //%}
 //%
 //%BOOL_DICT_INITS_##HELPER(VALUE_NAME, VALUE_TYPE)
 //%
 //%- (instancetype)initWithCapacity:(NSUInteger)numItems {
 //%  #pragma unused(numItems)
-//%  return [self initWithValues:NULL forKeys:NULL count:0];
+//%  return [self initWith##VNAME$u##s:NULL forKeys:NULL count:0];
 //%}
 //%
 //%BOOL_DICT_DEALLOC##HELPER()
@@ -1025,8 +1057,8 @@
 //%  }
 //%}
 //%
-//%- (void)enumerateKeysAndValuesUsingBlock:
-//%    (void (^)(BOOL key, VALUE_TYPE value, BOOL *stop))block {
+//%- (void)enumerateKeysAnd##VNAME$u##sUsingBlock:
+//%    (void (^)(BOOL key, VALUE_TYPE VNAME, BOOL *stop))block {
 //%  BOOL stop = NO;
 //%  if (BOOL_DICT_HAS##HELPER(0, )) {
 //%    block(NO, _values[0], &stop);
@@ -1164,6 +1196,10 @@
 //%
 //%PDDM-DEFINE GPBVALUE_POD(VALUE_NAME)
 //%value##VALUE_NAME
+//%PDDM-DEFINE DICTIONARY_VALIDATE_VALUE_POD(VALUE_NAME, EXTRA_INDENT)
+// Empty
+//%PDDM-DEFINE DICTIONARY_VALIDATE_KEY_POD(KEY_NAME, EXTRA_INDENT)
+// Empty
 
 //%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_POD()
 //%  BOOL _valueSet[2];
@@ -1282,7 +1318,7 @@
 //
 
 //%PDDM-DEFINE VALUE_FOR_KEY_OBJECT(KEY_TYPE, VALUE_NAME, VALUE_TYPE, KHELPER)
-//%- (VALUE_TYPE)valueForKey:(KEY_TYPE)key {
+//%- (VALUE_TYPE)objectForKey:(KEY_TYPE)key {
 //%  VALUE_TYPE result = [_dictionary objectForKey:WRAPPED##KHELPER(key)];
 //%  return result;
 //%}
@@ -1356,27 +1392,42 @@
 // Empty
 //%PDDM-DEFINE GPBVALUE_OBJECT(VALUE_NAME)
 //%valueString
-
+//%PDDM-DEFINE DICTIONARY_VALIDATE_VALUE_OBJECT(VALUE_NAME, EXTRA_INDENT)
+//%##EXTRA_INDENT$S##  if (!##VALUE_NAME) {
+//%##EXTRA_INDENT$S##    [NSException raise:NSInvalidArgumentException
+//%##EXTRA_INDENT$S##                format:@"Attempting to add nil object to a Dictionary"];
+//%##EXTRA_INDENT$S##  }
+//%
+//%PDDM-DEFINE DICTIONARY_VALIDATE_KEY_OBJECT(KEY_NAME, EXTRA_INDENT)
+//%##EXTRA_INDENT$S##  if (!##KEY_NAME) {
+//%##EXTRA_INDENT$S##    [NSException raise:NSInvalidArgumentException
+//%##EXTRA_INDENT$S##                format:@"Attempting to add nil key to a Dictionary"];
+//%##EXTRA_INDENT$S##  }
+//%
 
 //%PDDM-DEFINE BOOL_DICT_HAS_STORAGE_OBJECT()
 // Empty
 //%PDDM-DEFINE BOOL_DICT_INITS_OBJECT(VALUE_NAME, VALUE_TYPE)
-//%- (instancetype)initWithValues:(const VALUE_TYPE [])values
-//%                       forKeys:(const BOOL [])keys
-//%                         count:(NSUInteger)count {
+//%- (instancetype)initWithObjects:(const VALUE_TYPE [])objects
+//%                        forKeys:(const BOOL [])keys
+//%                          count:(NSUInteger)count {
 //%  self = [super init];
 //%  if (self) {
 //%    for (NSUInteger i = 0; i < count; ++i) {
+//%      if (!objects[i]) {
+//%        [NSException raise:NSInvalidArgumentException
+//%                    format:@"Attempting to add nil object to a Dictionary"];
+//%      }
 //%      int idx = keys[i] ? 1 : 0;
 //%      [_values[idx] release];
-//%      _values[idx] = (VALUE_TYPE)[values[i] retain];
+//%      _values[idx] = (VALUE_TYPE)[objects[i] retain];
 //%    }
 //%  }
 //%  return self;
 //%}
 //%
 //%- (instancetype)initWithDictionary:(GPBBool##VALUE_NAME##Dictionary *)dictionary {
-//%  self = [self initWithValues:NULL forKeys:NULL count:0];
+//%  self = [self initWithObjects:NULL forKeys:NULL count:0];
 //%  if (self) {
 //%    if (dictionary) {
 //%      _values[0] = [dictionary->_values[0] retain];
@@ -1399,7 +1450,7 @@
 //%PDDM-DEFINE BOOL_DICT_HASOBJECT(IDX, REF)
 //%REF##_values[IDX] != nil
 //%PDDM-DEFINE BOOL_VALUE_FOR_KEY_OBJECT(VALUE_TYPE)
-//%- (VALUE_TYPE)valueForKey:(BOOL)key {
+//%- (VALUE_TYPE)objectForKey:(BOOL)key {
 //%  return _values[key ? 1 : 0];
 //%}
 //%PDDM-DEFINE BOOL_SET_GPBVALUE_FOR_KEY_OBJECT(VALUE_NAME, VALUE_TYPE, VisP)
@@ -1425,16 +1476,20 @@
 //%  }
 //%}
 //%
-//%- (void)setValue:(VALUE_TYPE)value forKey:(BOOL)key {
+//%- (void)setObject:(VALUE_TYPE)object forKey:(BOOL)key {
+//%  if (!object) {
+//%    [NSException raise:NSInvalidArgumentException
+//%                format:@"Attempting to add nil object to a Dictionary"];
+//%  }
 //%  int idx = (key ? 1 : 0);
 //%  [_values[idx] release];
-//%  _values[idx] = [value retain];
+//%  _values[idx] = [object retain];
 //%  if (_autocreator) {
 //%    GPBAutocreatedDictionaryModified(_autocreator, self);
 //%  }
 //%}
 //%
-//%- (void)removeValueForKey:(BOOL)aKey {
+//%- (void)removeObjectForKey:(BOOL)aKey {
 //%  int idx = (aKey ? 1 : 0);
 //%  [_values[idx] release];
 //%  _values[idx] = nil;
@@ -1484,7 +1539,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32UInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -1690,7 +1745,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32Int32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -1896,7 +1951,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32UInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -2102,7 +2157,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32Int64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -2308,7 +2363,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32BoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -2514,7 +2569,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32FloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -2720,7 +2775,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32DoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -3188,30 +3243,30 @@
 }
 
 + (instancetype)dictionary {
-  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
 }
 
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(uint32_t)key {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithValues:&value
-                                                           forKeys:&key
-                                                             count:1] autorelease];
+  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                            forKeys:&key
+                                                              count:1] autorelease];
 }
 
-+ (instancetype)dictionaryWithValues:(const id [])values
-                             forKeys:(const uint32_t [])keys
-                               count:(NSUInteger)count {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const uint32_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithValues:values
+  return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithObjects:objects
                                                            forKeys:keys
                                                              count:count] autorelease];
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt32ObjectDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -3221,18 +3276,22 @@
 }
 
 - (instancetype)init {
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
-- (instancetype)initWithValues:(const id [])values
-                       forKeys:(const uint32_t [])keys
-                         count:(NSUInteger)count {
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const uint32_t [])keys
+                          count:(NSUInteger)count {
   self = [super init];
   if (self) {
     _dictionary = [[NSMutableDictionary alloc] init];
-    if (count && values && keys) {
+    if (count && objects && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
-        [_dictionary setObject:values[i] forKey:@(keys[i])];
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
       }
     }
   }
@@ -3240,7 +3299,7 @@
 }
 
 - (instancetype)initWithDictionary:(GPBUInt32ObjectDictionary *)dictionary {
-  self = [self initWithValues:NULL forKeys:NULL count:0];
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
   if (self) {
     if (dictionary) {
       [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
@@ -3251,7 +3310,7 @@
 
 - (instancetype)initWithCapacity:(NSUInteger)numItems {
   #pragma unused(numItems)
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
 - (void)dealloc {
@@ -3288,12 +3347,12 @@
   return _dictionary.count;
 }
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(uint32_t key, id value, BOOL *stop))block {
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint32_t key, id object, BOOL *stop))block {
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
-      block([aKey unsignedIntValue], aValue, stop);
+      block([aKey unsignedIntValue], aObject, stop);
   }];
 }
 
@@ -3330,11 +3389,11 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   __block size_t result = 0;
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
   }];
   size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
@@ -3348,18 +3407,18 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     // Write the tag.
     [outputStream writeInt32NoTag:tag];
     // Write the size of the message.
     size_t msgSize = ComputeDictUInt32FieldSize([aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     [outputStream writeInt32NoTag:(int32_t)msgSize];
     // Write the fields.
     WriteDictUInt32Field(outputStream, [aKey unsignedIntValue], kMapKeyFieldNumber, keyDataType);
-    WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
   }];
 }
 
@@ -3369,13 +3428,13 @@
 }
 
 - (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
-  [self enumerateKeysAndValuesUsingBlock:^(uint32_t key, id value, BOOL *stop) {
+  [self enumerateKeysAndObjectsUsingBlock:^(uint32_t key, id object, BOOL *stop) {
       #pragma unused(stop)
-      block([NSString stringWithFormat:@"%u", key], value);
+      block([NSString stringWithFormat:@"%u", key], object);
   }];
 }
 
-- (id)valueForKey:(uint32_t)key {
+- (id)objectForKey:(uint32_t)key {
   id result = [_dictionary objectForKey:@(key)];
   return result;
 }
@@ -3389,14 +3448,18 @@
   }
 }
 
-- (void)setValue:(id)value forKey:(uint32_t)key {
-  [_dictionary setObject:value forKey:@(key)];
+- (void)setObject:(id)object forKey:(uint32_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
   }
 }
 
-- (void)removeValueForKey:(uint32_t)aKey {
+- (void)removeObjectForKey:(uint32_t)aKey {
   [_dictionary removeObjectForKey:@(aKey)];
 }
 
@@ -3440,7 +3503,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32UInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -3646,7 +3709,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32Int32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -3852,7 +3915,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32UInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -4058,7 +4121,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32Int64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -4264,7 +4327,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32BoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -4470,7 +4533,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32FloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -4676,7 +4739,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32DoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -5144,30 +5207,30 @@
 }
 
 + (instancetype)dictionary {
-  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
 }
 
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(int32_t)key {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int32_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithValues:&value
-                                                          forKeys:&key
-                                                            count:1] autorelease];
+  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                           forKeys:&key
+                                                             count:1] autorelease];
 }
 
-+ (instancetype)dictionaryWithValues:(const id [])values
-                             forKeys:(const int32_t [])keys
-                               count:(NSUInteger)count {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const int32_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithValues:values
+  return [[(GPBInt32ObjectDictionary*)[self alloc] initWithObjects:objects
                                                           forKeys:keys
                                                             count:count] autorelease];
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt32ObjectDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt32ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -5177,18 +5240,22 @@
 }
 
 - (instancetype)init {
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
-- (instancetype)initWithValues:(const id [])values
-                       forKeys:(const int32_t [])keys
-                         count:(NSUInteger)count {
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const int32_t [])keys
+                          count:(NSUInteger)count {
   self = [super init];
   if (self) {
     _dictionary = [[NSMutableDictionary alloc] init];
-    if (count && values && keys) {
+    if (count && objects && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
-        [_dictionary setObject:values[i] forKey:@(keys[i])];
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
       }
     }
   }
@@ -5196,7 +5263,7 @@
 }
 
 - (instancetype)initWithDictionary:(GPBInt32ObjectDictionary *)dictionary {
-  self = [self initWithValues:NULL forKeys:NULL count:0];
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
   if (self) {
     if (dictionary) {
       [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
@@ -5207,7 +5274,7 @@
 
 - (instancetype)initWithCapacity:(NSUInteger)numItems {
   #pragma unused(numItems)
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
 - (void)dealloc {
@@ -5244,12 +5311,12 @@
   return _dictionary.count;
 }
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(int32_t key, id value, BOOL *stop))block {
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int32_t key, id object, BOOL *stop))block {
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
-      block([aKey intValue], aValue, stop);
+      block([aKey intValue], aObject, stop);
   }];
 }
 
@@ -5286,11 +5353,11 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   __block size_t result = 0;
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
   }];
   size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
@@ -5304,18 +5371,18 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     // Write the tag.
     [outputStream writeInt32NoTag:tag];
     // Write the size of the message.
     size_t msgSize = ComputeDictInt32FieldSize([aKey intValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     [outputStream writeInt32NoTag:(int32_t)msgSize];
     // Write the fields.
     WriteDictInt32Field(outputStream, [aKey intValue], kMapKeyFieldNumber, keyDataType);
-    WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
   }];
 }
 
@@ -5325,13 +5392,13 @@
 }
 
 - (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
-  [self enumerateKeysAndValuesUsingBlock:^(int32_t key, id value, BOOL *stop) {
+  [self enumerateKeysAndObjectsUsingBlock:^(int32_t key, id object, BOOL *stop) {
       #pragma unused(stop)
-      block([NSString stringWithFormat:@"%d", key], value);
+      block([NSString stringWithFormat:@"%d", key], object);
   }];
 }
 
-- (id)valueForKey:(int32_t)key {
+- (id)objectForKey:(int32_t)key {
   id result = [_dictionary objectForKey:@(key)];
   return result;
 }
@@ -5345,14 +5412,18 @@
   }
 }
 
-- (void)setValue:(id)value forKey:(int32_t)key {
-  [_dictionary setObject:value forKey:@(key)];
+- (void)setObject:(id)object forKey:(int32_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
   }
 }
 
-- (void)removeValueForKey:(int32_t)aKey {
+- (void)removeObjectForKey:(int32_t)aKey {
   [_dictionary removeObjectForKey:@(aKey)];
 }
 
@@ -5396,7 +5467,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64UInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -5602,7 +5673,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64Int32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -5808,7 +5879,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64UInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -6014,7 +6085,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64Int64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -6220,7 +6291,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64BoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -6426,7 +6497,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64FloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -6632,7 +6703,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64DoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -7100,30 +7171,30 @@
 }
 
 + (instancetype)dictionary {
-  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
 }
 
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(uint64_t)key {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(uint64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithValues:&value
-                                                           forKeys:&key
-                                                             count:1] autorelease];
+  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                            forKeys:&key
+                                                              count:1] autorelease];
 }
 
-+ (instancetype)dictionaryWithValues:(const id [])values
-                             forKeys:(const uint64_t [])keys
-                               count:(NSUInteger)count {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const uint64_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithValues:values
+  return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithObjects:objects
                                                            forKeys:keys
                                                              count:count] autorelease];
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBUInt64ObjectDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBUInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -7133,18 +7204,22 @@
 }
 
 - (instancetype)init {
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
-- (instancetype)initWithValues:(const id [])values
-                       forKeys:(const uint64_t [])keys
-                         count:(NSUInteger)count {
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const uint64_t [])keys
+                          count:(NSUInteger)count {
   self = [super init];
   if (self) {
     _dictionary = [[NSMutableDictionary alloc] init];
-    if (count && values && keys) {
+    if (count && objects && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
-        [_dictionary setObject:values[i] forKey:@(keys[i])];
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
       }
     }
   }
@@ -7152,7 +7227,7 @@
 }
 
 - (instancetype)initWithDictionary:(GPBUInt64ObjectDictionary *)dictionary {
-  self = [self initWithValues:NULL forKeys:NULL count:0];
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
   if (self) {
     if (dictionary) {
       [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
@@ -7163,7 +7238,7 @@
 
 - (instancetype)initWithCapacity:(NSUInteger)numItems {
   #pragma unused(numItems)
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
 - (void)dealloc {
@@ -7200,12 +7275,12 @@
   return _dictionary.count;
 }
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(uint64_t key, id value, BOOL *stop))block {
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(uint64_t key, id object, BOOL *stop))block {
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
-      block([aKey unsignedLongLongValue], aValue, stop);
+      block([aKey unsignedLongLongValue], aObject, stop);
   }];
 }
 
@@ -7242,11 +7317,11 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   __block size_t result = 0;
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
   }];
   size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
@@ -7260,18 +7335,18 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     // Write the tag.
     [outputStream writeInt32NoTag:tag];
     // Write the size of the message.
     size_t msgSize = ComputeDictUInt64FieldSize([aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     [outputStream writeInt32NoTag:(int32_t)msgSize];
     // Write the fields.
     WriteDictUInt64Field(outputStream, [aKey unsignedLongLongValue], kMapKeyFieldNumber, keyDataType);
-    WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
   }];
 }
 
@@ -7281,13 +7356,13 @@
 }
 
 - (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
-  [self enumerateKeysAndValuesUsingBlock:^(uint64_t key, id value, BOOL *stop) {
+  [self enumerateKeysAndObjectsUsingBlock:^(uint64_t key, id object, BOOL *stop) {
       #pragma unused(stop)
-      block([NSString stringWithFormat:@"%llu", key], value);
+      block([NSString stringWithFormat:@"%llu", key], object);
   }];
 }
 
-- (id)valueForKey:(uint64_t)key {
+- (id)objectForKey:(uint64_t)key {
   id result = [_dictionary objectForKey:@(key)];
   return result;
 }
@@ -7301,14 +7376,18 @@
   }
 }
 
-- (void)setValue:(id)value forKey:(uint64_t)key {
-  [_dictionary setObject:value forKey:@(key)];
+- (void)setObject:(id)object forKey:(uint64_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
   }
 }
 
-- (void)removeValueForKey:(uint64_t)aKey {
+- (void)removeObjectForKey:(uint64_t)aKey {
   [_dictionary removeObjectForKey:@(aKey)];
 }
 
@@ -7352,7 +7431,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64UInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64UInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -7558,7 +7637,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64Int32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64Int32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -7764,7 +7843,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64UInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64UInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -7970,7 +8049,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64Int64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64Int64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -8176,7 +8255,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64BoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64BoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -8382,7 +8461,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64FloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64FloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -8588,7 +8667,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64DoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64DoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9056,30 +9135,30 @@
 }
 
 + (instancetype)dictionary {
-  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
 }
 
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(int64_t)key {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(int64_t)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithValues:&value
-                                                          forKeys:&key
-                                                            count:1] autorelease];
+  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithObjects:&object
+                                                           forKeys:&key
+                                                             count:1] autorelease];
 }
 
-+ (instancetype)dictionaryWithValues:(const id [])values
-                             forKeys:(const int64_t [])keys
-                               count:(NSUInteger)count {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const int64_t [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithValues:values
+  return [[(GPBInt64ObjectDictionary*)[self alloc] initWithObjects:objects
                                                           forKeys:keys
                                                             count:count] autorelease];
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBInt64ObjectDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBInt64ObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9089,18 +9168,22 @@
 }
 
 - (instancetype)init {
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
-- (instancetype)initWithValues:(const id [])values
-                       forKeys:(const int64_t [])keys
-                         count:(NSUInteger)count {
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const int64_t [])keys
+                          count:(NSUInteger)count {
   self = [super init];
   if (self) {
     _dictionary = [[NSMutableDictionary alloc] init];
-    if (count && values && keys) {
+    if (count && objects && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
-        [_dictionary setObject:values[i] forKey:@(keys[i])];
+        if (!objects[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil object to a Dictionary"];
+        }
+        [_dictionary setObject:objects[i] forKey:@(keys[i])];
       }
     }
   }
@@ -9108,7 +9191,7 @@
 }
 
 - (instancetype)initWithDictionary:(GPBInt64ObjectDictionary *)dictionary {
-  self = [self initWithValues:NULL forKeys:NULL count:0];
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
   if (self) {
     if (dictionary) {
       [_dictionary addEntriesFromDictionary:dictionary->_dictionary];
@@ -9119,7 +9202,7 @@
 
 - (instancetype)initWithCapacity:(NSUInteger)numItems {
   #pragma unused(numItems)
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
 - (void)dealloc {
@@ -9156,12 +9239,12 @@
   return _dictionary.count;
 }
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(int64_t key, id value, BOOL *stop))block {
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(int64_t key, id object, BOOL *stop))block {
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
-      block([aKey longLongValue], aValue, stop);
+      block([aKey longLongValue], aObject, stop);
   }];
 }
 
@@ -9198,11 +9281,11 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   __block size_t result = 0;
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     result += GPBComputeRawVarint32SizeForInteger(msgSize) + msgSize;
   }];
   size_t tagSize = GPBComputeWireFormatTagSize(GPBFieldNumber(field), GPBDataTypeMessage);
@@ -9216,18 +9299,18 @@
   GPBDataType keyDataType = field.mapKeyDataType;
   uint32_t tag = GPBWireFormatMakeTag(GPBFieldNumber(field), GPBWireFormatLengthDelimited);
   [_dictionary enumerateKeysAndObjectsUsingBlock:^(NSNumber *aKey,
-                                                   id aValue,
+                                                   id aObject,
                                                    BOOL *stop) {
     #pragma unused(stop)
     // Write the tag.
     [outputStream writeInt32NoTag:tag];
     // Write the size of the message.
     size_t msgSize = ComputeDictInt64FieldSize([aKey longLongValue], kMapKeyFieldNumber, keyDataType);
-    msgSize += ComputeDictObjectFieldSize(aValue, kMapValueFieldNumber, valueDataType);
+    msgSize += ComputeDictObjectFieldSize(aObject, kMapValueFieldNumber, valueDataType);
     [outputStream writeInt32NoTag:(int32_t)msgSize];
     // Write the fields.
     WriteDictInt64Field(outputStream, [aKey longLongValue], kMapKeyFieldNumber, keyDataType);
-    WriteDictObjectField(outputStream, aValue, kMapValueFieldNumber, valueDataType);
+    WriteDictObjectField(outputStream, aObject, kMapValueFieldNumber, valueDataType);
   }];
 }
 
@@ -9237,13 +9320,13 @@
 }
 
 - (void)enumerateForTextFormat:(void (^)(id keyObj, id valueObj))block {
-  [self enumerateKeysAndValuesUsingBlock:^(int64_t key, id value, BOOL *stop) {
+  [self enumerateKeysAndObjectsUsingBlock:^(int64_t key, id object, BOOL *stop) {
       #pragma unused(stop)
-      block([NSString stringWithFormat:@"%lld", key], value);
+      block([NSString stringWithFormat:@"%lld", key], object);
   }];
 }
 
-- (id)valueForKey:(int64_t)key {
+- (id)objectForKey:(int64_t)key {
   id result = [_dictionary objectForKey:@(key)];
   return result;
 }
@@ -9257,14 +9340,18 @@
   }
 }
 
-- (void)setValue:(id)value forKey:(int64_t)key {
-  [_dictionary setObject:value forKey:@(key)];
+- (void)setObject:(id)object forKey:(int64_t)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
+  [_dictionary setObject:object forKey:@(key)];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
   }
 }
 
-- (void)removeValueForKey:(int64_t)aKey {
+- (void)removeObjectForKey:(int64_t)aKey {
   [_dictionary removeObjectForKey:@(aKey)];
 }
 
@@ -9308,7 +9395,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringUInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9329,6 +9416,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -9467,6 +9558,10 @@
 }
 
 - (void)setValue:(uint32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -9514,7 +9609,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9535,6 +9630,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -9673,6 +9772,10 @@
 }
 
 - (void)setValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -9720,7 +9823,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringUInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9741,6 +9844,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -9879,6 +9986,10 @@
 }
 
 - (void)setValue:(uint64_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -9926,7 +10037,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -9947,6 +10058,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -10085,6 +10200,10 @@
 }
 
 - (void)setValue:(int64_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -10132,7 +10251,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringBoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -10153,6 +10272,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -10291,6 +10414,10 @@
 }
 
 - (void)setValue:(BOOL)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -10338,7 +10465,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringFloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -10359,6 +10486,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -10497,6 +10628,10 @@
 }
 
 - (void)setValue:(float)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -10544,7 +10679,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBStringDoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBStringDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -10565,6 +10700,10 @@
     _dictionary = [[NSMutableDictionary alloc] init];
     if (count && values && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(values[i]) forKey:keys[i]];
       }
     }
@@ -10703,6 +10842,10 @@
 }
 
 - (void)setValue:(double)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -10795,6 +10938,10 @@
     _validationFunc = (func != NULL ? func : DictDefault_IsValidValue);
     if (count && rawValues && keys) {
       for (NSUInteger i = 0; i < count; ++i) {
+        if (!keys[i]) {
+          [NSException raise:NSInvalidArgumentException
+                      format:@"Attempting to add nil key to a Dictionary"];
+        }
         [_dictionary setObject:@(rawValues[i]) forKey:keys[i]];
       }
     }
@@ -10975,6 +11122,10 @@
 }
 
 - (void)setRawValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   [_dictionary setObject:@(value) forKey:key];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
@@ -10990,6 +11141,10 @@
 }
 
 - (void)setValue:(int32_t)value forKey:(NSString *)key {
+  if (!key) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil key to a Dictionary"];
+  }
   if (!_validationFunc(value)) {
     [NSException raise:NSInvalidArgumentException
                 format:@"GPBStringEnumDictionary: Attempt to set an unknown enum value (%d)",
@@ -11042,7 +11197,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolUInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolUInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -11283,7 +11438,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolInt32Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolInt32Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -11524,7 +11679,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolUInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolUInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -11765,7 +11920,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolInt64Dictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolInt64Dictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -12006,7 +12161,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolBoolDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolBoolDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -12247,7 +12402,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolFloatDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolFloatDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -12488,7 +12643,7 @@
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolDoubleDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolDoubleDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -12705,30 +12860,30 @@
 }
 
 + (instancetype)dictionary {
-  return [[[self alloc] initWithValues:NULL forKeys:NULL count:0] autorelease];
+  return [[[self alloc] initWithObjects:NULL forKeys:NULL count:0] autorelease];
 }
 
-+ (instancetype)dictionaryWithValue:(id)value
-                             forKey:(BOOL)key {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObject:(id)object
+                              forKey:(BOOL)key {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBBoolObjectDictionary*)[self alloc] initWithValues:&value
-                                                         forKeys:&key
-                                                           count:1] autorelease];
+  return [[(GPBBoolObjectDictionary*)[self alloc] initWithObjects:&object
+                                                          forKeys:&key
+                                                            count:1] autorelease];
 }
 
-+ (instancetype)dictionaryWithValues:(const id [])values
-                             forKeys:(const BOOL [])keys
-                               count:(NSUInteger)count {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
++ (instancetype)dictionaryWithObjects:(const id [])objects
+                              forKeys:(const BOOL [])keys
+                                count:(NSUInteger)count {
+  // Cast is needed so the compiler knows what class we are invoking initWithObjects:forKeys:count:
   // on to get the type correct.
-  return [[(GPBBoolObjectDictionary*)[self alloc] initWithValues:values
-                                                         forKeys:keys
-                                                           count:count] autorelease];
+  return [[(GPBBoolObjectDictionary*)[self alloc] initWithObjects:objects
+                                                          forKeys:keys
+                                                            count:count] autorelease];
 }
 
 + (instancetype)dictionaryWithDictionary:(GPBBoolObjectDictionary *)dictionary {
-  // Cast is needed so the compiler knows what class we are invoking initWithValues:forKeys:count:
+  // Cast is needed so the compiler knows what class we are invoking initWithDictionary:
   // on to get the type correct.
   return [[(GPBBoolObjectDictionary*)[self alloc] initWithDictionary:dictionary] autorelease];
 }
@@ -12738,25 +12893,29 @@
 }
 
 - (instancetype)init {
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
-- (instancetype)initWithValues:(const id [])values
-                       forKeys:(const BOOL [])keys
-                         count:(NSUInteger)count {
+- (instancetype)initWithObjects:(const id [])objects
+                        forKeys:(const BOOL [])keys
+                          count:(NSUInteger)count {
   self = [super init];
   if (self) {
     for (NSUInteger i = 0; i < count; ++i) {
+      if (!objects[i]) {
+        [NSException raise:NSInvalidArgumentException
+                    format:@"Attempting to add nil object to a Dictionary"];
+      }
       int idx = keys[i] ? 1 : 0;
       [_values[idx] release];
-      _values[idx] = (id)[values[i] retain];
+      _values[idx] = (id)[objects[i] retain];
     }
   }
   return self;
 }
 
 - (instancetype)initWithDictionary:(GPBBoolObjectDictionary *)dictionary {
-  self = [self initWithValues:NULL forKeys:NULL count:0];
+  self = [self initWithObjects:NULL forKeys:NULL count:0];
   if (self) {
     if (dictionary) {
       _values[0] = [dictionary->_values[0] retain];
@@ -12768,7 +12927,7 @@
 
 - (instancetype)initWithCapacity:(NSUInteger)numItems {
   #pragma unused(numItems)
-  return [self initWithValues:NULL forKeys:NULL count:0];
+  return [self initWithObjects:NULL forKeys:NULL count:0];
 }
 
 - (void)dealloc {
@@ -12822,7 +12981,7 @@
   return ((_values[0] != nil) ? 1 : 0) + ((_values[1] != nil) ? 1 : 0);
 }
 
-- (id)valueForKey:(BOOL)key {
+- (id)objectForKey:(BOOL)key {
   return _values[key ? 1 : 0];
 }
 
@@ -12842,8 +13001,8 @@
   }
 }
 
-- (void)enumerateKeysAndValuesUsingBlock:
-    (void (^)(BOOL key, id value, BOOL *stop))block {
+- (void)enumerateKeysAndObjectsUsingBlock:
+    (void (^)(BOOL key, id object, BOOL *stop))block {
   BOOL stop = NO;
   if (_values[0] != nil) {
     block(NO, _values[0], &stop);
@@ -12924,16 +13083,20 @@
   }
 }
 
-- (void)setValue:(id)value forKey:(BOOL)key {
+- (void)setObject:(id)object forKey:(BOOL)key {
+  if (!object) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Attempting to add nil object to a Dictionary"];
+  }
   int idx = (key ? 1 : 0);
   [_values[idx] release];
-  _values[idx] = [value retain];
+  _values[idx] = [object retain];
   if (_autocreator) {
     GPBAutocreatedDictionaryModified(_autocreator, self);
   }
 }
 
-- (void)removeValueForKey:(BOOL)aKey {
+- (void)removeObjectForKey:(BOOL)aKey {
   int idx = (aKey ? 1 : 0);
   [_values[idx] release];
   _values[idx] = nil;
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index d4c2fcc..332393e 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -127,7 +127,7 @@
 
 // Same as -[data], except a delimiter is added to the start of the data
 // indicating the size of the message data that follows.
-- (nullable NSData *)delimitedData;
+- (NSData *)delimitedData;
 
 // Returns the size of the object if it were serialized.
 // This is not a cached value. If you are following a pattern like this:
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index c655edd..fdb695e 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -55,10 +55,15 @@
 static NSString *const kGPBDataCoderKey = @"GPBData";
 
 #ifndef _GPBCompileAssert
-#define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg
-#define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg)
-#define _GPBCompileAssert(test, msg) \
-    typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
+  #if __has_feature(c_static_assert) || __has_extension(c_static_assert)
+    #define _GPBCompileAssert(test, msg) _Static_assert((test), #msg)
+  #else
+    // Pre-Xcode 7 support.
+    #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg
+    #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg)
+    #define _GPBCompileAssert(test, msg) \
+        typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
+  #endif  // __has_feature(c_static_assert) || __has_extension(c_static_assert)
 #endif // _GPBCompileAssert
 
 //
@@ -563,13 +568,13 @@
   id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!array) {
     // Check again after getting the lock.
-    OSSpinLockLock(&self->readOnlyMutex_);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
     array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
     if (!array) {
       array = CreateArrayForField(field, self);
       GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array);
     }
-    OSSpinLockUnlock(&self->readOnlyMutex_);
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
   }
   return array;
 }
@@ -593,13 +598,13 @@
   id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!dict) {
     // Check again after getting the lock.
-    OSSpinLockLock(&self->readOnlyMutex_);
+    dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
     dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
     if (!dict) {
       dict = CreateMapForField(field, self);
       GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict);
     }
-    OSSpinLockUnlock(&self->readOnlyMutex_);
+    dispatch_semaphore_signal(self->readOnlySemaphore_);
   }
   return dict;
 }
@@ -805,7 +810,7 @@
     messageStorage_ = (GPBMessage_StoragePtr)(
         ((uint8_t *)self) + class_getInstanceSize([self class]));
 
-    readOnlyMutex_ = OS_SPINLOCK_INIT;
+    readOnlySemaphore_ = dispatch_semaphore_create(1);
   }
 
   return self;
@@ -881,6 +886,7 @@
 - (void)dealloc {
   [self internalClear:NO];
   NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
+  dispatch_release(readOnlySemaphore_);
   [super dealloc];
 }
 
@@ -1212,7 +1218,8 @@
     NSLog(@"%@: Internal exception while building message delimitedData: %@",
           [self class], exception);
 #endif
-    data = nil;
+    // If it happens, truncate.
+    data.length = 0;
   }
   [stream release];
   return data;
@@ -1717,7 +1724,7 @@
   }
 
   // Check for an autocreated value.
-  OSSpinLockLock(&readOnlyMutex_);
+  dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER);
   value = [autocreatedExtensionMap_ objectForKey:extension];
   if (!value) {
     // Auto create the message extensions to match normal fields.
@@ -1734,7 +1741,7 @@
     [value release];
   }
 
-  OSSpinLockUnlock(&readOnlyMutex_);
+  dispatch_semaphore_signal(readOnlySemaphore_);
   return value;
 }
 
@@ -1791,7 +1798,12 @@
     extensionMap_ = [[NSMutableDictionary alloc] init];
   }
 
-  [extensionMap_ setObject:value forKey:extension];
+  // This pointless cast is for CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION.
+  // Without it, the compiler complains we're passing an id nullable when
+  // setObject:forKey: requires a id nonnull for the value. The check for
+  // !value at the start of the method ensures it isn't nil, but the check
+  // isn't smart enough to realize that.
+  [extensionMap_ setObject:(id)value forKey:extension];
 
   GPBExtensionDescriptor *descriptor = extension;
 
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
index d4c3501..b7e24fc 100644
--- a/objectivec/GPBMessage_PackagePrivate.h
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -62,7 +62,12 @@
   // by *read* operations such as getters (autocreation of message fields and
   // message extensions, not setting of values). Used to guarantee thread safety
   // for concurrent reads on the message.
-  OSSpinLock readOnlyMutex_;
+  // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+  // pointed out that they are vulnerable to live locking on iOS in cases of
+  // priority inversion:
+  //   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+  //   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+  dispatch_semaphore_t readOnlySemaphore_;
 }
 
 // Gets an extension value without autocreating the result if not found. (i.e.
diff --git a/objectivec/GPBProtocolBuffers.h b/objectivec/GPBProtocolBuffers.h
index 0c85259..677903e 100644
--- a/objectivec/GPBProtocolBuffers.h
+++ b/objectivec/GPBProtocolBuffers.h
@@ -41,6 +41,7 @@
 #import "GPBUnknownField.h"
 #import "GPBUnknownFieldSet.h"
 #import "GPBUtilities.h"
+#import "GPBWellKnownTypes.h"
 #import "GPBWireFormat.h"
 
 // Well-known proto types
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m
index 7036723..4570716 100644
--- a/objectivec/GPBRootObject.m
+++ b/objectivec/GPBRootObject.m
@@ -31,7 +31,6 @@
 #import "GPBRootObject_PackagePrivate.h"
 
 #import <objc/runtime.h>
-#import <libkern/OSAtomic.h>
 
 #import <CoreFoundation/CoreFoundation.h>
 
@@ -96,13 +95,19 @@
   return jenkins_one_at_a_time_hash(key);
 }
 
-static OSSpinLock gExtensionSingletonDictionaryLock_ = OS_SPINLOCK_INIT;
+// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have
+// pointed out that they are vulnerable to live locking on iOS in cases of
+// priority inversion:
+//   http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
+//   https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
+static dispatch_semaphore_t gExtensionSingletonDictionarySemaphore;
 static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL;
 static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL;
 
 + (void)initialize {
   // Ensure the global is started up.
   if (!gExtensionSingletonDictionary) {
+    gExtensionSingletonDictionarySemaphore = dispatch_semaphore_create(1);
     CFDictionaryKeyCallBacks keyCallBacks = {
       // See description above for reason for using custom dictionary.
       0,
@@ -134,9 +139,10 @@
 
 + (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field {
   const char *key = [field singletonNameC];
-  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
   CFDictionarySetValue(gExtensionSingletonDictionary, key, field);
-  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
 }
 
 static id ExtensionForName(id self, SEL _cmd) {
@@ -166,14 +172,24 @@
   key[classNameLen] = '_';
   memcpy(&key[classNameLen + 1], selName, selNameLen);
   key[classNameLen + 1 + selNameLen] = '\0';
-  OSSpinLockLock(&gExtensionSingletonDictionaryLock_);
+
+  // NOTE: Even though this method is called from another C function,
+  // gExtensionSingletonDictionarySemaphore and gExtensionSingletonDictionary
+  // will always be initialized. This is because this call flow is just to
+  // lookup the Extension, meaning the code is calling an Extension class
+  // message on a Message or Root class. This guarantees that the class was
+  // initialized and Message classes ensure their Root was also initialized.
+  NSAssert(gExtensionSingletonDictionary, @"Startup order broken!");
+
+  dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
+                          DISPATCH_TIME_FOREVER);
   id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
   if (extension) {
     // The method is getting wired in to the class, so no need to keep it in
     // the dictionary.
     CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
   }
-  OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_);
+  dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
   return extension;
 }
 
diff --git a/objectivec/GPBUnknownField.h b/objectivec/GPBUnknownField.h
index 12d72a9..43709ee 100644
--- a/objectivec/GPBUnknownField.h
+++ b/objectivec/GPBUnknownField.h
@@ -45,8 +45,8 @@
 @property(nonatomic, readonly, strong) GPBUInt64Array *varintList;
 @property(nonatomic, readonly, strong) GPBUInt32Array *fixed32List;
 @property(nonatomic, readonly, strong) GPBUInt64Array *fixed64List;
-@property(nonatomic, readonly, strong) NSArray *lengthDelimitedList;  // NSData
-@property(nonatomic, readonly, strong) NSArray *groupList;  // GPBUnknownFieldSet
+@property(nonatomic, readonly, strong) NSArray<NSData*> *lengthDelimitedList;
+@property(nonatomic, readonly, strong) NSArray<GPBUnknownFieldSet*> *groupList;
 
 // Only one of these should be used per Field.
 - (void)addVarint:(uint64_t)value;
diff --git a/objectivec/GPBUnknownField.m b/objectivec/GPBUnknownField.m
index c49c0df..22ed66a 100644
--- a/objectivec/GPBUnknownField.m
+++ b/objectivec/GPBUnknownField.m
@@ -39,8 +39,8 @@
   GPBUInt64Array *mutableVarintList_;
   GPBUInt32Array *mutableFixed32List_;
   GPBUInt64Array *mutableFixed64List_;
-  NSMutableArray *mutableLengthDelimitedList_;
-  NSMutableArray *mutableGroupList_;
+  NSMutableArray<NSData*> *mutableLengthDelimitedList_;
+  NSMutableArray<GPBUnknownFieldSet*> *mutableGroupList_;
 }
 
 @synthesize number = number_;
diff --git a/objectivec/GPBUnknownFieldSet.h b/objectivec/GPBUnknownFieldSet.h
index d785ca1..8db0132 100644
--- a/objectivec/GPBUnknownFieldSet.h
+++ b/objectivec/GPBUnknownFieldSet.h
@@ -42,8 +42,8 @@
 
 - (void)addField:(GPBUnknownField *)field;
 
-// Returns an NSArray of the GPBFields sorted by the field numbers.
-- (NSArray *)sortedFields;
+// Returns an NSArray of the GPBUnknownFields sorted by the field numbers.
+- (NSArray<GPBUnknownField*> *)sortedFields;
 
 @end
 
diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h
index 1301b43..5b55104 100644
--- a/objectivec/GPBUtilities.h
+++ b/objectivec/GPBUtilities.h
@@ -44,7 +44,7 @@
 // most likely won't exactly match the original .proto file.
 NSString *GPBTextFormatForMessage(GPBMessage *message,
                                   NSString * __nullable lineIndent);
-NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
+NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet * __nullable unknownSet,
                                           NSString * __nullable lineIndent);
 
 //
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 5ee6123..d4d6471 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -411,7 +411,7 @@
     return field.defaultValue.valueMessage;
   }
 
-  OSSpinLockLock(&self->readOnlyMutex_);
+  dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
   GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
   if (!result) {
     // For non repeated messages, create the object, set it and return it.
@@ -420,7 +420,7 @@
     result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
     GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
   }
-  OSSpinLockUnlock(&self->readOnlyMutex_);
+  dispatch_semaphore_signal(self->readOnlySemaphore_);
   return result;
 }
 
@@ -1253,7 +1253,7 @@
   if ([fieldName length] == 0) {
     fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
     // If there is only one entry, put the objc name as a comment, other wise
-    // add it before the the repeated values.
+    // add it before the repeated values.
     if (count > 1) {
       [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
     } else {
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
index b0a0712..6b34b9b 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
@@ -28,7 +28,6 @@
 		8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
 		8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; };
 		8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; };
-		8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; };
 		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
 		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
 		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
@@ -58,6 +57,7 @@
 		F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */; };
 		F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */; };
 		F45E57C71AE6DC6A000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */; };
+		F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */; };
 		F4E675971B21D0000054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675871B21D0000054530B /* Any.pbobjc.m */; };
 		F4E675991B21D0000054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675891B21D0000054530B /* Api.pbobjc.m */; };
 		F4E6759B1B21D0000054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758B1B21D0000054530B /* Empty.pbobjc.m */; };
@@ -157,7 +157,6 @@
 		8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; };
 		8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; };
 		8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; };
-		8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; };
 		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
 		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
@@ -193,6 +192,7 @@
 		F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionInternals.m; sourceTree = "<group>"; };
 		F45E57C61AE6DC6A000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; };
 		F4AC9E1D1A8BEB3500BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; };
+		F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GPBObjectiveCPlusPlusTest.mm; sourceTree = "<group>"; };
 		F4B6B8AF1A9CC98000892426 /* GPBUnknownField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B61A9CD1DE00892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; };
@@ -415,8 +415,8 @@
 				F4487C821AAF6AB300531423 /* GPBMessageTests+Merge.m */,
 				F4487C741AADF7F500531423 /* GPBMessageTests+Runtime.m */,
 				F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */,
+				F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */,
 				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
-				8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */,
 				8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */,
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
@@ -564,8 +564,9 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
+				LastSwiftUpdateCheck = 0710;
 				LastTestingUpgradeCheck = 0600;
-				LastUpgradeCheck = 0630;
+				LastUpgradeCheck = 0710;
 				TargetAttributes = {
 					8BBEA4A5147C727100C4ADB7 = {
 						TestTargetID = 8B9A5EA41831993600A9D33B;
@@ -668,6 +669,7 @@
 				8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */,
 				F4E675B21B21D0A70054530B /* SourceContext.pbobjc.m in Sources */,
 				8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */,
+				F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
 				F4487C7F1AAF62CD00531423 /* GPBMessageTests+Serialization.m in Sources */,
 				8B4248DC1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m in Sources */,
 				F4E675B01B21D0A70054530B /* Empty.pbobjc.m in Sources */,
@@ -684,7 +686,6 @@
 				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
 				F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
 				F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */,
-				8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */,
 				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
 				F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */,
 				F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
@@ -752,6 +753,7 @@
 				);
 				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:identifier}";
 				PRODUCT_NAME = UnitTests;
 				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -769,6 +771,7 @@
 				);
 				INFOPLIST_FILE = "Tests/UnitTests-Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:identifier}";
 				PRODUCT_NAME = UnitTests;
 				SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnitTests-Bridging-Header.h";
 			};
@@ -783,10 +786,12 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				ENABLE_TESTABILITY = YES;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
@@ -827,6 +832,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
index 3b3eeb1..25814c5 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0630"
+   LastUpgradeVersion = "0710"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -23,10 +23,10 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Release"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Release">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
             skipped = "NO">
@@ -159,6 +159,9 @@
                   Identifier = "GPBInt64UInt64DictionaryTests">
                </Test>
                <Test
+                  Identifier = "GPBObjectiveCPlusPlusTests">
+               </Test>
+               <Test
                   Identifier = "GPBStringBoolDictionaryTests">
                </Test>
                <Test
@@ -180,9 +183,6 @@
                   Identifier = "GPBStringInt64DictionaryTests">
                </Test>
                <Test
-                  Identifier = "GPBStringTests">
-               </Test>
-               <Test
                   Identifier = "GPBStringUInt32DictionaryTests">
                </Test>
                <Test
@@ -284,15 +284,18 @@
             </SkippedTests>
          </TestableReference>
       </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Release"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
       <MacroExpansion>
          <BuildableReference
@@ -307,10 +310,10 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <MacroExpansion>
          <BuildableReference
diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
index 583a464..8f510f5 100644
--- a/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
+++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0630"
+   LastUpgradeVersion = "0710"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -51,10 +51,10 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
             skipped = "NO">
@@ -81,15 +81,18 @@
             ReferencedContainer = "container:ProtocolBuffers_OSX.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
       <MacroExpansion>
          <BuildableReference
@@ -104,10 +107,10 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <MacroExpansion>
          <BuildableReference
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
index 23e9f16..e9d3fc9 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
@@ -36,7 +36,6 @@
 		8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB31831993600A9D33B /* AppDelegate.m */; };
 		8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB51831993600A9D33B /* Images.xcassets */; };
 		8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; };
-		8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; };
 		8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; };
 		8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; };
 		8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; };
@@ -66,6 +65,7 @@
 		F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */; };
 		F45C69CC16DFD08D0081955B /* GPBExtensionInternals.m in Sources */ = {isa = PBXBuildFile; fileRef = F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */; };
 		F45E57C91AE6DC98000B7D99 /* text_format_map_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */; };
+		F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */; };
 		F4E675C81B21D1610054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B71B21D1440054530B /* Any.pbobjc.m */; };
 		F4E675C91B21D1610054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B91B21D1440054530B /* Api.pbobjc.m */; };
 		F4E675CA1B21D1610054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BC1B21D1440054530B /* Empty.pbobjc.m */; };
@@ -178,7 +178,6 @@
 		8B9A5EAD1831993600A9D33B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		8B9A5EB31831993600A9D33B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
 		8B9A5EB51831993600A9D33B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
-		8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; };
 		8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; };
 		8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; };
@@ -214,6 +213,7 @@
 		F45C69CB16DFD08D0081955B /* GPBExtensionInternals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBExtensionInternals.m; sourceTree = "<group>"; };
 		F45E57C81AE6DC98000B7D99 /* text_format_map_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_map_unittest_data.txt; sourceTree = "<group>"; };
 		F4AC9E1C1A8BEB1000BD6E83 /* unittest_cycle.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_cycle.proto; sourceTree = "<group>"; };
+		F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GPBObjectiveCPlusPlusTest.mm; sourceTree = "<group>"; };
 		F4B6B8B01A9CC99500892426 /* GPBUnknownField_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownField_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
 		F4B6B8B31A9CD1C600892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; };
@@ -453,8 +453,8 @@
 				F4487C841AAF6AC500531423 /* GPBMessageTests+Merge.m */,
 				F4487C761AADF84900531423 /* GPBMessageTests+Runtime.m */,
 				F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */,
+				F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */,
 				F41C175C1833D3310064ED4D /* GPBPerfTests.m */,
-				8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */,
 				8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */,
 				7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */,
 				7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */,
@@ -641,8 +641,9 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
+				LastSwiftUpdateCheck = 0710;
 				LastTestingUpgradeCheck = 0600;
-				LastUpgradeCheck = 0630;
+				LastUpgradeCheck = 0710;
 				TargetAttributes = {
 					8BBEA4A5147C727100C4ADB7 = {
 						TestTargetID = 8B9A5EA41831993600A9D33B;
@@ -770,6 +771,7 @@
 				F4E675CE1B21D1610054530B /* Type.pbobjc.m in Sources */,
 				F4353D1F1AB88243005A6198 /* GPBDescriptorTests.m in Sources */,
 				F4E675CF1B21D1610054530B /* Wrappers.pbobjc.m in Sources */,
+				F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */,
 				F4E675C81B21D1610054530B /* Any.pbobjc.m in Sources */,
 				8B4248B41A8BD96E00BC1EC6 /* GPBSwiftTests.swift in Sources */,
 				5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */,
@@ -780,7 +782,6 @@
 				F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */,
 				F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */,
 				F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */,
-				8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */,
 				8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */,
 				F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */,
 				F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
@@ -861,6 +862,7 @@
 				CLANG_ENABLE_OBJC_ARC = YES;
 				INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME:rfc1034identifier}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
@@ -875,6 +877,7 @@
 				CLANG_ENABLE_OBJC_ARC = YES;
 				INFOPLIST_FILE = "$(SRCROOT)/Tests/iOSTestHarness/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.1;
+				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME:rfc1034identifier}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				WRAPPER_EXTENSION = app;
@@ -945,11 +948,13 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				ENABLE_TESTABILITY = YES;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
@@ -990,6 +995,7 @@
 				CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
 				CLANG_STATIC_ANALYZER_MODE = deep;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
 				CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
index 4898eb5..0b96b75 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/PerformanceTests.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0630"
+   LastUpgradeVersion = "0710"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -23,10 +23,10 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Release"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Release">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
             skipped = "NO">
@@ -159,6 +159,9 @@
                   Identifier = "GPBInt64UInt64DictionaryTests">
                </Test>
                <Test
+                  Identifier = "GPBObjectiveCPlusPlusTests">
+               </Test>
+               <Test
                   Identifier = "GPBStringBoolDictionaryTests">
                </Test>
                <Test
@@ -180,9 +183,6 @@
                   Identifier = "GPBStringInt64DictionaryTests">
                </Test>
                <Test
-                  Identifier = "GPBStringTests">
-               </Test>
-               <Test
                   Identifier = "GPBStringUInt32DictionaryTests">
                </Test>
                <Test
@@ -293,15 +293,18 @@
             ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Release"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
       <BuildableProductRunnable
          runnableDebuggingMode = "0">
@@ -317,10 +320,10 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <MacroExpansion>
          <BuildableReference
diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
index 19267fc..7d219bc 100644
--- a/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
+++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/xcshareddata/xcschemes/ProtocolBuffers.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0630"
+   LastUpgradeVersion = "0710"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -51,10 +51,10 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
             skipped = "NO">
@@ -81,15 +81,18 @@
             ReferencedContainer = "container:ProtocolBuffers_iOS.xcodeproj">
          </BuildableReference>
       </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
       allowLocationSimulation = "YES">
       <BuildableProductRunnable
          runnableDebuggingMode = "0">
@@ -105,10 +108,10 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <MacroExpansion>
          <BuildableReference
diff --git a/objectivec/README.md b/objectivec/README.md
index 134bf1a..c7313e4 100644
--- a/objectivec/README.md
+++ b/objectivec/README.md
@@ -10,10 +10,10 @@
 Requirements
 ------------
 
-The Objective C implemention requires:
+The Objective C implementation requires:
 
 - Objective C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X).
-- Xcode 6.3 (or later).
+- Xcode 7.0 (or later).
 - The library code does *not* use ARC (for performance reasons), but it all can
   be called from ARC code.
 
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
index 579fe65..b0e39d2 100644
--- a/objectivec/Tests/GPBCodedInputStreamTests.m
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -225,8 +225,10 @@
   // Serialize and parse it.  Make sure to parse from an InputStream, not
   // directly from a ByteString, so that CodedInputStream uses buffered
   // reading.
+  NSData *messageData = message.data;
+  XCTAssertNotNil(messageData);
   GPBCodedInputStream* stream =
-      [GPBCodedInputStream streamWithData:message.data];
+      [GPBCodedInputStream streamWithData:messageData];
   TestAllTypes* message2 = [TestAllTypes parseFromCodedInputStream:stream
                                                  extensionRegistry:nil
                                                              error:NULL];
@@ -264,6 +266,9 @@
 }
 
 // Verifies fix for b/10315336.
+// Note: Now that there isn't a custom string class under the hood, this test
+// isn't as critical, but it does cover bad input and if a custom class is added
+// again, it will help validate that class' handing of bad utf8.
 - (void)testReadMalformedString {
   NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
   GPBCodedOutputStream* output =
@@ -274,7 +279,7 @@
   [output writeRawVarint32:tag];
   [output writeRawVarint32:5];
   // Create an invalid utf-8 byte array.
-  uint8_t bytes[5] = {0xc2, 0xf2};
+  uint8_t bytes[] = {0xc2, 0xf2, 0x0, 0x0, 0x0};
   [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]];
   [output flush];
 
@@ -284,6 +289,7 @@
   TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
                                                 extensionRegistry:nil
                                                             error:NULL];
+  XCTAssertNotNil(message);
   // Make sure we can read string properties twice without crashing.
   XCTAssertEqual([message.defaultString length], (NSUInteger)0);
   XCTAssertEqualObjects(@"", message.defaultString);
diff --git a/objectivec/Tests/GPBDictionaryTests+Bool.m b/objectivec/Tests/GPBDictionaryTests+Bool.m
index 43650f5..afa3d11 100644
--- a/objectivec/Tests/GPBDictionaryTests+Bool.m
+++ b/objectivec/Tests/GPBDictionaryTests+Bool.m
@@ -167,10 +167,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -468,10 +468,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -769,10 +769,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -1070,10 +1070,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -1371,10 +1371,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -1672,10 +1672,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -1973,10 +1973,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -2147,7 +2147,7 @@
 
 @end
 
-//%PDDM-EXPAND TESTS_FOR_BOOL_KEY_OBJECT_VALUE(Object, id, @"abc", @"def")
+//%PDDM-EXPAND TESTS_FOR_BOOL_KEY_OBJECT_VALUE(Object, NSString*, @"abc", @"def")
 // This block of code is generated, do not edit it directly.
 
 #pragma mark - Bool -> Object
@@ -2158,49 +2158,49 @@
 @implementation GPBBoolObjectDictionaryTests
 
 - (void)testEmpty {
-  GPBBoolObjectDictionary *dict = [[GPBBoolObjectDictionary alloc] init];
+  GPBBoolObjectDictionary<NSString*> *dict = [[GPBBoolObjectDictionary alloc] init];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:YES]);
-  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue, stop)
+  XCTAssertNil([dict objectForKey:YES]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
     XCTFail(@"Shouldn't get here!");
   }];
   [dict release];
 }
 
 - (void)testOne {
-  GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionaryWithValue:@"abc" forKey:YES];
+  GPBBoolObjectDictionary<NSString*> *dict = [GPBBoolObjectDictionary dictionaryWithObject:@"abc" forKey:YES];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertNil([dict valueForKey:NO]);
-  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) {
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
     XCTAssertEqual(aKey, YES);
-    XCTAssertEqualObjects(aValue, @"abc");
+    XCTAssertEqualObjects(aObject, @"abc");
     XCTAssertNotEqual(stop, NULL);
   }];
 }
 
 - (void)testBasics {
   const BOOL kKeys[] = { YES, NO };
-  const id kValues[] = { @"abc", @"def" };
-  GPBBoolObjectDictionary *dict =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                              forKeys:kKeys
-                                                count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"def");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
 
   __block NSUInteger idx = 0;
   BOOL *seenKeys = malloc(2 * sizeof(BOOL));
-  id *seenValues = malloc(2 * sizeof(id));
-  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) {
+  NSString* *seenObjects = malloc(2 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
     XCTAssertLessThan(idx, 2U);
     seenKeys[idx] = aKey;
-    seenValues[idx] = aValue;
+    seenObjects[idx] = aObject;
     XCTAssertNotEqual(stop, NULL);
     ++idx;
   }];
@@ -2209,18 +2209,18 @@
     for (int j = 0; (j < 2) && !foundKey; ++j) {
       if (kKeys[i] == seenKeys[j]) {
         foundKey = YES;
-        XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
       }
     }
     XCTAssertTrue(foundKey, @"i = %d", i);
   }
   free(seenKeys);
-  free(seenValues);
+  free(seenObjects);
 
   // Stopping the enumeration.
   idx = 0;
-  [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue)
+  [dict enumerateKeysAndObjectsUsingBlock:^(BOOL aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
     if (idx == 0) *stop = YES;
     XCTAssertNotEqual(idx, 2U);
     ++idx;
@@ -2231,33 +2231,33 @@
 - (void)testEquality {
   const BOOL kKeys1[] = { YES, NO };
   const BOOL kKeys2[] = { NO, YES };
-  const id kValues1[] = { @"abc", @"def" };
-  const id kValues2[] = { @"def", @"abc" };
-  const id kValues3[] = { @"def" };
-  GPBBoolObjectDictionary *dict1 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues1
-                                              forKeys:kKeys1
-                                                count:GPBARRAYSIZE(kValues1)];
+  const NSString* kObjects1[] = { @"abc", @"def" };
+  const NSString* kObjects2[] = { @"def", @"abc" };
+  const NSString* kObjects3[] = { @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict1 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1);
-  GPBBoolObjectDictionary *dict1prime =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues1
-                                              forKeys:kKeys1
-                                                count:GPBARRAYSIZE(kValues1)];
+  GPBBoolObjectDictionary<NSString*> *dict1prime =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1prime);
-  GPBBoolObjectDictionary *dict2 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues2
-                                              forKeys:kKeys1
-                                                count:GPBARRAYSIZE(kValues2)];
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects2
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
-  GPBBoolObjectDictionary *dict3 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues1
-                                              forKeys:kKeys2
-                                                count:GPBARRAYSIZE(kValues1)];
+  GPBBoolObjectDictionary<NSString*> *dict3 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects1
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict3);
-  GPBBoolObjectDictionary *dict4 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues3
-                                              forKeys:kKeys1
-                                                count:GPBARRAYSIZE(kValues3)];
+  GPBBoolObjectDictionary<NSString*> *dict4 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects3
+                                               forKeys:kKeys1
+                                                 count:GPBARRAYSIZE(kObjects3)];
   XCTAssertNotNil(dict4);
 
   // 1/1Prime should be different objects, but equal.
@@ -2266,10 +2266,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 Fewer pairs; not equal
@@ -2284,14 +2284,14 @@
 
 - (void)testCopy {
   const BOOL kKeys[] = { YES, NO };
-  const id kValues[] = { @"abc", @"def" };
-  GPBBoolObjectDictionary *dict =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                              forKeys:kKeys
-                                                count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBBoolObjectDictionary *dict2 = [dict copy];
+  GPBBoolObjectDictionary<NSString*> *dict2 = [dict copy];
   XCTAssertNotNil(dict2);
 
   // Should be new object but equal.
@@ -2305,14 +2305,14 @@
 
 - (void)testDictionaryFromDictionary {
   const BOOL kKeys[] = { YES, NO };
-  const id kValues[] = { @"abc", @"def" };
-  GPBBoolObjectDictionary *dict =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                              forKeys:kKeys
-                                                count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBBoolObjectDictionary *dict2 =
+  GPBBoolObjectDictionary<NSString*> *dict2 =
       [GPBBoolObjectDictionary dictionaryWithDictionary:dict];
   XCTAssertNotNil(dict2);
 
@@ -2323,89 +2323,89 @@
 }
 
 - (void)testAdds {
-  GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionary];
+  GPBBoolObjectDictionary<NSString*> *dict = [GPBBoolObjectDictionary dictionary];
   XCTAssertNotNil(dict);
 
   XCTAssertEqual(dict.count, 0U);
-  [dict setValue:@"abc" forKey:YES];
+  [dict setObject:@"abc" forKey:YES];
   XCTAssertEqual(dict.count, 1U);
 
   const BOOL kKeys[] = { NO };
-  const id kValues[] = { @"def" };
-  GPBBoolObjectDictionary *dict2 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                              forKeys:kKeys
-                                                count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                               forKeys:kKeys
+                                                 count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 2U);
 
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"def");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
   [dict2 release];
 }
 
 - (void)testRemove {
   const BOOL kKeys[] = { YES, NO};
-  const id kValues[] = { @"abc", @"def" };
-  GPBBoolObjectDictionary *dict =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                       forKeys:kKeys
-                                         count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 2U);
 
-  [dict removeValueForKey:NO];
+  [dict removeObjectForKey:NO];
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertNil([dict valueForKey:NO]);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
 
   // Remove again does nothing.
-  [dict removeValueForKey:NO];
+  [dict removeObjectForKey:NO];
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertNil([dict valueForKey:NO]);
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertNil([dict objectForKey:NO]);
 
   [dict removeAll];
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:YES]);
-  XCTAssertNil([dict valueForKey:NO]);
+  XCTAssertNil([dict objectForKey:YES]);
+  XCTAssertNil([dict objectForKey:NO]);
   [dict release];
 }
 
 - (void)testInplaceMutation {
   const BOOL kKeys[] = { YES, NO };
-  const id kValues[] = { @"abc", @"def" };
-  GPBBoolObjectDictionary *dict =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues
-                                       forKeys:kKeys
-                                         count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def" };
+  GPBBoolObjectDictionary<NSString*> *dict =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects
+                                        forKeys:kKeys
+                                          count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"def");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
 
-  [dict setValue:@"def" forKey:YES];
+  [dict setObject:@"def" forKey:YES];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"def");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"def");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"def");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
 
-  [dict setValue:@"abc" forKey:NO];
+  [dict setObject:@"abc" forKey:NO];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"def");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"def");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"abc");
 
   const BOOL kKeys2[] = { NO, YES };
-  const id kValues2[] = { @"def", @"abc" };
-  GPBBoolObjectDictionary *dict2 =
-      [[GPBBoolObjectDictionary alloc] initWithValues:kValues2
-                                              forKeys:kKeys2
-                                                count:GPBARRAYSIZE(kValues2)];
+  const NSString* kObjects2[] = { @"def", @"abc" };
+  GPBBoolObjectDictionary<NSString*> *dict2 =
+      [[GPBBoolObjectDictionary alloc] initWithObjects:kObjects2
+                                               forKeys:kKeys2
+                                                 count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:YES], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:NO], @"def");
+  XCTAssertEqualObjects([dict objectForKey:YES], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:NO], @"def");
 
   [dict2 release];
   [dict release];
diff --git a/objectivec/Tests/GPBDictionaryTests+Int32.m b/objectivec/Tests/GPBDictionaryTests+Int32.m
index 1ee099e..54dd2ed 100644
--- a/objectivec/Tests/GPBDictionaryTests+Int32.m
+++ b/objectivec/Tests/GPBDictionaryTests+Int32.m
@@ -211,10 +211,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -568,10 +568,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -925,10 +925,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1282,10 +1282,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1639,10 +1639,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1996,10 +1996,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2353,10 +2353,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2710,10 +2710,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3071,10 +3071,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3363,51 +3363,51 @@
 @implementation GPBInt32ObjectDictionaryTests
 
 - (void)testEmpty {
-  GPBInt32ObjectDictionary *dict = [[GPBInt32ObjectDictionary alloc] init];
+  GPBInt32ObjectDictionary<NSString*> *dict = [[GPBInt32ObjectDictionary alloc] init];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:11]);
-  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue, stop)
+  XCTAssertNil([dict objectForKey:11]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
     XCTFail(@"Shouldn't get here!");
   }];
   [dict release];
 }
 
 - (void)testOne {
-  GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:11];
+  GPBInt32ObjectDictionary<NSString*> *dict = [GPBInt32ObjectDictionary dictionaryWithObject:@"abc" forKey:11];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertNil([dict valueForKey:12]);
-  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) {
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertEqual(aKey, 11);
-    XCTAssertEqualObjects(aValue, @"abc");
+    XCTAssertEqualObjects(aObject, @"abc");
     XCTAssertNotEqual(stop, NULL);
   }];
 }
 
 - (void)testBasics {
   const int32_t kKeys[] = { 11, 12, 13 };
-  const id kValues[] = { @"abc", @"def", @"ghi" };
-  GPBInt32ObjectDictionary *dict =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:12], @"def");
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertNil([dict valueForKey:14]);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertNil([dict objectForKey:14]);
 
   __block NSUInteger idx = 0;
   int32_t *seenKeys = malloc(3 * sizeof(int32_t));
-  id *seenValues = malloc(3 * sizeof(id));
-  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) {
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertLessThan(idx, 3U);
     seenKeys[idx] = aKey;
-    seenValues[idx] = aValue;
+    seenObjects[idx] = aObject;
     XCTAssertNotEqual(stop, NULL);
     ++idx;
   }];
@@ -3416,18 +3416,18 @@
     for (int j = 0; (j < 3) && !foundKey; ++j) {
       if (kKeys[i] == seenKeys[j]) {
         foundKey = YES;
-        XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
       }
     }
     XCTAssertTrue(foundKey, @"i = %d", i);
   }
   free(seenKeys);
-  free(seenValues);
+  free(seenObjects);
 
   // Stopping the enumeration.
   idx = 0;
-  [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue)
+  [dict enumerateKeysAndObjectsUsingBlock:^(int32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
     if (idx == 1) *stop = YES;
     XCTAssertNotEqual(idx, 2U);
     ++idx;
@@ -3438,33 +3438,33 @@
 - (void)testEquality {
   const int32_t kKeys1[] = { 11, 12, 13, 14 };
   const int32_t kKeys2[] = { 12, 11, 14 };
-  const id kValues1[] = { @"abc", @"def", @"ghi" };
-  const id kValues2[] = { @"abc", @"jkl", @"ghi" };
-  const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict1 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues1)];
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict1 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1);
-  GPBInt32ObjectDictionary *dict1prime =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues1)];
+  GPBInt32ObjectDictionary<NSString*> *dict1prime =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1prime);
-  GPBInt32ObjectDictionary *dict2 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues2)];
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
-  GPBInt32ObjectDictionary *dict3 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys2
-                                                 count:GPBARRAYSIZE(kValues1)];
+  GPBInt32ObjectDictionary<NSString*> *dict3 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict3);
-  GPBInt32ObjectDictionary *dict4 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues3
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues3)];
+  GPBInt32ObjectDictionary<NSString*> *dict4 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects3)];
   XCTAssertNotNil(dict4);
 
   // 1/1Prime should be different objects, but equal.
@@ -3473,10 +3473,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3491,14 +3491,14 @@
 
 - (void)testCopy {
   const int32_t kKeys[] = { 11, 12, 13, 14 };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBInt32ObjectDictionary *dict2 = [dict copy];
+  GPBInt32ObjectDictionary<NSString*> *dict2 = [dict copy];
   XCTAssertNotNil(dict2);
 
   // Should be new object but equal.
@@ -3512,14 +3512,14 @@
 
 - (void)testDictionaryFromDictionary {
   const int32_t kKeys[] = { 11, 12, 13, 14 };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBInt32ObjectDictionary *dict2 =
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
       [GPBInt32ObjectDictionary dictionaryWithDictionary:dict];
   XCTAssertNotNil(dict2);
 
@@ -3530,112 +3530,112 @@
 }
 
 - (void)testAdds {
-  GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionary];
+  GPBInt32ObjectDictionary<NSString*> *dict = [GPBInt32ObjectDictionary dictionary];
   XCTAssertNotNil(dict);
 
   XCTAssertEqual(dict.count, 0U);
-  [dict setValue:@"abc" forKey:11];
+  [dict setObject:@"abc" forKey:11];
   XCTAssertEqual(dict.count, 1U);
 
   const int32_t kKeys[] = { 12, 13, 14 };
-  const id kValues[] = { @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict2 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
 
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:12], @"def");
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
   [dict2 release];
 }
 
 - (void)testRemove {
   const int32_t kKeys[] = { 11, 12, 13, 14 };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                        forKeys:kKeys
-                                          count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
 
-  [dict removeValueForKey:12];
+  [dict removeObjectForKey:12];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertNil([dict valueForKey:12]);
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
 
   // Remove again does nothing.
-  [dict removeValueForKey:12];
+  [dict removeObjectForKey:12];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertNil([dict valueForKey:12]);
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
 
-  [dict removeValueForKey:14];
+  [dict removeObjectForKey:14];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertNil([dict valueForKey:12]);
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertNil([dict valueForKey:14]);
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertNil([dict objectForKey:14]);
 
   [dict removeAll];
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:11]);
-  XCTAssertNil([dict valueForKey:12]);
-  XCTAssertNil([dict valueForKey:13]);
-  XCTAssertNil([dict valueForKey:14]);
+  XCTAssertNil([dict objectForKey:11]);
+  XCTAssertNil([dict objectForKey:12]);
+  XCTAssertNil([dict objectForKey:13]);
+  XCTAssertNil([dict objectForKey:14]);
   [dict release];
 }
 
 - (void)testInplaceMutation {
   const int32_t kKeys[] = { 11, 12, 13, 14 };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt32ObjectDictionary *dict =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues
-                                        forKeys:kKeys
-                                          count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt32ObjectDictionary<NSString*> *dict =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:12], @"def");
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:11], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
 
-  [dict setValue:@"jkl" forKey:11];
+  [dict setObject:@"jkl" forKey:11];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:12], @"def");
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"jkl");
 
-  [dict setValue:@"def" forKey:14];
+  [dict setObject:@"def" forKey:14];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:12], @"def");
-  XCTAssertEqualObjects([dict valueForKey:13], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:14], @"def");
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"def");
+  XCTAssertEqualObjects([dict objectForKey:13], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:14], @"def");
 
   const int32_t kKeys2[] = { 12, 13 };
-  const id kValues2[] = { @"ghi", @"abc" };
-  GPBInt32ObjectDictionary *dict2 =
-      [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2
-                                               forKeys:kKeys2
-                                                 count:GPBARRAYSIZE(kValues2)];
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:11], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:12], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:13], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:14], @"def");
+  XCTAssertEqualObjects([dict objectForKey:11], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:12], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:13], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:14], @"def");
 
   [dict2 release];
   [dict release];
diff --git a/objectivec/Tests/GPBDictionaryTests+Int64.m b/objectivec/Tests/GPBDictionaryTests+Int64.m
index 4a94e03..66bc648 100644
--- a/objectivec/Tests/GPBDictionaryTests+Int64.m
+++ b/objectivec/Tests/GPBDictionaryTests+Int64.m
@@ -211,10 +211,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -568,10 +568,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -925,10 +925,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1282,10 +1282,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1639,10 +1639,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1996,10 +1996,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2353,10 +2353,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2710,10 +2710,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3071,10 +3071,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3363,51 +3363,51 @@
 @implementation GPBInt64ObjectDictionaryTests
 
 - (void)testEmpty {
-  GPBInt64ObjectDictionary *dict = [[GPBInt64ObjectDictionary alloc] init];
+  GPBInt64ObjectDictionary<NSString*> *dict = [[GPBInt64ObjectDictionary alloc] init];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:21LL]);
-  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue, stop)
+  XCTAssertNil([dict objectForKey:21LL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
     XCTFail(@"Shouldn't get here!");
   }];
   [dict release];
 }
 
 - (void)testOne {
-  GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:21LL];
+  GPBInt64ObjectDictionary<NSString*> *dict = [GPBInt64ObjectDictionary dictionaryWithObject:@"abc" forKey:21LL];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertNil([dict valueForKey:22LL]);
-  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) {
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertEqual(aKey, 21LL);
-    XCTAssertEqualObjects(aValue, @"abc");
+    XCTAssertEqualObjects(aObject, @"abc");
     XCTAssertNotEqual(stop, NULL);
   }];
 }
 
 - (void)testBasics {
   const int64_t kKeys[] = { 21LL, 22LL, 23LL };
-  const id kValues[] = { @"abc", @"def", @"ghi" };
-  GPBInt64ObjectDictionary *dict =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertNil([dict valueForKey:24LL]);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertNil([dict objectForKey:24LL]);
 
   __block NSUInteger idx = 0;
   int64_t *seenKeys = malloc(3 * sizeof(int64_t));
-  id *seenValues = malloc(3 * sizeof(id));
-  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) {
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertLessThan(idx, 3U);
     seenKeys[idx] = aKey;
-    seenValues[idx] = aValue;
+    seenObjects[idx] = aObject;
     XCTAssertNotEqual(stop, NULL);
     ++idx;
   }];
@@ -3416,18 +3416,18 @@
     for (int j = 0; (j < 3) && !foundKey; ++j) {
       if (kKeys[i] == seenKeys[j]) {
         foundKey = YES;
-        XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
       }
     }
     XCTAssertTrue(foundKey, @"i = %d", i);
   }
   free(seenKeys);
-  free(seenValues);
+  free(seenObjects);
 
   // Stopping the enumeration.
   idx = 0;
-  [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue)
+  [dict enumerateKeysAndObjectsUsingBlock:^(int64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
     if (idx == 1) *stop = YES;
     XCTAssertNotEqual(idx, 2U);
     ++idx;
@@ -3438,33 +3438,33 @@
 - (void)testEquality {
   const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL };
   const int64_t kKeys2[] = { 22LL, 21LL, 24LL };
-  const id kValues1[] = { @"abc", @"def", @"ghi" };
-  const id kValues2[] = { @"abc", @"jkl", @"ghi" };
-  const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict1 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues1)];
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict1 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1);
-  GPBInt64ObjectDictionary *dict1prime =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues1)];
+  GPBInt64ObjectDictionary<NSString*> *dict1prime =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1prime);
-  GPBInt64ObjectDictionary *dict2 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues2)];
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
-  GPBInt64ObjectDictionary *dict3 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1
-                                               forKeys:kKeys2
-                                                 count:GPBARRAYSIZE(kValues1)];
+  GPBInt64ObjectDictionary<NSString*> *dict3 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict3);
-  GPBInt64ObjectDictionary *dict4 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues3
-                                               forKeys:kKeys1
-                                                 count:GPBARRAYSIZE(kValues3)];
+  GPBInt64ObjectDictionary<NSString*> *dict4 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects3
+                                                forKeys:kKeys1
+                                                  count:GPBARRAYSIZE(kObjects3)];
   XCTAssertNotNil(dict4);
 
   // 1/1Prime should be different objects, but equal.
@@ -3473,10 +3473,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3491,14 +3491,14 @@
 
 - (void)testCopy {
   const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBInt64ObjectDictionary *dict2 = [dict copy];
+  GPBInt64ObjectDictionary<NSString*> *dict2 = [dict copy];
   XCTAssertNotNil(dict2);
 
   // Should be new object but equal.
@@ -3512,14 +3512,14 @@
 
 - (void)testDictionaryFromDictionary {
   const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBInt64ObjectDictionary *dict2 =
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
       [GPBInt64ObjectDictionary dictionaryWithDictionary:dict];
   XCTAssertNotNil(dict2);
 
@@ -3530,112 +3530,112 @@
 }
 
 - (void)testAdds {
-  GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionary];
+  GPBInt64ObjectDictionary<NSString*> *dict = [GPBInt64ObjectDictionary dictionary];
   XCTAssertNotNil(dict);
 
   XCTAssertEqual(dict.count, 0U);
-  [dict setValue:@"abc" forKey:21LL];
+  [dict setObject:@"abc" forKey:21LL];
   XCTAssertEqual(dict.count, 1U);
 
   const int64_t kKeys[] = { 22LL, 23LL, 24LL };
-  const id kValues[] = { @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict2 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                               forKeys:kKeys
-                                                 count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                forKeys:kKeys
+                                                  count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
 
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
   [dict2 release];
 }
 
 - (void)testRemove {
   const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                        forKeys:kKeys
-                                          count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
 
-  [dict removeValueForKey:22LL];
+  [dict removeObjectForKey:22LL];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertNil([dict valueForKey:22LL]);
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
 
   // Remove again does nothing.
-  [dict removeValueForKey:22LL];
+  [dict removeObjectForKey:22LL];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertNil([dict valueForKey:22LL]);
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
 
-  [dict removeValueForKey:24LL];
+  [dict removeObjectForKey:24LL];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertNil([dict valueForKey:22LL]);
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertNil([dict valueForKey:24LL]);
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertNil([dict objectForKey:24LL]);
 
   [dict removeAll];
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:21LL]);
-  XCTAssertNil([dict valueForKey:22LL]);
-  XCTAssertNil([dict valueForKey:23LL]);
-  XCTAssertNil([dict valueForKey:24LL]);
+  XCTAssertNil([dict objectForKey:21LL]);
+  XCTAssertNil([dict objectForKey:22LL]);
+  XCTAssertNil([dict objectForKey:23LL]);
+  XCTAssertNil([dict objectForKey:24LL]);
   [dict release];
 }
 
 - (void)testInplaceMutation {
   const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBInt64ObjectDictionary *dict =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues
-                                        forKeys:kKeys
-                                          count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBInt64ObjectDictionary<NSString*> *dict =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                         forKeys:kKeys
+                                           count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
 
-  [dict setValue:@"jkl" forKey:21LL];
+  [dict setObject:@"jkl" forKey:21LL];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"jkl");
 
-  [dict setValue:@"def" forKey:24LL];
+  [dict setObject:@"def" forKey:24LL];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"def");
 
   const int64_t kKeys2[] = { 22LL, 23LL };
-  const id kValues2[] = { @"ghi", @"abc" };
-  GPBInt64ObjectDictionary *dict2 =
-      [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2
-                                               forKeys:kKeys2
-                                                 count:GPBARRAYSIZE(kValues2)];
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                forKeys:kKeys2
+                                                  count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:22LL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:23LL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:24LL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:21LL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:22LL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:23LL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:24LL], @"def");
 
   [dict2 release];
   [dict release];
diff --git a/objectivec/Tests/GPBDictionaryTests+String.m b/objectivec/Tests/GPBDictionaryTests+String.m
index 09fbc60..bfa10b1 100644
--- a/objectivec/Tests/GPBDictionaryTests+String.m
+++ b/objectivec/Tests/GPBDictionaryTests+String.m
@@ -211,10 +211,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -568,10 +568,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -925,10 +925,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1282,10 +1282,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1639,10 +1639,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1996,10 +1996,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2353,10 +2353,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2710,10 +2710,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3071,10 +3071,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt32.m b/objectivec/Tests/GPBDictionaryTests+UInt32.m
index f8d280f..499f2ad 100644
--- a/objectivec/Tests/GPBDictionaryTests+UInt32.m
+++ b/objectivec/Tests/GPBDictionaryTests+UInt32.m
@@ -211,10 +211,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -568,10 +568,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -925,10 +925,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1282,10 +1282,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1639,10 +1639,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1996,10 +1996,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2353,10 +2353,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2710,10 +2710,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3071,10 +3071,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3363,51 +3363,51 @@
 @implementation GPBUInt32ObjectDictionaryTests
 
 - (void)testEmpty {
-  GPBUInt32ObjectDictionary *dict = [[GPBUInt32ObjectDictionary alloc] init];
+  GPBUInt32ObjectDictionary<NSString*> *dict = [[GPBUInt32ObjectDictionary alloc] init];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:1U]);
-  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue, stop)
+  XCTAssertNil([dict objectForKey:1U]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
     XCTFail(@"Shouldn't get here!");
   }];
   [dict release];
 }
 
 - (void)testOne {
-  GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:1U];
+  GPBUInt32ObjectDictionary<NSString*> *dict = [GPBUInt32ObjectDictionary dictionaryWithObject:@"abc" forKey:1U];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertNil([dict valueForKey:2U]);
-  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) {
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertEqual(aKey, 1U);
-    XCTAssertEqualObjects(aValue, @"abc");
+    XCTAssertEqualObjects(aObject, @"abc");
     XCTAssertNotEqual(stop, NULL);
   }];
 }
 
 - (void)testBasics {
   const uint32_t kKeys[] = { 1U, 2U, 3U };
-  const id kValues[] = { @"abc", @"def", @"ghi" };
-  GPBUInt32ObjectDictionary *dict =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"def");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertNil([dict valueForKey:4U]);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertNil([dict objectForKey:4U]);
 
   __block NSUInteger idx = 0;
   uint32_t *seenKeys = malloc(3 * sizeof(uint32_t));
-  id *seenValues = malloc(3 * sizeof(id));
-  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) {
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertLessThan(idx, 3U);
     seenKeys[idx] = aKey;
-    seenValues[idx] = aValue;
+    seenObjects[idx] = aObject;
     XCTAssertNotEqual(stop, NULL);
     ++idx;
   }];
@@ -3416,18 +3416,18 @@
     for (int j = 0; (j < 3) && !foundKey; ++j) {
       if (kKeys[i] == seenKeys[j]) {
         foundKey = YES;
-        XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
       }
     }
     XCTAssertTrue(foundKey, @"i = %d", i);
   }
   free(seenKeys);
-  free(seenValues);
+  free(seenObjects);
 
   // Stopping the enumeration.
   idx = 0;
-  [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue)
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint32_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
     if (idx == 1) *stop = YES;
     XCTAssertNotEqual(idx, 2U);
     ++idx;
@@ -3438,33 +3438,33 @@
 - (void)testEquality {
   const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U };
   const uint32_t kKeys2[] = { 2U, 1U, 4U };
-  const id kValues1[] = { @"abc", @"def", @"ghi" };
-  const id kValues2[] = { @"abc", @"jkl", @"ghi" };
-  const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict1 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues1)];
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict1 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1);
-  GPBUInt32ObjectDictionary *dict1prime =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues1)];
+  GPBUInt32ObjectDictionary<NSString*> *dict1prime =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1prime);
-  GPBUInt32ObjectDictionary *dict2 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues2)];
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
-  GPBUInt32ObjectDictionary *dict3 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys2
-                                                  count:GPBARRAYSIZE(kValues1)];
+  GPBUInt32ObjectDictionary<NSString*> *dict3 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict3);
-  GPBUInt32ObjectDictionary *dict4 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues3
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues3)];
+  GPBUInt32ObjectDictionary<NSString*> *dict4 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects3
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects3)];
   XCTAssertNotNil(dict4);
 
   // 1/1Prime should be different objects, but equal.
@@ -3473,10 +3473,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3491,14 +3491,14 @@
 
 - (void)testCopy {
   const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBUInt32ObjectDictionary *dict2 = [dict copy];
+  GPBUInt32ObjectDictionary<NSString*> *dict2 = [dict copy];
   XCTAssertNotNil(dict2);
 
   // Should be new object but equal.
@@ -3512,14 +3512,14 @@
 
 - (void)testDictionaryFromDictionary {
   const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBUInt32ObjectDictionary *dict2 =
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
       [GPBUInt32ObjectDictionary dictionaryWithDictionary:dict];
   XCTAssertNotNil(dict2);
 
@@ -3530,112 +3530,112 @@
 }
 
 - (void)testAdds {
-  GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionary];
+  GPBUInt32ObjectDictionary<NSString*> *dict = [GPBUInt32ObjectDictionary dictionary];
   XCTAssertNotNil(dict);
 
   XCTAssertEqual(dict.count, 0U);
-  [dict setValue:@"abc" forKey:1U];
+  [dict setObject:@"abc" forKey:1U];
   XCTAssertEqual(dict.count, 1U);
 
   const uint32_t kKeys[] = { 2U, 3U, 4U };
-  const id kValues[] = { @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict2 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
 
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"def");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
   [dict2 release];
 }
 
 - (void)testRemove {
   const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                         forKeys:kKeys
-                                           count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
 
-  [dict removeValueForKey:2U];
+  [dict removeObjectForKey:2U];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertNil([dict valueForKey:2U]);
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
 
   // Remove again does nothing.
-  [dict removeValueForKey:2U];
+  [dict removeObjectForKey:2U];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertNil([dict valueForKey:2U]);
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
 
-  [dict removeValueForKey:4U];
+  [dict removeObjectForKey:4U];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertNil([dict valueForKey:2U]);
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertNil([dict valueForKey:4U]);
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertNil([dict objectForKey:4U]);
 
   [dict removeAll];
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:1U]);
-  XCTAssertNil([dict valueForKey:2U]);
-  XCTAssertNil([dict valueForKey:3U]);
-  XCTAssertNil([dict valueForKey:4U]);
+  XCTAssertNil([dict objectForKey:1U]);
+  XCTAssertNil([dict objectForKey:2U]);
+  XCTAssertNil([dict objectForKey:3U]);
+  XCTAssertNil([dict objectForKey:4U]);
   [dict release];
 }
 
 - (void)testInplaceMutation {
   const uint32_t kKeys[] = { 1U, 2U, 3U, 4U };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt32ObjectDictionary *dict =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues
-                                         forKeys:kKeys
-                                           count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt32ObjectDictionary<NSString*> *dict =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"def");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
 
-  [dict setValue:@"jkl" forKey:1U];
+  [dict setObject:@"jkl" forKey:1U];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"def");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"jkl");
 
-  [dict setValue:@"def" forKey:4U];
+  [dict setObject:@"def" forKey:4U];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"def");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"def");
 
   const uint32_t kKeys2[] = { 2U, 3U };
-  const id kValues2[] = { @"ghi", @"abc" };
-  GPBUInt32ObjectDictionary *dict2 =
-      [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2
-                                                forKeys:kKeys2
-                                                  count:GPBARRAYSIZE(kValues2)];
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt32ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt32ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:1U], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:2U], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:3U], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:4U], @"def");
+  XCTAssertEqualObjects([dict objectForKey:1U], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:2U], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:3U], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:4U], @"def");
 
   [dict2 release];
   [dict release];
diff --git a/objectivec/Tests/GPBDictionaryTests+UInt64.m b/objectivec/Tests/GPBDictionaryTests+UInt64.m
index cebd6df..327e154 100644
--- a/objectivec/Tests/GPBDictionaryTests+UInt64.m
+++ b/objectivec/Tests/GPBDictionaryTests+UInt64.m
@@ -211,10 +211,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -568,10 +568,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -925,10 +925,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1282,10 +1282,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1639,10 +1639,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -1996,10 +1996,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2353,10 +2353,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -2710,10 +2710,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3071,10 +3071,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different values; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same values; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3363,51 +3363,51 @@
 @implementation GPBUInt64ObjectDictionaryTests
 
 - (void)testEmpty {
-  GPBUInt64ObjectDictionary *dict = [[GPBUInt64ObjectDictionary alloc] init];
+  GPBUInt64ObjectDictionary<NSString*> *dict = [[GPBUInt64ObjectDictionary alloc] init];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:31ULL]);
-  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue, stop)
+  XCTAssertNil([dict objectForKey:31ULL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject, stop)
     XCTFail(@"Shouldn't get here!");
   }];
   [dict release];
 }
 
 - (void)testOne {
-  GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:31ULL];
+  GPBUInt64ObjectDictionary<NSString*> *dict = [GPBUInt64ObjectDictionary dictionaryWithObject:@"abc" forKey:31ULL];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 1U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertNil([dict valueForKey:32ULL]);
-  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) {
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertEqual(aKey, 31ULL);
-    XCTAssertEqualObjects(aValue, @"abc");
+    XCTAssertEqualObjects(aObject, @"abc");
     XCTAssertNotEqual(stop, NULL);
   }];
 }
 
 - (void)testBasics {
   const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL };
-  const id kValues[] = { @"abc", @"def", @"ghi" };
-  GPBUInt64ObjectDictionary *dict =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertNil([dict valueForKey:34ULL]);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertNil([dict objectForKey:34ULL]);
 
   __block NSUInteger idx = 0;
   uint64_t *seenKeys = malloc(3 * sizeof(uint64_t));
-  id *seenValues = malloc(3 * sizeof(id));
-  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) {
+  NSString* *seenObjects = malloc(3 * sizeof(NSString*));
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
     XCTAssertLessThan(idx, 3U);
     seenKeys[idx] = aKey;
-    seenValues[idx] = aValue;
+    seenObjects[idx] = aObject;
     XCTAssertNotEqual(stop, NULL);
     ++idx;
   }];
@@ -3416,18 +3416,18 @@
     for (int j = 0; (j < 3) && !foundKey; ++j) {
       if (kKeys[i] == seenKeys[j]) {
         foundKey = YES;
-        XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+        XCTAssertEqualObjects(kObjects[i], seenObjects[j], @"i = %d, j = %d", i, j);
       }
     }
     XCTAssertTrue(foundKey, @"i = %d", i);
   }
   free(seenKeys);
-  free(seenValues);
+  free(seenObjects);
 
   // Stopping the enumeration.
   idx = 0;
-  [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) {
-    #pragma unused(aKey, aValue)
+  [dict enumerateKeysAndObjectsUsingBlock:^(uint64_t aKey, NSString* aObject, BOOL *stop) {
+    #pragma unused(aKey, aObject)
     if (idx == 1) *stop = YES;
     XCTAssertNotEqual(idx, 2U);
     ++idx;
@@ -3438,33 +3438,33 @@
 - (void)testEquality {
   const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL };
   const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL };
-  const id kValues1[] = { @"abc", @"def", @"ghi" };
-  const id kValues2[] = { @"abc", @"jkl", @"ghi" };
-  const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict1 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues1)];
+  const NSString* kObjects1[] = { @"abc", @"def", @"ghi" };
+  const NSString* kObjects2[] = { @"abc", @"jkl", @"ghi" };
+  const NSString* kObjects3[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict1 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1);
-  GPBUInt64ObjectDictionary *dict1prime =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues1)];
+  GPBUInt64ObjectDictionary<NSString*> *dict1prime =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict1prime);
-  GPBUInt64ObjectDictionary *dict2 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues2)];
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
-  GPBUInt64ObjectDictionary *dict3 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1
-                                                forKeys:kKeys2
-                                                  count:GPBARRAYSIZE(kValues1)];
+  GPBUInt64ObjectDictionary<NSString*> *dict3 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects1
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects1)];
   XCTAssertNotNil(dict3);
-  GPBUInt64ObjectDictionary *dict4 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues3
-                                                forKeys:kKeys1
-                                                  count:GPBARRAYSIZE(kValues3)];
+  GPBUInt64ObjectDictionary<NSString*> *dict4 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects3
+                                                 forKeys:kKeys1
+                                                   count:GPBARRAYSIZE(kObjects3)];
   XCTAssertNotNil(dict4);
 
   // 1/1Prime should be different objects, but equal.
@@ -3473,10 +3473,10 @@
   // Equal, so they must have same hash.
   XCTAssertEqual([dict1 hash], [dict1prime hash]);
 
-  // 2 is save keys, different values; not equal.
+  // 2 is same keys, different objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict2);
 
-  // 3 is different keys, samae values; not equal.
+  // 3 is different keys, same objects; not equal.
   XCTAssertNotEqualObjects(dict1, dict3);
 
   // 4 extra pair; not equal
@@ -3491,14 +3491,14 @@
 
 - (void)testCopy {
   const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBUInt64ObjectDictionary *dict2 = [dict copy];
+  GPBUInt64ObjectDictionary<NSString*> *dict2 = [dict copy];
   XCTAssertNotNil(dict2);
 
   // Should be new object but equal.
@@ -3512,14 +3512,14 @@
 
 - (void)testDictionaryFromDictionary {
   const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
 
-  GPBUInt64ObjectDictionary *dict2 =
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
       [GPBUInt64ObjectDictionary dictionaryWithDictionary:dict];
   XCTAssertNotNil(dict2);
 
@@ -3530,112 +3530,112 @@
 }
 
 - (void)testAdds {
-  GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionary];
+  GPBUInt64ObjectDictionary<NSString*> *dict = [GPBUInt64ObjectDictionary dictionary];
   XCTAssertNotNil(dict);
 
   XCTAssertEqual(dict.count, 0U);
-  [dict setValue:@"abc" forKey:31ULL];
+  [dict setObject:@"abc" forKey:31ULL];
   XCTAssertEqual(dict.count, 1U);
 
   const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL };
-  const id kValues[] = { @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict2 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                                forKeys:kKeys
-                                                  count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                                 forKeys:kKeys
+                                                   count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
 
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
   [dict2 release];
 }
 
 - (void)testRemove {
   const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                         forKeys:kKeys
-                                           count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
 
-  [dict removeValueForKey:32ULL];
+  [dict removeObjectForKey:32ULL];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertNil([dict valueForKey:32ULL]);
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
 
   // Remove again does nothing.
-  [dict removeValueForKey:32ULL];
+  [dict removeObjectForKey:32ULL];
   XCTAssertEqual(dict.count, 3U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertNil([dict valueForKey:32ULL]);
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
 
-  [dict removeValueForKey:34ULL];
+  [dict removeObjectForKey:34ULL];
   XCTAssertEqual(dict.count, 2U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertNil([dict valueForKey:32ULL]);
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertNil([dict valueForKey:34ULL]);
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertNil([dict objectForKey:34ULL]);
 
   [dict removeAll];
   XCTAssertEqual(dict.count, 0U);
-  XCTAssertNil([dict valueForKey:31ULL]);
-  XCTAssertNil([dict valueForKey:32ULL]);
-  XCTAssertNil([dict valueForKey:33ULL]);
-  XCTAssertNil([dict valueForKey:34ULL]);
+  XCTAssertNil([dict objectForKey:31ULL]);
+  XCTAssertNil([dict objectForKey:32ULL]);
+  XCTAssertNil([dict objectForKey:33ULL]);
+  XCTAssertNil([dict objectForKey:34ULL]);
   [dict release];
 }
 
 - (void)testInplaceMutation {
   const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL };
-  const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" };
-  GPBUInt64ObjectDictionary *dict =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues
-                                         forKeys:kKeys
-                                           count:GPBARRAYSIZE(kValues)];
+  const NSString* kObjects[] = { @"abc", @"def", @"ghi", @"jkl" };
+  GPBUInt64ObjectDictionary<NSString*> *dict =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects
+                                          forKeys:kKeys
+                                            count:GPBARRAYSIZE(kObjects)];
   XCTAssertNotNil(dict);
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
 
-  [dict setValue:@"jkl" forKey:31ULL];
+  [dict setObject:@"jkl" forKey:31ULL];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"jkl");
 
-  [dict setValue:@"def" forKey:34ULL];
+  [dict setObject:@"def" forKey:34ULL];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"def");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"def");
 
   const uint64_t kKeys2[] = { 32ULL, 33ULL };
-  const id kValues2[] = { @"ghi", @"abc" };
-  GPBUInt64ObjectDictionary *dict2 =
-      [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2
-                                                forKeys:kKeys2
-                                                  count:GPBARRAYSIZE(kValues2)];
+  const NSString* kObjects2[] = { @"ghi", @"abc" };
+  GPBUInt64ObjectDictionary<NSString*> *dict2 =
+      [[GPBUInt64ObjectDictionary alloc] initWithObjects:kObjects2
+                                                 forKeys:kKeys2
+                                                   count:GPBARRAYSIZE(kObjects2)];
   XCTAssertNotNil(dict2);
   [dict addEntriesFromDictionary:dict2];
   XCTAssertEqual(dict.count, 4U);
-  XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl");
-  XCTAssertEqualObjects([dict valueForKey:32ULL], @"ghi");
-  XCTAssertEqualObjects([dict valueForKey:33ULL], @"abc");
-  XCTAssertEqualObjects([dict valueForKey:34ULL], @"def");
+  XCTAssertEqualObjects([dict objectForKey:31ULL], @"jkl");
+  XCTAssertEqualObjects([dict objectForKey:32ULL], @"ghi");
+  XCTAssertEqualObjects([dict objectForKey:33ULL], @"abc");
+  XCTAssertEqualObjects([dict objectForKey:34ULL], @"def");
 
   [dict2 release];
   [dict release];
diff --git a/objectivec/Tests/GPBDictionaryTests.pddm b/objectivec/Tests/GPBDictionaryTests.pddm
index ee26fac..0951294 100644
--- a/objectivec/Tests/GPBDictionaryTests.pddm
+++ b/objectivec/Tests/GPBDictionaryTests.pddm
@@ -30,7 +30,7 @@
 
 //%PDDM-DEFINE TEST_FOR_POD_KEY(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4)
 //%TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4)
-//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, id, @"abc", @"def", @"ghi", @"jkl")
+//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, NSString*, @"abc", @"def", @"ghi", @"jkl")
 
 //%PDDM-DEFINE TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4)
 //%TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP)
@@ -45,12 +45,19 @@
 //%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4)
 
 //%PDDM-DEFINE TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
-//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
+//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , value, POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
 
 //%PDDM-DEFINE TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VAL1, VAL2, VAL3, VAL4)
-//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, , VAL1, VAL2, VAL3, VAL4)
+//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, , VAL1, VAL2, VAL3, VAL4)
 
-//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLPOD(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLEnum(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary
+//%PDDM-DEFINE DICTIONARY_CLASS_DECLOBJECT(KEY_NAME, VALUE_NAME, VALUE_TYPE)
+//%GPB##KEY_NAME##VALUE_NAME##Dictionary<VALUE_TYPE>
+
+//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
 //%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase
@@ -59,51 +66,51 @@
 //%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests
 //%
 //%- (void)testEmpty {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 0U);
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
-//%    #pragma unused(aKey, aValue, stop)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u, stop)
 //%    XCTFail(@"Shouldn't get here!");
 //%  }];
 //%  [dict release];
 //%}
 //%
 //%- (void)testOne {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWith##VNAME$u##:VAL1 forKey:KEY1];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 1U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
 //%    XCTAssertEqual##KSUFFIX(aKey, KEY1);
-//%    XCTAssertEqual##VSUFFIX(aValue, VAL1);
+//%    XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1);
 //%    XCTAssertNotEqual(stop, NULL);
 //%  }];
 //%}
 //%
 //%- (void)testBasics {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 3U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
 //%
 //%  __block NSUInteger idx = 0;
 //%  KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP));
-//%  VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE));
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%  VALUE_TYPE *seen##VNAME$u##s = malloc(3 * sizeof(VALUE_TYPE));
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
 //%    XCTAssertLessThan(idx, 3U);
 //%    seenKeys[idx] = aKey;
-//%    seenValues[idx] = aValue;
+//%    seen##VNAME$u##s[idx] = a##VNAME$u##;
 //%    XCTAssertNotEqual(stop, NULL);
 //%    ++idx;
 //%  }];
@@ -112,18 +119,18 @@
 //%    for (int j = 0; (j < 3) && !foundKey; ++j) {
 //%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
 //%        foundKey = YES;
-//%        XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+//%        XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j);
 //%      }
 //%    }
 //%    XCTAssertTrue(foundKey, @"i = %d", i);
 //%  }
 //%  free(seenKeys);
-//%  free(seenValues);
+//%  free(seen##VNAME$u##s);
 //%
 //%  // Stopping the enumeration.
 //%  idx = 0;
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
-//%    #pragma unused(aKey, aValue)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u)
 //%    if (idx == 1) *stop = YES;
 //%    XCTAssertNotEqual(idx, 2U);
 //%    ++idx;
@@ -134,33 +141,33 @@
 //%- (void)testEquality {
 //%  const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 };
-//%  const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 };
-//%  const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 };
-//%  const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2, VAL3 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL1, VAL4, VAL3 };
+//%  const VALUE_TYPE k##VNAME$u##s3[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict1);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict1prime);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues2)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
 //%  XCTAssertNotNil(dict2);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys2
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict3);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues3)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s3
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s3)];
 //%  XCTAssertNotNil(dict4);
 //%
 //%  // 1/1Prime should be different objects, but equal.
@@ -169,10 +176,10 @@
 //%  // Equal, so they must have same hash.
 //%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
 //%
-//%  // 2 is save keys, different values; not equal.
+//%  // 2 is same keys, different ##VNAME##s; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict2);
 //%
-//%  // 3 is different keys, samae values; not equal.
+//%  // 3 is different keys, same ##VNAME##s; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict3);
 //%
 //%  // 4 extra pair; not equal
@@ -187,14 +194,14 @@
 //%
 //%- (void)testCopy {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
 //%  XCTAssertNotNil(dict2);
 //%
 //%  // Should be new object but equal.
@@ -208,14 +215,14 @@
 //%
 //%- (void)testDictionaryFromDictionary {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
 //%  XCTAssertNotNil(dict2);
 //%
@@ -226,60 +233,60 @@
 //%}
 //%
 //%- (void)testAdds {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
 //%  XCTAssertNotNil(dict);
 //%
 //%  XCTAssertEqual(dict.count, 0U);
-//%  [dict setValue:VAL1 forKey:KEY1];
+//%  [dict set##VNAME$u##:VAL1 forKey:KEY1];
 //%  XCTAssertEqual(dict.count, 1U);
 //%
 //%  const KEY_TYPE KisP##kKeys[] = { KEY2, KEY3, KEY4 };
-//%  const VALUE_TYPE kValues[] = { VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict2);
 //%  [dict add##VACCESSOR##EntriesFromDictionary:dict2];
 //%  XCTAssertEqual(dict.count, 4U);
 //%
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
 //%  [dict2 release];
 //%}
 //%
 //%- (void)testRemove {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                 forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                   count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 4U);
 //%
-//%  [dict removeValueForKey:KEY2];
+//%  [dict remove##VNAME$u##ForKey:KEY2];
 //%  XCTAssertEqual(dict.count, 3U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
 //%
 //%  // Remove again does nothing.
-//%  [dict removeValueForKey:KEY2];
+//%  [dict remove##VNAME$u##ForKey:KEY2];
 //%  XCTAssertEqual(dict.count, 3U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
 //%
-//%  [dict removeValueForKey:KEY4];
+//%  [dict remove##VNAME$u##ForKey:KEY4];
 //%  XCTAssertEqual(dict.count, 2U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY4)
 //%
 //%  [dict removeAll];
@@ -293,45 +300,45 @@
 //%
 //%- (void)testInplaceMutation {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                 forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                   count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 4U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
 //%
-//%  [dict setValue:VAL4 forKey:KEY1];
+//%  [dict set##VNAME$u##:VAL4 forKey:KEY1];
 //%  XCTAssertEqual(dict.count, 4U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL4)
 //%
-//%  [dict setValue:VAL2 forKey:KEY4];
+//%  [dict set##VNAME$u##:VAL2 forKey:KEY4];
 //%  XCTAssertEqual(dict.count, 4U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL2)
 //%
 //%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 };
-//%  const VALUE_TYPE kValues2[] = { VAL3, VAL1 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys2
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues2)];
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL3, VAL1 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
 //%  XCTAssertNotNil(dict2);
 //%  [dict add##VACCESSOR##EntriesFromDictionary:dict2];
 //%  XCTAssertEqual(dict.count, 4U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3)
-//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL4)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL3)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY3, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY4, VAL2)
 //%
 //%  [dict2 release];
 //%  [dict release];
@@ -353,7 +360,7 @@
 //%- (void)testRawBasics {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
@@ -429,31 +436,31 @@
 //%  const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 };  // Unknown
 //%  const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 };  // Unknown
 //%  const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
 //%  XCTAssertNotNil(dict1);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
 //%  XCTAssertNotNil(dict1prime);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues2
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues2)];
 //%  XCTAssertNotNil(dict2);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues1
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys2
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues1)];
 //%  XCTAssertNotNil(dict3);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues3
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys1
@@ -466,10 +473,10 @@
 //%  // Equal, so they must have same hash.
 //%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
 //%
-//%  // 2 is save keys, different values; not equal.
+//%  // 2 is same keys, different values; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict2);
 //%
-//%  // 3 is different keys, samae values; not equal.
+//%  // 3 is different keys, same values; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict3);
 //%
 //%  // 4 extra pair; not equal
@@ -485,14 +492,14 @@
 //%- (void)testCopyWithUnknowns {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknown
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
 //%  XCTAssertNotNil(dict2);
 //%
 //%  // Should be new pointer, but equal objects.
@@ -507,14 +514,14 @@
 //%- (void)testDictionaryFromDictionary {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
 //%  XCTAssertNotNil(dict2);
 //%
@@ -526,7 +533,7 @@
 //%}
 //%
 //%- (void)testUnknownAdds {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%    [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue];
 //%  XCTAssertNotNil(dict);
 //%
@@ -539,7 +546,7 @@
 //%
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL3, VAL4 };  // Unknown
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
 //%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
@@ -559,7 +566,7 @@
 //%- (void)testUnknownRemove {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
@@ -601,7 +608,7 @@
 //%- (void)testInplaceMutationUnknowns {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };  // Unknowns
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
@@ -637,7 +644,7 @@
 //%
 //%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 };
 //%  const VALUE_TYPE kValues2[] = { VAL3, VAL2 };  // Unknown
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues2
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys2
@@ -657,14 +664,14 @@
 //%- (void)testCopyUnknowns {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 };
 //%  const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
 //%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
 //%           KEY_NAME$S VALUE_NAME$S                                  rawValues:kValues
 //%           KEY_NAME$S VALUE_NAME$S                                    forKeys:kKeys
 //%           KEY_NAME$S VALUE_NAME$S                                      count:GPBARRAYSIZE(kValues)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
 //%  XCTAssertNotNil(dict2);
 //%
 //%  // Should be new pointer, but equal objects.
@@ -709,9 +716,9 @@
 //%PDDM-DEFINE DECLARE_VALUE_STORAGEOBJECT(VALUE_TYPE, NAME)
 // Empty
 //%PDDM-DEFINE VALUE_NOT_FOUNDOBJECT(DICT, KEY)
-//%  XCTAssertNil([DICT valueForKey:KEY]);
+//%  XCTAssertNil([DICT objectForKey:KEY]);
 //%PDDM-DEFINE TEST_VALUEOBJECT(DICT, STORAGE, KEY, VALUE)
-//%  XCTAssertEqualObjects([DICT valueForKey:KEY], VALUE);
+//%  XCTAssertEqualObjects([DICT objectForKey:KEY], VALUE);
 //%PDDM-DEFINE COMPARE_KEYSObjects(KEY1, KEY2)
 //%[KEY1 isEqual:KEY2]
 
@@ -768,12 +775,12 @@
 //TODO(thomasvl): enum tests
 
 //%PDDM-DEFINE BOOL_TESTS_FOR_POD_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2)
-//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , POD, VAL1, VAL2)
+//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , value, POD, VAL1, VAL2)
 
 //%PDDM-DEFINE TESTS_FOR_BOOL_KEY_OBJECT_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2)
-//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, VAL1, VAL2)
+//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, VAL1, VAL2)
 
-//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2)
+//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VAL1, VAL2)
 //%#pragma mark - KEY_NAME -> VALUE_NAME
 //%
 //%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase
@@ -782,49 +789,49 @@
 //%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests
 //%
 //%- (void)testEmpty {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 0U);
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY1)
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
-//%    #pragma unused(aKey, aValue, stop)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u##, stop)
 //%    XCTFail(@"Shouldn't get here!");
 //%  }];
 //%  [dict release];
 //%}
 //%
 //%- (void)testOne {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWith##VNAME$u##:VAL1 forKey:KEY1];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 1U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) {
 //%    XCTAssertEqual##KSUFFIX(aKey, KEY1);
-//%    XCTAssertEqual##VSUFFIX(aValue, VAL1);
+//%    XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1);
 //%    XCTAssertNotEqual(stop, NULL);
 //%  }];
 //%}
 //%
 //%- (void)testBasics {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 2U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
 //%
 //%  __block NSUInteger idx = 0;
 //%  KEY_TYPE KisP##*seenKeys = malloc(2 * sizeof(KEY_TYPE##KisP));
-//%  VALUE_TYPE *seenValues = malloc(2 * sizeof(VALUE_TYPE));
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
+//%  VALUE_TYPE *seen##VNAME$u##s = malloc(2 * sizeof(VALUE_TYPE));
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
 //%    XCTAssertLessThan(idx, 2U);
 //%    seenKeys[idx] = aKey;
-//%    seenValues[idx] = aValue;
+//%    seen##VNAME$u##s[idx] = a##VNAME$u;
 //%    XCTAssertNotEqual(stop, NULL);
 //%    ++idx;
 //%  }];
@@ -833,18 +840,18 @@
 //%    for (int j = 0; (j < 2) && !foundKey; ++j) {
 //%      if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) {
 //%        foundKey = YES;
-//%        XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
+//%        XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j);
 //%      }
 //%    }
 //%    XCTAssertTrue(foundKey, @"i = %d", i);
 //%  }
 //%  free(seenKeys);
-//%  free(seenValues);
+//%  free(seen##VNAME$u##s);
 //%
 //%  // Stopping the enumeration.
 //%  idx = 0;
-//%  [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) {
-//%    #pragma unused(aKey, aValue)
+//%  [dict enumerateKeysAnd##VNAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) {
+//%    #pragma unused(aKey, a##VNAME$u)
 //%    if (idx == 0) *stop = YES;
 //%    XCTAssertNotEqual(idx, 2U);
 //%    ++idx;
@@ -855,33 +862,33 @@
 //%- (void)testEquality {
 //%  const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2 };
 //%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 };
-//%  const VALUE_TYPE kValues1[] = { VAL1, VAL2 };
-//%  const VALUE_TYPE kValues2[] = { VAL2, VAL1 };
-//%  const VALUE_TYPE kValues3[] = { VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2 };
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 };
+//%  const VALUE_TYPE k##VNAME$u##s3[] = { VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict1);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict1prime);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues2)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
 //%  XCTAssertNotNil(dict2);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys2
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues1)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s1)];
 //%  XCTAssertNotNil(dict3);
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys1
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues3)];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s3
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys1
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s3)];
 //%  XCTAssertNotNil(dict4);
 //%
 //%  // 1/1Prime should be different objects, but equal.
@@ -890,10 +897,10 @@
 //%  // Equal, so they must have same hash.
 //%  XCTAssertEqual([dict1 hash], [dict1prime hash]);
 //%
-//%  // 2 is save keys, different values; not equal.
+//%  // 2 is same keys, different ##VNAME##s; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict2);
 //%
-//%  // 3 is different keys, samae values; not equal.
+//%  // 3 is different keys, same ##VNAME##s; not equal.
 //%  XCTAssertNotEqualObjects(dict1, dict3);
 //%
 //%  // 4 Fewer pairs; not equal
@@ -908,14 +915,14 @@
 //%
 //%- (void)testCopy {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy];
 //%  XCTAssertNotNil(dict2);
 //%
 //%  // Should be new object but equal.
@@ -929,14 +936,14 @@
 //%
 //%- (void)testDictionaryFromDictionary {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
 //%      [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict];
 //%  XCTAssertNotNil(dict2);
 //%
@@ -947,47 +954,47 @@
 //%}
 //%
 //%- (void)testAdds {
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary];
 //%  XCTAssertNotNil(dict);
 //%
 //%  XCTAssertEqual(dict.count, 0U);
-//%  [dict setValue:VAL1 forKey:KEY1];
+//%  [dict set##VNAME$u:VAL1 forKey:KEY1];
 //%  XCTAssertEqual(dict.count, 1U);
 //%
 //%  const KEY_TYPE KisP##kKeys[] = { KEY2 };
-//%  const VALUE_TYPE kValues[] = { VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict2);
 //%  [dict addEntriesFromDictionary:dict2];
 //%  XCTAssertEqual(dict.count, 2U);
 //%
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
 //%  [dict2 release];
 //%}
 //%
 //%- (void)testRemove {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2};
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                 forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                   count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 2U);
 //%
-//%  [dict removeValueForKey:KEY2];
+//%  [dict remove##VNAME$u##ForKey:KEY2];
 //%  XCTAssertEqual(dict.count, 1U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
 //%
 //%  // Remove again does nothing.
-//%  [dict removeValueForKey:KEY2];
+//%  [dict remove##VNAME$u##ForKey:KEY2];
 //%  XCTAssertEqual(dict.count, 1U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
 //%VALUE_NOT_FOUND##VHELPER(dict, KEY2)
 //%
 //%  [dict removeAll];
@@ -999,37 +1006,37 @@
 //%
 //%- (void)testInplaceMutation {
 //%  const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 };
-//%  const VALUE_TYPE kValues[] = { VAL1, VAL2 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues
-//%           KEY_NAME$S VALUE_NAME$S                 forKeys:kKeys
-//%           KEY_NAME$S VALUE_NAME$S                   count:GPBARRAYSIZE(kValues)];
+//%  const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##  forKeys:kKeys
+//%           KEY_NAME$S VALUE_NAME$S          ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s)];
 //%  XCTAssertNotNil(dict);
 //%  XCTAssertEqual(dict.count, 2U);
-//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
 //%
-//%  [dict setValue:VAL2 forKey:KEY1];
+//%  [dict set##VNAME$u##:VAL2 forKey:KEY1];
 //%  XCTAssertEqual(dict.count, 2U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
 //%
-//%  [dict setValue:VAL1 forKey:KEY2];
+//%  [dict set##VNAME$u##:VAL1 forKey:KEY2];
 //%  XCTAssertEqual(dict.count, 2U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL1)
 //%
 //%  const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 };
-//%  const VALUE_TYPE kValues2[] = { VAL2, VAL1 };
-//%  GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 =
-//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2
-//%           KEY_NAME$S VALUE_NAME$S                        forKeys:kKeys2
-//%           KEY_NAME$S VALUE_NAME$S                          count:GPBARRAYSIZE(kValues2)];
+//%  const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 };
+//%  DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 =
+//%      [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VNAME$u##s:k##VNAME$u##s2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##  forKeys:kKeys2
+//%           KEY_NAME$S VALUE_NAME$S                 ##VNAME$S##    count:GPBARRAYSIZE(k##VNAME$u##s2)];
 //%  XCTAssertNotNil(dict2);
 //%  [dict addEntriesFromDictionary:dict2];
 //%  XCTAssertEqual(dict.count, 2U);
-//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1)
-//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY1, VAL1)
+//%TEST_VALUE##VHELPER(dict, VNAME, KEY2, VAL2)
 //%
 //%  [dict2 release];
 //%  [dict release];
diff --git a/objectivec/Tests/GPBMessageTests+Merge.m b/objectivec/Tests/GPBMessageTests+Merge.m
index 3b6fdbd..c0bd589 100644
--- a/objectivec/Tests/GPBMessageTests+Merge.m
+++ b/objectivec/Tests/GPBMessageTests+Merge.m
@@ -675,21 +675,20 @@
 
   TestAllTypes *subMsg = [TestAllTypes message];
   subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:100];
-  msg1.mapInt32Message = [GPBInt32ObjectDictionary dictionary];
-  [msg1.mapInt32Message setValue:subMsg forKey:0];
+  [msg1.mapInt32Message setObject:subMsg forKey:0];
   subMsg = nil;
 
   subMsg = [TestAllTypes message];
   subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:101];
-  msg2.mapInt32Message = [GPBInt32ObjectDictionary dictionary];
-  [msg2.mapInt32Message setValue:subMsg forKey:0];
+
+  [msg2.mapInt32Message setObject:subMsg forKey:0];
   subMsg = nil;
 
   [msg1 mergeFrom:msg2];
 
   // Checks repeated field is overwritten.
   XCTAssertEqual(msg1.mapInt32Message.count, 1U);
-  subMsg = [msg1.mapInt32Message valueForKey:0];
+  subMsg = [msg1.mapInt32Message objectForKey:0];
   XCTAssertNotNil(subMsg);
   XCTAssertEqual(subMsg.repeatedInt32Array.count, 1U);
   XCTAssertEqual([subMsg.repeatedInt32Array valueAtIndex:0], 101);
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m
index 8942a84..5e19771 100644
--- a/objectivec/Tests/GPBMessageTests+Runtime.m
+++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -2059,9 +2059,9 @@
 
   // Ensure the messages are unique per map.
   [msg1.mapInt32ForeignMessage
-      enumerateKeysAndValuesUsingBlock:^(int32_t key, id value, BOOL *stop) {
+      enumerateKeysAndObjectsUsingBlock:^(int32_t key, id value, BOOL *stop) {
 #pragma unused(stop)
-        ForeignMessage *subMsg2 = [msg2.mapInt32ForeignMessage valueForKey:key];
+        ForeignMessage *subMsg2 = [msg2.mapInt32ForeignMessage objectForKey:key];
         XCTAssertNotEqual(value, subMsg2);  // Ptr compare, new object.
       }];
 }
@@ -2074,8 +2074,7 @@
 
   // Add an uninitialized message.
   TestRequired *subMsg = [[TestRequired alloc] init];
-  msg.mapField = [GPBInt32ObjectDictionary dictionary];
-  [msg.mapField setValue:subMsg forKey:0];
+  [msg.mapField setObject:subMsg forKey:0];
   XCTAssertFalse(msg.initialized);
 
   // Initialize uninitialized message
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index ae4be9e..0d811a9 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -121,8 +121,9 @@
   fooWithExtras.enumValue = DropUnknownsFooWithExtraFields_NestedEnum_Baz;
   fooWithExtras.extraInt32Value = 2;
 
-  DropUnknownsFoo *foo =
-      [DropUnknownsFoo parseFromData:[fooWithExtras data] error:NULL];
+  NSData *data = [fooWithExtras data];
+  XCTAssertNotNil(data);
+  DropUnknownsFoo *foo = [DropUnknownsFoo parseFromData:data error:NULL];
 
   XCTAssertEqual(foo.int32Value, 1);
   XCTAssertEqual(foo.enumValue, DropUnknownsFoo_NestedEnum_Baz);
@@ -130,8 +131,9 @@
   XCTAssertEqual([foo.unknownFields countOfFields], 0U);
 
   [fooWithExtras release];
+  data = [foo data];
   fooWithExtras =
-      [DropUnknownsFooWithExtraFields parseFromData:[foo data] error:NULL];
+      [DropUnknownsFooWithExtraFields parseFromData:data error:NULL];
   XCTAssertEqual(fooWithExtras.int32Value, 1);
   XCTAssertEqual(fooWithExtras.enumValue,
                  DropUnknownsFooWithExtraFields_NestedEnum_Baz);
@@ -149,7 +151,9 @@
                                        rawValue:Message3_Enum_Extra3];
   orig.oneofEnum = Message3_Enum_Extra3;
 
-  Message2 *msg = [[Message2 alloc] initWithData:[orig data] error:NULL];
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
+  Message2 *msg = [[Message2 alloc] initWithData:data error:NULL];
 
   // None of the fields should be set.
 
@@ -201,8 +205,10 @@
 
   // Everything should be there via raw values.
 
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
   UnknownEnumsMyMessage *msg =
-      [UnknownEnumsMyMessage parseFromData:[orig data] error:NULL];
+      [UnknownEnumsMyMessage parseFromData:data error:NULL];
 
   XCTAssertEqual(msg.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue);
   XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(msg),
@@ -224,7 +230,8 @@
 
   // Everything should go out and come back.
 
-  orig = [UnknownEnumsMyMessagePlusExtra parseFromData:[msg data] error:NULL];
+  data = [msg data];
+  orig = [UnknownEnumsMyMessagePlusExtra parseFromData:data error:NULL];
 
   XCTAssertEqual(orig.e, UnknownEnumsMyEnumPlusExtra_EExtra);
   XCTAssertEqual(orig.repeatedEArray.count, 1U);
@@ -243,7 +250,9 @@
 //%    MESSAGE *orig = [[MESSAGE alloc] init];
 //%    orig.oneof##FIELD = VALUE;
 //%    XCTAssertEqual(orig.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
-//%    MESSAGE *msg = [MESSAGE parseFromData:[orig data] error:NULL];
+//%    NSData *data = [orig data];
+//%    XCTAssertNotNil(data);
+//%    MESSAGE *msg = [MESSAGE parseFromData:data error:NULL];
 //%    XCTAssertEqual(msg.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD);
 //%    XCTAssertEqual##EQ_SUFFIX(msg.oneof##FIELD, VALUE);
 //%    [orig release];
@@ -311,7 +320,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofInt32 = 1;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32);
     XCTAssertEqual(msg.oneofInt32, 1);
     [orig release];
@@ -321,7 +332,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofInt64 = 2;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64);
     XCTAssertEqual(msg.oneofInt64, 2);
     [orig release];
@@ -331,7 +344,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofUint32 = 3U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32);
     XCTAssertEqual(msg.oneofUint32, 3U);
     [orig release];
@@ -341,7 +356,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofUint64 = 4U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64);
     XCTAssertEqual(msg.oneofUint64, 4U);
     [orig release];
@@ -351,7 +368,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSint32 = 5;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32);
     XCTAssertEqual(msg.oneofSint32, 5);
     [orig release];
@@ -361,7 +380,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSint64 = 6;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64);
     XCTAssertEqual(msg.oneofSint64, 6);
     [orig release];
@@ -371,7 +392,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFixed32 = 7U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32);
     XCTAssertEqual(msg.oneofFixed32, 7U);
     [orig release];
@@ -381,7 +404,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFixed64 = 8U;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64);
     XCTAssertEqual(msg.oneofFixed64, 8U);
     [orig release];
@@ -391,7 +416,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSfixed32 = 9;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32);
     XCTAssertEqual(msg.oneofSfixed32, 9);
     [orig release];
@@ -401,7 +428,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofSfixed64 = 10;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64);
     XCTAssertEqual(msg.oneofSfixed64, 10);
     [orig release];
@@ -411,7 +440,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofFloat = 11.0f;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat);
     XCTAssertEqual(msg.oneofFloat, 11.0f);
     [orig release];
@@ -421,7 +452,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofDouble = 12.0;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble);
     XCTAssertEqual(msg.oneofDouble, 12.0);
     [orig release];
@@ -431,7 +464,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofBool = NO;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBool);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool);
     XCTAssertEqual(msg.oneofBool, NO);
     [orig release];
@@ -441,7 +476,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofString = @"foo";
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofString);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString);
     XCTAssertEqualObjects(msg.oneofString, @"foo");
     [orig release];
@@ -451,7 +488,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes);
     XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
     [orig release];
@@ -461,7 +500,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofGroup = group;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup);
     XCTAssertEqualObjects(msg.oneofGroup, group);
     [orig release];
@@ -471,7 +512,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofMessage = subMessage;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage);
     XCTAssertEqualObjects(msg.oneofMessage, subMessage);
     [orig release];
@@ -481,7 +524,9 @@
     Message2 *orig = [[Message2 alloc] init];
     orig.oneofEnum = Message2_Enum_Bar;
     XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
-    Message2 *msg = [Message2 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message2 *msg = [Message2 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum);
     XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
     [orig release];
@@ -504,7 +549,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofInt32 = 1;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32);
     XCTAssertEqual(msg.oneofInt32, 1);
     [orig release];
@@ -514,7 +561,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofInt64 = 2;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64);
     XCTAssertEqual(msg.oneofInt64, 2);
     [orig release];
@@ -524,7 +573,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofUint32 = 3U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32);
     XCTAssertEqual(msg.oneofUint32, 3U);
     [orig release];
@@ -534,7 +585,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofUint64 = 4U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64);
     XCTAssertEqual(msg.oneofUint64, 4U);
     [orig release];
@@ -544,7 +597,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSint32 = 5;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32);
     XCTAssertEqual(msg.oneofSint32, 5);
     [orig release];
@@ -554,7 +609,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSint64 = 6;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64);
     XCTAssertEqual(msg.oneofSint64, 6);
     [orig release];
@@ -564,7 +621,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFixed32 = 7U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32);
     XCTAssertEqual(msg.oneofFixed32, 7U);
     [orig release];
@@ -574,7 +633,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFixed64 = 8U;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64);
     XCTAssertEqual(msg.oneofFixed64, 8U);
     [orig release];
@@ -584,7 +645,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSfixed32 = 9;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32);
     XCTAssertEqual(msg.oneofSfixed32, 9);
     [orig release];
@@ -594,7 +657,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofSfixed64 = 10;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64);
     XCTAssertEqual(msg.oneofSfixed64, 10);
     [orig release];
@@ -604,7 +669,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofFloat = 11.0f;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat);
     XCTAssertEqual(msg.oneofFloat, 11.0f);
     [orig release];
@@ -614,7 +681,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofDouble = 12.0;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble);
     XCTAssertEqual(msg.oneofDouble, 12.0);
     [orig release];
@@ -624,7 +693,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofBool = YES;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBool);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool);
     XCTAssertEqual(msg.oneofBool, YES);
     [orig release];
@@ -634,7 +705,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofString = @"foo";
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofString);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString);
     XCTAssertEqualObjects(msg.oneofString, @"foo");
     [orig release];
@@ -644,7 +717,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding];
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes);
     XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]);
     [orig release];
@@ -656,7 +731,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofMessage = subMessage;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage);
     XCTAssertEqualObjects(msg.oneofMessage, subMessage);
     [orig release];
@@ -666,7 +743,9 @@
     Message3 *orig = [[Message3 alloc] init];
     orig.oneofEnum = Message2_Enum_Bar;
     XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
-    Message3 *msg = [Message3 parseFromData:[orig data] error:NULL];
+    NSData *data = [orig data];
+    XCTAssertNotNil(data);
+    Message3 *msg = [Message3 parseFromData:data error:NULL];
     XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum);
     XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar);
     [orig release];
@@ -927,15 +1006,18 @@
   [orig.unknownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumExtra
                           forKey:0];
 
-  TestEnumMap *msg1 = [TestEnumMap parseFromData:[orig data] error:NULL];
+  NSData *data = [orig data];
+  XCTAssertNotNil(data);
+  TestEnumMap *msg1 = [TestEnumMap parseFromData:data error:NULL];
   XCTAssertEqual(msg1.knownMapField.count, 1U);
   int32_t val = -1;
   XCTAssertTrue([msg1.knownMapField valueForKey:0 value:&val]);
   XCTAssertEqual(val, Proto2MapEnum_Proto2MapEnumFoo);
   XCTAssertEqual(msg1.unknownFields.countOfFields, 1U);
 
+  data = [msg1 data];
   TestEnumMapPlusExtra *msg2 =
-      [TestEnumMapPlusExtra parseFromData:[msg1 data] error:NULL];
+      [TestEnumMapPlusExtra parseFromData:data error:NULL];
   val = -1;
   XCTAssertEqual(msg2.knownMapField.count, 1U);
   XCTAssertTrue([msg2.knownMapField valueForKey:0 value:&val]);
@@ -994,18 +1076,19 @@
   val2.optionalInt32 = 129;
   [msg.mapStringMessage setValue:val1 forKey:@"228"];
   [msg.mapStringMessage setValue:val2 forKey:@"2029"];
-  [msg.mapInt32Bytes setValue:DataFromCStr("1030 bytes") forKey:230];
-  [msg.mapInt32Bytes setValue:DataFromCStr("131") forKey:2031];
+  [msg.mapInt32Bytes setObject:DataFromCStr("1030 bytes") forKey:230];
+  [msg.mapInt32Bytes setObject:DataFromCStr("131") forKey:2031];
   [msg.mapInt32Enum setValue:Message2_Enum_Bar forKey:232];
   [msg.mapInt32Enum setValue:Message2_Enum_Baz forKey:2033];
   Message2 *val3 = [[Message2 alloc] init];
   val3.optionalInt32 = 1034;
   Message2 *val4 = [[Message2 alloc] init];
   val4.optionalInt32 = 135;
-  [msg.mapInt32Message setValue:val3 forKey:234];
-  [msg.mapInt32Message setValue:val4 forKey:2035];
+  [msg.mapInt32Message setObject:val3 forKey:234];
+  [msg.mapInt32Message setObject:val4 forKey:2035];
 
   NSData *data = [msg data];
+  XCTAssertNotNil(data);
   Message2 *msg2 = [[Message2 alloc] initWithData:data error:NULL];
 
   XCTAssertNotEqual(msg2, msg);  // Pointer comparison
diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m
index cd0de8f..7b37ca9 100644
--- a/objectivec/Tests/GPBMessageTests.m
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -55,7 +55,6 @@
   [message setOptionalInt32:1];
   [message setOptionalString:@"foo"];
   [message setOptionalForeignMessage:[ForeignMessage message]];
-  message.repeatedStringArray = [NSMutableArray array];
   [message.repeatedStringArray addObject:@"bar"];
   return message;
 }
@@ -67,7 +66,6 @@
   ForeignMessage *foreignMessage = [ForeignMessage message];
   [foreignMessage setC:3];
   [message setOptionalForeignMessage:foreignMessage];
-  message.repeatedStringArray = [NSMutableArray array];
   [message.repeatedStringArray addObject:@"qux"];
   return message;
 }
@@ -76,7 +74,6 @@
   TestAllTypes *message = [TestAllTypes message];
   [message setOptionalInt64:2];
   [message setOptionalString:@"baz"];
-  message.repeatedStringArray = [NSMutableArray array];
   [message.repeatedStringArray addObject:@"qux"];
   return message;
 }
@@ -89,7 +86,6 @@
   ForeignMessage *foreignMessage = [ForeignMessage message];
   [foreignMessage setC:3];
   [message setOptionalForeignMessage:foreignMessage];
-  message.repeatedStringArray = [NSMutableArray array];
   [message.repeatedStringArray addObject:@"qux"];
   [message.repeatedStringArray addObject:@"bar"];
   return message;
@@ -102,7 +98,6 @@
   [message setOptionalString:@"foo"];
   ForeignMessage *foreignMessage = [ForeignMessage message];
   [message setOptionalForeignMessage:foreignMessage];
-  message.repeatedStringArray = [NSMutableArray array];
   [message.repeatedStringArray addObject:@"qux"];
   [message.repeatedStringArray addObject:@"bar"];
   return message;
@@ -195,7 +190,9 @@
 
   // Test merging from data.
   result = [self mergeExtensionsDestination];
-  [result mergeFromData:[[self mergeExtensionsSource] data]
+  NSData *data = [[self mergeExtensionsSource] data];
+  XCTAssertNotNil(data);
+  [result mergeFromData:data
       extensionRegistry:[UnittestRoot extensionRegistry]];
   resultData = [result data];
   XCTAssertEqualObjects(resultData, mergeResultData);
@@ -246,7 +243,6 @@
   [message setOptionalMessage:self.testRequiredInitialized];
   XCTAssertTrue(message.initialized);
 
-  message.repeatedMessageArray = [NSMutableArray array];
   [message.repeatedMessageArray addObject:[TestRequired message]];
   XCTAssertFalse(message.initialized);
 
@@ -298,7 +294,6 @@
 - (void)testDataFromNestedUninitialized {
   TestRequiredForeign *message = [TestRequiredForeign message];
   [message setOptionalMessage:[TestRequired message]];
-  message.repeatedMessageArray = [NSMutableArray array];
   [message.repeatedMessageArray addObject:[TestRequired message]];
   [message.repeatedMessageArray addObject:[TestRequired message]];
   NSData *data = [message data];
@@ -317,7 +312,6 @@
 
   TestRequiredForeign *message = [TestRequiredForeign message];
   [message setOptionalMessage:[TestRequired message]];
-  message.repeatedMessageArray = [NSMutableArray array];
   [message.repeatedMessageArray addObject:[TestRequired message]];
   [message.repeatedMessageArray addObject:[TestRequired message]];
 
@@ -1884,7 +1878,9 @@
   XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One);
   XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne);
   // Bounce to wire and back.
-  EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
+  NSData *data = [msg data];
+  XCTAssertNotNil(data);
+  EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:data error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
   XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One);
@@ -1896,7 +1892,9 @@
   XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two);
   XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo);
   // Bounce to wire and back.
-  msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
+  data = [msg data];
+  XCTAssertNotNil(data);
+  msgPrime = [EnumTestMsg parseFromData:data error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
   XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two);
@@ -1917,7 +1915,9 @@
   XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne);
   XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo);
   // Bounce to wire and back.
-  msgPrime = [EnumTestMsg parseFromData:[msg data] error:NULL];
+  data = [msg data];
+  XCTAssertNotNil(data);
+  msgPrime = [EnumTestMsg parseFromData:data error:NULL];
   XCTAssertEqualObjects(msgPrime, msg);
   XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0],
                  EnumTestMsg_MyEnum_Zero);
diff --git a/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm b/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm
new file mode 100644
index 0000000..9ba8fd0
--- /dev/null
+++ b/objectivec/Tests/GPBObjectiveCPlusPlusTest.mm
@@ -0,0 +1,69 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#import "GPBTestUtilities.h"
+
+
+//
+// This is just a compile test (here to make sure things never regress).
+//
+// Objective C++ can run into issues with how the NS_ENUM/CF_ENUM declartion
+// works because of the C++ spec being used for that compilation unit. So
+// the fact that these imports all work without errors/warning means things
+// are still good.
+//
+// The "well know types" should have cross file enums needing imports.
+#import "GPBProtocolBuffers.h"
+// Some of the tests explicitly use cross file enums also.
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestImport.pbobjc.h"
+
+// Sanity check the conditions of the test within the Xcode project.
+#if !__cplusplus
+  #error This isn't compiled as Objective C++?
+#elif __cplusplus >= 201103L
+  // If this trips, it means the Xcode default might have change (or someone
+  // edited the testing project) and it might be time to revisit the GPB_ENUM
+  // define in GPBBootstrap.h.
+  #warning Did the Xcode default for C++ spec change?
+#endif
+
+
+// Dummy XCTest.
+@interface GPBObjectiveCPlusPlusTests : GPBTestCase
+@end
+
+@implementation GPBObjectiveCPlusPlusTests
+- (void)testCPlusPlus {
+  // Nothing, This was a compile test.
+  XCTAssertTrue(YES);
+}
+@end
diff --git a/objectivec/Tests/GPBStringTests.m b/objectivec/Tests/GPBStringTests.m
deleted file mode 100644
index 802afa7..0000000
--- a/objectivec/Tests/GPBStringTests.m
+++ /dev/null
@@ -1,513 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#import <XCTest/XCTest.h>
-
-#import "GPBCodedInputStream_PackagePrivate.h"
-#import "GPBTestUtilities.h"
-
-@interface TestClass : NSObject
-@property(nonatomic, retain) NSString *foo;
-@end
-
-@implementation TestClass
-@synthesize foo;
-@end
-
-@interface GPBStringTests : XCTestCase {
-  NSMutableArray *nsStrings_;
-  NSMutableArray *gpbStrings_;
-}
-
-@end
-
-@implementation GPBStringTests
-
-- (void)setUp {
-  [super setUp];
-  const char *strings[] = {
-      "ascii string",
-      "non-ascii string \xc3\xa9",  // e with acute accent
-      "\xe2\x99\xa1",               // White Heart
-      "mix \xe2\x99\xa4 string",    // White Spade
-
-      // Decomposed forms from http://www.unicode.org/reports/tr15/
-      // 1.2 Singletons
-      "\xe2\x84\xa8 = A\xcc\x8a = \xc3\x85", "\xe2\x84\xa6 = \xce\xa9",
-
-      // 1.2 Canonical Composites
-      "A\xcc\x8a = \xc3\x85",
-      "o\xcc\x82 = \xc3\xb4",
-
-      // 1.2 Multiple Combining Marks
-      "s\xcc\xa3\xcc\x87 = \xe1\xb9\xa9",
-      "\xe1\xb8\x8b\xcc\xa3 = d\xcc\xa3\xcc\x87 = \xe1\xb8\x8d \xcc\x87",
-      "q\xcc\x87\xcc\xa3 = q\xcc\xa3\xcc\x87",
-
-      // BOM
-      "\xEF\xBB\xBF String with BOM",
-      "String with \xEF\xBB\xBF in middle",
-      "String with end bom \xEF\xBB\xBF",
-      "\xEF\xBB\xBF\xe2\x99\xa1",  // BOM White Heart
-      "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM",
-
-      // Supplementary Plane
-      "\xf0\x9d\x84\x9e",  // MUSICAL SYMBOL G CLEF
-
-      // Tags
-      "\xf3\xa0\x80\x81",  // Language Tag
-
-      // Variation Selectors
-      "\xf3\xa0\x84\x80",  // VARIATION SELECTOR-17
-
-      // Specials
-      "\xef\xbb\xbf\xef\xbf\xbd\xef\xbf\xbf",
-
-      // Left To Right/Right To Left
-      // http://unicode.org/reports/tr9/
-
-      // Hello! <RTL marker>!Merhaba<LTR marker>
-      "Hello! \xE2\x80\x8F!\xd9\x85\xd8\xb1\xd8\xad\xd8\xa8\xd8\xa7\xE2\x80\x8E",
-
-      "\xE2\x80\x8E LTR At Start",
-      "LTR At End\xE2\x80\x8E",
-      "\xE2\x80\x8F RTL At Start",
-      "RTL At End\xE2\x80\x8F",
-      "\xE2\x80\x8E\xE2\x80\x8E Double LTR \xE2\x80\x8E\xE2\x80\x8E",
-      "\xE2\x80\x8F\xE2\x80\x8F Double RTL \xE2\x80\x8F\xE2\x80\x8F",
-      "\xE2\x80\x8F\xE2\x80\x8E LTR-RTL LTR-RTL \xE2\x80\x8E\xE2\x80\x8F",
-  };
-  size_t stringsSize = GPBARRAYSIZE(strings);
-  size_t numberUnicodeStrings = 17375;
-  nsStrings_ = [[NSMutableArray alloc]
-      initWithCapacity:stringsSize + numberUnicodeStrings];
-  gpbStrings_ = [[NSMutableArray alloc]
-      initWithCapacity:stringsSize + numberUnicodeStrings];
-  for (size_t i = 0; i < stringsSize; ++i) {
-    size_t length = strlen(strings[i]);
-    NSString *nsString = [[NSString alloc] initWithBytes:strings[i]
-                                                  length:length
-                                                encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    GPBString *gpbString = GPBCreateGPBStringWithUTF8(strings[i], length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-
-  // Generate all UTF8 characters in a variety of strings
-  // UTF8-1 - 1 Byte UTF 8 chars
-  int length = 0x7F + 1;
-  char *buffer = (char *)calloc(length, 1);
-  for (int i = 0; i < length; ++i) {
-    buffer[i] = (char)i;
-  }
-  NSString *nsString = [[NSString alloc] initWithBytes:buffer
-                                                length:length
-                                              encoding:NSUTF8StringEncoding];
-  [nsStrings_ addObject:nsString];
-  [nsString release];
-  GPBString *gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-  [gpbStrings_ addObject:gpbString];
-  [gpbString release];
-
-  // UTF8-2 - 2 Byte UTF 8 chars
-  int pointLength = 0xbf - 0x80 + 1;
-  length = pointLength * 2;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0xc2; i <= 0xdf; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  free(buffer);
-
-  // UTF8-3 - 3 Byte UTF 8 chars
-  length = pointLength * 3;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0xa0; i <= 0xbf; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)0xE0;
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  for (int i = 0xe1; i <= 0xec; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  for (int i = 0x80; i <= 0x9f; ++i) {
-    char *bufferPtr = buffer;
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      (*bufferPtr++) = (char)0xED;
-      (*bufferPtr++) = (char)i;
-      (*bufferPtr++) = (char)j;
-    }
-    nsString = [[NSString alloc] initWithBytes:buffer
-                                        length:length
-                                      encoding:NSUTF8StringEncoding];
-    [nsStrings_ addObject:nsString];
-    [nsString release];
-    gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-    [gpbStrings_ addObject:gpbString];
-    [gpbString release];
-  }
-  for (int i = 0xee; i <= 0xef; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  free(buffer);
-
-  // UTF8-4 - 4 Byte UTF 8 chars
-  length = pointLength * 4;
-  buffer = (char *)calloc(length, 1);
-  for (int i = 0x90; i <= 0xbf; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)0xF0;
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  for (int i = 0xf1; i <= 0xf3; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        char *bufferPtr = buffer;
-        for (int m = 0x80; m <= 0xbf; ++m) {
-          (*bufferPtr++) = (char)i;
-          (*bufferPtr++) = (char)j;
-          (*bufferPtr++) = (char)k;
-          (*bufferPtr++) = (char)m;
-        }
-        nsString = [[NSString alloc] initWithBytes:buffer
-                                            length:length
-                                          encoding:NSUTF8StringEncoding];
-        [nsStrings_ addObject:nsString];
-        [nsString release];
-        gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-        [gpbStrings_ addObject:gpbString];
-        [gpbString release];
-      }
-    }
-  }
-  for (int i = 0x80; i <= 0x8f; ++i) {
-    for (int j = 0x80; j <= 0xbf; ++j) {
-      char *bufferPtr = buffer;
-      for (int k = 0x80; k <= 0xbf; ++k) {
-        (*bufferPtr++) = (char)0xF4;
-        (*bufferPtr++) = (char)i;
-        (*bufferPtr++) = (char)j;
-        (*bufferPtr++) = (char)k;
-      }
-      nsString = [[NSString alloc] initWithBytes:buffer
-                                          length:length
-                                        encoding:NSUTF8StringEncoding];
-      [nsStrings_ addObject:nsString];
-      [nsString release];
-      gpbString = GPBCreateGPBStringWithUTF8(buffer, length);
-      [gpbStrings_ addObject:gpbString];
-      [gpbString release];
-    }
-  }
-  free(buffer);
-}
-
-- (void)tearDown {
-  [nsStrings_ release];
-  [gpbStrings_ release];
-  [super tearDown];
-}
-
-- (void)testLength {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqual([nsString length], [gpbString length], @"%@ %@", nsString,
-                   gpbString);
-    ++i;
-  }
-}
-
-- (void)testLengthOfBytesUsingEncoding {
-  NSStringEncoding encodings[] = {
-    NSUTF8StringEncoding,
-    NSASCIIStringEncoding,
-    NSISOLatin1StringEncoding,
-    NSMacOSRomanStringEncoding,
-    NSUTF16StringEncoding,
-    NSUTF32StringEncoding,
-  };
-
-  for (size_t j = 0; j < GPBARRAYSIZE(encodings); ++j) {
-    NSStringEncoding testEncoding = encodings[j];
-    size_t i = 0;
-    for (NSString *nsString in nsStrings_) {
-      GPBString *gpbString = gpbStrings_[i];
-      XCTAssertEqual([nsString lengthOfBytesUsingEncoding:testEncoding],
-                     [gpbString lengthOfBytesUsingEncoding:testEncoding],
-                     @"%@ %@", nsString, gpbString);
-      ++i;
-    }
-  }
-}
-
-- (void)testHash {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqual([nsString hash], [gpbString hash], @"%@ %@", nsString,
-                   gpbString);
-    ++i;
-  }
-}
-
-- (void)testEquality {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testCharacterAtIndex {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    NSUInteger length = [nsString length];
-    for (size_t j = 0; j < length; ++j) {
-      unichar nsChar = [nsString characterAtIndex:j];
-      unichar pbChar = [gpbString characterAtIndex:j];
-      XCTAssertEqual(nsChar, pbChar, @"%@ %@ %zu", nsString, gpbString, j);
-    }
-    ++i;
-  }
-}
-
-- (void)testCopy {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = [[gpbStrings_[i] copy] autorelease];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testMutableCopy {
-  size_t i = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = [[gpbStrings_[i] mutableCopy] autorelease];
-    XCTAssertEqualObjects(nsString, gpbString);
-    ++i;
-  }
-}
-
-- (void)testGetBytes {
-  // Do an attempt at a reasonably exhaustive test of get bytes.
-  // Get bytes with options other than 0 should always fall through to Apple
-  // code so we don't bother testing that path.
-  size_t i = 0;
-  char pbBuffer[256];
-  char nsBuffer[256];
-  int count = 0;
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i];
-    for (int j = 0; j < 100; ++j) {
-      // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange]
-      // does not return reliable results if the maxLength argument is 0,
-      // or range is 0,0.
-      // Radar 16385183
-      NSUInteger length = [nsString length];
-      NSUInteger maxBufferCount = (arc4random() % (length + 3)) + 1;
-      NSUInteger rangeStart = arc4random() % length;
-      NSUInteger rangeLength = arc4random() % (length - rangeStart);
-
-      NSRange range = NSMakeRange(rangeStart, rangeLength);
-
-      NSStringEncoding encodings[] = {
-        NSASCIIStringEncoding,
-        NSUTF8StringEncoding,
-        NSUTF16StringEncoding,
-      };
-
-      for (size_t k = 0; k < GPBARRAYSIZE(encodings); ++k) {
-        NSStringEncoding encoding = encodings[k];
-        NSUInteger pbUsedBufferCount = 0;
-        NSUInteger nsUsedBufferCount = 0;
-        NSRange pbLeftOver = NSMakeRange(0, 0);
-        NSRange nsLeftOver = NSMakeRange(0, 0);
-
-        BOOL pbGotBytes = [gpbString getBytes:pbBuffer
-                                    maxLength:maxBufferCount
-                                   usedLength:&pbUsedBufferCount
-                                     encoding:encoding
-                                      options:0
-                                        range:range
-                               remainingRange:&pbLeftOver];
-        BOOL nsGotBytes = [nsString getBytes:nsBuffer
-                                   maxLength:maxBufferCount
-                                  usedLength:&nsUsedBufferCount
-                                    encoding:encoding
-                                     options:0
-                                       range:range
-                              remainingRange:&nsLeftOver];
-        XCTAssertEqual(
-            (bool)pbGotBytes, (bool)nsGotBytes,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbUsedBufferCount, nsUsedBufferCount,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbLeftOver.location, nsLeftOver.location,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        XCTAssertEqual(
-            pbLeftOver.length, nsLeftOver.length,
-            @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ "
-            @"Used: %tu, %tu LeftOver %@, %@)",
-            count, gpbString, nsString, encoding, maxBufferCount,
-            NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount,
-            NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver));
-        ++count;
-      }
-    }
-    ++i;
-  }
-}
-
-- (void)testLengthAndGetBytes {
-  // This test exists as an attempt to ferret out a bug.
-  // http://b/13516532
-  size_t i = 0;
-  char pbBuffer[256];
-  char nsBuffer[256];
-  for (NSString *nsString in nsStrings_) {
-    GPBString *gpbString = gpbStrings_[i++];
-    NSUInteger nsLength =
-        [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-    NSUInteger pbLength =
-        [gpbString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
-    XCTAssertEqual(nsLength, pbLength, @"%@ %@", nsString, gpbString);
-    NSUInteger pbUsedBufferCount = 0;
-    NSUInteger nsUsedBufferCount = 0;
-    NSRange pbLeftOver = NSMakeRange(0, 0);
-    NSRange nsLeftOver = NSMakeRange(0, 0);
-    NSRange range = NSMakeRange(0, [gpbString length]);
-    BOOL pbGotBytes = [gpbString getBytes:pbBuffer
-                                maxLength:sizeof(pbBuffer)
-                               usedLength:&pbUsedBufferCount
-                                 encoding:NSUTF8StringEncoding
-                                  options:0
-                                    range:range
-                           remainingRange:&pbLeftOver];
-    BOOL nsGotBytes = [nsString getBytes:nsBuffer
-                               maxLength:sizeof(nsBuffer)
-                              usedLength:&nsUsedBufferCount
-                                encoding:NSUTF8StringEncoding
-                                 options:0
-                                   range:range
-                          remainingRange:&nsLeftOver];
-    XCTAssertTrue(pbGotBytes, @"%@", gpbString);
-    XCTAssertTrue(nsGotBytes, @"%@", nsString);
-    XCTAssertEqual(pbUsedBufferCount, pbLength, @"%@", gpbString);
-    XCTAssertEqual(nsUsedBufferCount, nsLength, @"%@", nsString);
-  }
-}
-
-@end
diff --git a/objectivec/Tests/GPBSwiftTests.swift b/objectivec/Tests/GPBSwiftTests.swift
index 5fbe74f..36ed2a6 100644
--- a/objectivec/Tests/GPBSwiftTests.swift
+++ b/objectivec/Tests/GPBSwiftTests.swift
@@ -83,8 +83,8 @@
     XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
     XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
     XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
-    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno")
-    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
     XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
     XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue)
     XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue)
@@ -96,8 +96,8 @@
     XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
     XCTAssertEqual(intValue, Int32(401))
     XCTAssertEqual(msg.mapStringString.count, Int(2))
-    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as! String, "foo")
-    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as! String, "abc")
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
     XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
     XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
     XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
@@ -173,8 +173,8 @@
     XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300))
     XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301))
     XCTAssertEqual(msg.repeatedStringArray.count, Int(2))
-    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno")
-    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as? String, "mno")
+    XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as? String, "pqr")
     XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0))
     XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2))
     XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message3_Enum.Bar.rawValue)
@@ -189,8 +189,8 @@
     XCTAssertTrue(msg.mapInt32Int32.valueForKey(501, value:&intValue))
     XCTAssertEqual(intValue, Int32(401))
     XCTAssertEqual(msg.mapStringString.count, Int(2))
-    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as! String, "foo")
-    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as! String, "abc")
+    XCTAssertEqual(msg.mapStringString.objectForKey("bar") as? String, "foo")
+    XCTAssertEqual(msg.mapStringString.objectForKey("xyz") as? String, "abc")
     XCTAssertEqual(msg.mapInt32Enum.count, UInt(2))
     XCTAssertTrue(msg.mapInt32Enum.valueForKey(600, value:&intValue))
     XCTAssertEqual(intValue, Message2_Enum.Bar.rawValue)
diff --git a/objectivec/Tests/GPBTestUtilities.m b/objectivec/Tests/GPBTestUtilities.m
index 3d85c74..726761a 100644
--- a/objectivec/Tests/GPBTestUtilities.m
+++ b/objectivec/Tests/GPBTestUtilities.m
@@ -1110,7 +1110,7 @@
     [dataStr release];
 
     NSData *data = [[NSData alloc] initWithUint32_gpbtu:i + 1];
-    [message.mapInt32Bytes setValue:data forKey:113 + i * 100];
+    [message.mapInt32Bytes setObject:data forKey:113 + i * 100];
     [data release];
 
     [message.mapInt32Enum
@@ -1119,7 +1119,7 @@
 
     ForeignMessage *subMsg = [[ForeignMessage alloc] init];
     subMsg.c = i + 1;
-    [message.mapInt32ForeignMessage setValue:subMsg forKey:115 + i * 100];
+    [message.mapInt32ForeignMessage setObject:subMsg forKey:115 + i * 100];
     [subMsg release];
   }
 }
diff --git a/objectivec/Tests/GPBWireFormatTests.m b/objectivec/Tests/GPBWireFormatTests.m
index c124421..2a406f1 100644
--- a/objectivec/Tests/GPBWireFormatTests.m
+++ b/objectivec/Tests/GPBWireFormatTests.m
@@ -167,12 +167,12 @@
   XCTAssertEqual([raw.itemArray[2] typeId], kUnknownTypeId);
 
   TestMessageSetExtension1* message1 =
-      [TestMessageSetExtension1 parseFromData:[raw.itemArray[0] message]
+      [TestMessageSetExtension1 parseFromData:[((RawMessageSet_Item*)raw.itemArray[0]) message]
                                         error:NULL];
   XCTAssertEqual(message1.i, 123);
 
   TestMessageSetExtension2* message2 =
-      [TestMessageSetExtension2 parseFromData:[raw.itemArray[1] message]
+      [TestMessageSetExtension2 parseFromData:[((RawMessageSet_Item*)raw.itemArray[1]) message]
                                         error:NULL];
   XCTAssertEqualObjects(message2.str, @"foo");
 
@@ -190,7 +190,6 @@
     TestMessageSetExtension1* message = [TestMessageSetExtension1 message];
     message.i = 123;
     item.message = [message data];
-    raw.itemArray = [NSMutableArray array];
     [raw.itemArray addObject:item];
   }
 
diff --git a/objectivec/Tests/UnitTests-Info.plist b/objectivec/Tests/UnitTests-Info.plist
index 6501355..460a7d9 100644
--- a/objectivec/Tests/UnitTests-Info.plist
+++ b/objectivec/Tests/UnitTests-Info.plist
@@ -7,7 +7,7 @@
 	<key>CFBundleExecutable</key>
 	<string>${EXECUTABLE_NAME}</string>
 	<key>CFBundleIdentifier</key>
-	<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundlePackageType</key>
diff --git a/objectivec/Tests/iOSTestHarness/Info.plist b/objectivec/Tests/iOSTestHarness/Info.plist
index 31ab157..24bd333 100644
--- a/objectivec/Tests/iOSTestHarness/Info.plist
+++ b/objectivec/Tests/iOSTestHarness/Info.plist
@@ -9,7 +9,7 @@
 	<key>CFBundleExecutable</key>
 	<string>${EXECUTABLE_NAME}</string>
 	<key>CFBundleIdentifier</key>
-	<string>com.google.${PRODUCT_NAME:rfc1034identifier}</string>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
index 6511b8e..9866b5b 100644
--- a/objectivec/google/protobuf/Any.pbobjc.h
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
@@ -34,6 +34,7 @@
 // `Any` contains an arbitrary serialized message along with a URL
 // that describes the type of the serialized message.
 //
+//
 // JSON
 // ====
 // The JSON representation of an `Any` value uses the regular
@@ -54,8 +55,8 @@
 //
 // If the embedded message type is well-known and has a custom JSON
 // representation, that representation will be embedded adding a field
-// `value` which holds the custom JSON in addition to the the `@type`
-// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+// `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",
@@ -72,7 +73,7 @@
 // * If no schema is provided, `https` is assumed.
 // * The last segment of the URL's path must represent the fully
 //   qualified name of the type (as in `path/google.protobuf.Duration`).
-// * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+// * 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
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
index d6292cb..8d82b15 100644
--- a/objectivec/google/protobuf/Api.pbobjc.h
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -4,13 +4,16 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
 
 CF_EXTERN_C_BEGIN
 
+@class GPBMethod;
+@class GPBMixin;
+@class GPBOption;
 @class GPBSourceContext;
 GPB_ENUM_FWD_DECLARE(GPBSyntax);
 
@@ -47,13 +50,11 @@
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
 // The methods of this api, in unspecified order.
-// |methodsArray| contains |GPBMethod|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethod*> *methodsArray;
 @property(nonatomic, readonly) NSUInteger methodsArray_Count;
 
 // Any metadata attached to the API.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 // A version string for this api. If specified, must have the form
@@ -84,8 +85,7 @@
 @property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext;
 
 // Included APIs. See [Mixin][].
-// |mixinsArray| contains |GPBMixin|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *mixinsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMixin*> *mixinsArray;
 @property(nonatomic, readonly) NSUInteger mixinsArray_Count;
 
 // The source syntax of the service.
@@ -127,8 +127,7 @@
 @property(nonatomic, readwrite) BOOL responseStreaming;
 
 // Any metadata attached to the method.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 // The source syntax of this method.
@@ -174,7 +173,6 @@
 //
 //     package google.storage.v2;
 //     service Storage {
-//       // (-- see AccessControl.GetAcl --)
 //       rpc GetAcl(GetAclRequest) returns (Acl);
 //
 //       // Get a data record.
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.h b/objectivec/google/protobuf/Descriptor.pbobjc.h
index 2a86a7e..2ab2024 100644
--- a/objectivec/google/protobuf/Descriptor.pbobjc.h
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.h
@@ -4,21 +4,35 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
 
 CF_EXTERN_C_BEGIN
 
+@class GPBDescriptorProto;
+@class GPBDescriptorProto_ExtensionRange;
+@class GPBDescriptorProto_ReservedRange;
+@class GPBEnumDescriptorProto;
 @class GPBEnumOptions;
+@class GPBEnumValueDescriptorProto;
 @class GPBEnumValueOptions;
+@class GPBFieldDescriptorProto;
 @class GPBFieldOptions;
+@class GPBFileDescriptorProto;
 @class GPBFileOptions;
+@class GPBGeneratedCodeInfo_Annotation;
 @class GPBMessageOptions;
+@class GPBMethodDescriptorProto;
 @class GPBMethodOptions;
+@class GPBOneofDescriptorProto;
+@class GPBServiceDescriptorProto;
 @class GPBServiceOptions;
 @class GPBSourceCodeInfo;
+@class GPBSourceCodeInfo_Location;
+@class GPBUninterpretedOption;
+@class GPBUninterpretedOption_NamePart;
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -151,8 +165,7 @@
 // files it parses.
 @interface GPBFileDescriptorSet : GPBMessage
 
-// |fileArray| contains |GPBFileDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fileArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBFileDescriptorProto*> *fileArray;
 @property(nonatomic, readonly) NSUInteger fileArray_Count;
 
 @end
@@ -186,8 +199,7 @@
 @property(nonatomic, readwrite, copy, null_resettable) NSString *package;
 
 // Names of files imported by this file.
-// |dependencyArray| contains |NSString|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *dependencyArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *dependencyArray;
 @property(nonatomic, readonly) NSUInteger dependencyArray_Count;
 
 // Indexes of the public imported files in the dependency list above.
@@ -200,20 +212,16 @@
 @property(nonatomic, readonly) NSUInteger weakDependencyArray_Count;
 
 // All top-level definitions in this file.
-// |messageTypeArray| contains |GPBDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *messageTypeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBDescriptorProto*> *messageTypeArray;
 @property(nonatomic, readonly) NSUInteger messageTypeArray_Count;
 
-// |enumTypeArray| contains |GPBEnumDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumDescriptorProto*> *enumTypeArray;
 @property(nonatomic, readonly) NSUInteger enumTypeArray_Count;
 
-// |serviceArray| contains |GPBServiceDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *serviceArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBServiceDescriptorProto*> *serviceArray;
 @property(nonatomic, readonly) NSUInteger serviceArray_Count;
 
-// |extensionArray| contains |GPBFieldDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBFieldDescriptorProto*> *extensionArray;
 @property(nonatomic, readonly) NSUInteger extensionArray_Count;
 
 @property(nonatomic, readwrite) BOOL hasOptions;
@@ -254,41 +262,33 @@
 @property(nonatomic, readwrite) BOOL hasName;
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-// |fieldArray| contains |GPBFieldDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBFieldDescriptorProto*> *fieldArray;
 @property(nonatomic, readonly) NSUInteger fieldArray_Count;
 
-// |extensionArray| contains |GPBFieldDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBFieldDescriptorProto*> *extensionArray;
 @property(nonatomic, readonly) NSUInteger extensionArray_Count;
 
-// |nestedTypeArray| contains |GPBDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nestedTypeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBDescriptorProto*> *nestedTypeArray;
 @property(nonatomic, readonly) NSUInteger nestedTypeArray_Count;
 
-// |enumTypeArray| contains |GPBEnumDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumDescriptorProto*> *enumTypeArray;
 @property(nonatomic, readonly) NSUInteger enumTypeArray_Count;
 
-// |extensionRangeArray| contains |GPBDescriptorProto_ExtensionRange|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionRangeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBDescriptorProto_ExtensionRange*> *extensionRangeArray;
 @property(nonatomic, readonly) NSUInteger extensionRangeArray_Count;
 
-// |oneofDeclArray| contains |GPBOneofDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofDeclArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOneofDescriptorProto*> *oneofDeclArray;
 @property(nonatomic, readonly) NSUInteger oneofDeclArray_Count;
 
 @property(nonatomic, readwrite) BOOL hasOptions;
 @property(nonatomic, readwrite, strong, null_resettable) GPBMessageOptions *options;
 
-// |reservedRangeArray| contains |GPBDescriptorProto_ReservedRange|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedRangeArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBDescriptorProto_ReservedRange*> *reservedRangeArray;
 @property(nonatomic, readonly) NSUInteger reservedRangeArray_Count;
 
 // Reserved field names, which may not be used by fields in the same message.
 // A given name may only be reserved once.
-// |reservedNameArray| contains |NSString|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedNameArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *reservedNameArray;
 @property(nonatomic, readonly) NSUInteger reservedNameArray_Count;
 
 @end
@@ -344,6 +344,7 @@
   GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7,
   GPBFieldDescriptorProto_FieldNumber_Options = 8,
   GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9,
+  GPBFieldDescriptorProto_FieldNumber_JsonName = 10,
 };
 
 // Describes a field within a message.
@@ -389,6 +390,13 @@
 @property(nonatomic, readwrite) BOOL hasOneofIndex;
 @property(nonatomic, readwrite) int32_t oneofIndex;
 
+// JSON name of this field. The value is set by protocol compiler. If the
+// user has set a "json_name" option on this field, that option's value
+// will be used. Otherwise, it's deduced from the field's name by converting
+// it to camelCase.
+@property(nonatomic, readwrite) BOOL hasJsonName;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName;
+
 @property(nonatomic, readwrite) BOOL hasOptions;
 @property(nonatomic, readwrite, strong, null_resettable) GPBFieldOptions *options;
 
@@ -422,8 +430,7 @@
 @property(nonatomic, readwrite) BOOL hasName;
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-// |valueArray| contains |GPBEnumValueDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valueArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValueDescriptorProto*> *valueArray;
 @property(nonatomic, readonly) NSUInteger valueArray_Count;
 
 @property(nonatomic, readwrite) BOOL hasOptions;
@@ -467,8 +474,7 @@
 @property(nonatomic, readwrite) BOOL hasName;
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-// |methodArray| contains |GPBMethodDescriptorProto|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBMethodDescriptorProto*> *methodArray;
 @property(nonatomic, readonly) NSUInteger methodArray_Count;
 
 @property(nonatomic, readwrite) BOOL hasOptions;
@@ -642,8 +648,7 @@
 @property(nonatomic, readwrite) BOOL javananoUseDeprecatedPackage;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -719,8 +724,7 @@
 @property(nonatomic, readwrite) BOOL mapEntry;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -809,8 +813,7 @@
 @property(nonatomic, readwrite) BOOL weak;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -838,8 +841,7 @@
 @property(nonatomic, readwrite) BOOL deprecated;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -861,8 +863,7 @@
 @property(nonatomic, readwrite) BOOL deprecated;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -884,8 +885,7 @@
 @property(nonatomic, readwrite) BOOL deprecated;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -907,8 +907,7 @@
 @property(nonatomic, readwrite) BOOL deprecated;
 
 // The parser stores options it doesn't recognize here. See above.
-// |uninterpretedOptionArray| contains |GPBUninterpretedOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption*> *uninterpretedOptionArray;
 @property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count;
 
 @end
@@ -933,8 +932,7 @@
 // in them.
 @interface GPBUninterpretedOption : GPBMessage
 
-// |nameArray| contains |GPBUninterpretedOption_NamePart|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nameArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBUninterpretedOption_NamePart*> *nameArray;
 @property(nonatomic, readonly) NSUInteger nameArray_Count;
 
 // The value of the uninterpreted option, in whatever type the tokenizer
@@ -1034,8 +1032,7 @@
 // - Code which tries to interpret locations should probably be designed to
 //   ignore those that it doesn't understand, as more types of locations could
 //   be recorded in the future.
-// |locationArray| contains |GPBSourceCodeInfo_Location|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *locationArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBSourceCodeInfo_Location*> *locationArray;
 @property(nonatomic, readonly) NSUInteger locationArray_Count;
 
 @end
@@ -1139,12 +1136,62 @@
 @property(nonatomic, readwrite) BOOL hasTrailingComments;
 @property(nonatomic, readwrite, copy, null_resettable) NSString *trailingComments;
 
-// |leadingDetachedCommentsArray| contains |NSString|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *leadingDetachedCommentsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *leadingDetachedCommentsArray;
 @property(nonatomic, readonly) NSUInteger leadingDetachedCommentsArray_Count;
 
 @end
 
+#pragma mark - GPBGeneratedCodeInfo
+
+typedef GPB_ENUM(GPBGeneratedCodeInfo_FieldNumber) {
+  GPBGeneratedCodeInfo_FieldNumber_AnnotationArray = 1,
+};
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+@interface GPBGeneratedCodeInfo : GPBMessage
+
+// An Annotation connects some span of text in generated code to an element
+// of its generating .proto file.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBGeneratedCodeInfo_Annotation*> *annotationArray;
+@property(nonatomic, readonly) NSUInteger annotationArray_Count;
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo_Annotation
+
+typedef GPB_ENUM(GPBGeneratedCodeInfo_Annotation_FieldNumber) {
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray = 1,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile = 2,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin = 3,
+  GPBGeneratedCodeInfo_Annotation_FieldNumber_End = 4,
+};
+
+@interface GPBGeneratedCodeInfo_Annotation : GPBMessage
+
+// Identifies the element in the original source .proto file. This field
+// is formatted the same as SourceCodeInfo.Location.path.
+@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *pathArray;
+@property(nonatomic, readonly) NSUInteger pathArray_Count;
+
+// Identifies the filesystem path to the original source .proto.
+@property(nonatomic, readwrite) BOOL hasSourceFile;
+@property(nonatomic, readwrite, copy, null_resettable) NSString *sourceFile;
+
+// Identifies the starting offset in bytes in the generated code
+// that relates to the identified object.
+@property(nonatomic, readwrite) BOOL hasBegin;
+@property(nonatomic, readwrite) int32_t begin;
+
+// Identifies the ending offset in bytes in the generated code that
+// relates to the identified offset. The end offset should be one past
+// the last relevant byte (so the length of the text = end - begin).
+@property(nonatomic, readwrite) BOOL hasEnd;
+@property(nonatomic, readwrite) int32_t end;
+
+@end
+
 NS_ASSUME_NONNULL_END
 
 CF_EXTERN_C_END
diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.m b/objectivec/google/protobuf/Descriptor.pbobjc.m
index 8d69867..4030989 100644
--- a/objectivec/google/protobuf/Descriptor.pbobjc.m
+++ b/objectivec/google/protobuf/Descriptor.pbobjc.m
@@ -578,6 +578,7 @@
 @dynamic hasExtendee, extendee;
 @dynamic hasDefaultValue, defaultValue;
 @dynamic hasOneofIndex, oneofIndex;
+@dynamic hasJsonName, jsonName;
 @dynamic hasOptions, options;
 
 typedef struct GPBFieldDescriptorProto__storage_ {
@@ -591,6 +592,7 @@
   NSString *typeName;
   NSString *defaultValue;
   GPBFieldOptions *options;
+  NSString *jsonName;
 } GPBFieldDescriptorProto__storage_;
 
 // This method is threadsafe because it is initially called
@@ -679,7 +681,7 @@
       {
         .name = "options",
         .number = GPBFieldDescriptorProto_FieldNumber_Options,
-        .hasIndex = 8,
+        .hasIndex = 9,
         .flags = GPBFieldOptional,
         .dataType = GPBDataTypeMessage,
         .offset = offsetof(GPBFieldDescriptorProto__storage_, options),
@@ -698,6 +700,17 @@
         .dataTypeSpecific.className = NULL,
         .fieldOptions = NULL,
       },
+      {
+        .name = "jsonName",
+        .number = GPBFieldDescriptorProto_FieldNumber_JsonName,
+        .hasIndex = 8,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBFieldDescriptorProto__storage_, jsonName),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
     };
     static GPBMessageEnumDescription enums[] = {
       { .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor },
@@ -1421,7 +1434,11 @@
         .offset = offsetof(GPBFileOptions__storage_, javananoUseDeprecatedPackage),
         .defaultValue.valueBool = NO,
         .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\030\001",
+      #else
         .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
       },
       {
         .name = "uninterpretedOptionArray",
@@ -2428,5 +2445,150 @@
 
 @end
 
+#pragma mark - GPBGeneratedCodeInfo
+
+@implementation GPBGeneratedCodeInfo
+
+@dynamic annotationArray, annotationArray_Count;
+
+typedef struct GPBGeneratedCodeInfo__storage_ {
+  uint32_t _has_storage_[1];
+  NSMutableArray *annotationArray;
+} GPBGeneratedCodeInfo__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "annotationArray",
+        .number = GPBGeneratedCodeInfo_FieldNumber_AnnotationArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated,
+        .dataType = GPBDataTypeMessage,
+        .offset = offsetof(GPBGeneratedCodeInfo__storage_, annotationArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = GPBStringifySymbol(GPBGeneratedCodeInfo_Annotation),
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBGeneratedCodeInfo__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
+#pragma mark - GPBGeneratedCodeInfo_Annotation
+
+@implementation GPBGeneratedCodeInfo_Annotation
+
+@dynamic pathArray, pathArray_Count;
+@dynamic hasSourceFile, sourceFile;
+@dynamic hasBegin, begin;
+@dynamic hasEnd, end;
+
+typedef struct GPBGeneratedCodeInfo_Annotation__storage_ {
+  uint32_t _has_storage_[1];
+  int32_t begin;
+  int32_t end;
+  GPBInt32Array *pathArray;
+  NSString *sourceFile;
+} GPBGeneratedCodeInfo_Annotation__storage_;
+
+// This method is threadsafe because it is initially called
+// in +initialize for each subclass.
++ (GPBDescriptor *)descriptor {
+  static GPBDescriptor *descriptor = nil;
+  if (!descriptor) {
+    static GPBMessageFieldDescription fields[] = {
+      {
+        .name = "pathArray",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray,
+        .hasIndex = GPBNoHasBit,
+        .flags = GPBFieldRepeated | GPBFieldPacked,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, pathArray),
+        .defaultValue.valueMessage = nil,
+        .dataTypeSpecific.className = NULL,
+      #if GPBOBJC_INCLUDE_FIELD_OPTIONS
+        .fieldOptions = "\000\000\000\002\020\001",
+      #else
+        .fieldOptions = NULL,
+      #endif  // GPBOBJC_INCLUDE_FIELD_OPTIONS
+      },
+      {
+        .name = "sourceFile",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile,
+        .hasIndex = 1,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, sourceFile),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "begin",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin,
+        .hasIndex = 2,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, begin),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+      {
+        .name = "end",
+        .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_End,
+        .hasIndex = 3,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeInt32,
+        .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, end),
+        .defaultValue.valueInt32 = 0,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
+    };
+    GPBDescriptor *localDescriptor =
+        [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo_Annotation class]
+                                     rootClass:[GPBDescriptorRoot class]
+                                          file:GPBDescriptorRoot_FileDescriptor()
+                                        fields:fields
+                                    fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription)
+                                        oneofs:NULL
+                                    oneofCount:0
+                                         enums:NULL
+                                     enumCount:0
+                                        ranges:NULL
+                                    rangeCount:0
+                                   storageSize:sizeof(GPBGeneratedCodeInfo_Annotation__storage_)
+                                    wireFormat:NO];
+    NSAssert(descriptor == nil, @"Startup recursed!");
+    descriptor = localDescriptor;
+  }
+  return descriptor;
+}
+
+@end
+
 
 // @@protoc_insertion_point(global_scope)
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index 9ecba19..b592640 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
index ff7f384..bace614 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.h
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
index 0cdbd57..f4bc265 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.h
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
@@ -61,7 +61,7 @@
 //     z: 8
 //
 // The result will not contain specific values for fields x,y and z
-// (there value will be set to the default, and omitted in proto text
+// (their value will be set to the default, and omitted in proto text
 // output):
 //
 //
@@ -155,8 +155,7 @@
 @interface GPBFieldMask : GPBMessage
 
 // The set of field mask paths.
-// |pathsArray| contains |NSString|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *pathsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *pathsArray;
 @property(nonatomic, readonly) NSUInteger pathsArray_Count;
 
 @end
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
index 6bc5714..8480db1 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.h
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
index 7513cf9..293dea4 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.h
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
@@ -13,6 +13,7 @@
 
 @class GPBListValue;
 @class GPBStruct;
+@class GPBValue;
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -60,8 +61,7 @@
 @interface GPBStruct : GPBMessage
 
 // Map of dynamically typed values.
-// |fields| values are |GPBValue|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, GPBValue*> *fields;
 @property(nonatomic, readonly) NSUInteger fields_Count;
 
 @end
@@ -135,8 +135,7 @@
 @interface GPBListValue : GPBMessage
 
 // Repeated field of dynamically typed values.
-// |valuesArray| contains |GPBValue|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBValue*> *valuesArray;
 @property(nonatomic, readonly) NSUInteger valuesArray_Count;
 
 @end
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index a1f68bd..79b24ec 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
index 44ef05c..a7d03a2 100644
--- a/objectivec/google/protobuf/Type.pbobjc.h
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
@@ -12,19 +12,22 @@
 CF_EXTERN_C_BEGIN
 
 @class GPBAny;
+@class GPBEnumValue;
+@class GPBField;
+@class GPBOption;
 @class GPBSourceContext;
 
 NS_ASSUME_NONNULL_BEGIN
 
 #pragma mark - Enum GPBSyntax
 
-// Syntax specifies the syntax in which a service element was defined.
+// The syntax in which a protocol buffer element is defined.
 typedef GPB_ENUM(GPBSyntax) {
   GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  // Syntax "proto2"
+  // Syntax `proto2`.
   GPBSyntax_SyntaxProto2 = 0,
 
-  // Syntax "proto3"
+  // Syntax `proto3`.
   GPBSyntax_SyntaxProto3 = 1,
 };
 
@@ -34,7 +37,7 @@
 
 #pragma mark - Enum GPBField_Kind
 
-// Kind represents a basic field type.
+// Basic field types.
 typedef GPB_ENUM(GPBField_Kind) {
   GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
   // Field type unknown.
@@ -67,7 +70,7 @@
   // Field type string.
   GPBField_Kind_TypeString = 9,
 
-  // Field type group (deprecated proto2 type)
+  // Field type group. Proto2 syntax only, and deprecated.
   GPBField_Kind_TypeGroup = 10,
 
   // Field type message.
@@ -101,17 +104,16 @@
 
 #pragma mark - Enum GPBField_Cardinality
 
-// Cardinality represents whether a field is optional, required, or
-// repeated.
+// Whether a field is optional, required, or repeated.
 typedef GPB_ENUM(GPBField_Cardinality) {
   GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
-  // The field cardinality is unknown. Typically an error condition.
+  // For fields with unknown cardinality.
   GPBField_Cardinality_CardinalityUnknown = 0,
 
   // For optional fields.
   GPBField_Cardinality_CardinalityOptional = 1,
 
-  // For required fields. Not used for proto3.
+  // For required fields. Proto2 syntax only.
   GPBField_Cardinality_CardinalityRequired = 2,
 
   // For repeated fields.
@@ -144,25 +146,22 @@
   GPBType_FieldNumber_Syntax = 6,
 };
 
-// A light-weight descriptor for a proto message type.
+// A protocol buffer message type.
 @interface GPBType : GPBMessage
 
 // The fully qualified message name.
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
 // The list of fields.
-// |fieldsArray| contains |GPBField|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldsArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBField*> *fieldsArray;
 @property(nonatomic, readonly) NSUInteger fieldsArray_Count;
 
-// The list of oneof definitions.
-// |oneofsArray| contains |NSString|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofsArray;
+// The list of types appearing in `oneof` definitions in this type.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *oneofsArray;
 @property(nonatomic, readonly) NSUInteger oneofsArray_Count;
 
-// The proto options.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+// The protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 // The source context.
@@ -189,41 +188,45 @@
   GPBField_FieldNumber_Packed = 8,
   GPBField_FieldNumber_OptionsArray = 9,
   GPBField_FieldNumber_JsonName = 10,
+  GPBField_FieldNumber_DefaultValue = 11,
 };
 
-// Field represents a single field of a message type.
+// A single field of a message type.
 @interface GPBField : GPBMessage
 
-// The field kind.
+// The field type.
 @property(nonatomic, readwrite) GPBField_Kind kind;
 
-// The field cardinality, i.e. optional/required/repeated.
+// The field cardinality.
 @property(nonatomic, readwrite) GPBField_Cardinality cardinality;
 
-// The proto field number.
+// The field number.
 @property(nonatomic, readwrite) int32_t number;
 
 // The field name.
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-// The type URL (without the scheme) when the type is MESSAGE or ENUM,
-// such as `type.googleapis.com/google.protobuf.Empty`.
+// 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;
 
-// Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
+// 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.
 @property(nonatomic, readwrite) BOOL packed;
 
-// The proto options.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+// The protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
-// The JSON name for this field.
+// 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.
+@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue;
+
 @end
 
 int32_t GPBField_Kind_RawValue(GPBField *message);
@@ -249,13 +252,11 @@
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
 // Enum value definitions.
-// |enumvalueArray| contains |GPBEnumValue|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumvalueArray;
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBEnumValue*> *enumvalueArray;
 @property(nonatomic, readonly) NSUInteger enumvalueArray_Count;
 
-// Proto options for the enum type.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+// Protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 // The source context.
@@ -287,9 +288,8 @@
 // Enum value number.
 @property(nonatomic, readwrite) int32_t number;
 
-// Proto options for the enum value.
-// |optionsArray| contains |GPBOption|
-@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray;
+// Protocol buffer options.
+@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<GPBOption*> *optionsArray;
 @property(nonatomic, readonly) NSUInteger optionsArray_Count;
 
 @end
@@ -301,13 +301,14 @@
   GPBOption_FieldNumber_Value = 2,
 };
 
-// Proto option attached to messages/fields/enums etc.
+// A protocol buffer option, which can be attached to a message, field,
+// enumeration, etc.
 @interface GPBOption : GPBMessage
 
-// Proto option name.
+// The option's name. For example, `"java_package"`.
 @property(nonatomic, readwrite, copy, null_resettable) NSString *name;
 
-// Proto option value.
+// The option's value. For example, `"com.google.protobuf"`.
 @property(nonatomic, readwrite) BOOL hasValue;
 @property(nonatomic, readwrite, strong, null_resettable) GPBAny *value;
 
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
index 4485e90..b4e0a5f 100644
--- a/objectivec/google/protobuf/Type.pbobjc.m
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -208,6 +208,7 @@
 @dynamic packed;
 @dynamic optionsArray, optionsArray_Count;
 @dynamic jsonName;
+@dynamic defaultValue;
 
 typedef struct GPBField__storage_ {
   uint32_t _has_storage_[1];
@@ -220,6 +221,7 @@
   NSString *typeURL;
   NSMutableArray *optionsArray;
   NSString *jsonName;
+  NSString *defaultValue;
 } GPBField__storage_;
 
 // This method is threadsafe because it is initially called
@@ -327,6 +329,17 @@
         .dataTypeSpecific.className = NULL,
         .fieldOptions = NULL,
       },
+      {
+        .name = "defaultValue",
+        .number = GPBField_FieldNumber_DefaultValue,
+        .hasIndex = 9,
+        .flags = GPBFieldOptional,
+        .dataType = GPBDataTypeString,
+        .offset = offsetof(GPBField__storage_, defaultValue),
+        .defaultValue.valueString = nil,
+        .dataTypeSpecific.className = NULL,
+        .fieldOptions = NULL,
+      },
     };
     static GPBMessageEnumDescription enums[] = {
       { .enumDescriptorFunc = GPBField_Kind_EnumDescriptor },
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
index a9a260b..580945c 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.h
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -4,7 +4,7 @@
 #import "GPBProtocolBuffers.h"
 
 #if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000
-#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.
+#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
 // @@protoc_insertion_point(imports)
diff --git a/post_process_dist.sh b/post_process_dist.sh
index 6d5b85d..82736bd 100755
--- a/post_process_dist.sh
+++ b/post_process_dist.sh
@@ -27,7 +27,7 @@
 
 set -ex
 
-LANGUAGES="cpp csharp java javanano objectivec python ruby"
+LANGUAGES="cpp csharp java javanano js objectivec python ruby"
 BASENAME=`basename $1 .tar.gz`
 VERSION=${BASENAME:9}
 
diff --git a/protobuf.bzl b/protobuf.bzl
new file mode 100644
index 0000000..f674a6c
--- /dev/null
+++ b/protobuf.bzl
@@ -0,0 +1,295 @@
+# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
+
+def _GetPath(ctx, path):
+  if ctx.label.workspace_root:
+    return ctx.label.workspace_root + '/' + path
+  else:
+    return path
+
+def _GenDir(ctx):
+  if not ctx.attr.includes:
+    return ctx.label.workspace_root
+  if not ctx.attr.includes[0]:
+    return _GetPath(ctx, ctx.label.package)
+  if not ctx.label.package:
+    return _GetPath(ctx, ctx.attr.includes[0])
+  return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
+
+def _CcOuts(srcs):
+  return [s[:-len(".proto")] +  ".pb.h" for s in srcs] + \
+         [s[:-len(".proto")] + ".pb.cc" for s in srcs]
+
+def _PyOuts(srcs):
+  return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
+
+def _RelativeOutputPath(path, include):
+  if include == None:
+    return path
+
+  if not path.startswith(include):
+    fail("Include path %s isn't part of the path %s." % (include, path))
+
+  if include and include[-1] != '/':
+    include = include + '/'
+
+  path = path[len(include):]
+
+  if not path.startswith(PACKAGE_NAME):
+    fail("The package %s is not within the path %s" % (PACKAGE_NAME, path))
+
+  if not PACKAGE_NAME:
+    return path
+
+  return path[len(PACKAGE_NAME)+1:]
+
+def _proto_gen_impl(ctx):
+  """General implementation for generating protos"""
+  srcs = ctx.files.srcs
+  deps = []
+  deps += ctx.files.srcs
+  gen_dir = _GenDir(ctx)
+  if gen_dir:
+    import_flags = ["-I" + gen_dir]
+  else:
+    import_flags = ["-I."]
+
+  for dep in ctx.attr.deps:
+    import_flags += dep.proto.import_flags
+    deps += dep.proto.deps
+
+  args = []
+  if ctx.attr.gen_cc:
+    args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+  if ctx.attr.gen_py:
+    args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
+
+  if args:
+    ctx.action(
+        inputs=srcs + deps,
+        outputs=ctx.outputs.outs,
+        arguments=args + import_flags + [s.path for s in srcs],
+        executable=ctx.executable.protoc,
+    )
+
+  return struct(
+      proto=struct(
+          srcs=srcs,
+          import_flags=import_flags,
+          deps=deps,
+      ),
+  )
+
+_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,
+            executable = True,
+            single_file = True,
+            mandatory = True,
+        ),
+        "gen_cc": attr.bool(),
+        "gen_py": attr.bool(),
+        "outs": attr.output_list(),
+    },
+    output_to_genfiles = True,
+    implementation = _proto_gen_impl,
+)
+
+def cc_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        cc_libs=[],
+        include=None,
+        protoc="//google/protobuf:protoc",
+        internal_bootstrap_hack=False,
+        default_runtime="//google/protobuf:protobuf",
+        **kargs):
+  """Bazel rule to create a C++ protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the cc_proto_library.
+    srcs: the .proto files of the cc_proto_library.
+    deps: a list of dependency labels; must be cc_proto_library.
+    cc_libs: a list of other cc_library targets depended by the generated
+        cc_library.
+    include: a string indicating the include path of the .proto files.
+    protoc: the label of the protocol compiler to generate the sources.
+    internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
+        for bootstraping. When it is set to True, no files will be generated.
+        The rule will simply be a provider for .proto files, so that other
+        cc_proto_library can depend on it.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated cc_library target.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  if internal_bootstrap_hack:
+    # For pre-checked-in generated files, we add the internal_bootstrap_hack
+    # which will skip the codegen action.
+    _proto_gen(
+        name=name + "_genproto",
+        srcs=srcs,
+        deps=[s + "_genproto" for s in deps],
+        includes=includes,
+        protoc=protoc,
+        visibility=["//visibility:public"],
+    )
+    # An empty cc_library to make rule dependency consistent.
+    native.cc_library(
+        name=name,
+        **kargs)
+    return
+
+  outs = _CcOuts(srcs)
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      gen_cc=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if default_runtime and not default_runtime in cc_libs:
+    cc_libs += [default_runtime]
+
+  native.cc_library(
+      name=name,
+      srcs=outs,
+      deps=cc_libs + deps,
+      includes=includes,
+      **kargs)
+
+
+def internal_copied_filegroup(
+        name,
+        srcs,
+        include,
+        **kargs):
+  """Bazel rule to fix sources file to workaround with python path issues.
+
+  Args:
+    name: the name of the internal_copied_filegroup rule, which will be the
+        name of the generated filegroup.
+    srcs: the source files to be copied.
+    include: the expected import root of the source.
+    **kargs: extra arguments that will be passed into the filegroup.
+  """
+  outs = [_RelativeOutputPath(s, include) for s in srcs]
+
+  native.genrule(
+      name=name+"_genrule",
+      srcs=srcs,
+      outs=outs,
+      cmd=" && ".join(["cp $(location %s) $(location %s)" %
+                       (s, _RelativeOutputPath(s, include))
+                       for s in srcs]))
+
+  native.filegroup(
+      name=name,
+      srcs=outs,
+      **kargs)
+
+
+def py_proto_library(
+        name,
+        srcs=[],
+        deps=[],
+        py_libs=[],
+        py_extra_srcs=[],
+        include=None,
+        default_runtime="//google/protobuf:protobuf_python",
+        protoc="//google/protobuf:protoc",
+        **kargs):
+  """Bazel rule to create a Python protobuf library from proto source files
+
+  NOTE: the rule is only an internal workaround to generate protos. The
+  interface may change and the rule may be removed when bazel has introduced
+  the native rule.
+
+  Args:
+    name: the name of the py_proto_library.
+    srcs: the .proto files of the py_proto_library.
+    deps: a list of dependency labels; must be py_proto_library.
+    py_libs: a list of other py_library targets depended by the generated
+        py_library.
+    py_extra_srcs: extra source files that will be added to the output
+        py_library. This attribute is used for internal bootstrapping.
+    include: a string indicating the include path of the .proto files.
+    default_runtime: the implicitly default runtime which will be depended on by
+        the generated py_library target.
+    protoc: the label of the protocol compiler to generate the sources.
+    **kargs: other keyword arguments that are passed to cc_library.
+
+  """
+  outs = _PyOuts(srcs)
+
+  includes = []
+  if include != None:
+    includes = [include]
+
+  _proto_gen(
+      name=name + "_genproto",
+      srcs=srcs,
+      deps=[s + "_genproto" for s in deps],
+      includes=includes,
+      protoc=protoc,
+      gen_py=1,
+      outs=outs,
+      visibility=["//visibility:public"],
+  )
+
+  if include != None:
+    # Copy the output files to the desired location to make the import work.
+    internal_copied_filegroup_name=name + "_internal_copied_filegroup"
+    internal_copied_filegroup(
+        name=internal_copied_filegroup_name,
+        srcs=outs,
+        include=include)
+    outs=[internal_copied_filegroup_name]
+
+  if default_runtime and not default_runtime in py_libs + deps:
+    py_libs += [default_runtime]
+
+  native.py_library(
+      name=name,
+      srcs=outs+py_extra_srcs,
+      deps=py_libs+deps,
+      **kargs)
+
+def internal_protobuf_py_tests(
+    name,
+    modules=[],
+    **kargs):
+  """Bazel rules to create batch tests for protobuf internal.
+
+  Args:
+    name: the name of the rule.
+    modules: a list of modules for tests. The macro will create a py_test for
+        each of the parameter with the source "google/protobuf/%s.py"
+    kargs: extra parameters that will be passed into the py_test.
+
+  """
+  for m in modules:
+    s = _RelativeOutputPath(
+        "python/google/protobuf/internal/%s.py" % m, "python")
+    native.py_test(
+        name="py_%s" % m,
+        srcs=[s],
+        main=s,
+        **kargs)
diff --git a/protoc-artifacts/README.md b/protoc-artifacts/README.md
index 06091cf..4320f65 100644
--- a/protoc-artifacts/README.md
+++ b/protoc-artifacts/README.md
@@ -55,7 +55,7 @@
 configure GPG and Sonatype account.
 
 You need to perform the deployment for every platform that you want to
-suppport. DO NOT close the staging repository until you have done the
+support. DO NOT close the staging repository until you have done the
 deployment for all platforms. Currently the following platforms are supported:
 - Linux (x86_32 and x86_64)
 - Windows (x86_32 and x86_64) with
@@ -134,7 +134,7 @@
 ```
 
 ### Tested build environments
-We have succesfully built artifacts on the following environments:
+We have successfully built artifacts on the following environments:
 - Linux x86_32 and x86_64:
  - Centos 6.6 (within Docker 1.6.1)
  - Ubuntu 14.04.2 64-bit
diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml
index cdf1770..e9728a0 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-1</version>
+  <version>3.0.0-beta-2</version>
   <packaging>pom</packaging>
   <name>Protobuf Compiler</name>
   <description>
diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py
index ed88480..533821c 100755
--- a/python/google/protobuf/__init__.py
+++ b/python/google/protobuf/__init__.py
@@ -30,4 +30,4 @@
 
 # Copyright 2007 Google Inc. All Rights Reserved.
 
-__version__ = '3.0.0a4'
+__version__ = '3.0.0b2'
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 95b703f..5f613c8 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2007 Google Inc. All Rights Reserved.
-
 """Descriptors essentially contain exactly the information found in a .proto
 file, in types that make this information accessible in Python.
 """
@@ -40,7 +38,6 @@
 
 from google.protobuf.internal import api_implementation
 
-
 _USE_C_DESCRIPTORS = False
 if api_implementation.Type() == 'cpp':
   # Used by MakeDescriptor in cpp mode
@@ -221,6 +218,9 @@
     fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
       objects as in |fields|, but indexed by "name" attribute in each
       FieldDescriptor.
+    fields_by_camelcase_name: (dict str -> FieldDescriptor) Same
+      FieldDescriptor objects as in |fields|, but indexed by
+      "camelcase_name" attribute in each FieldDescriptor.
 
     nested_types: (list of Descriptors) Descriptor references
       for all protocol message types nested within this one.
@@ -292,6 +292,7 @@
       field.containing_type = self
     self.fields_by_number = dict((f.number, f) for f in fields)
     self.fields_by_name = dict((f.name, f) for f in fields)
+    self._fields_by_camelcase_name = None
 
     self.nested_types = nested_types
     for nested_type in nested_types:
@@ -317,6 +318,13 @@
       oneof.containing_type = self
     self.syntax = syntax or "proto2"
 
+  @property
+  def fields_by_camelcase_name(self):
+    if self._fields_by_camelcase_name is None:
+      self._fields_by_camelcase_name = dict(
+          (f.camelcase_name, f) for f in self.fields)
+    return self._fields_by_camelcase_name
+
   def EnumValueName(self, enum, value):
     """Returns the string name of an enum value.
 
@@ -365,6 +373,7 @@
     name: (str) Name of this field, exactly as it appears in .proto.
     full_name: (str) Name of this field, including containing scope.  This is
       particularly relevant for extensions.
+    camelcase_name: (str) Camelcase name of this field.
     index: (int) Dense, 0-indexed index giving the order that this
       field textually appears within its message in the .proto file.
     number: (int) Tag number declared for this field in the .proto file.
@@ -509,6 +518,7 @@
     super(FieldDescriptor, self).__init__(options, 'FieldOptions')
     self.name = name
     self.full_name = full_name
+    self._camelcase_name = None
     self.index = index
     self.number = number
     self.type = type
@@ -530,6 +540,12 @@
     else:
       self._cdescriptor = None
 
+  @property
+  def camelcase_name(self):
+    if self._camelcase_name is None:
+      self._camelcase_name = _ToCamelCase(self.name)
+    return self._camelcase_name
+
   @staticmethod
   def ProtoTypeToCppProtoType(proto_type):
     """Converts from a Python proto type to a C++ Proto Type.
@@ -770,25 +786,33 @@
   message_types_by_name: Dict of message names of their descriptors.
   enum_types_by_name: Dict of enum names and their descriptors.
   extensions_by_name: Dict of extension names and their descriptors.
+  pool: the DescriptorPool this descriptor belongs to.  When not passed to the
+    constructor, the global default pool is used.
   """
 
   if _USE_C_DESCRIPTORS:
     _C_DESCRIPTOR_CLASS = _message.FileDescriptor
 
     def __new__(cls, name, package, options=None, serialized_pb=None,
-                dependencies=None, syntax=None):
+                dependencies=None, syntax=None, pool=None):
       # FileDescriptor() is called from various places, not only from generated
       # files, to register dynamic proto files and messages.
       if serialized_pb:
+        # TODO(amauryfa): use the pool passed as argument. This will work only
+        # for C++-implemented DescriptorPools.
         return _message.default_pool.AddSerializedFile(serialized_pb)
       else:
         return super(FileDescriptor, cls).__new__(cls)
 
   def __init__(self, name, package, options=None, serialized_pb=None,
-               dependencies=None, syntax=None):
+               dependencies=None, syntax=None, pool=None):
     """Constructor."""
     super(FileDescriptor, self).__init__(options, 'FileOptions')
 
+    if pool is None:
+      from google.protobuf import descriptor_pool
+      pool = descriptor_pool.Default()
+    self.pool = pool
     self.message_types_by_name = {}
     self.name = name
     self.package = package
@@ -822,6 +846,27 @@
   return message
 
 
+def _ToCamelCase(name):
+  """Converts name to camel-case and returns it."""
+  capitalize_next = False
+  result = []
+
+  for c in name:
+    if c == '_':
+      if result:
+        capitalize_next = True
+    elif capitalize_next:
+      result.append(c.upper())
+      capitalize_next = False
+    else:
+      result += c
+
+  # Lower-case the first letter.
+  if result and result[0].isupper():
+    result[0] = result[0].lower()
+  return ''.join(result)
+
+
 def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
                    syntax=None):
   """Make a protobuf Descriptor given a DescriptorProto protobuf.
diff --git a/python/google/protobuf/descriptor_database.py b/python/google/protobuf/descriptor_database.py
index b10021e..1333f99 100644
--- a/python/google/protobuf/descriptor_database.py
+++ b/python/google/protobuf/descriptor_database.py
@@ -65,6 +65,7 @@
       raise DescriptorDatabaseConflictingDefinitionError(
           '%s already added, but with different descriptor.' % proto_name)
 
+    # Add the top-level Message, Enum and Extension descriptors to the index.
     package = file_desc_proto.package
     for message in file_desc_proto.message_type:
       self._file_desc_protos_by_symbol.update(
@@ -72,6 +73,9 @@
     for enum in file_desc_proto.enum_type:
       self._file_desc_protos_by_symbol[
           '.'.join((package, enum.name))] = file_desc_proto
+    for extension in file_desc_proto.extension:
+      self._file_desc_protos_by_symbol[
+          '.'.join((package, extension.name))] = file_desc_proto
 
   def FindFileByName(self, name):
     """Finds the file descriptor proto by file name.
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 6a1b4b5..3e80795 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -83,6 +83,12 @@
 class DescriptorPool(object):
   """A collection of protobufs dynamically constructed by descriptor protos."""
 
+  if _USE_C_DESCRIPTORS:
+
+    def __new__(cls, descriptor_db=None):
+      # pylint: disable=protected-access
+      return descriptor._message.DescriptorPool(descriptor_db)
+
   def __init__(self, descriptor_db=None):
     """Initializes a Pool of proto buffs.
 
@@ -264,6 +270,39 @@
       self.FindFileContainingSymbol(full_name)
     return self._enum_descriptors[full_name]
 
+  def FindFieldByName(self, full_name):
+    """Loads the named field descriptor from the pool.
+
+    Args:
+      full_name: The full name of the field descriptor to load.
+
+    Returns:
+      The field descriptor for the named field.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    message_name, _, field_name = full_name.rpartition('.')
+    message_descriptor = self.FindMessageTypeByName(message_name)
+    return message_descriptor.fields_by_name[field_name]
+
+  def FindExtensionByName(self, full_name):
+    """Loads the named extension descriptor from the pool.
+
+    Args:
+      full_name: The full name of the extension descriptor to load.
+
+    Returns:
+      A FieldDescriptor, describing the named extension.
+    """
+    full_name = _NormalizeFullyQualifiedName(full_name)
+    message_name, _, extension_name = full_name.rpartition('.')
+    try:
+      # Most extensions are nested inside a message.
+      scope = self.FindMessageTypeByName(message_name)
+    except KeyError:
+      # Some extensions are defined at file scope.
+      scope = self.FindFileContainingSymbol(full_name)
+    return scope.extensions_by_name[extension_name]
+
   def _ConvertFileProtoToFileDescriptor(self, file_proto):
     """Creates a FileDescriptor from a proto or returns a cached copy.
 
@@ -282,6 +321,7 @@
       direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
 
       file_descriptor = descriptor.FileDescriptor(
+          pool=self,
           name=file_proto.name,
           package=file_proto.package,
           syntax=file_proto.syntax,
@@ -598,10 +638,24 @@
         field_desc.default_value = text_encoding.CUnescape(
             field_proto.default_value)
       else:
+        # All other types are of the "int" type.
         field_desc.default_value = int(field_proto.default_value)
     else:
       field_desc.has_default_value = False
-      field_desc.default_value = None
+      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
+          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
+        field_desc.default_value = 0.0
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
+        field_desc.default_value = u''
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
+        field_desc.default_value = False
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
+        field_desc.default_value = field_desc.enum_type.values[0].number
+      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        field_desc.default_value = b''
+      else:
+        # All other types are of the "int" type.
+        field_desc.default_value = 0
 
     field_desc.type = field_proto.type
 
@@ -680,3 +734,16 @@
 
 def _PrefixWithDot(name):
   return name if name.startswith('.') else '.%s' % name
+
+
+if _USE_C_DESCRIPTORS:
+  # TODO(amauryfa): This pool could be constructed from Python code, when we
+  # support a flag like 'use_cpp_generated_pool=True'.
+  # pylint: disable=protected-access
+  _DEFAULT = descriptor._message.default_pool
+else:
+  _DEFAULT = DescriptorPool()
+
+
+def Default():
+  return _DEFAULT
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/python/google/protobuf/internal/any_test.proto
similarity index 82%
copy from src/google/protobuf/compiler/cpp/test_large_enum_value.proto
copy to python/google/protobuf/internal/any_test.proto
index cb6ca1b..cd641ca 100644
--- a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
+++ b/python/google/protobuf/internal/any_test.proto
@@ -28,16 +28,15 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Test that proto2 compiler can generate valid code when the enum value
-// is INT_MAX. Note that this is a compile-only test and this proto is not
-// referenced in any C++ code.
-syntax = "proto2";
+// Author: jieluo@google.com (Jie Luo)
 
-package protobuf_unittest;
+syntax = "proto3";
 
-message TestLargeEnumValue {
-  enum EnumWithLargeValue {
-    VALUE_1 = 1;
-    VALUE_MAX = 0x7fffffff;
-  }
+package google.protobuf.internal;
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  google.protobuf.Any value = 1;
+  int32 int_value = 2;
 }
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index 9c8275e..97cdd84 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -464,6 +464,9 @@
       return val
 
   def __contains__(self, item):
+    # We check the key's type to match the strong-typing flavor of the API.
+    # Also this makes it easier to match the behavior of the C++ implementation.
+    self._key_checker.CheckValue(item)
     return item in self._values
 
   # We need to override this explicitly, because our defaultdict-like behavior
@@ -491,10 +494,20 @@
   def __iter__(self):
     return iter(self._values)
 
+  def __repr__(self):
+    return repr(self._values)
+
   def MergeFrom(self, other):
     self._values.update(other._values)
     self._message_listener.Modified()
 
+  def InvalidateIterators(self):
+    # It appears that the only way to reliably invalidate iterators to
+    # self._values is to ensure that its size changes.
+    original = self._values
+    self._values = original.copy()
+    original[None] = None
+
   # This is defined in the abstract base, but we can do it much more cheaply.
   def clear(self):
     self._values.clear()
@@ -576,12 +589,22 @@
   def __iter__(self):
     return iter(self._values)
 
+  def __repr__(self):
+    return repr(self._values)
+
   def MergeFrom(self, other):
     for key in other:
       self[key].MergeFrom(other[key])
     # self._message_listener.Modified() not required here, because
     # mutations to submessages already propagate.
 
+  def InvalidateIterators(self):
+    # It appears that the only way to reliably invalidate iterators to
+    # self._values is to ensure that its size changes.
+    original = self._values
+    self._values = original.copy()
+    original[None] = None
+
   # This is defined in the abstract base, but we can do it much more cheaply.
   def clear(self):
     self._values.clear()
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index 4fd7a86..31869e4 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2009 Google Inc. All Rights Reserved.
-
 """Code for decoding protocol buffer primitives.
 
 This code is very similar to encoder.py -- read the docs for that module first.
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 2a482fb..f1d6bf9 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -35,11 +35,13 @@
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 import os
+
 try:
   import unittest2 as unittest
 except ImportError:
   import unittest
-
+from google.protobuf import unittest_import_pb2
+from google.protobuf import unittest_import_public_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import api_implementation
@@ -47,16 +49,21 @@
 from google.protobuf.internal import descriptor_pool_test2_pb2
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import test_util
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
+from google.protobuf import message_factory
 from google.protobuf import symbol_database
 
 
 class DescriptorPoolTest(unittest.TestCase):
 
+  def CreatePool(self):
+    return descriptor_pool.DescriptorPool()
+
   def setUp(self):
-    self.pool = descriptor_pool.DescriptorPool()
+    self.pool = self.CreatePool()
     self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
         factory_test1_pb2.DESCRIPTOR.serialized_pb)
     self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString(
@@ -88,7 +95,7 @@
         'google.protobuf.python.internal.Factory1Message')
     self.assertIsInstance(file_desc1, descriptor.FileDescriptor)
     self.assertEqual('google/protobuf/internal/factory_test1.proto',
-                      file_desc1.name)
+                     file_desc1.name)
     self.assertEqual('google.protobuf.python.internal', file_desc1.package)
     self.assertIn('Factory1Message', file_desc1.message_types_by_name)
 
@@ -96,7 +103,7 @@
         'google.protobuf.python.internal.Factory2Message')
     self.assertIsInstance(file_desc2, descriptor.FileDescriptor)
     self.assertEqual('google/protobuf/internal/factory_test2.proto',
-                      file_desc2.name)
+                     file_desc2.name)
     self.assertEqual('google.protobuf.python.internal', file_desc2.package)
     self.assertIn('Factory2Message', file_desc2.message_types_by_name)
 
@@ -110,7 +117,7 @@
     self.assertIsInstance(msg1, descriptor.Descriptor)
     self.assertEqual('Factory1Message', msg1.name)
     self.assertEqual('google.protobuf.python.internal.Factory1Message',
-                      msg1.full_name)
+                     msg1.full_name)
     self.assertEqual(None, msg1.containing_type)
 
     nested_msg1 = msg1.nested_types[0]
@@ -131,7 +138,7 @@
     self.assertIsInstance(msg2, descriptor.Descriptor)
     self.assertEqual('Factory2Message', msg2.name)
     self.assertEqual('google.protobuf.python.internal.Factory2Message',
-                      msg2.full_name)
+                     msg2.full_name)
     self.assertIsNone(msg2.containing_type)
 
     nested_msg2 = msg2.nested_types[0]
@@ -222,6 +229,37 @@
     with self.assertRaises(KeyError):
       self.pool.FindEnumTypeByName('Does not exist')
 
+  def testFindFieldByName(self):
+    field = self.pool.FindFieldByName(
+        'google.protobuf.python.internal.Factory1Message.list_value')
+    self.assertEqual(field.name, 'list_value')
+    self.assertEqual(field.label, field.LABEL_REPEATED)
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('Does not exist')
+
+  def testFindExtensionByName(self):
+    # An extension defined in a message.
+    extension = self.pool.FindExtensionByName(
+        'google.protobuf.python.internal.Factory2Message.one_more_field')
+    self.assertEqual(extension.name, 'one_more_field')
+    # An extension defined at file scope.
+    extension = self.pool.FindExtensionByName(
+        'google.protobuf.python.internal.another_field')
+    self.assertEqual(extension.name, 'another_field')
+    self.assertEqual(extension.number, 1002)
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('Does not exist')
+
+  def testExtensionsAreNotFields(self):
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName('google.protobuf.python.internal.another_field')
+    with self.assertRaises(KeyError):
+      self.pool.FindFieldByName(
+          'google.protobuf.python.internal.Factory2Message.one_more_field')
+    with self.assertRaises(KeyError):
+      self.pool.FindExtensionByName(
+          'google.protobuf.python.internal.Factory1Message.list_value')
+
   def testUserDefinedDB(self):
     db = descriptor_database.DescriptorDatabase()
     self.pool = descriptor_pool.DescriptorPool(db)
@@ -230,8 +268,7 @@
     self.testFindMessageTypeByName()
 
   def testAddSerializedFile(self):
-    db = descriptor_database.DescriptorDatabase()
-    self.pool = descriptor_pool.DescriptorPool(db)
+    self.pool = descriptor_pool.DescriptorPool()
     self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString())
     self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString())
     self.testFindMessageTypeByName()
@@ -273,6 +310,56 @@
         'google/protobuf/internal/descriptor_pool_test1.proto')
     _CheckDefaultValue(file_descriptor)
 
+  def testDefaultValueForCustomMessages(self):
+    """Check the value returned by non-existent fields."""
+    def _CheckValueAndType(value, expected_value, expected_type):
+      self.assertEqual(value, expected_value)
+      self.assertIsInstance(value, expected_type)
+
+    def _CheckDefaultValues(msg):
+      try:
+        int64 = long
+      except NameError:  # Python3
+        int64 = int
+      try:
+        unicode_type = unicode
+      except NameError:  # Python3
+        unicode_type = str
+      _CheckValueAndType(msg.optional_int32, 0, int)
+      _CheckValueAndType(msg.optional_uint64, 0, (int64, int))
+      _CheckValueAndType(msg.optional_float, 0, (float, int))
+      _CheckValueAndType(msg.optional_double, 0, (float, int))
+      _CheckValueAndType(msg.optional_bool, False, bool)
+      _CheckValueAndType(msg.optional_string, u'', unicode_type)
+      _CheckValueAndType(msg.optional_bytes, b'', bytes)
+      _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int)
+    # First for the generated message
+    _CheckDefaultValues(unittest_pb2.TestAllTypes())
+    # Then for a message built with from the DescriptorPool.
+    pool = descriptor_pool.DescriptorPool()
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_public_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_import_pb2.DESCRIPTOR.serialized_pb))
+    pool.Add(descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb))
+    message_class = message_factory.MessageFactory(pool).GetPrototype(
+        pool.FindMessageTypeByName(
+            unittest_pb2.TestAllTypes.DESCRIPTOR.full_name))
+    _CheckDefaultValues(message_class())
+
+
+@unittest.skipIf(api_implementation.Type() != 'cpp',
+                            'explicit tests of the C++ implementation')
+class CppDescriptorPoolTest(DescriptorPoolTest):
+  # TODO(amauryfa): remove when descriptor_pool.DescriptorPool() creates true
+  # C++ descriptor pool object for C++ implementation.
+
+  def CreatePool(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    return _message.DescriptorPool()
+
 
 class ProtoFile(object):
 
@@ -467,6 +554,8 @@
         pool.FindFileContainingSymbol(
             prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name)
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                    'With the cpp implementation, Add() must be called first')
   def testMessage(self):
     self._TestMessage('')
     self._TestMessage('.')
@@ -501,10 +590,14 @@
         pool.FindFileContainingSymbol(
             prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name)
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                    'With the cpp implementation, Add() must be called first')
   def testEnum(self):
     self._TestEnum('')
     self._TestEnum('.')
 
+  @unittest.skipIf(api_implementation.Type() == 'cpp',
+                    'With the cpp implementation, Add() must be called first')
   def testFile(self):
     pool = descriptor_pool.DescriptorPool()
     pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR)
@@ -519,6 +612,76 @@
       pool.FindFileContainingSymbol(
           'protobuf_unittest.TestAllTypes')
 
+  def _GetDescriptorPoolClass(self):
+    # Test with both implementations of descriptor pools.
+    if api_implementation.Type() == 'cpp':
+      # pylint: disable=g-import-not-at-top
+      from google.protobuf.pyext import _message
+      return _message.DescriptorPool
+    else:
+      return descriptor_pool.DescriptorPool
+
+  def testEmptyDescriptorPool(self):
+    # Check that an empty DescriptorPool() contains no message.
+    pool = self._GetDescriptorPoolClass()()
+    proto_file_name = descriptor_pb2.DESCRIPTOR.name
+    self.assertRaises(KeyError, pool.FindFileByName, proto_file_name)
+    # Add the above file to the pool
+    file_descriptor = descriptor_pb2.FileDescriptorProto()
+    descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor)
+    pool.Add(file_descriptor)
+    # Now it exists.
+    self.assertTrue(pool.FindFileByName(proto_file_name))
+
+  def testCustomDescriptorPool(self):
+    # Create a new pool, and add a file descriptor.
+    pool = self._GetDescriptorPoolClass()()
+    file_desc = descriptor_pb2.FileDescriptorProto(
+        name='some/file.proto', package='package')
+    file_desc.message_type.add(name='Message')
+    pool.Add(file_desc)
+    self.assertEqual(pool.FindFileByName('some/file.proto').name,
+                     'some/file.proto')
+    self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
+                     'Message')
+
+
+@unittest.skipIf(
+    api_implementation.Type() != 'cpp',
+    'default_pool is only supported by the C++ implementation')
+class DefaultPoolTest(unittest.TestCase):
+
+  def testFindMethods(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    self.assertIs(
+        pool.FindFileByName('google/protobuf/unittest.proto'),
+        unittest_pb2.DESCRIPTOR)
+    self.assertIs(
+        pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertIs(
+        pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertIs(
+        pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
+        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
+    self.assertIs(
+        pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
+        unittest_pb2.ForeignEnum.DESCRIPTOR)
+    self.assertIs(
+        pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
+
+  def testAddFileDescriptor(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
+    pool.Add(file_desc)
+    pool.AddSerializedFile(file_desc.SerializeToString())
+
 
 TEST1_FILE = ProtoFile(
     'google/protobuf/internal/descriptor_pool_test1.proto',
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index 34843a6..fee09a5 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
 #
 # Protocol Buffers - Google's data interchange format
 # Copyright 2008 Google Inc.  All rights reserved.
@@ -36,20 +36,21 @@
 
 import sys
 
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
 from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import api_implementation
+from google.protobuf.internal import test_util
 from google.protobuf import descriptor
+from google.protobuf import descriptor_pool
 from google.protobuf import symbol_database
 from google.protobuf import text_format
 
-try:
-  import unittest2 as unittest
-except ImportError:
-  import unittest
-
 
 TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """
 name: 'TestEmptyMessage'
@@ -75,9 +76,9 @@
     enum_proto.value.add(name='FOREIGN_BAR', number=5)
     enum_proto.value.add(name='FOREIGN_BAZ', number=6)
 
-    descriptor_pool = symbol_database.Default().pool
-    descriptor_pool.Add(file_proto)
-    self.my_file = descriptor_pool.FindFileByName(file_proto.name)
+    self.pool = self.GetDescriptorPool()
+    self.pool.Add(file_proto)
+    self.my_file = self.pool.FindFileByName(file_proto.name)
     self.my_message = self.my_file.message_types_by_name[message_proto.name]
     self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
 
@@ -97,6 +98,9 @@
             self.my_method
         ])
 
+  def GetDescriptorPool(self):
+    return symbol_database.Default().pool
+
   def testEnumValueName(self):
     self.assertEqual(self.my_message.EnumValueName('ForeignEnum', 4),
                      'FOREIGN_FOO')
@@ -393,6 +397,9 @@
   def testFileDescriptor(self):
     self.assertEqual(self.my_file.name, 'some/filename/some.proto')
     self.assertEqual(self.my_file.package, 'protobuf_unittest')
+    self.assertEqual(self.my_file.pool, self.pool)
+    # Generated modules also belong to the default pool.
+    self.assertEqual(unittest_pb2.DESCRIPTOR.pool, descriptor_pool.Default())
 
   @unittest.skipIf(
       api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
@@ -407,6 +414,13 @@
       message_descriptor.fields.append(None)
 
 
+class NewDescriptorTest(DescriptorTest):
+  """Redo the same tests as above, but with a separate DescriptorPool."""
+
+  def GetDescriptorPool(self):
+    return descriptor_pool.DescriptorPool()
+
+
 class GeneratedDescriptorTest(unittest.TestCase):
   """Tests for the properties of descriptors in generated code."""
 
@@ -425,10 +439,12 @@
     self.CheckDescriptorSequence(message_descriptor.fields)
     self.CheckDescriptorMapping(message_descriptor.fields_by_name)
     self.CheckDescriptorMapping(message_descriptor.fields_by_number)
+    self.CheckDescriptorMapping(message_descriptor.fields_by_camelcase_name)
 
   def CheckFieldDescriptor(self, field_descriptor):
     # Basic properties
     self.assertEqual(field_descriptor.name, 'optional_int32')
+    self.assertEqual(field_descriptor.camelcase_name, 'optionalInt32')
     self.assertEqual(field_descriptor.full_name,
                      'protobuf_unittest.TestAllTypes.optional_int32')
     self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes')
@@ -437,6 +453,10 @@
     self.assertEqual(
         field_descriptor.containing_type.fields_by_name['optional_int32'],
         field_descriptor)
+    self.assertEqual(
+        field_descriptor.containing_type.fields_by_camelcase_name[
+            'optionalInt32'],
+        field_descriptor)
     self.assertIn(field_descriptor, [field_descriptor])
     self.assertIn(field_descriptor, {field_descriptor: None})
 
@@ -481,6 +501,9 @@
     self.CheckMessageDescriptor(message_descriptor)
     field_descriptor = message_descriptor.fields_by_name['optional_int32']
     self.CheckFieldDescriptor(field_descriptor)
+    field_descriptor = message_descriptor.fields_by_camelcase_name[
+        'optionalInt32']
+    self.CheckFieldDescriptor(field_descriptor)
 
   def testCppDescriptorContainer(self):
     # Check that the collection is still valid even if the parent disappeared.
@@ -779,5 +802,20 @@
     self.assertEqual(101,
                       options.Extensions[unittest_custom_options_pb2.msgopt].i)
 
+  def testCamelcaseName(self):
+    descriptor_proto = descriptor_pb2.DescriptorProto()
+    descriptor_proto.name = 'Bar'
+    names = ['foo_foo', 'FooBar', 'fooBaz', 'fooFoo', 'foobar']
+    camelcase_names = ['fooFoo', 'fooBar', 'fooBaz', 'fooFoo', 'foobar']
+    for index in range(len(names)):
+      field = descriptor_proto.field.add()
+      field.number = index + 1
+      field.name = names[index]
+    result = descriptor.MakeDescriptor(descriptor_proto)
+    for index in range(len(camelcase_names)):
+      self.assertEqual(result.fields[index].camelcase_name,
+                       camelcase_names[index])
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index d72cd29..48ef2df 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2009 Google Inc. All Rights Reserved.
-
 """Code for encoding protocol message primitives.
 
 Contains the logic for encoding every logical protocol field type
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
new file mode 100644
index 0000000..49e96a4
--- /dev/null
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -0,0 +1,768 @@
+#! /usr/bin/env python
+#
+# 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.
+
+"""Test for google.protobuf.json_format."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import json
+import math
+import sys
+
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
+from google.protobuf import any_pb2
+from google.protobuf import duration_pb2
+from google.protobuf import field_mask_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import timestamp_pb2
+from google.protobuf import wrappers_pb2
+from google.protobuf.internal import well_known_types
+from google.protobuf import json_format
+from google.protobuf.util import json_format_proto3_pb2
+
+
+class JsonFormatBase(unittest.TestCase):
+
+  def FillAllFields(self, message):
+    message.int32_value = 20
+    message.int64_value = -20
+    message.uint32_value = 3120987654
+    message.uint64_value = 12345678900
+    message.float_value = float('-inf')
+    message.double_value = 3.1415
+    message.bool_value = True
+    message.string_value = 'foo'
+    message.bytes_value = b'bar'
+    message.message_value.value = 10
+    message.enum_value = json_format_proto3_pb2.BAR
+    # Repeated
+    message.repeated_int32_value.append(0x7FFFFFFF)
+    message.repeated_int32_value.append(-2147483648)
+    message.repeated_int64_value.append(9007199254740992)
+    message.repeated_int64_value.append(-9007199254740992)
+    message.repeated_uint32_value.append(0xFFFFFFF)
+    message.repeated_uint32_value.append(0x7FFFFFF)
+    message.repeated_uint64_value.append(9007199254740992)
+    message.repeated_uint64_value.append(9007199254740991)
+    message.repeated_float_value.append(0)
+
+    message.repeated_double_value.append(1E-15)
+    message.repeated_double_value.append(float('inf'))
+    message.repeated_bool_value.append(True)
+    message.repeated_bool_value.append(False)
+    message.repeated_string_value.append('Few symbols!#$,;')
+    message.repeated_string_value.append('bar')
+    message.repeated_bytes_value.append(b'foo')
+    message.repeated_bytes_value.append(b'bar')
+    message.repeated_message_value.add().value = 10
+    message.repeated_message_value.add().value = 11
+    message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
+    message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
+    self.message = message
+
+  def CheckParseBack(self, message, parsed_message):
+    json_format.Parse(json_format.MessageToJson(message),
+                      parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def CheckError(self, text, error_message):
+    message = json_format_proto3_pb2.TestMessage()
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        error_message,
+        json_format.Parse, text, message)
+
+
+class JsonFormatTest(JsonFormatBase):
+
+  def testEmptyMessageToJson(self):
+    message = json_format_proto3_pb2.TestMessage()
+    self.assertEqual(json_format.MessageToJson(message),
+                     '{}')
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testPartialMessageToJson(self):
+    message = json_format_proto3_pb2.TestMessage(
+        string_value='test',
+        repeated_int32_value=[89, 4])
+    self.assertEqual(json.loads(json_format.MessageToJson(message)),
+                     json.loads('{"stringValue": "test", '
+                                '"repeatedInt32Value": [89, 4]}'))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testAllFieldsToJson(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = ('{"int32Value": 20, '
+            '"int64Value": "-20", '
+            '"uint32Value": 3120987654,'
+            '"uint64Value": "12345678900",'
+            '"floatValue": "-Infinity",'
+            '"doubleValue": 3.1415,'
+            '"boolValue": true,'
+            '"stringValue": "foo",'
+            '"bytesValue": "YmFy",'
+            '"messageValue": {"value": 10},'
+            '"enumValue": "BAR",'
+            '"repeatedInt32Value": [2147483647, -2147483648],'
+            '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
+            '"repeatedUint32Value": [268435455, 134217727],'
+            '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
+            '"repeatedFloatValue": [0],'
+            '"repeatedDoubleValue": [1e-15, "Infinity"],'
+            '"repeatedBoolValue": [true, false],'
+            '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
+            '"repeatedBytesValue": ["Zm9v", "YmFy"],'
+            '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
+            '"repeatedEnumValue": ["FOO", "BAR"]'
+            '}')
+    self.FillAllFields(message)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message)),
+        json.loads(text))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message)
+    self.assertEqual(message, parsed_message)
+
+  def testJsonEscapeString(self):
+    message = json_format_proto3_pb2.TestMessage()
+    if sys.version_info[0] < 3:
+      message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
+    else:
+      message.string_value = '&\n<\"\r>\b\t\f\\\001/'
+      message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
+    self.assertEqual(
+        json_format.MessageToJson(message),
+        '{\n  "stringValue": '
+        '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+    text = u'{"int32Value": "\u0031"}'
+    json_format.Parse(text, message)
+    self.assertEqual(message.int32_value, 1)
+
+  def testAlwaysSeriliaze(self):
+    message = json_format_proto3_pb2.TestMessage(
+        string_value='foo')
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"repeatedStringValue": [],'
+                   '"stringValue": "foo",'
+                   '"repeatedBoolValue": [],'
+                   '"repeatedUint32Value": [],'
+                   '"repeatedInt32Value": [],'
+                   '"enumValue": "FOO",'
+                   '"int32Value": 0,'
+                   '"floatValue": 0,'
+                   '"int64Value": "0",'
+                   '"uint32Value": 0,'
+                   '"repeatedBytesValue": [],'
+                   '"repeatedUint64Value": [],'
+                   '"repeatedDoubleValue": [],'
+                   '"bytesValue": "",'
+                   '"boolValue": false,'
+                   '"repeatedEnumValue": [],'
+                   '"uint64Value": "0",'
+                   '"doubleValue": 0,'
+                   '"repeatedFloatValue": [],'
+                   '"repeatedInt64Value": [],'
+                   '"repeatedMessageValue": []}'))
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.CheckParseBack(message, parsed_message)
+
+  def testMapFields(self):
+    message = json_format_proto3_pb2.TestMap()
+    message.bool_map[True] = 1
+    message.bool_map[False] = 2
+    message.int32_map[1] = 2
+    message.int32_map[2] = 3
+    message.int64_map[1] = 2
+    message.int64_map[2] = 3
+    message.uint32_map[1] = 2
+    message.uint32_map[2] = 3
+    message.uint64_map[1] = 2
+    message.uint64_map[2] = 3
+    message.string_map['1'] = 2
+    message.string_map['null'] = 3
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"boolMap": {"false": 2, "true": 1},'
+                   '"int32Map": {"1": 2, "2": 3},'
+                   '"int64Map": {"1": 2, "2": 3},'
+                   '"uint32Map": {"1": 2, "2": 3},'
+                   '"uint64Map": {"1": 2, "2": 3},'
+                   '"stringMap": {"1": 2, "null": 3}'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestMap()
+    self.CheckParseBack(message, parsed_message)
+
+  def testOneofFields(self):
+    message = json_format_proto3_pb2.TestOneof()
+    # Always print does not affect oneof fields.
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{}')
+    message.oneof_int32_value = 0
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "oneofInt32Value": 0\n'
+        '}')
+    parsed_message = json_format_proto3_pb2.TestOneof()
+    self.CheckParseBack(message, parsed_message)
+
+  def testTimestampMessage(self):
+    message = json_format_proto3_pb2.TestTimestamp()
+    message.value.seconds = 0
+    message.value.nanos = 0
+    message.repeated_value.add().seconds = 20
+    message.repeated_value[0].nanos = 1
+    message.repeated_value.add().seconds = 0
+    message.repeated_value[1].nanos = 10000
+    message.repeated_value.add().seconds = 100000000
+    message.repeated_value[2].nanos = 0
+    # Maximum time
+    message.repeated_value.add().seconds = 253402300799
+    message.repeated_value[3].nanos = 999999999
+    # Minimum time
+    message.repeated_value.add().seconds = -62135596800
+    message.repeated_value[4].nanos = 0
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"value": "1970-01-01T00:00:00Z",'
+                   '"repeatedValue": ['
+                   '  "1970-01-01T00:00:20.000000001Z",'
+                   '  "1970-01-01T00:00:00.000010Z",'
+                   '  "1973-03-03T09:46:40Z",'
+                   '  "9999-12-31T23:59:59.999999999Z",'
+                   '  "0001-01-01T00:00:00Z"'
+                   ']'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestTimestamp()
+    self.CheckParseBack(message, parsed_message)
+    text = (r'{"value": "1970-01-01T00:00:00.01+08:00",'
+            r'"repeatedValue":['
+            r'  "1970-01-01T00:00:00.01+08:30",'
+            r'  "1970-01-01T00:00:00.01-01:23"]}')
+    json_format.Parse(text, parsed_message)
+    self.assertEqual(parsed_message.value.seconds, -8 * 3600)
+    self.assertEqual(parsed_message.value.nanos, 10000000)
+    self.assertEqual(parsed_message.repeated_value[0].seconds, -8.5 * 3600)
+    self.assertEqual(parsed_message.repeated_value[1].seconds, 3600 + 23 * 60)
+
+  def testDurationMessage(self):
+    message = json_format_proto3_pb2.TestDuration()
+    message.value.seconds = 1
+    message.repeated_value.add().seconds = 0
+    message.repeated_value[0].nanos = 10
+    message.repeated_value.add().seconds = -1
+    message.repeated_value[1].nanos = -1000
+    message.repeated_value.add().seconds = 10
+    message.repeated_value[2].nanos = 11000000
+    message.repeated_value.add().seconds = -315576000000
+    message.repeated_value.add().seconds = 315576000000
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{'
+                   '"value": "1s",'
+                   '"repeatedValue": ['
+                   '  "0.000000010s",'
+                   '  "-1.000001s",'
+                   '  "10.011s",'
+                   '  "-315576000000s",'
+                   '  "315576000000s"'
+                   ']'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestDuration()
+    self.CheckParseBack(message, parsed_message)
+
+  def testFieldMaskMessage(self):
+    message = json_format_proto3_pb2.TestFieldMask()
+    message.value.paths.append('foo.bar')
+    message.value.paths.append('bar')
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "value": "foo.bar,bar"\n'
+        '}')
+    parsed_message = json_format_proto3_pb2.TestFieldMask()
+    self.CheckParseBack(message, parsed_message)
+
+  def testWrapperMessage(self):
+    message = json_format_proto3_pb2.TestWrapper()
+    message.bool_value.value = False
+    message.int32_value.value = 0
+    message.string_value.value = ''
+    message.bytes_value.value = b''
+    message.repeated_bool_value.add().value = True
+    message.repeated_bool_value.add().value = False
+    message.repeated_int32_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads('{\n'
+                   '  "int32Value": 0,'
+                   '  "boolValue": false,'
+                   '  "stringValue": "",'
+                   '  "bytesValue": "",'
+                   '  "repeatedBoolValue": [true, false],'
+                   '  "repeatedInt32Value": [0],'
+                   '  "repeatedUint32Value": [],'
+                   '  "repeatedFloatValue": [],'
+                   '  "repeatedDoubleValue": [],'
+                   '  "repeatedBytesValue": [],'
+                   '  "repeatedInt64Value": [],'
+                   '  "repeatedUint64Value": [],'
+                   '  "repeatedStringValue": []'
+                   '}'))
+    parsed_message = json_format_proto3_pb2.TestWrapper()
+    self.CheckParseBack(message, parsed_message)
+
+  def testStructMessage(self):
+    message = json_format_proto3_pb2.TestStruct()
+    message.value['name'] = 'Jim'
+    message.value['age'] = 10
+    message.value['attend'] = True
+    message.value['email'] = None
+    message.value.get_or_create_struct('address')['city'] = 'SFO'
+    message.value['address']['house_number'] = 1024
+    struct_list = message.value.get_or_create_list('list')
+    struct_list.extend([6, 'seven', True, False, None])
+    struct_list.add_struct()['subkey2'] = 9
+    message.repeated_value.add()['age'] = 11
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": {'
+            '    "address": {'
+            '      "city": "SFO", '
+            '      "house_number": 1024'
+            '    }, '
+            '    "age": 10, '
+            '    "name": "Jim", '
+            '    "attend": true, '
+            '    "email": null, '
+            '    "list": [6, "seven", true, false, null, {"subkey2": 9}]'
+            '  },'
+            '  "repeatedValue": [{"age": 11}, {}]'
+            '}'))
+    parsed_message = json_format_proto3_pb2.TestStruct()
+    self.CheckParseBack(message, parsed_message)
+
+  def testValueMessage(self):
+    message = json_format_proto3_pb2.TestValue()
+    message.value.string_value = 'hello'
+    message.repeated_value.add().number_value = 11.1
+    message.repeated_value.add().bool_value = False
+    message.repeated_value.add().null_value = 0
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": "hello",'
+            '  "repeatedValue": [11.1, false, null]'
+            '}'))
+    parsed_message = json_format_proto3_pb2.TestValue()
+    self.CheckParseBack(message, parsed_message)
+    # Can't parse back if the Value message is not set.
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{'
+            '  "value": "hello",'
+            '  "repeatedValue": [11.1, false, null, null]'
+            '}'))
+
+  def testListValueMessage(self):
+    message = json_format_proto3_pb2.TestListValue()
+    message.value.values.add().number_value = 11.1
+    message.value.values.add().null_value = 0
+    message.value.values.add().bool_value = True
+    message.value.values.add().string_value = 'hello'
+    message.value.values.add().struct_value['name'] = 'Jim'
+    message.repeated_value.add().values.add().number_value = 1
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, False)),
+        json.loads(
+            '{"value": [11.1, null, true, "hello", {"name": "Jim"}]\n,'
+            '"repeatedValue": [[1], []]}'))
+    parsed_message = json_format_proto3_pb2.TestListValue()
+    self.CheckParseBack(message, parsed_message)
+
+  def testAnyMessage(self):
+    message = json_format_proto3_pb2.TestAny()
+    value1 = json_format_proto3_pb2.MessageType()
+    value2 = json_format_proto3_pb2.MessageType()
+    value1.value = 1234
+    value2.value = 5678
+    message.value.Pack(value1)
+    message.repeated_value.add().Pack(value1)
+    message.repeated_value.add().Pack(value2)
+    message.repeated_value.add()
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "repeatedValue": [ {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 1234\n'
+            '  }, {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 5678\n'
+            '  },\n'
+            '  {}],\n'
+            '  "value": {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "value": 1234\n'
+            '  }\n'
+            '}\n'))
+    parsed_message = json_format_proto3_pb2.TestAny()
+    self.CheckParseBack(message, parsed_message)
+
+  def testWellKnownInAnyMessage(self):
+    message = any_pb2.Any()
+    int32_value = wrappers_pb2.Int32Value()
+    int32_value.value = 1234
+    message.Pack(int32_value)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": \"type.googleapis.com/google.protobuf.Int32Value\",\n'
+            '  "value": 1234\n'
+            '}\n'))
+    parsed_message = any_pb2.Any()
+    self.CheckParseBack(message, parsed_message)
+
+    timestamp = timestamp_pb2.Timestamp()
+    message.Pack(timestamp)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Timestamp",\n'
+            '  "value": "1970-01-01T00:00:00Z"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    duration = duration_pb2.Duration()
+    duration.seconds = 1
+    message.Pack(duration)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Duration",\n'
+            '  "value": "1s"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    field_mask = field_mask_pb2.FieldMask()
+    field_mask.paths.append('foo.bar')
+    field_mask.paths.append('bar')
+    message.Pack(field_mask)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.FieldMask",\n'
+            '  "value": "foo.bar,bar"\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    struct_message = struct_pb2.Struct()
+    struct_message['name'] = 'Jim'
+    message.Pack(struct_message)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Struct",\n'
+            '  "value": {"name": "Jim"}\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+    nested_any = any_pb2.Any()
+    int32_value.value = 5678
+    nested_any.Pack(int32_value)
+    message.Pack(nested_any)
+    self.assertEqual(
+        json.loads(json_format.MessageToJson(message, True)),
+        json.loads(
+            '{\n'
+            '  "@type": "type.googleapis.com/google.protobuf.Any",\n'
+            '  "value": {\n'
+            '    "@type": "type.googleapis.com/google.protobuf.Int32Value",\n'
+            '    "value": 5678\n'
+            '  }\n'
+            '}\n'))
+    self.CheckParseBack(message, parsed_message)
+
+  def testParseNull(self):
+    message = json_format_proto3_pb2.TestMessage()
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    self.FillAllFields(parsed_message)
+    json_format.Parse('{"int32Value": null, '
+                      '"int64Value": null, '
+                      '"uint32Value": null,'
+                      '"uint64Value": null,'
+                      '"floatValue": null,'
+                      '"doubleValue": null,'
+                      '"boolValue": null,'
+                      '"stringValue": null,'
+                      '"bytesValue": null,'
+                      '"messageValue": null,'
+                      '"enumValue": null,'
+                      '"repeatedInt32Value": null,'
+                      '"repeatedInt64Value": null,'
+                      '"repeatedUint32Value": null,'
+                      '"repeatedUint64Value": null,'
+                      '"repeatedFloatValue": null,'
+                      '"repeatedDoubleValue": null,'
+                      '"repeatedBoolValue": null,'
+                      '"repeatedStringValue": null,'
+                      '"repeatedBytesValue": null,'
+                      '"repeatedMessageValue": null,'
+                      '"repeatedEnumValue": null'
+                      '}',
+                      parsed_message)
+    self.assertEqual(message, parsed_message)
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse repeatedInt32Value field: '
+        'null is not allowed to be used as an element in a repeated field.',
+        json_format.Parse,
+        '{"repeatedInt32Value":[1, null]}',
+        parsed_message)
+
+  def testNanFloat(self):
+    message = json_format_proto3_pb2.TestMessage()
+    message.float_value = float('nan')
+    text = '{\n  "floatValue": "NaN"\n}'
+    self.assertEqual(json_format.MessageToJson(message), text)
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message)
+    self.assertTrue(math.isnan(parsed_message.float_value))
+
+  def testParseEmptyText(self):
+    self.CheckError('',
+                    r'Failed to load JSON: (Expecting value)|(No JSON).')
+
+  def testParseBadEnumValue(self):
+    self.CheckError(
+        '{"enumValue": 1}',
+        'Enum value must be a string literal with double quotes. '
+        'Type "proto3.EnumType" has no value named 1.')
+    self.CheckError(
+        '{"enumValue": "baz"}',
+        'Enum value must be a string literal with double quotes. '
+        'Type "proto3.EnumType" has no value named baz.')
+
+  def testParseBadIdentifer(self):
+    self.CheckError('{int32Value: 1}',
+                    (r'Failed to load JSON: Expecting property name'
+                     r'( enclosed in double quotes)?: line 1'))
+    self.CheckError('{"unknownName": 1}',
+                    'Message type "proto3.TestMessage" has no field named '
+                    '"unknownName".')
+
+  def testDuplicateField(self):
+    # Duplicate key check is not supported for python2.6
+    if sys.version_info < (2, 7):
+      return
+    self.CheckError('{"int32Value": 1,\n"int32Value":2}',
+                    'Failed to load JSON: duplicate key int32Value.')
+
+  def testInvalidBoolValue(self):
+    self.CheckError('{"boolValue": 1}',
+                    'Failed to parse boolValue field: '
+                    'Expected true or false without quotes.')
+    self.CheckError('{"boolValue": "true"}',
+                    'Failed to parse boolValue field: '
+                    'Expected true or false without quotes.')
+
+  def testInvalidIntegerValue(self):
+    message = json_format_proto3_pb2.TestMessage()
+    text = '{"int32Value": 0x12345}'
+    self.assertRaises(json_format.ParseError,
+                      json_format.Parse, text, message)
+    self.CheckError('{"int32Value": 012345}',
+                    (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
+                     r'line 1.'))
+    self.CheckError('{"int32Value": 1.0}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: 1.0.')
+    self.CheckError('{"int32Value": " 1 "}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: " 1 ".')
+    self.CheckError('{"int32Value": "1 "}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: "1 ".')
+    self.CheckError('{"int32Value": 12345678901234567890}',
+                    'Failed to parse int32Value field: Value out of range: '
+                    '12345678901234567890.')
+    self.CheckError('{"int32Value": 1e5}',
+                    'Failed to parse int32Value field: '
+                    'Couldn\'t parse integer: 100000.0.')
+    self.CheckError('{"uint32Value": -1}',
+                    'Failed to parse uint32Value field: '
+                    'Value out of range: -1.')
+
+  def testInvalidFloatValue(self):
+    self.CheckError('{"floatValue": "nan"}',
+                    'Failed to parse floatValue field: Couldn\'t '
+                    'parse float "nan", use "NaN" instead.')
+
+  def testInvalidBytesValue(self):
+    self.CheckError('{"bytesValue": "AQI"}',
+                    'Failed to parse bytesValue field: Incorrect padding.')
+    self.CheckError('{"bytesValue": "AQI*"}',
+                    'Failed to parse bytesValue field: Incorrect padding.')
+
+  def testInvalidMap(self):
+    message = json_format_proto3_pb2.TestMap()
+    text = '{"int32Map": {"null": 2, "2": 3}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse int32Map field: invalid literal',
+        json_format.Parse, text, message)
+    text = '{"int32Map": {1: 2, "2": 3}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        (r'Failed to load JSON: Expecting property name'
+         r'( enclosed in double quotes)?: line 1'),
+        json_format.Parse, text, message)
+    text = '{"boolMap": {"null": 1}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse boolMap field: Expected "true" or "false", not null.',
+        json_format.Parse, text, message)
+    if sys.version_info < (2, 7):
+      return
+    text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to load JSON: duplicate key a',
+        json_format.Parse, text, message)
+
+  def testInvalidTimestamp(self):
+    message = json_format_proto3_pb2.TestTimestamp()
+    text = '{"value": "10000-01-01T00:00:00.00Z"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'time data \'10000-01-01T00:00:00\' does not match'
+        ' format \'%Y-%m-%dT%H:%M:%S\'.',
+        json_format.Parse, text, message)
+    text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'nanos 0123456789012 more than 9 fractional digits.',
+        json_format.Parse, text, message)
+    text = '{"value": "1972-01-01T01:00:00.01+08"}'
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        (r'Invalid timezone offset value: \+08.'),
+        json_format.Parse, text, message)
+    # Time smaller than minimum time.
+    text = '{"value": "0000-01-01T00:00:00Z"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse value field: year is out of range.',
+        json_format.Parse, text, message)
+    # Time bigger than maxinum time.
+    message.value.seconds = 253402300800
+    self.assertRaisesRegexp(
+        OverflowError,
+        'date value out of range',
+        json_format.MessageToJson, message)
+
+  def testInvalidOneof(self):
+    message = json_format_proto3_pb2.TestOneof()
+    text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Message type "proto3.TestOneof"'
+        ' should not have multiple "oneof_value" oneof fields.',
+        json_format.Parse, text, message)
+
+  def testInvalidListValue(self):
+    message = json_format_proto3_pb2.TestListValue()
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        r'Failed to parse value field: ListValue must be in \[\] which is 1234',
+        json_format.Parse, text, message)
+
+  def testInvalidStruct(self):
+    message = json_format_proto3_pb2.TestStruct()
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        'Failed to parse value field: Struct must be in a dict which is 1234',
+        json_format.Parse, text, message)
+
+  def testInvalidAny(self):
+    message = any_pb2.Any()
+    text = '{"@type": "type.googleapis.com/google.protobuf.Int32Value"}'
+    self.assertRaisesRegexp(
+        KeyError,
+        'value',
+        json_format.Parse, text, message)
+    text = '{"value": 1234}'
+    self.assertRaisesRegexp(
+        json_format.ParseError,
+        '@type is missing when parsing any message.',
+        json_format.Parse, text, message)
+    text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
+    self.assertRaisesRegexp(
+        TypeError,
+        'Can not find message descriptor by type_url: '
+        'type.googleapis.com/MessageNotExist.',
+        json_format.Parse, text, message)
+    # Only last part is to be used.
+    text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
+            r'"value": 1234}')
+    json_format.Parse(text, message)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index 0d880a7..2fbe5ea 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -105,8 +105,8 @@
   def testGetMessages(self):
     # performed twice because multiple calls with the same input must be allowed
     for _ in range(2):
-      messages = message_factory.GetMessages([self.factory_test2_fd,
-                                              self.factory_test1_fd])
+      messages = message_factory.GetMessages([self.factory_test1_fd,
+                                              self.factory_test2_fd])
       self.assertTrue(
           set(['google.protobuf.python.internal.Factory2Message',
                'google.protobuf.python.internal.Factory1Message'],
@@ -117,7 +117,7 @@
           set(['google.protobuf.python.internal.Factory2Message.one_more_field',
                'google.protobuf.python.internal.another_field'],
              ).issubset(
-                set(messages['google.protobuf.python.internal.Factory1Message']
+                 set(messages['google.protobuf.python.internal.Factory1Message']
                      ._extensions_by_name.keys())))
       factory_msg1 = messages['google.protobuf.python.internal.Factory1Message']
       msg1 = messages['google.protobuf.python.internal.Factory1Message']()
diff --git a/python/google/protobuf/internal/message_set_extensions.proto b/python/google/protobuf/internal/message_set_extensions.proto
index 702c8d0..14e5f19 100644
--- a/python/google/protobuf/internal/message_set_extensions.proto
+++ b/python/google/protobuf/internal/message_set_extensions.proto
@@ -54,6 +54,14 @@
   optional string str = 25;
 }
 
+message TestMessageSetExtension3 {
+  optional string text = 35;
+}
+
+extend TestMessageSet {
+  optional TestMessageSetExtension3 message_set_extension3 = 98418655;
+}
+
 // This message was used to generate
 // //net/proto2/python/internal/testdata/message_set_message, but is commented
 // out since it must not actually exist in code, to simulate an "unknown"
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index d99b89b..d03f2d2 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -43,17 +43,14 @@
 
 __author__ = 'gps@google.com (Gregory P. Smith)'
 
+
 import collections
 import copy
 import math
 import operator
 import pickle
-import sys
-
 import six
-
-if six.PY3:
-  long = int
+import sys
 
 try:
   import unittest2 as unittest
@@ -63,11 +60,15 @@
 from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf.internal import any_test_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import packed_field_test_pb2
 from google.protobuf.internal import test_util
 from google.protobuf import message
 
+if six.PY3:
+  long = int
+
 # Python pre-2.6 does not have isinf() or isnan() functions, so we have
 # to provide our own.
 def isnan(val):
@@ -442,7 +443,7 @@
     message.repeated_nested_message.add().bb = 24
     message.repeated_nested_message.add().bb = 10
     message.repeated_nested_message.sort(key=lambda z: z.bb // 10)
-    self.assertEquals(
+    self.assertEqual(
         [13, 11, 10, 21, 20, 24, 33],
         [n.bb for n in message.repeated_nested_message])
 
@@ -451,7 +452,7 @@
     pb = message.SerializeToString()
     message.Clear()
     message.MergeFromString(pb)
-    self.assertEquals(
+    self.assertEqual(
         [13, 11, 10, 21, 20, 24, 33],
         [n.bb for n in message.repeated_nested_message])
 
@@ -914,7 +915,6 @@
     with self.assertRaises(pickle.PickleError) as _:
       pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
 
-
   def testSortEmptyRepeatedCompositeContainer(self, message_module):
     """Exercise a scenario that has led to segfaults in the past.
     """
@@ -1280,12 +1280,13 @@
 
     self.assertIsInstance(msg.map_string_string['abc'], six.text_type)
 
-    # Accessing an unset key still throws TypeError of the type of the key
+    # Accessing an unset key still throws TypeError if the type of the key
     # is incorrect.
     with self.assertRaises(TypeError):
       msg.map_string_string[123]
 
-    self.assertFalse(123 in msg.map_string_string)
+    with self.assertRaises(TypeError):
+      123 in msg.map_string_string
 
   def testMapGet(self):
     # Need to test that get() properly returns the default, even though the dict
@@ -1592,31 +1593,49 @@
     # For the C++ implementation this tests the correctness of
     # ScalarMapContainer::Release()
     msg = map_unittest_pb2.TestMap()
-    map = msg.map_int32_int32
+    int32_map = msg.map_int32_int32
 
-    map[2] = 4
-    map[3] = 6
-    map[4] = 8
+    int32_map[2] = 4
+    int32_map[3] = 6
+    int32_map[4] = 8
 
     msg.ClearField('map_int32_int32')
+    self.assertEqual(b'', msg.SerializeToString())
     matching_dict = {2: 4, 3: 6, 4: 8}
-    self.assertMapIterEquals(map.items(), matching_dict)
+    self.assertMapIterEquals(int32_map.items(), matching_dict)
 
-  def testMapIterValidAfterFieldCleared(self):
-    # Map iterator needs to work even if field is cleared.
+  def testMessageMapValidAfterFieldCleared(self):
+    # Map needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    int32_foreign_message = msg.map_int32_foreign_message
+
+    int32_foreign_message[2].c = 5
+
+    msg.ClearField('map_int32_foreign_message')
+    self.assertEqual(b'', msg.SerializeToString())
+    self.assertTrue(2 in int32_foreign_message.keys())
+
+  def testMapIterInvalidatedByClearField(self):
+    # Map iterator is invalidated when field is cleared.
+    # But this case does need to not crash the interpreter.
     # For the C++ implementation this tests the correctness of
     # ScalarMapContainer::Release()
     msg = map_unittest_pb2.TestMap()
 
-    msg.map_int32_int32[2] = 4
-    msg.map_int32_int32[3] = 6
-    msg.map_int32_int32[4] = 8
-
-    it = msg.map_int32_int32.items()
+    it = iter(msg.map_int32_int32)
 
     msg.ClearField('map_int32_int32')
-    matching_dict = {2: 4, 3: 6, 4: 8}
-    self.assertMapIterEquals(it, matching_dict)
+    with self.assertRaises(RuntimeError):
+      for _ in it:
+        pass
+
+    it = iter(msg.map_int32_foreign_message)
+    msg.ClearField('map_int32_foreign_message')
+    with self.assertRaises(RuntimeError):
+      for _ in it:
+        pass
 
   def testMapDelete(self):
     msg = map_unittest_pb2.TestMap()
@@ -1647,6 +1666,37 @@
     msg.map_string_foreign_message['foo'].c = 5
     self.assertEqual(0, len(msg.FindInitializationErrors()))
 
+  def testAnyMessage(self):
+    # Creates and sets message.
+    msg = any_test_pb2.TestAny()
+    msg_descriptor = msg.DESCRIPTOR
+    all_types = unittest_pb2.TestAllTypes()
+    all_descriptor = all_types.DESCRIPTOR
+    all_types.repeated_string.append(u'\u00fc\ua71f')
+    # Packs to Any.
+    msg.value.Pack(all_types)
+    self.assertEqual(msg.value.type_url,
+                     'type.googleapis.com/%s' % all_descriptor.full_name)
+    self.assertEqual(msg.value.value,
+                     all_types.SerializeToString())
+    # Tests Is() method.
+    self.assertTrue(msg.value.Is(all_descriptor))
+    self.assertFalse(msg.value.Is(msg_descriptor))
+    # Unpacks Any.
+    unpacked_message = unittest_pb2.TestAllTypes()
+    self.assertTrue(msg.value.Unpack(unpacked_message))
+    self.assertEqual(all_types, unpacked_message)
+    # Unpacks to different type.
+    self.assertFalse(msg.value.Unpack(msg))
+    # Only Any messages have Pack method.
+    try:
+      msg.Pack(all_types)
+    except AttributeError:
+      pass
+    else:
+      raise AttributeError('%s should not have Pack method.' %
+                           msg_descriptor.full_name)
+
 
 
 class ValidTypeNamesTest(unittest.TestCase):
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
index 161fc5e..1850be5 100644
--- a/python/google/protobuf/internal/missing_enum_values.proto
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -50,3 +50,7 @@
   repeated NestedEnum repeated_nested_enum = 2;
   repeated NestedEnum packed_nested_enum = 3 [packed = true];
 }
+
+message JustString {
+  required string dummy = 1;
+}
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
index 1eda10f..822ad89 100644
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -34,14 +34,12 @@
 
 try:
     from collections import OrderedDict
-except ImportError: 
+except ImportError:
     from ordereddict import OrderedDict  #PY26
-
 try:
-  import unittest2 as unittest  #PY26
+  import unittest2 as unittest
 except ImportError:
   import unittest
-
 from google.protobuf import descriptor_pb2
 from google.protobuf import descriptor_pool
 from google.protobuf import proto_builder
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 4e5032a..87f6066 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2007 Google Inc. All Rights Reserved.
-#
 # This code is meant to work on Python 2.4 and above only.
 #
 # TODO(robinson): Helpers for verbose, common checks like seeing if a
@@ -67,6 +65,7 @@
 from google.protobuf.internal import enum_type_wrapper
 from google.protobuf.internal import message_listener as message_listener_mod
 from google.protobuf.internal import type_checkers
+from google.protobuf.internal import well_known_types
 from google.protobuf.internal import wire_format
 from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message as message_mod
@@ -74,6 +73,7 @@
 from google.protobuf import text_format
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
+_AnyFullTypeName = 'google.protobuf.Any'
 
 
 class GeneratedProtocolMessageType(type):
@@ -129,6 +129,8 @@
       Newly-allocated class.
     """
     descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY]
+    if descriptor.full_name in well_known_types.WKTBASES:
+      bases += (well_known_types.WKTBASES[descriptor.full_name],)
     _AddClassAttributesForNestedExtensions(descriptor, dictionary)
     _AddSlots(descriptor, dictionary)
 
@@ -263,7 +265,6 @@
           field.containing_type.has_options and
           field.containing_type.GetOptions().message_set_wire_format and
           field.type == _FieldDescriptor.TYPE_MESSAGE and
-          field.message_type == field.extension_scope and
           field.label == _FieldDescriptor.LABEL_OPTIONAL)
 
 
@@ -545,7 +546,8 @@
   try:
     return message_descriptor.fields_by_name[field_name]
   except KeyError:
-    raise ValueError('Protocol message has no "%s" field.' % field_name)
+    raise ValueError('Protocol message %s has no "%s" field.' %
+                     (message_descriptor.name, field_name))
 
 
 def _AddPropertiesForFields(descriptor, cls):
@@ -850,9 +852,15 @@
         else:
           return
       except KeyError:
-        raise ValueError('Protocol message has no "%s" field.' % field_name)
+        raise ValueError('Protocol message %s() has no "%s" field.' %
+                         (message_descriptor.name, field_name))
 
     if field in self._fields:
+      # To match the C++ implementation, we need to invalidate iterators
+      # for map fields when ClearField() happens.
+      if hasattr(self._fields[field], 'InvalidateIterators'):
+        self._fields[field].InvalidateIterators()
+
       # Note:  If the field is a sub-message, its listener will still point
       #   at us.  That's fine, because the worst than can happen is that it
       #   will call _Modified() and invalidate our byte size.  Big deal.
@@ -906,7 +914,19 @@
       return extension_handle in self._fields
   cls.HasExtension = HasExtension
 
-def _UnpackAny(msg):
+def _InternalUnpackAny(msg):
+  """Unpacks Any message and returns the unpacked message.
+
+  This internal method is differnt from public Any Unpack method which takes
+  the target message as argument. _InternalUnpackAny method does not have
+  target message type and need to find the message type in descriptor pool.
+
+  Args:
+    msg: An Any message to be unpacked.
+
+  Returns:
+    The unpacked message.
+  """
   type_url = msg.type_url
   db = symbol_database.Default()
 
@@ -937,9 +957,9 @@
     if self is other:
       return True
 
-    if self.DESCRIPTOR.full_name == "google.protobuf.Any":
-      any_a = _UnpackAny(self)
-      any_b = _UnpackAny(other)
+    if self.DESCRIPTOR.full_name == _AnyFullTypeName:
+      any_a = _InternalUnpackAny(self)
+      any_b = _InternalUnpackAny(other)
       if any_a and any_b:
         return any_a == any_b
 
@@ -964,6 +984,13 @@
   cls.__str__ = __str__
 
 
+def _AddReprMethod(message_descriptor, cls):
+  """Helper for _AddMessageMethods()."""
+  def __repr__(self):
+    return text_format.MessageToString(self)
+  cls.__repr__ = __repr__
+
+
 def _AddUnicodeMethod(unused_message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
 
@@ -1272,6 +1299,7 @@
   _AddClearMethod(message_descriptor, cls)
   _AddEqualsMethod(message_descriptor, cls)
   _AddStrMethod(message_descriptor, cls)
+  _AddReprMethod(message_descriptor, cls)
   _AddUnicodeMethod(message_descriptor, cls)
   _AddSetListenerMethod(cls)
   _AddByteSizeMethod(message_descriptor, cls)
@@ -1282,6 +1310,7 @@
   _AddMergeFromMethod(cls)
   _AddWhichOneofMethod(message_descriptor, cls)
 
+
 def _AddPrivateHelperMethods(message_descriptor, cls):
   """Adds implementation of private helper methods to cls."""
 
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index 2661135..752f2f5 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -38,14 +38,13 @@
 import copy
 import gc
 import operator
+import six
 import struct
+
 try:
   import unittest2 as unittest
 except ImportError:
   import unittest
-
-import six
-
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
@@ -1799,7 +1798,6 @@
     # Just check the default value.
     self.assertEqual(57, msg.inner.value)
 
-
 #  Since we had so many tests for protocol buffer equality, we broke these out
 #  into separate TestCase classes.
 
@@ -2396,8 +2394,10 @@
     extension_message2 = message_set_extensions_pb2.TestMessageSetExtension2
     extension1 = extension_message1.message_set_extension
     extension2 = extension_message2.message_set_extension
+    extension3 = message_set_extensions_pb2.message_set_extension3
     proto.Extensions[extension1].i = 123
     proto.Extensions[extension2].str = 'foo'
+    proto.Extensions[extension3].text = 'bar'
 
     # Serialize using the MessageSet wire format (this is specified in the
     # .proto file).
@@ -2409,7 +2409,7 @@
     self.assertEqual(
         len(serialized),
         raw.MergeFromString(serialized))
-    self.assertEqual(2, len(raw.item))
+    self.assertEqual(3, len(raw.item))
 
     message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     self.assertEqual(
@@ -2423,6 +2423,12 @@
         message2.MergeFromString(raw.item[1].message))
     self.assertEqual('foo', message2.str)
 
+    message3 = message_set_extensions_pb2.TestMessageSetExtension3()
+    self.assertEqual(
+        len(raw.item[2].message),
+        message3.MergeFromString(raw.item[2].message))
+    self.assertEqual('bar', message3.text)
+
     # Deserialize using the MessageSet wire format.
     proto2 = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(
@@ -2430,6 +2436,7 @@
         proto2.MergeFromString(serialized))
     self.assertEqual(123, proto2.Extensions[extension1].i)
     self.assertEqual('foo', proto2.Extensions[extension2].str)
+    self.assertEqual('bar', proto2.Extensions[extension3].text)
 
     # Check byte size.
     self.assertEqual(proto2.ByteSize(), len(serialized))
@@ -2759,9 +2766,10 @@
   def testInitArgsUnknownFieldName(self):
     def InitalizeEmptyMessageWithExtraKeywordArg():
       unused_proto = unittest_pb2.TestEmptyMessage(unknown='unknown')
-    self._CheckRaises(ValueError,
-                      InitalizeEmptyMessageWithExtraKeywordArg,
-                      'Protocol message has no "unknown" field.')
+    self._CheckRaises(
+        ValueError,
+        InitalizeEmptyMessageWithExtraKeywordArg,
+        'Protocol message TestEmptyMessage has no "unknown" field.')
 
   def testInitRequiredKwargs(self):
     proto = unittest_pb2.TestRequired(a=1, b=1, c=1)
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
index 9744226..0cb935a 100644
--- a/python/google/protobuf/internal/symbol_database_test.py
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -37,22 +37,27 @@
 except ImportError:
   import unittest
 from google.protobuf import unittest_pb2
+from google.protobuf import descriptor
 from google.protobuf import symbol_database
 
-
 class SymbolDatabaseTest(unittest.TestCase):
 
   def _Database(self):
-    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
+    # TODO(b/17734095): Remove this difference when the C++ implementation
+    # supports multiple databases.
+    if descriptor._USE_C_DESCRIPTORS:
+      return symbol_database.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
 
   def testGetPrototype(self):
     instance = self._Database().GetPrototype(
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index d332b77..0e14556 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -34,6 +34,7 @@
 
 __author__ = 'kenton@google.com (Kenton Varda)'
 
+
 import re
 import six
 import string
@@ -50,8 +51,22 @@
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import test_util
+from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf import text_format
 
+
+# Low-level nuts-n-bolts tests.
+class SimpleTextFormatTests(unittest.TestCase):
+
+  # The members of _QUOTES are formatted into a regexp template that
+  # expects single characters.  Therefore it's an error (in addition to being
+  # non-sensical in the first place) to try to specify a "quote mark" that is
+  # more than one character.
+  def TestQuoteMarksAreSingleChars(self):
+    for quote in text_format._QUOTES:
+      self.assertEqual(1, len(quote))
+
+
 # Base class with some common functionality.
 class TextFormatBase(unittest.TestCase):
 
@@ -286,6 +301,19 @@
     self.assertEqual(u'one', message.repeated_string[0])
     self.assertEqual(u'two', message.repeated_string[1])
 
+  def testParseRepeatedScalarShortFormat(self, message_module):
+    message = message_module.TestAllTypes()
+    text = ('repeated_int64: [100, 200];\n'
+            'repeated_int64: 300,\n'
+            'repeated_string: ["one", "two"];\n')
+    text_format.Parse(text, message)
+
+    self.assertEqual(100, message.repeated_int64[0])
+    self.assertEqual(200, message.repeated_int64[1])
+    self.assertEqual(300, message.repeated_int64[2])
+    self.assertEqual(u'one', message.repeated_string[0])
+    self.assertEqual(u'two', message.repeated_string[1])
+
   def testParseEmptyText(self, message_module):
     message = message_module.TestAllTypes()
     text = ''
@@ -300,7 +328,7 @@
   def testParseSingleWord(self, message_module):
     message = message_module.TestAllTypes()
     text = 'foo'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
          r'"foo".'),
@@ -309,7 +337,7 @@
   def testParseUnknownField(self, message_module):
     message = message_module.TestAllTypes()
     text = 'unknown_field: 8\n'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
          r'"unknown_field".'),
@@ -318,7 +346,7 @@
   def testParseBadEnumValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
          r'has no value named BARR.'),
@@ -326,7 +354,7 @@
 
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: 100'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
          r'has no value with number 100.'),
@@ -335,7 +363,7 @@
   def testParseBadIntValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_int32: bork'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:17 : Couldn\'t parse integer: bork'),
         text_format.Parse, text, message)
@@ -389,7 +417,7 @@
 # Ideally the schemas would be made more similar so these tests could pass.
 class OnlyWorksWithProto2RightNowTests(TextFormatBase):
 
-  def testPrintAllFieldsPointy(self, message_module):
+  def testPrintAllFieldsPointy(self):
     message = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(message)
     self.CompareToGoldenFile(
@@ -552,6 +580,15 @@
         '  }\n'
         '}\n')
 
+    message = message_set_extensions_pb2.TestMessageSet()
+    ext = message_set_extensions_pb2.message_set_extension3
+    message.Extensions[ext].text = 'bar'
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        '[google.protobuf.internal.TestMessageSetExtension3] {\n'
+        '  text: \"bar\"\n'
+        '}\n')
+
   def testPrintMessageSetAsOneLine(self):
     message = unittest_mset_pb2.TestMessageSetContainer()
     ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
@@ -626,15 +663,125 @@
     text_format.Parse(ascii_text, parsed_message)
     self.assertEqual(message, parsed_message)
 
+  def testParseAllowedUnknownExtension(self):
+    # Skip over unknown extension correctly.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [unknown_extension] {\n'
+            '    i: 23\n'
+            '    [nested_unknown_ext]: {\n'
+            '      i: 23\n'
+            '      test: "test_string"\n'
+            '      floaty_float: -0.315\n'
+            '      num: -inf\n'
+            '      multiline_str: "abc"\n'
+            '          "def"\n'
+            '          "xyz."\n'
+            '      [nested_unknown_ext]: <\n'
+            '        i: 23\n'
+            '        i: 24\n'
+            '        pointfloat: .3\n'
+            '        test: "test_string"\n'
+            '        floaty_float: -0.315\n'
+            '        num: -inf\n'
+            '        long_string: "test" "test2" \n'
+            '      >\n'
+            '    }\n'
+            '  }\n'
+            '  [unknown_extension]: 5\n'
+            '}\n')
+    text_format.Parse(text, message, allow_unknown_extension=True)
+    golden = 'message_set {\n}\n'
+    self.CompareToGoldenText(text_format.MessageToString(message), golden)
+
+    # Catch parse errors in unknown extension.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    i:\n'  # Missing value.
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: }',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    str: "malformed string\n'  # Missing closing quote.
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: "',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [unknown_extension] {\n'
+                 '    str: "malformed\n multiline\n string\n'
+                 '  }\n'
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          'Invalid field value: "',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  [malformed_extension] <\n'
+                 '    i: -5\n'
+                 '  \n'  # Missing '>' here.
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          '5:1 : Expected ">".',
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    # Don't allow unknown fields with allow_unknown_extension=True.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    malformed = ('message_set {\n'
+                 '  unknown_field: true\n'
+                 '  \n'  # Missing '>' here.
+                 '}\n')
+    six.assertRaisesRegex(self,
+                          text_format.ParseError,
+                          ('2:3 : Message type '
+                           '"proto2_wireformat_unittest.TestMessageSet" has no'
+                           ' field named "unknown_field".'),
+                          text_format.Parse, malformed, message,
+                          allow_unknown_extension=True)
+
+    # Parse known extension correcty.
+    message = unittest_mset_pb2.TestMessageSetContainer()
+    text = ('message_set {\n'
+            '  [protobuf_unittest.TestMessageSetExtension1] {\n'
+            '    i: 23\n'
+            '  }\n'
+            '  [protobuf_unittest.TestMessageSetExtension2] {\n'
+            '    str: \"foo\"\n'
+            '  }\n'
+            '}\n')
+    text_format.Parse(text, message, allow_unknown_extension=True)
+    ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
+    ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
+    self.assertEqual(23, message.message_set.Extensions[ext1].i)
+    self.assertEqual('foo', message.message_set.Extensions[ext2].str)
+
   def testParseBadExtension(self):
     message = unittest_pb2.TestAllExtensions()
     text = '[unknown_extension]: 8\n'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         '1:2 : Extension "unknown_extension" not registered.',
         text_format.Parse, text, message)
     message = unittest_pb2.TestAllTypes()
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
          'extensions.'),
@@ -653,7 +800,7 @@
     message = unittest_pb2.TestAllExtensions()
     text = ('[protobuf_unittest.optional_int32_extension]: 42 '
             '[protobuf_unittest.optional_int32_extension]: 67')
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
          'should not have multiple '
@@ -664,7 +811,7 @@
     message = unittest_pb2.TestAllTypes()
     text = ('optional_nested_message { bb: 1 } '
             'optional_nested_message { bb: 2 }')
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
          'should not have multiple "bb" fields.'),
@@ -674,7 +821,7 @@
     message = unittest_pb2.TestAllTypes()
     text = ('optional_int32: 42 '
             'optional_int32: 67')
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError,
         ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
          'have multiple "optional_int32" fields.'),
@@ -683,11 +830,11 @@
   def testParseGroupNotClosed(self):
     message = unittest_pb2.TestAllTypes()
     text = 'RepeatedGroup: <'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError, '1:16 : Expected ">".',
         text_format.Parse, text, message)
     text = 'RepeatedGroup: {'
-    six.assertRaisesRegex(self, 
+    six.assertRaisesRegex(self,
         text_format.ParseError, '1:16 : Expected "}".',
         text_format.Parse, text, message)
 
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 8fa3d8c..f30ca6a 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2008 Google Inc. All Rights Reserved.
-
 """Provides type checking routines.
 
 This module defines type checking utilities in the forms of dictionaries:
@@ -52,6 +50,7 @@
 if six.PY3:
   long = int
 
+from google.protobuf.internal import api_implementation
 from google.protobuf.internal import decoder
 from google.protobuf.internal import encoder
 from google.protobuf.internal import wire_format
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 011d3b5..9685b8b 100755
--- a/python/google/protobuf/internal/unknown_fields_test.py
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -39,7 +39,6 @@
   import unittest2 as unittest
 except ImportError:
   import unittest
-
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
@@ -262,6 +261,19 @@
         decoder(value, 0, len(value), self.message, result_dict)
     return result_dict[field_descriptor]
 
+  def testUnknownParseMismatchEnumValue(self):
+    just_string = missing_enum_values_pb2.JustString()
+    just_string.dummy = 'blah'
+
+    missing = missing_enum_values_pb2.TestEnumValues()
+    # The parse is invalid, storing the string proto into the set of
+    # unknown fields.
+    missing.ParseFromString(just_string.SerializeToString())
+
+    # Fetching the enum field shouldn't crash, instead returning the
+    # default value.
+    self.assertEqual(missing.optional_nested_enum, 0)
+
   @SkipIfCppImplementation
   def testUnknownEnumValue(self):
     self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
new file mode 100644
index 0000000..d35fcc5
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -0,0 +1,720 @@
+# 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.
+
+"""Contains well known classes.
+
+This files defines well known classes which need extra maintenance including:
+  - Any
+  - Duration
+  - FieldMask
+  - Struct
+  - Timestamp
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from datetime import datetime
+from datetime import timedelta
+import six
+
+from google.protobuf.descriptor import FieldDescriptor
+
+_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
+_NANOS_PER_SECOND = 1000000000
+_NANOS_PER_MILLISECOND = 1000000
+_NANOS_PER_MICROSECOND = 1000
+_MILLIS_PER_SECOND = 1000
+_MICROS_PER_SECOND = 1000000
+_SECONDS_PER_DAY = 24 * 3600
+
+
+class Error(Exception):
+  """Top-level module error."""
+
+
+class ParseError(Error):
+  """Thrown in case of parsing error."""
+
+
+class Any(object):
+  """Class for Any Message type."""
+
+  def Pack(self, msg, type_url_prefix='type.googleapis.com/'):
+    """Packs the specified message into current Any message."""
+    if len(type_url_prefix) < 1 or type_url_prefix[-1] != '/':
+      self.type_url = '%s/%s' % (type_url_prefix, msg.DESCRIPTOR.full_name)
+    else:
+      self.type_url = '%s%s' % (type_url_prefix, msg.DESCRIPTOR.full_name)
+    self.value = msg.SerializeToString()
+
+  def Unpack(self, msg):
+    """Unpacks the current Any message into specified message."""
+    descriptor = msg.DESCRIPTOR
+    if not self.Is(descriptor):
+      return False
+    msg.ParseFromString(self.value)
+    return True
+
+  def Is(self, descriptor):
+    """Checks if this Any represents the given protobuf type."""
+    # Only last part is to be used: b/25630112
+    return self.type_url.split('/')[-1] == descriptor.full_name
+
+
+class Timestamp(object):
+  """Class for Timestamp message type."""
+
+  def ToJsonString(self):
+    """Converts Timestamp to RFC 3339 date string format.
+
+    Returns:
+      A string converted from timestamp. The string is always Z-normalized
+      and uses 3, 6 or 9 fractional digits as required to represent the
+      exact time. Example of the return format: '1972-01-01T10:00:20.021Z'
+    """
+    nanos = self.nanos % _NANOS_PER_SECOND
+    total_sec = self.seconds + (self.nanos - nanos) // _NANOS_PER_SECOND
+    seconds = total_sec % _SECONDS_PER_DAY
+    days = (total_sec - seconds) // _SECONDS_PER_DAY
+    dt = datetime(1970, 1, 1) + timedelta(days, seconds)
+
+    result = dt.isoformat()
+    if (nanos % 1e9) == 0:
+      # If there are 0 fractional digits, the fractional
+      # point '.' should be omitted when serializing.
+      return result + 'Z'
+    if (nanos % 1e6) == 0:
+      # Serialize 3 fractional digits.
+      return result + '.%03dZ' % (nanos / 1e6)
+    if (nanos % 1e3) == 0:
+      # Serialize 6 fractional digits.
+      return result + '.%06dZ' % (nanos / 1e3)
+    # Serialize 9 fractional digits.
+    return result + '.%09dZ' % nanos
+
+  def FromJsonString(self, value):
+    """Parse a RFC 3339 date string format to Timestamp.
+
+    Args:
+      value: A date string. Any fractional digits (or none) and any offset are
+          accepted as long as they fit into nano-seconds precision.
+          Example of accepted format: '1972-01-01T10:00:20.021-05:00'
+
+    Raises:
+      ParseError: On parsing problems.
+    """
+    timezone_offset = value.find('Z')
+    if timezone_offset == -1:
+      timezone_offset = value.find('+')
+    if timezone_offset == -1:
+      timezone_offset = value.rfind('-')
+    if timezone_offset == -1:
+      raise ParseError(
+          'Failed to parse timestamp: missing valid timezone offset.')
+    time_value = value[0:timezone_offset]
+    # Parse datetime and nanos.
+    point_position = time_value.find('.')
+    if point_position == -1:
+      second_value = time_value
+      nano_value = ''
+    else:
+      second_value = time_value[:point_position]
+      nano_value = time_value[point_position + 1:]
+    date_object = datetime.strptime(second_value, _TIMESTAMPFOMAT)
+    td = date_object - datetime(1970, 1, 1)
+    seconds = td.seconds + td.days * _SECONDS_PER_DAY
+    if len(nano_value) > 9:
+      raise ParseError(
+          'Failed to parse Timestamp: nanos {0} more than '
+          '9 fractional digits.'.format(nano_value))
+    if nano_value:
+      nanos = round(float('0.' + nano_value) * 1e9)
+    else:
+      nanos = 0
+    # Parse timezone offsets.
+    if value[timezone_offset] == 'Z':
+      if len(value) != timezone_offset + 1:
+        raise ParseError('Failed to parse timestamp: invalid trailing'
+                         ' data {0}.'.format(value))
+    else:
+      timezone = value[timezone_offset:]
+      pos = timezone.find(':')
+      if pos == -1:
+        raise ParseError(
+            'Invalid timezone offset value: {0}.'.format(timezone))
+      if timezone[0] == '+':
+        seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+      else:
+        seconds += (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+    # Set seconds and nanos
+    self.seconds = int(seconds)
+    self.nanos = int(nanos)
+
+  def GetCurrentTime(self):
+    """Get the current UTC into Timestamp."""
+    self.FromDatetime(datetime.utcnow())
+
+  def ToNanoseconds(self):
+    """Converts Timestamp to nanoseconds since epoch."""
+    return self.seconds * _NANOS_PER_SECOND + self.nanos
+
+  def ToMicroseconds(self):
+    """Converts Timestamp to microseconds since epoch."""
+    return (self.seconds * _MICROS_PER_SECOND +
+            self.nanos // _NANOS_PER_MICROSECOND)
+
+  def ToMilliseconds(self):
+    """Converts Timestamp to milliseconds since epoch."""
+    return (self.seconds * _MILLIS_PER_SECOND +
+            self.nanos // _NANOS_PER_MILLISECOND)
+
+  def ToSeconds(self):
+    """Converts Timestamp to seconds since epoch."""
+    return self.seconds
+
+  def FromNanoseconds(self, nanos):
+    """Converts nanoseconds since epoch to Timestamp."""
+    self.seconds = nanos // _NANOS_PER_SECOND
+    self.nanos = nanos % _NANOS_PER_SECOND
+
+  def FromMicroseconds(self, micros):
+    """Converts microseconds since epoch to Timestamp."""
+    self.seconds = micros // _MICROS_PER_SECOND
+    self.nanos = (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND
+
+  def FromMilliseconds(self, millis):
+    """Converts milliseconds since epoch to Timestamp."""
+    self.seconds = millis // _MILLIS_PER_SECOND
+    self.nanos = (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND
+
+  def FromSeconds(self, seconds):
+    """Converts seconds since epoch to Timestamp."""
+    self.seconds = seconds
+    self.nanos = 0
+
+  def ToDatetime(self):
+    """Converts Timestamp to datetime."""
+    return datetime.utcfromtimestamp(
+        self.seconds + self.nanos / float(_NANOS_PER_SECOND))
+
+  def FromDatetime(self, dt):
+    """Converts datetime to Timestamp."""
+    td = dt - datetime(1970, 1, 1)
+    self.seconds = td.seconds + td.days * _SECONDS_PER_DAY
+    self.nanos = td.microseconds * _NANOS_PER_MICROSECOND
+
+
+class Duration(object):
+  """Class for Duration message type."""
+
+  def ToJsonString(self):
+    """Converts Duration to string format.
+
+    Returns:
+      A string converted from self. The string format will contains
+      3, 6, or 9 fractional digits depending on the precision required to
+      represent the exact Duration value. For example: "1s", "1.010s",
+      "1.000000100s", "-3.100s"
+    """
+    if self.seconds < 0 or self.nanos < 0:
+      result = '-'
+      seconds = - self.seconds + int((0 - self.nanos) // 1e9)
+      nanos = (0 - self.nanos) % 1e9
+    else:
+      result = ''
+      seconds = self.seconds + int(self.nanos // 1e9)
+      nanos = self.nanos % 1e9
+    result += '%d' % seconds
+    if (nanos % 1e9) == 0:
+      # If there are 0 fractional digits, the fractional
+      # point '.' should be omitted when serializing.
+      return result + 's'
+    if (nanos % 1e6) == 0:
+      # Serialize 3 fractional digits.
+      return result + '.%03ds' % (nanos / 1e6)
+    if (nanos % 1e3) == 0:
+      # Serialize 6 fractional digits.
+      return result + '.%06ds' % (nanos / 1e3)
+    # Serialize 9 fractional digits.
+    return result + '.%09ds' % nanos
+
+  def FromJsonString(self, value):
+    """Converts a string to Duration.
+
+    Args:
+      value: A string to be converted. The string must end with 's'. Any
+          fractional digits (or none) are accepted as long as they fit into
+          precision. For example: "1s", "1.01s", "1.0000001s", "-3.100s
+
+    Raises:
+      ParseError: On parsing problems.
+    """
+    if len(value) < 1 or value[-1] != 's':
+      raise ParseError(
+          'Duration must end with letter "s": {0}.'.format(value))
+    try:
+      pos = value.find('.')
+      if pos == -1:
+        self.seconds = int(value[:-1])
+        self.nanos = 0
+      else:
+        self.seconds = int(value[:pos])
+        if value[0] == '-':
+          self.nanos = int(round(float('-0{0}'.format(value[pos: -1])) *1e9))
+        else:
+          self.nanos = int(round(float('0{0}'.format(value[pos: -1])) *1e9))
+    except ValueError:
+      raise ParseError(
+          'Couldn\'t parse duration: {0}.'.format(value))
+
+  def ToNanoseconds(self):
+    """Converts a Duration to nanoseconds."""
+    return self.seconds * _NANOS_PER_SECOND + self.nanos
+
+  def ToMicroseconds(self):
+    """Converts a Duration to microseconds."""
+    micros = _RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND)
+    return self.seconds * _MICROS_PER_SECOND + micros
+
+  def ToMilliseconds(self):
+    """Converts a Duration to milliseconds."""
+    millis = _RoundTowardZero(self.nanos, _NANOS_PER_MILLISECOND)
+    return self.seconds * _MILLIS_PER_SECOND + millis
+
+  def ToSeconds(self):
+    """Converts a Duration to seconds."""
+    return self.seconds
+
+  def FromNanoseconds(self, nanos):
+    """Converts nanoseconds to Duration."""
+    self._NormalizeDuration(nanos // _NANOS_PER_SECOND,
+                            nanos % _NANOS_PER_SECOND)
+
+  def FromMicroseconds(self, micros):
+    """Converts microseconds to Duration."""
+    self._NormalizeDuration(
+        micros // _MICROS_PER_SECOND,
+        (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND)
+
+  def FromMilliseconds(self, millis):
+    """Converts milliseconds to Duration."""
+    self._NormalizeDuration(
+        millis // _MILLIS_PER_SECOND,
+        (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND)
+
+  def FromSeconds(self, seconds):
+    """Converts seconds to Duration."""
+    self.seconds = seconds
+    self.nanos = 0
+
+  def ToTimedelta(self):
+    """Converts Duration to timedelta."""
+    return timedelta(
+        seconds=self.seconds, microseconds=_RoundTowardZero(
+            self.nanos, _NANOS_PER_MICROSECOND))
+
+  def FromTimedelta(self, td):
+    """Convertd timedelta to Duration."""
+    self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY,
+                            td.microseconds * _NANOS_PER_MICROSECOND)
+
+  def _NormalizeDuration(self, seconds, nanos):
+    """Set Duration by seconds and nonas."""
+    # Force nanos to be negative if the duration is negative.
+    if seconds < 0 and nanos > 0:
+      seconds += 1
+      nanos -= _NANOS_PER_SECOND
+    self.seconds = seconds
+    self.nanos = nanos
+
+
+def _RoundTowardZero(value, divider):
+  """Truncates the remainder part after division."""
+  # For some languanges, the sign of the remainder is implementation
+  # dependent if any of the operands is negative. Here we enforce
+  # "rounded toward zero" semantics. For example, for (-5) / 2 an
+  # implementation may give -3 as the result with the remainder being
+  # 1. This function ensures we always return -2 (closer to zero).
+  result = value // divider
+  remainder = value % divider
+  if result < 0 and remainder > 0:
+    return result + 1
+  else:
+    return result
+
+
+class FieldMask(object):
+  """Class for FieldMask message type."""
+
+  def ToJsonString(self):
+    """Converts FieldMask to string according to proto3 JSON spec."""
+    return ','.join(self.paths)
+
+  def FromJsonString(self, value):
+    """Converts string to FieldMask according to proto3 JSON spec."""
+    self.Clear()
+    for path in value.split(','):
+      self.paths.append(path)
+
+  def IsValidForDescriptor(self, message_descriptor):
+    """Checks whether the FieldMask is valid for Message Descriptor."""
+    for path in self.paths:
+      if not _IsValidPath(message_descriptor, path):
+        return False
+    return True
+
+  def AllFieldsFromDescriptor(self, message_descriptor):
+    """Gets all direct fields of Message Descriptor to FieldMask."""
+    self.Clear()
+    for field in message_descriptor.fields:
+      self.paths.append(field.name)
+
+  def CanonicalFormFromMask(self, mask):
+    """Converts a FieldMask to the canonical form.
+
+    Removes paths that are covered by another path. For example,
+    "foo.bar" is covered by "foo" and will be removed if "foo"
+    is also in the FieldMask. Then sorts all paths in alphabetical order.
+
+    Args:
+      mask: The original FieldMask to be converted.
+    """
+    tree = _FieldMaskTree(mask)
+    tree.ToFieldMask(self)
+
+  def Union(self, mask1, mask2):
+    """Merges mask1 and mask2 into this FieldMask."""
+    _CheckFieldMaskMessage(mask1)
+    _CheckFieldMaskMessage(mask2)
+    tree = _FieldMaskTree(mask1)
+    tree.MergeFromFieldMask(mask2)
+    tree.ToFieldMask(self)
+
+  def Intersect(self, mask1, mask2):
+    """Intersects mask1 and mask2 into this FieldMask."""
+    _CheckFieldMaskMessage(mask1)
+    _CheckFieldMaskMessage(mask2)
+    tree = _FieldMaskTree(mask1)
+    intersection = _FieldMaskTree()
+    for path in mask2.paths:
+      tree.IntersectPath(path, intersection)
+    intersection.ToFieldMask(self)
+
+  def MergeMessage(
+      self, source, destination,
+      replace_message_field=False, replace_repeated_field=False):
+    """Merges fields specified in FieldMask from source to destination.
+
+    Args:
+      source: Source message.
+      destination: The destination message to be merged into.
+      replace_message_field: Replace message field if True. Merge message
+          field if False.
+      replace_repeated_field: Replace repeated field if True. Append
+          elements of repeated field if False.
+    """
+    tree = _FieldMaskTree(self)
+    tree.MergeMessage(
+        source, destination, replace_message_field, replace_repeated_field)
+
+
+def _IsValidPath(message_descriptor, path):
+  """Checks whether the path is valid for Message Descriptor."""
+  parts = path.split('.')
+  last = parts.pop()
+  for name in parts:
+    field = message_descriptor.fields_by_name[name]
+    if (field is None or
+        field.label == FieldDescriptor.LABEL_REPEATED or
+        field.type != FieldDescriptor.TYPE_MESSAGE):
+      return False
+    message_descriptor = field.message_type
+  return last in message_descriptor.fields_by_name
+
+
+def _CheckFieldMaskMessage(message):
+  """Raises ValueError if message is not a FieldMask."""
+  message_descriptor = message.DESCRIPTOR
+  if (message_descriptor.name != 'FieldMask' or
+      message_descriptor.file.name != 'google/protobuf/field_mask.proto'):
+    raise ValueError('Message {0} is not a FieldMask.'.format(
+        message_descriptor.full_name))
+
+
+class _FieldMaskTree(object):
+  """Represents a FieldMask in a tree structure.
+
+  For example, given a FieldMask "foo.bar,foo.baz,bar.baz",
+  the FieldMaskTree will be:
+      [_root] -+- foo -+- bar
+            |       |
+            |       +- baz
+            |
+            +- bar --- baz
+  In the tree, each leaf node represents a field path.
+  """
+
+  def __init__(self, field_mask=None):
+    """Initializes the tree by FieldMask."""
+    self._root = {}
+    if field_mask:
+      self.MergeFromFieldMask(field_mask)
+
+  def MergeFromFieldMask(self, field_mask):
+    """Merges a FieldMask to the tree."""
+    for path in field_mask.paths:
+      self.AddPath(path)
+
+  def AddPath(self, path):
+    """Adds a field path into the tree.
+
+    If the field path to add is a sub-path of an existing field path
+    in the tree (i.e., a leaf node), it means the tree already matches
+    the given path so nothing will be added to the tree. If the path
+    matches an existing non-leaf node in the tree, that non-leaf node
+    will be turned into a leaf node with all its children removed because
+    the path matches all the node's children. Otherwise, a new path will
+    be added.
+
+    Args:
+      path: The field path to add.
+    """
+    node = self._root
+    for name in path.split('.'):
+      if name not in node:
+        node[name] = {}
+      elif not node[name]:
+        # Pre-existing empty node implies we already have this entire tree.
+        return
+      node = node[name]
+    # Remove any sub-trees we might have had.
+    node.clear()
+
+  def ToFieldMask(self, field_mask):
+    """Converts the tree to a FieldMask."""
+    field_mask.Clear()
+    _AddFieldPaths(self._root, '', field_mask)
+
+  def IntersectPath(self, path, intersection):
+    """Calculates the intersection part of a field path with this tree.
+
+    Args:
+      path: The field path to calculates.
+      intersection: The out tree to record the intersection part.
+    """
+    node = self._root
+    for name in path.split('.'):
+      if name not in node:
+        return
+      elif not node[name]:
+        intersection.AddPath(path)
+        return
+      node = node[name]
+    intersection.AddLeafNodes(path, node)
+
+  def AddLeafNodes(self, prefix, node):
+    """Adds leaf nodes begin with prefix to this tree."""
+    if not node:
+      self.AddPath(prefix)
+    for name in node:
+      child_path = prefix + '.' + name
+      self.AddLeafNodes(child_path, node[name])
+
+  def MergeMessage(
+      self, source, destination,
+      replace_message, replace_repeated):
+    """Merge all fields specified by this tree from source to destination."""
+    _MergeMessage(
+        self._root, source, destination, replace_message, replace_repeated)
+
+
+def _StrConvert(value):
+  """Converts value to str if it is not."""
+  # This file is imported by c extension and some methods like ClearField
+  # requires string for the field name. py2/py3 has different text
+  # type and may use unicode.
+  if not isinstance(value, str):
+    return value.encode('utf-8')
+  return value
+
+
+def _MergeMessage(
+    node, source, destination, replace_message, replace_repeated):
+  """Merge all fields specified by a sub-tree from source to destination."""
+  source_descriptor = source.DESCRIPTOR
+  for name in node:
+    child = node[name]
+    field = source_descriptor.fields_by_name[name]
+    if field is None:
+      raise ValueError('Error: Can\'t find field {0} in message {1}.'.format(
+          name, source_descriptor.full_name))
+    if child:
+      # Sub-paths are only allowed for singular message fields.
+      if (field.label == FieldDescriptor.LABEL_REPEATED or
+          field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE):
+        raise ValueError('Error: Field {0} in message {1} is not a singular '
+                         'message field and cannot have sub-fields.'.format(
+                             name, source_descriptor.full_name))
+      _MergeMessage(
+          child, getattr(source, name), getattr(destination, name),
+          replace_message, replace_repeated)
+      continue
+    if field.label == FieldDescriptor.LABEL_REPEATED:
+      if replace_repeated:
+        destination.ClearField(_StrConvert(name))
+      repeated_source = getattr(source, name)
+      repeated_destination = getattr(destination, name)
+      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+        for item in repeated_source:
+          repeated_destination.add().MergeFrom(item)
+      else:
+        repeated_destination.extend(repeated_source)
+    else:
+      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+        if replace_message:
+          destination.ClearField(_StrConvert(name))
+        if source.HasField(name):
+          getattr(destination, name).MergeFrom(getattr(source, name))
+      else:
+        setattr(destination, name, getattr(source, name))
+
+
+def _AddFieldPaths(node, prefix, field_mask):
+  """Adds the field paths descended from node to field_mask."""
+  if not node:
+    field_mask.paths.append(prefix)
+    return
+  for name in sorted(node):
+    if prefix:
+      child_path = prefix + '.' + name
+    else:
+      child_path = name
+    _AddFieldPaths(node[name], child_path, field_mask)
+
+
+_INT_OR_FLOAT = six.integer_types + (float,)
+
+
+def _SetStructValue(struct_value, value):
+  if value is None:
+    struct_value.null_value = 0
+  elif isinstance(value, bool):
+    # Note: this check must come before the number check because in Python
+    # True and False are also considered numbers.
+    struct_value.bool_value = value
+  elif isinstance(value, six.string_types):
+    struct_value.string_value = value
+  elif isinstance(value, _INT_OR_FLOAT):
+    struct_value.number_value = value
+  else:
+    raise ValueError('Unexpected type')
+
+
+def _GetStructValue(struct_value):
+  which = struct_value.WhichOneof('kind')
+  if which == 'struct_value':
+    return struct_value.struct_value
+  elif which == 'null_value':
+    return None
+  elif which == 'number_value':
+    return struct_value.number_value
+  elif which == 'string_value':
+    return struct_value.string_value
+  elif which == 'bool_value':
+    return struct_value.bool_value
+  elif which == 'list_value':
+    return struct_value.list_value
+  elif which is None:
+    raise ValueError('Value not set')
+
+
+class Struct(object):
+  """Class for Struct message type."""
+
+  __slots__ = []
+
+  def __getitem__(self, key):
+    return _GetStructValue(self.fields[key])
+
+  def __setitem__(self, key, value):
+    _SetStructValue(self.fields[key], value)
+
+  def get_or_create_list(self, key):
+    """Returns a list for this key, creating if it didn't exist already."""
+    return self.fields[key].list_value
+
+  def get_or_create_struct(self, key):
+    """Returns a struct for this key, creating if it didn't exist already."""
+    return self.fields[key].struct_value
+
+  # TODO(haberman): allow constructing/merging from dict.
+
+
+class ListValue(object):
+  """Class for ListValue message type."""
+
+  def __len__(self):
+    return len(self.values)
+
+  def append(self, value):
+    _SetStructValue(self.values.add(), value)
+
+  def extend(self, elem_seq):
+    for value in elem_seq:
+      self.append(value)
+
+  def __getitem__(self, index):
+    """Retrieves item by the specified index."""
+    return _GetStructValue(self.values.__getitem__(index))
+
+  def __setitem__(self, index, value):
+    _SetStructValue(self.values.__getitem__(index), value)
+
+  def items(self):
+    for i in range(len(self)):
+      yield self[i]
+
+  def add_struct(self):
+    """Appends and returns a struct value as the next value in the list."""
+    return self.values.add().struct_value
+
+  def add_list(self):
+    """Appends and returns a list value as the next value in the list."""
+    return self.values.add().list_value
+
+
+WKTBASES = {
+    'google.protobuf.Any': Any,
+    'google.protobuf.Duration': Duration,
+    'google.protobuf.FieldMask': FieldMask,
+    'google.protobuf.ListValue': ListValue,
+    'google.protobuf.Struct': Struct,
+    'google.protobuf.Timestamp': Timestamp,
+}
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
new file mode 100644
index 0000000..6acbee2
--- /dev/null
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -0,0 +1,636 @@
+#! /usr/bin/env python
+#
+# 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.
+
+"""Test for google.protobuf.internal.well_known_types."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from datetime import datetime
+
+try:
+  import unittest2 as unittest
+except ImportError:
+  import unittest
+
+from google.protobuf import any_pb2
+from google.protobuf import duration_pb2
+from google.protobuf import field_mask_pb2
+from google.protobuf import struct_pb2
+from google.protobuf import timestamp_pb2
+from google.protobuf import unittest_pb2
+from google.protobuf.internal import any_test_pb2
+from google.protobuf.internal import test_util
+from google.protobuf.internal import well_known_types
+from google.protobuf import descriptor
+from google.protobuf import text_format
+
+
+class TimeUtilTestBase(unittest.TestCase):
+
+  def CheckTimestampConversion(self, message, text):
+    self.assertEqual(text, message.ToJsonString())
+    parsed_message = timestamp_pb2.Timestamp()
+    parsed_message.FromJsonString(text)
+    self.assertEqual(message, parsed_message)
+
+  def CheckDurationConversion(self, message, text):
+    self.assertEqual(text, message.ToJsonString())
+    parsed_message = duration_pb2.Duration()
+    parsed_message.FromJsonString(text)
+    self.assertEqual(message, parsed_message)
+
+
+class TimeUtilTest(TimeUtilTestBase):
+
+  def testTimestampSerializeAndParse(self):
+    message = timestamp_pb2.Timestamp()
+    # Generated output should contain 3, 6, or 9 fractional digits.
+    message.seconds = 0
+    message.nanos = 0
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00Z')
+    message.nanos = 10000000
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.010Z')
+    message.nanos = 10000
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000010Z')
+    message.nanos = 10
+    self.CheckTimestampConversion(message, '1970-01-01T00:00:00.000000010Z')
+    # Test min timestamps.
+    message.seconds = -62135596800
+    message.nanos = 0
+    self.CheckTimestampConversion(message, '0001-01-01T00:00:00Z')
+    # Test max timestamps.
+    message.seconds = 253402300799
+    message.nanos = 999999999
+    self.CheckTimestampConversion(message, '9999-12-31T23:59:59.999999999Z')
+    # Test negative timestamps.
+    message.seconds = -1
+    self.CheckTimestampConversion(message, '1969-12-31T23:59:59.999999999Z')
+
+    # Parsing accepts an fractional digits as long as they fit into nano
+    # precision.
+    message.FromJsonString('1970-01-01T00:00:00.1Z')
+    self.assertEqual(0, message.seconds)
+    self.assertEqual(100000000, message.nanos)
+    # Parsing accpets offsets.
+    message.FromJsonString('1970-01-01T00:00:00-08:00')
+    self.assertEqual(8 * 3600, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+  def testDurationSerializeAndParse(self):
+    message = duration_pb2.Duration()
+    # Generated output should contain 3, 6, or 9 fractional digits.
+    message.seconds = 0
+    message.nanos = 0
+    self.CheckDurationConversion(message, '0s')
+    message.nanos = 10000000
+    self.CheckDurationConversion(message, '0.010s')
+    message.nanos = 10000
+    self.CheckDurationConversion(message, '0.000010s')
+    message.nanos = 10
+    self.CheckDurationConversion(message, '0.000000010s')
+
+    # Test min and max
+    message.seconds = 315576000000
+    message.nanos = 999999999
+    self.CheckDurationConversion(message, '315576000000.999999999s')
+    message.seconds = -315576000000
+    message.nanos = -999999999
+    self.CheckDurationConversion(message, '-315576000000.999999999s')
+
+    # Parsing accepts an fractional digits as long as they fit into nano
+    # precision.
+    message.FromJsonString('0.1s')
+    self.assertEqual(100000000, message.nanos)
+    message.FromJsonString('0.0000001s')
+    self.assertEqual(100, message.nanos)
+
+  def testTimestampIntegerConversion(self):
+    message = timestamp_pb2.Timestamp()
+    message.FromNanoseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.000000001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToNanoseconds())
+
+    message.FromNanoseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999999999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToNanoseconds())
+
+    message.FromMicroseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.000001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMicroseconds())
+
+    message.FromMicroseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMicroseconds())
+
+    message.FromMilliseconds(1)
+    self.assertEqual('1970-01-01T00:00:00.001Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMilliseconds())
+
+    message.FromMilliseconds(-1)
+    self.assertEqual('1969-12-31T23:59:59.999Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMilliseconds())
+
+    message.FromSeconds(1)
+    self.assertEqual('1970-01-01T00:00:01Z',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToSeconds())
+
+    message.FromSeconds(-1)
+    self.assertEqual('1969-12-31T23:59:59Z',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToSeconds())
+
+    message.FromNanoseconds(1999)
+    self.assertEqual(1, message.ToMicroseconds())
+    # For negative values, Timestamp will be rounded down.
+    # For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds
+    # will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than
+    # "1970-01-01T00:00:00Z" (i.e., 0s).
+    message.FromNanoseconds(-1999)
+    self.assertEqual(-2, message.ToMicroseconds())
+
+  def testDurationIntegerConversion(self):
+    message = duration_pb2.Duration()
+    message.FromNanoseconds(1)
+    self.assertEqual('0.000000001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToNanoseconds())
+
+    message.FromNanoseconds(-1)
+    self.assertEqual('-0.000000001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToNanoseconds())
+
+    message.FromMicroseconds(1)
+    self.assertEqual('0.000001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMicroseconds())
+
+    message.FromMicroseconds(-1)
+    self.assertEqual('-0.000001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMicroseconds())
+
+    message.FromMilliseconds(1)
+    self.assertEqual('0.001s',
+                     message.ToJsonString())
+    self.assertEqual(1, message.ToMilliseconds())
+
+    message.FromMilliseconds(-1)
+    self.assertEqual('-0.001s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToMilliseconds())
+
+    message.FromSeconds(1)
+    self.assertEqual('1s', message.ToJsonString())
+    self.assertEqual(1, message.ToSeconds())
+
+    message.FromSeconds(-1)
+    self.assertEqual('-1s',
+                     message.ToJsonString())
+    self.assertEqual(-1, message.ToSeconds())
+
+    # Test truncation behavior.
+    message.FromNanoseconds(1999)
+    self.assertEqual(1, message.ToMicroseconds())
+
+    # For negative values, Duration will be rounded towards 0.
+    message.FromNanoseconds(-1999)
+    self.assertEqual(-1, message.ToMicroseconds())
+
+  def testDatetimeConverison(self):
+    message = timestamp_pb2.Timestamp()
+    dt = datetime(1970, 1, 1)
+    message.FromDatetime(dt)
+    self.assertEqual(dt, message.ToDatetime())
+
+    message.FromMilliseconds(1999)
+    self.assertEqual(datetime(1970, 1, 1, 0, 0, 1, 999000),
+                     message.ToDatetime())
+
+  def testTimedeltaConversion(self):
+    message = duration_pb2.Duration()
+    message.FromNanoseconds(1999999999)
+    td = message.ToTimedelta()
+    self.assertEqual(1, td.seconds)
+    self.assertEqual(999999, td.microseconds)
+
+    message.FromNanoseconds(-1999999999)
+    td = message.ToTimedelta()
+    self.assertEqual(-1, td.days)
+    self.assertEqual(86398, td.seconds)
+    self.assertEqual(1, td.microseconds)
+
+    message.FromMicroseconds(-1)
+    td = message.ToTimedelta()
+    self.assertEqual(-1, td.days)
+    self.assertEqual(86399, td.seconds)
+    self.assertEqual(999999, td.microseconds)
+    converted_message = duration_pb2.Duration()
+    converted_message.FromTimedelta(td)
+    self.assertEqual(message, converted_message)
+
+  def testInvalidTimestamp(self):
+    message = timestamp_pb2.Timestamp()
+    self.assertRaisesRegexp(
+        ValueError,
+        'time data \'10000-01-01T00:00:00\' does not match'
+        ' format \'%Y-%m-%dT%H:%M:%S\'',
+        message.FromJsonString, '10000-01-01T00:00:00.00Z')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'nanos 0123456789012 more than 9 fractional digits.',
+        message.FromJsonString,
+        '1970-01-01T00:00:00.0123456789012Z')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        (r'Invalid timezone offset value: \+08.'),
+        message.FromJsonString,
+        '1972-01-01T01:00:00.01+08',)
+    self.assertRaisesRegexp(
+        ValueError,
+        'year is out of range',
+        message.FromJsonString,
+        '0000-01-01T00:00:00Z')
+    message.seconds = 253402300800
+    self.assertRaisesRegexp(
+        OverflowError,
+        'date value out of range',
+        message.ToJsonString)
+
+  def testInvalidDuration(self):
+    message = duration_pb2.Duration()
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'Duration must end with letter "s": 1.',
+        message.FromJsonString, '1')
+    self.assertRaisesRegexp(
+        well_known_types.ParseError,
+        'Couldn\'t parse duration: 1...2s.',
+        message.FromJsonString, '1...2s')
+
+
+class FieldMaskTest(unittest.TestCase):
+
+  def testStringFormat(self):
+    mask = field_mask_pb2.FieldMask()
+    self.assertEqual('', mask.ToJsonString())
+    mask.paths.append('foo')
+    self.assertEqual('foo', mask.ToJsonString())
+    mask.paths.append('bar')
+    self.assertEqual('foo,bar', mask.ToJsonString())
+
+    mask.FromJsonString('')
+    self.assertEqual('', mask.ToJsonString())
+    mask.FromJsonString('foo')
+    self.assertEqual(['foo'], mask.paths)
+    mask.FromJsonString('foo,bar')
+    self.assertEqual(['foo', 'bar'], mask.paths)
+
+  def testDescriptorToFieldMask(self):
+    mask = field_mask_pb2.FieldMask()
+    msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
+    mask.AllFieldsFromDescriptor(msg_descriptor)
+    self.assertEqual(75, len(mask.paths))
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    for field in msg_descriptor.fields:
+      self.assertTrue(field.name in mask.paths)
+    mask.paths.append('optional_nested_message.bb')
+    self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
+    mask.paths.append('repeated_nested_message.bb')
+    self.assertFalse(mask.IsValidForDescriptor(msg_descriptor))
+
+  def testCanonicalFrom(self):
+    mask = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    # Paths will be sorted.
+    mask.FromJsonString('baz.quz,bar,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString())
+    # Duplicated paths will be removed.
+    mask.FromJsonString('foo,bar,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,foo', out_mask.ToJsonString())
+    # Sub-paths of other paths will be removed.
+    mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString())
+
+    # Test more deeply nested cases.
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar.baz1,foo.bar.baz2',
+                     out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar.baz1,foo.bar.baz2',
+                     out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo.bar', out_mask.ToJsonString())
+    mask.FromJsonString(
+        'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo')
+    out_mask.CanonicalFormFromMask(mask)
+    self.assertEqual('foo', out_mask.ToJsonString())
+
+  def testUnion(self):
+    mask1 = field_mask_pb2.FieldMask()
+    mask2 = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    mask1.FromJsonString('foo,baz')
+    mask2.FromJsonString('bar,quz')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString())
+    # Overlap with duplicated paths.
+    mask1.FromJsonString('foo,baz.bb')
+    mask2.FromJsonString('baz.bb,quz')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString())
+    # Overlap with paths covering some other paths.
+    mask1.FromJsonString('foo.bar.baz,quz')
+    mask2.FromJsonString('foo.bar,bar')
+    out_mask.Union(mask1, mask2)
+    self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString())
+
+  def testIntersect(self):
+    mask1 = field_mask_pb2.FieldMask()
+    mask2 = field_mask_pb2.FieldMask()
+    out_mask = field_mask_pb2.FieldMask()
+    # Test cases without overlapping.
+    mask1.FromJsonString('foo,baz')
+    mask2.FromJsonString('bar,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('', out_mask.ToJsonString())
+    # Overlap with duplicated paths.
+    mask1.FromJsonString('foo,baz.bb')
+    mask2.FromJsonString('baz.bb,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('baz.bb', out_mask.ToJsonString())
+    # Overlap with paths covering some other paths.
+    mask1.FromJsonString('foo.bar.baz,quz')
+    mask2.FromJsonString('foo.bar,bar')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
+    mask1.FromJsonString('foo.bar,bar')
+    mask2.FromJsonString('foo.bar.baz,quz')
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
+
+  def testMergeMessage(self):
+    # Test merge one field.
+    src = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(src)
+    for field in src.DESCRIPTOR.fields:
+      if field.containing_oneof:
+        continue
+      field_name = field.name
+      dst = unittest_pb2.TestAllTypes()
+      # Only set one path to mask.
+      mask = field_mask_pb2.FieldMask()
+      mask.paths.append(field_name)
+      mask.MergeMessage(src, dst)
+      # The expected result message.
+      msg = unittest_pb2.TestAllTypes()
+      if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        repeated_src = getattr(src, field_name)
+        repeated_msg = getattr(msg, field_name)
+        if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          for item in repeated_src:
+            repeated_msg.add().CopyFrom(item)
+        else:
+          repeated_msg.extend(repeated_src)
+      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        getattr(msg, field_name).CopyFrom(getattr(src, field_name))
+      else:
+        setattr(msg, field_name, getattr(src, field_name))
+      # Only field specified in mask is merged.
+      self.assertEqual(msg, dst)
+
+    # Test merge nested fields.
+    nested_src = unittest_pb2.NestedTestAllTypes()
+    nested_dst = unittest_pb2.NestedTestAllTypes()
+    nested_src.child.payload.optional_int32 = 1234
+    nested_src.child.child.payload.optional_int32 = 5678
+    mask = field_mask_pb2.FieldMask()
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(0, nested_dst.child.child.payload.optional_int32)
+
+    mask.FromJsonString('child.child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    nested_dst.Clear()
+    mask.FromJsonString('child.child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(0, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    nested_dst.Clear()
+    mask.FromJsonString('child')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(5678, nested_dst.child.child.payload.optional_int32)
+
+    # Test MergeOptions.
+    nested_dst.Clear()
+    nested_dst.child.payload.optional_int64 = 4321
+    # Message fields will be merged by default.
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(4321, nested_dst.child.payload.optional_int64)
+    # Change the behavior to replace message fields.
+    mask.FromJsonString('child.payload')
+    mask.MergeMessage(nested_src, nested_dst, True, False)
+    self.assertEqual(1234, nested_dst.child.payload.optional_int32)
+    self.assertEqual(0, nested_dst.child.payload.optional_int64)
+
+    # By default, fields missing in source are not cleared in destination.
+    nested_dst.payload.optional_int32 = 1234
+    self.assertTrue(nested_dst.HasField('payload'))
+    mask.FromJsonString('payload')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertTrue(nested_dst.HasField('payload'))
+    # But they are cleared when replacing message fields.
+    nested_dst.Clear()
+    nested_dst.payload.optional_int32 = 1234
+    mask.FromJsonString('payload')
+    mask.MergeMessage(nested_src, nested_dst, True, False)
+    self.assertFalse(nested_dst.HasField('payload'))
+
+    nested_src.payload.repeated_int32.append(1234)
+    nested_dst.payload.repeated_int32.append(5678)
+    # Repeated fields will be appended by default.
+    mask.FromJsonString('payload.repeated_int32')
+    mask.MergeMessage(nested_src, nested_dst)
+    self.assertEqual(2, len(nested_dst.payload.repeated_int32))
+    self.assertEqual(5678, nested_dst.payload.repeated_int32[0])
+    self.assertEqual(1234, nested_dst.payload.repeated_int32[1])
+    # Change the behavior to replace repeated fields.
+    mask.FromJsonString('payload.repeated_int32')
+    mask.MergeMessage(nested_src, nested_dst, False, True)
+    self.assertEqual(1, len(nested_dst.payload.repeated_int32))
+    self.assertEqual(1234, nested_dst.payload.repeated_int32[0])
+
+
+class StructTest(unittest.TestCase):
+
+  def testStruct(self):
+    struct = struct_pb2.Struct()
+    struct_class = struct.__class__
+
+    struct['key1'] = 5
+    struct['key2'] = 'abc'
+    struct['key3'] = True
+    struct.get_or_create_struct('key4')['subkey'] = 11.0
+    struct_list = struct.get_or_create_list('key5')
+    struct_list.extend([6, 'seven', True, False, None])
+    struct_list.add_struct()['subkey2'] = 9
+
+    self.assertTrue(isinstance(struct, well_known_types.Struct))
+    self.assertEquals(5, struct['key1'])
+    self.assertEquals('abc', struct['key2'])
+    self.assertIs(True, struct['key3'])
+    self.assertEquals(11, struct['key4']['subkey'])
+    inner_struct = struct_class()
+    inner_struct['subkey2'] = 9
+    self.assertEquals([6, 'seven', True, False, None, inner_struct],
+                      list(struct['key5'].items()))
+
+    serialized = struct.SerializeToString()
+
+    struct2 = struct_pb2.Struct()
+    struct2.ParseFromString(serialized)
+
+    self.assertEquals(struct, struct2)
+
+    self.assertTrue(isinstance(struct2, well_known_types.Struct))
+    self.assertEquals(5, struct2['key1'])
+    self.assertEquals('abc', struct2['key2'])
+    self.assertIs(True, struct2['key3'])
+    self.assertEquals(11, struct2['key4']['subkey'])
+    self.assertEquals([6, 'seven', True, False, None, inner_struct],
+                      list(struct2['key5'].items()))
+
+    struct_list = struct2['key5']
+    self.assertEquals(6, struct_list[0])
+    self.assertEquals('seven', struct_list[1])
+    self.assertEquals(True, struct_list[2])
+    self.assertEquals(False, struct_list[3])
+    self.assertEquals(None, struct_list[4])
+    self.assertEquals(inner_struct, struct_list[5])
+
+    struct_list[1] = 7
+    self.assertEquals(7, struct_list[1])
+
+    struct_list.add_list().extend([1, 'two', True, False, None])
+    self.assertEquals([1, 'two', True, False, None],
+                      list(struct_list[6].items()))
+
+    text_serialized = str(struct)
+    struct3 = struct_pb2.Struct()
+    text_format.Merge(text_serialized, struct3)
+    self.assertEquals(struct, struct3)
+
+    struct.get_or_create_struct('key3')['replace'] = 12
+    self.assertEquals(12, struct['key3']['replace'])
+
+
+class AnyTest(unittest.TestCase):
+
+  def testAnyMessage(self):
+    # Creates and sets message.
+    msg = any_test_pb2.TestAny()
+    msg_descriptor = msg.DESCRIPTOR
+    all_types = unittest_pb2.TestAllTypes()
+    all_descriptor = all_types.DESCRIPTOR
+    all_types.repeated_string.append(u'\u00fc\ua71f')
+    # Packs to Any.
+    msg.value.Pack(all_types)
+    self.assertEqual(msg.value.type_url,
+                     'type.googleapis.com/%s' % all_descriptor.full_name)
+    self.assertEqual(msg.value.value,
+                     all_types.SerializeToString())
+    # Tests Is() method.
+    self.assertTrue(msg.value.Is(all_descriptor))
+    self.assertFalse(msg.value.Is(msg_descriptor))
+    # Unpacks Any.
+    unpacked_message = unittest_pb2.TestAllTypes()
+    self.assertTrue(msg.value.Unpack(unpacked_message))
+    self.assertEqual(all_types, unpacked_message)
+    # Unpacks to different type.
+    self.assertFalse(msg.value.Unpack(msg))
+    # Only Any messages have Pack method.
+    try:
+      msg.Pack(all_types)
+    except AttributeError:
+      pass
+    else:
+      raise AttributeError('%s should not have Pack method.' %
+                           msg_descriptor.full_name)
+
+  def testPackWithCustomTypeUrl(self):
+    submessage = any_test_pb2.TestAny()
+    submessage.int_value = 12345
+    msg = any_pb2.Any()
+    # Pack with a custom type URL prefix.
+    msg.Pack(submessage, 'type.myservice.com')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with a custom type URL prefix ending with '/'.
+    msg.Pack(submessage, 'type.myservice.com/')
+    self.assertEqual(msg.type_url,
+                     'type.myservice.com/%s' % submessage.DESCRIPTOR.full_name)
+    # Pack with an empty type URL prefix.
+    msg.Pack(submessage, '')
+    self.assertEqual(msg.type_url,
+                     '/%s' % submessage.DESCRIPTOR.full_name)
+    # Test unpacking the type.
+    unpacked_message = any_test_pb2.TestAny()
+    self.assertTrue(msg.Unpack(unpacked_message))
+    self.assertEqual(submessage, unpacked_message)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
new file mode 100644
index 0000000..23382bd
--- /dev/null
+++ b/python/google/protobuf/json_format.py
@@ -0,0 +1,645 @@
+# 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.
+
+"""Contains routines for printing protocol messages in JSON format.
+
+Simple usage example:
+
+  # Create a proto object and serialize it to a json format string.
+  message = my_proto_pb2.MyMessage(foo='bar')
+  json_string = json_format.MessageToJson(message)
+
+  # Parse a json format string to proto object.
+  message = json_format.Parse(json_string, my_proto_pb2.MyMessage())
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import base64
+import json
+import math
+import six
+import sys
+
+from google.protobuf import descriptor
+from google.protobuf import symbol_database
+
+_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
+_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
+                        descriptor.FieldDescriptor.CPPTYPE_UINT32,
+                        descriptor.FieldDescriptor.CPPTYPE_INT64,
+                        descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64,
+                          descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
+                          descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
+_INFINITY = 'Infinity'
+_NEG_INFINITY = '-Infinity'
+_NAN = 'NaN'
+
+
+class Error(Exception):
+  """Top-level module error for json_format."""
+
+
+class SerializeToJsonError(Error):
+  """Thrown if serialization to JSON fails."""
+
+
+class ParseError(Error):
+  """Thrown in case of parsing error."""
+
+
+def MessageToJson(message, including_default_value_fields=False):
+  """Converts protobuf message to JSON format.
+
+  Args:
+    message: The protocol buffers message instance to serialize.
+    including_default_value_fields: If True, singular primitive fields,
+        repeated fields, and map fields will always be serialized.  If
+        False, only serialize non-empty fields.  Singular message fields
+        and oneof fields are not affected by this option.
+
+  Returns:
+    A string containing the JSON formatted protocol buffer message.
+  """
+  js = _MessageToJsonObject(message, including_default_value_fields)
+  return json.dumps(js, indent=2)
+
+
+def _MessageToJsonObject(message, including_default_value_fields):
+  """Converts message to an object according to Proto3 JSON Specification."""
+  message_descriptor = message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    return _WrapperMessageToJsonObject(message)
+  if full_name in _WKTJSONMETHODS:
+    return _WKTJSONMETHODS[full_name][0](
+        message, including_default_value_fields)
+  js = {}
+  return _RegularMessageToJsonObject(
+      message, js, including_default_value_fields)
+
+
+def _IsMapEntry(field):
+  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
+def _RegularMessageToJsonObject(message, js, including_default_value_fields):
+  """Converts normal message according to Proto3 JSON Specification."""
+  fields = message.ListFields()
+  include_default = including_default_value_fields
+
+  try:
+    for field, value in fields:
+      name = field.camelcase_name
+      if _IsMapEntry(field):
+        # Convert a map field.
+        v_field = field.message_type.fields_by_name['value']
+        js_map = {}
+        for key in value:
+          if isinstance(key, bool):
+            if key:
+              recorded_key = 'true'
+            else:
+              recorded_key = 'false'
+          else:
+            recorded_key = key
+          js_map[recorded_key] = _FieldToJsonObject(
+              v_field, value[key], including_default_value_fields)
+        js[name] = js_map
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        # Convert a repeated field.
+        js[name] = [_FieldToJsonObject(field, k, include_default)
+                    for k in value]
+      else:
+        js[name] = _FieldToJsonObject(field, value, include_default)
+
+    # Serialize default value if including_default_value_fields is True.
+    if including_default_value_fields:
+      message_descriptor = message.DESCRIPTOR
+      for field in message_descriptor.fields:
+        # Singular message fields and oneof fields will not be affected.
+        if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
+             field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
+            field.containing_oneof):
+          continue
+        name = field.camelcase_name
+        if name in js:
+          # Skip the field which has been serailized already.
+          continue
+        if _IsMapEntry(field):
+          js[name] = {}
+        elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          js[name] = []
+        else:
+          js[name] = _FieldToJsonObject(field, field.default_value)
+
+  except ValueError as e:
+    raise SerializeToJsonError(
+        'Failed to serialize {0} field: {1}.'.format(field.name, e))
+
+  return js
+
+
+def _FieldToJsonObject(
+    field, value, including_default_value_fields=False):
+  """Converts field value according to Proto3 JSON Specification."""
+  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+    return _MessageToJsonObject(value, including_default_value_fields)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+    enum_value = field.enum_type.values_by_number.get(value, None)
+    if enum_value is not None:
+      return enum_value.name
+    else:
+      raise SerializeToJsonError('Enum field contains an integer value '
+                                 'which can not mapped to an enum value.')
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      # Use base64 Data encoding for bytes
+      return base64.b64encode(value).decode('utf-8')
+    else:
+      return value
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+    return bool(value)
+  elif field.cpp_type in _INT64_TYPES:
+    return str(value)
+  elif field.cpp_type in _FLOAT_TYPES:
+    if math.isinf(value):
+      if value < 0.0:
+        return _NEG_INFINITY
+      else:
+        return _INFINITY
+    if math.isnan(value):
+      return _NAN
+  return value
+
+
+def _AnyMessageToJsonObject(message, including_default):
+  """Converts Any message according to Proto3 JSON Specification."""
+  if not message.ListFields():
+    return {}
+  js = {}
+  type_url = message.type_url
+  js['@type'] = type_url
+  sub_message = _CreateMessageFromTypeUrl(type_url)
+  sub_message.ParseFromString(message.value)
+  message_descriptor = sub_message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    js['value'] = _WrapperMessageToJsonObject(sub_message)
+    return js
+  if full_name in _WKTJSONMETHODS:
+    js['value'] = _WKTJSONMETHODS[full_name][0](sub_message, including_default)
+    return js
+  return _RegularMessageToJsonObject(sub_message, js, including_default)
+
+
+def _CreateMessageFromTypeUrl(type_url):
+  # TODO(jieluo): Should add a way that users can register the type resolver
+  # instead of the default one.
+  db = symbol_database.Default()
+  type_name = type_url.split('/')[-1]
+  try:
+    message_descriptor = db.pool.FindMessageTypeByName(type_name)
+  except KeyError:
+    raise TypeError(
+        'Can not find message descriptor by type_url: {0}.'.format(type_url))
+  message_class = db.GetPrototype(message_descriptor)
+  return message_class()
+
+
+def _GenericMessageToJsonObject(message, unused_including_default):
+  """Converts message by ToJsonString according to Proto3 JSON Specification."""
+  # Duration, Timestamp and FieldMask have ToJsonString method to do the
+  # convert. Users can also call the method directly.
+  return message.ToJsonString()
+
+
+def _ValueMessageToJsonObject(message, unused_including_default=False):
+  """Converts Value message according to Proto3 JSON Specification."""
+  which = message.WhichOneof('kind')
+  # If the Value message is not set treat as null_value when serialize
+  # to JSON. The parse back result will be different from original message.
+  if which is None or which == 'null_value':
+    return None
+  if which == 'list_value':
+    return _ListValueMessageToJsonObject(message.list_value)
+  if which == 'struct_value':
+    value = message.struct_value
+  else:
+    value = getattr(message, which)
+  oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
+  return _FieldToJsonObject(oneof_descriptor, value)
+
+
+def _ListValueMessageToJsonObject(message, unused_including_default=False):
+  """Converts ListValue message according to Proto3 JSON Specification."""
+  return [_ValueMessageToJsonObject(value)
+          for value in message.values]
+
+
+def _StructMessageToJsonObject(message, unused_including_default=False):
+  """Converts Struct message according to Proto3 JSON Specification."""
+  fields = message.fields
+  js = {}
+  for key in fields.keys():
+    js[key] = _ValueMessageToJsonObject(fields[key])
+  return js
+
+
+def _IsWrapperMessage(message_descriptor):
+  return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
+
+
+def _WrapperMessageToJsonObject(message):
+  return _FieldToJsonObject(
+      message.DESCRIPTOR.fields_by_name['value'], message.value)
+
+
+def _DuplicateChecker(js):
+  result = {}
+  for name, value in js:
+    if name in result:
+      raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name))
+    result[name] = value
+  return result
+
+
+def Parse(text, message):
+  """Parses a JSON representation of a protocol message into a message.
+
+  Args:
+    text: Message JSON representation.
+    message: A protocol beffer message to merge into.
+
+  Returns:
+    The same message passed as argument.
+
+  Raises::
+    ParseError: On JSON parsing problems.
+  """
+  if not isinstance(text, six.text_type): text = text.decode('utf-8')
+  try:
+    if sys.version_info < (2, 7):
+      # object_pair_hook is not supported before python2.7
+      js = json.loads(text)
+    else:
+      js = json.loads(text, object_pairs_hook=_DuplicateChecker)
+  except ValueError as e:
+    raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
+  _ConvertMessage(js, message)
+  return message
+
+
+def _ConvertFieldValuePair(js, message):
+  """Convert field value pairs into regular message.
+
+  Args:
+    js: A JSON object to convert the field value pairs.
+    message: A regular protocol message to record the data.
+
+  Raises:
+    ParseError: In case of problems converting.
+  """
+  names = []
+  message_descriptor = message.DESCRIPTOR
+  for name in js:
+    try:
+      field = message_descriptor.fields_by_camelcase_name.get(name, None)
+      if not field:
+        raise ParseError(
+            'Message type "{0}" has no field named "{1}".'.format(
+                message_descriptor.full_name, name))
+      if name in names:
+        raise ParseError(
+            'Message type "{0}" should not have multiple "{1}" fields.'.format(
+                message.DESCRIPTOR.full_name, name))
+      names.append(name)
+      # Check no other oneof field is parsed.
+      if field.containing_oneof is not None:
+        oneof_name = field.containing_oneof.name
+        if oneof_name in names:
+          raise ParseError('Message type "{0}" should not have multiple "{1}" '
+                           'oneof fields.'.format(
+                               message.DESCRIPTOR.full_name, oneof_name))
+        names.append(oneof_name)
+
+      value = js[name]
+      if value is None:
+        message.ClearField(field.name)
+        continue
+
+      # Parse field value.
+      if _IsMapEntry(field):
+        message.ClearField(field.name)
+        _ConvertMapFieldValue(value, message, field)
+      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        message.ClearField(field.name)
+        if not isinstance(value, list):
+          raise ParseError('repeated field {0} must be in [] which is '
+                           '{1}.'.format(name, value))
+        if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          # Repeated message field.
+          for item in value:
+            sub_message = getattr(message, field.name).add()
+            # None is a null_value in Value.
+            if (item is None and
+                sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
+              raise ParseError('null is not allowed to be used as an element'
+                               ' in a repeated field.')
+            _ConvertMessage(item, sub_message)
+        else:
+          # Repeated scalar field.
+          for item in value:
+            if item is None:
+              raise ParseError('null is not allowed to be used as an element'
+                               ' in a repeated field.')
+            getattr(message, field.name).append(
+                _ConvertScalarFieldValue(item, field))
+      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        sub_message = getattr(message, field.name)
+        _ConvertMessage(value, sub_message)
+      else:
+        setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+    except ParseError as e:
+      if field and field.containing_oneof is None:
+        raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+      else:
+        raise ParseError(str(e))
+    except ValueError as e:
+      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+    except TypeError as e:
+      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+
+
+def _ConvertMessage(value, message):
+  """Convert a JSON object into a message.
+
+  Args:
+    value: A JSON object.
+    message: A WKT or regular protocol message to record the data.
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  message_descriptor = message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    _ConvertWrapperMessage(value, message)
+  elif full_name in _WKTJSONMETHODS:
+    _WKTJSONMETHODS[full_name][1](value, message)
+  else:
+    _ConvertFieldValuePair(value, message)
+
+
+def _ConvertAnyMessage(value, message):
+  """Convert a JSON representation into Any message."""
+  if isinstance(value, dict) and not value:
+    return
+  try:
+    type_url = value['@type']
+  except KeyError:
+    raise ParseError('@type is missing when parsing any message.')
+
+  sub_message = _CreateMessageFromTypeUrl(type_url)
+  message_descriptor = sub_message.DESCRIPTOR
+  full_name = message_descriptor.full_name
+  if _IsWrapperMessage(message_descriptor):
+    _ConvertWrapperMessage(value['value'], sub_message)
+  elif full_name in _WKTJSONMETHODS:
+    _WKTJSONMETHODS[full_name][1](value['value'], sub_message)
+  else:
+    del value['@type']
+    _ConvertFieldValuePair(value, sub_message)
+  # Sets Any message
+  message.value = sub_message.SerializeToString()
+  message.type_url = type_url
+
+
+def _ConvertGenericMessage(value, message):
+  """Convert a JSON representation into message with FromJsonString."""
+  # Durantion, Timestamp, FieldMask have FromJsonString method to do the
+  # convert. Users can also call the method directly.
+  message.FromJsonString(value)
+
+
+_INT_OR_FLOAT = six.integer_types + (float,)
+
+
+def _ConvertValueMessage(value, message):
+  """Convert a JSON representation into Value message."""
+  if isinstance(value, dict):
+    _ConvertStructMessage(value, message.struct_value)
+  elif isinstance(value, list):
+    _ConvertListValueMessage(value, message.list_value)
+  elif value is None:
+    message.null_value = 0
+  elif isinstance(value, bool):
+    message.bool_value = value
+  elif isinstance(value, six.string_types):
+    message.string_value = value
+  elif isinstance(value, _INT_OR_FLOAT):
+    message.number_value = value
+  else:
+    raise ParseError('Unexpected type for Value message.')
+
+
+def _ConvertListValueMessage(value, message):
+  """Convert a JSON representation into ListValue message."""
+  if not isinstance(value, list):
+    raise ParseError(
+        'ListValue must be in [] which is {0}.'.format(value))
+  message.ClearField('values')
+  for item in value:
+    _ConvertValueMessage(item, message.values.add())
+
+
+def _ConvertStructMessage(value, message):
+  """Convert a JSON representation into Struct message."""
+  if not isinstance(value, dict):
+    raise ParseError(
+        'Struct must be in a dict which is {0}.'.format(value))
+  for key in value:
+    _ConvertValueMessage(value[key], message.fields[key])
+  return
+
+
+def _ConvertWrapperMessage(value, message):
+  """Convert a JSON representation into Wrapper message."""
+  field = message.DESCRIPTOR.fields_by_name['value']
+  setattr(message, 'value', _ConvertScalarFieldValue(value, field))
+
+
+def _ConvertMapFieldValue(value, message, field):
+  """Convert map field value for a message map field.
+
+  Args:
+    value: A JSON object to convert the map field value.
+    message: A protocol message to record the converted data.
+    field: The descriptor of the map field to be converted.
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  if not isinstance(value, dict):
+    raise ParseError(
+        'Map field {0} must be in a dict which is {1}.'.format(
+            field.name, value))
+  key_field = field.message_type.fields_by_name['key']
+  value_field = field.message_type.fields_by_name['value']
+  for key in value:
+    key_value = _ConvertScalarFieldValue(key, key_field, True)
+    if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      _ConvertMessage(value[key], getattr(message, field.name)[key_value])
+    else:
+      getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+          value[key], value_field)
+
+
+def _ConvertScalarFieldValue(value, field, require_str=False):
+  """Convert a single scalar field value.
+
+  Args:
+    value: A scalar value to convert the scalar field value.
+    field: The descriptor of the field to convert.
+    require_str: If True, the field value must be a str.
+
+  Returns:
+    The converted scalar field value
+
+  Raises:
+    ParseError: In case of convert problems.
+  """
+  if field.cpp_type in _INT_TYPES:
+    return _ConvertInteger(value)
+  elif field.cpp_type in _FLOAT_TYPES:
+    return _ConvertFloat(value)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+    return _ConvertBool(value, require_str)
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+      return base64.b64decode(value)
+    else:
+      return value
+  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+    # Convert an enum value.
+    enum_value = field.enum_type.values_by_name.get(value, None)
+    if enum_value is None:
+      raise ParseError(
+          'Enum value must be a string literal with double quotes. '
+          'Type "{0}" has no value named {1}.'.format(
+              field.enum_type.full_name, value))
+    return enum_value.number
+
+
+def _ConvertInteger(value):
+  """Convert an integer.
+
+  Args:
+    value: A scalar value to convert.
+
+  Returns:
+    The integer value.
+
+  Raises:
+    ParseError: If an integer couldn't be consumed.
+  """
+  if isinstance(value, float):
+    raise ParseError('Couldn\'t parse integer: {0}.'.format(value))
+
+  if isinstance(value, six.text_type) and value.find(' ') != -1:
+    raise ParseError('Couldn\'t parse integer: "{0}".'.format(value))
+
+  return int(value)
+
+
+def _ConvertFloat(value):
+  """Convert an floating point number."""
+  if value == 'nan':
+    raise ParseError('Couldn\'t parse float "nan", use "NaN" instead.')
+  try:
+    # Assume Python compatible syntax.
+    return float(value)
+  except ValueError:
+    # Check alternative spellings.
+    if value == _NEG_INFINITY:
+      return float('-inf')
+    elif value == _INFINITY:
+      return float('inf')
+    elif value == _NAN:
+      return float('nan')
+    else:
+      raise ParseError('Couldn\'t parse float: {0}.'.format(value))
+
+
+def _ConvertBool(value, require_str):
+  """Convert a boolean value.
+
+  Args:
+    value: A scalar value to convert.
+    require_str: If True, value must be a str.
+
+  Returns:
+    The bool parsed.
+
+  Raises:
+    ParseError: If a boolean value couldn't be consumed.
+  """
+  if require_str:
+    if value == 'true':
+      return True
+    elif value == 'false':
+      return False
+    else:
+      raise ParseError('Expected "true" or "false", not {0}.'.format(value))
+
+  if not isinstance(value, bool):
+    raise ParseError('Expected true or false without quotes.')
+  return value
+
+_WKTJSONMETHODS = {
+    'google.protobuf.Any': [_AnyMessageToJsonObject,
+                            _ConvertAnyMessage],
+    'google.protobuf.Duration': [_GenericMessageToJsonObject,
+                                 _ConvertGenericMessage],
+    'google.protobuf.FieldMask': [_GenericMessageToJsonObject,
+                                  _ConvertGenericMessage],
+    'google.protobuf.ListValue': [_ListValueMessageToJsonObject,
+                                  _ConvertListValueMessage],
+    'google.protobuf.Struct': [_StructMessageToJsonObject,
+                               _ConvertStructMessage],
+    'google.protobuf.Timestamp': [_GenericMessageToJsonObject,
+                                  _ConvertGenericMessage],
+    'google.protobuf.Value': [_ValueMessageToJsonObject,
+                              _ConvertValueMessage]
+}
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
index 36062a5..1b059d1 100644
--- a/python/google/protobuf/message_factory.py
+++ b/python/google/protobuf/message_factory.py
@@ -28,8 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2012 Google Inc. All Rights Reserved.
-
 """Provides a factory class for generating dynamic messages.
 
 The easiest way to use this class is if you have access to the FileDescriptor
@@ -41,7 +39,6 @@
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
-from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
 from google.protobuf import message
 from google.protobuf import reflection
@@ -52,8 +49,7 @@
 
   def __init__(self, pool=None):
     """Initializes a new factory."""
-    self.pool = (pool or descriptor_pool.DescriptorPool(
-        descriptor_database.DescriptorDatabase()))
+    self.pool = pool or descriptor_pool.DescriptorPool()
 
     # local cache of all classes built from protobuf descriptors
     self._classes = {}
diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py
index 700e3c2..736caed 100644
--- a/python/google/protobuf/proto_builder.py
+++ b/python/google/protobuf/proto_builder.py
@@ -48,7 +48,7 @@
     factory: a MessageFactory instance.
     full_name: str, the fully qualified name of the proto type.
   Returns:
-    a class, for the type identified by full_name.
+    A class, for the type identified by full_name.
   Raises:
     KeyError, if the proto is not found in the factory's descriptor pool.
   """
@@ -57,7 +57,7 @@
   return proto_cls
 
 
-def MakeSimpleProtoClass(fields, full_name, pool=None):
+def MakeSimpleProtoClass(fields, full_name=None, pool=None):
   """Create a Protobuf class whose fields are basic types.
 
   Note: this doesn't validate field names!
@@ -66,18 +66,20 @@
     fields: dict of {name: field_type} mappings for each field in the proto. If
         this is an OrderedDict the order will be maintained, otherwise the
         fields will be sorted by name.
-    full_name: str, the fully-qualified name of the proto type.
+    full_name: optional str, the fully-qualified name of the proto type.
     pool: optional DescriptorPool instance.
   Returns:
     a class, the new protobuf class with a FileDescriptor.
   """
   factory = message_factory.MessageFactory(pool=pool)
-  try:
-    proto_cls = _GetMessageFromFactory(factory, full_name)
-    return proto_cls
-  except KeyError:
-    # The factory's DescriptorPool doesn't know about this class yet.
-    pass
+
+  if full_name is not None:
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
 
   # Get a list of (name, field_type) tuples from the fields dict. If fields was
   # an OrderedDict we keep the order, but otherwise we sort the field to ensure
@@ -94,6 +96,25 @@
     fields_hash.update(str(f_type).encode('utf-8'))
   proto_file_name = fields_hash.hexdigest() + '.proto'
 
+  # If the proto is anonymous, use the same hash to name it.
+  if full_name is None:
+    full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' +
+                 fields_hash.hexdigest())
+    try:
+      proto_cls = _GetMessageFromFactory(factory, full_name)
+      return proto_cls
+    except KeyError:
+      # The factory's DescriptorPool doesn't know about this class yet.
+      pass
+
+  # This is the first time we see this proto: add a new descriptor to the pool.
+  factory.pool.Add(
+      _MakeFileDescriptorProto(proto_file_name, full_name, field_items))
+  return _GetMessageFromFactory(factory, full_name)
+
+
+def _MakeFileDescriptorProto(proto_file_name, full_name, field_items):
+  """Populate FileDescriptorProto for MessageFactory's DescriptorPool."""
   package, name = full_name.rsplit('.', 1)
   file_proto = descriptor_pb2.FileDescriptorProto()
   file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name)
@@ -106,6 +127,4 @@
     field_proto.number = f_number
     field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
     field_proto.type = f_type
-
-  factory.pool.Add(file_proto)
-  return _GetMessageFromFactory(factory, full_name)
+  return file_proto
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 3806643..a875a7b 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -203,6 +203,14 @@
   PyObject* message_class(cdescriptor_pool::GetMessageClass(
       pool, message_type));
   if (message_class == NULL) {
+    // The Options message was not found in the current DescriptorPool.
+    // In this case, there cannot be extensions to these options, and we can
+    // try to use the basic pool instead.
+    PyErr_Clear();
+    message_class = cdescriptor_pool::GetMessageClass(
+      GetDefaultDescriptorPool(), message_type);
+  }
+  if (message_class == NULL) {
     PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
                  message_type->full_name().c_str());
     return NULL;
@@ -211,6 +219,12 @@
   if (value == NULL) {
     return NULL;
   }
+  if (!PyObject_TypeCheck(value.get(), &CMessage_Type)) {
+      PyErr_Format(PyExc_TypeError, "Invalid class for %s: %s",
+                   message_type->full_name().c_str(),
+                   Py_TYPE(value.get())->tp_name);
+      return NULL;
+  }
   CMessage* cmsg = reinterpret_cast<CMessage*>(value.get());
 
   const Reflection* reflection = options.GetReflection();
@@ -223,8 +237,7 @@
     options.SerializeToString(&serialized);
     io::CodedInputStream input(
         reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
-    input.SetExtensionRegistry(pool->pool,
-                               GetDescriptorPool()->message_factory);
+    input.SetExtensionRegistry(pool->pool, pool->message_factory);
     bool success = cmsg->message->MergePartialFromCodedStream(&input);
     if (!success) {
       PyErr_Format(PyExc_ValueError, "Error parsing Options message");
@@ -233,7 +246,7 @@
   }
 
   // Cache the result.
-  Py_INCREF(value);
+  Py_INCREF(value.get());
   (*pool->descriptor_options)[descriptor] = value.get();
 
   return value.release();
@@ -328,7 +341,8 @@
   PyDescriptorPool* pool = GetDescriptorPool_FromPool(
       GetFileDescriptor(descriptor)->pool());
   if (pool == NULL) {
-    Py_DECREF(py_descriptor);
+    // Don't DECREF, the object is not fully initialized.
+    PyObject_Del(py_descriptor);
     return NULL;
   }
   Py_INCREF(pool);
@@ -414,8 +428,14 @@
 }
 
 static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
+  // Retuns the canonical class for the given descriptor.
+  // This is the class that was registered with the primary descriptor pool
+  // which contains this descriptor.
+  // This might not be the one you expect! For example the returned object does
+  // not know about extensions defined in a custom pool.
   PyObject* concrete_class(cdescriptor_pool::GetMessageClass(
-      GetDescriptorPool(), _GetDescriptor(self)));
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()),
+      _GetDescriptor(self)));
   Py_XINCREF(concrete_class);
   return concrete_class;
 }
@@ -424,6 +444,11 @@
   return NewMessageFieldsByName(_GetDescriptor(self));
 }
 
+static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self,
+                                          void *closure) {
+  return NewMessageFieldsByCamelcaseName(_GetDescriptor(self));
+}
+
 static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
   return NewMessageFieldsByNumber(_GetDescriptor(self));
 }
@@ -564,6 +589,8 @@
 
   { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"},
   { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"},
+  { "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL,
+    "Fields by camelCase name"},
   { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"},
   { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"},
   { "nested_types_by_name", (getter)GetNestedTypesByName, NULL,
@@ -662,6 +689,10 @@
   return PyString_FromCppString(_GetDescriptor(self)->name());
 }
 
+static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->camelcase_name());
+}
+
 static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
   return PyInt_FromLong(_GetDescriptor(self)->type());
 }
@@ -850,6 +881,7 @@
 static PyGetSetDef Getters[] = {
   { "full_name", (getter)GetFullName, NULL, "Full name"},
   { "name", (getter)GetName, NULL, "Unqualified name"},
+  { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
   { "type", (getter)GetType, NULL, "C++ Type"},
   { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
   { "label", (getter)GetLabel, NULL, "Label"},
@@ -1070,6 +1102,15 @@
       &PyEnumDescriptor_Type, enum_descriptor, NULL);
 }
 
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const EnumDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
 namespace enumvalue_descriptor {
 
 // Unchecked accessor to the C++ pointer.
@@ -1187,6 +1228,13 @@
   descriptor::Dealloc(&self->base);
 }
 
+static PyObject* GetPool(PyFileDescriptor *self, void *closure) {
+  PyObject* pool = reinterpret_cast<PyObject*>(
+      GetDescriptorPool_FromPool(_GetDescriptor(self)->pool()));
+  Py_XINCREF(pool);
+  return pool;
+}
+
 static PyObject* GetName(PyFileDescriptor *self, void *closure) {
   return PyString_FromCppString(_GetDescriptor(self)->name());
 }
@@ -1266,6 +1314,7 @@
 }
 
 static PyGetSetDef Getters[] = {
+  { "pool", (getter)GetPool, NULL, "pool"},
   { "name", (getter)GetName, NULL, "name"},
   { "package", (getter)GetPackage, NULL, "package"},
   { "serialized_pb", (getter)GetSerializedPb},
@@ -1328,8 +1377,8 @@
   0,                                    // tp_descr_set
   0,                                    // tp_dictoffset
   0,                                    // tp_init
-  PyType_GenericAlloc,                  // tp_alloc
-  PyType_GenericNew,                    // tp_new
+  0,                                    // tp_alloc
+  0,                                    // tp_new
   PyObject_Del,                         // tp_free
 };
 
@@ -1359,6 +1408,15 @@
   return py_descriptor;
 }
 
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
+  if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
+    PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
+    return NULL;
+  }
+  return reinterpret_cast<const FileDescriptor*>(
+      reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
+}
+
 namespace oneof_descriptor {
 
 // Unchecked accessor to the C++ pointer.
@@ -1454,7 +1512,8 @@
     if (obj == NULL) {
       return false;
     }
-    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj) < 0) {
+    if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) <
+        0) {
       return false;
     }
   }
@@ -1463,7 +1522,7 @@
 
 static bool AddIntConstant(PyTypeObject *type, const char* name, int value) {
   ScopedPyObjectPtr obj(PyInt_FromLong(value));
-  if (PyDict_SetItemString(type->tp_dict, name, obj) < 0) {
+  if (PyDict_SetItemString(type->tp_dict, name, obj.get()) < 0) {
     return false;
   }
   return true;
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index b255040..eb99df1 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -72,6 +72,8 @@
 // exception set.
 const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj);
 const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj);
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj);
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj);
 
 // Returns the raw C++ pointer.
 const void* PyDescriptor_AsVoidPtr(PyObject* obj);
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 92e11e3..e505d81 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -79,9 +79,12 @@
 typedef int (*CountMethod)(PyContainer* self);
 typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
 typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
+typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
+                                                const string& name);
 typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
 typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
 typedef const string& (*GetItemNameMethod)(const void* descriptor);
+typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor);
 typedef int (*GetItemNumberMethod)(const void* descriptor);
 typedef int (*GetItemIndexMethod)(const void* descriptor);
 
@@ -95,6 +98,9 @@
   // Retrieve item by name (usually a call to some 'FindByName' method).
   // Used by "by_name" mappings.
   GetByNameMethod get_by_name_fn;
+  // Retrieve item by camelcase name (usually a call to some
+  // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
+  GetByCamelcaseNameMethod get_by_camelcase_name_fn;
   // Retrieve item by declared number (field tag, or enum value).
   // Used by "by_number" mappings.
   GetByNumberMethod get_by_number_fn;
@@ -102,6 +108,9 @@
   NewObjectFromItemMethod new_object_from_item_fn;
   // Retrieve the name of an item. Used by iterators on "by_name" mappings.
   GetItemNameMethod get_item_name_fn;
+  // Retrieve the camelcase name of an item. Used by iterators on
+  // "by_camelcase_name" mappings.
+  GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
   // Retrieve the number of an item. Used by iterators on "by_number" mappings.
   GetItemNumberMethod get_item_number_fn;
   // Retrieve the index of an item for the container type.
@@ -125,6 +134,7 @@
   enum ContainerKind {
     KIND_SEQUENCE,
     KIND_BYNAME,
+    KIND_BYCAMELCASENAME,
     KIND_BYNUMBER,
   } kind;
 };
@@ -172,6 +182,23 @@
             self, string(name, name_size));
         return true;
       }
+    case PyContainer::KIND_BYCAMELCASENAME:
+      {
+        char* camelcase_name;
+        Py_ssize_t name_size;
+        if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) {
+          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+            // Not a string, cannot be in the container.
+            PyErr_Clear();
+            *item = NULL;
+            return true;
+          }
+          return false;
+        }
+        *item = self->container_def->get_by_camelcase_name_fn(
+            self, string(camelcase_name, name_size));
+        return true;
+      }
     case PyContainer::KIND_BYNUMBER:
       {
         Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
@@ -203,6 +230,12 @@
         const string& name(self->container_def->get_item_name_fn(item));
         return PyString_FromStringAndSize(name.c_str(), name.size());
       }
+    case PyContainer::KIND_BYCAMELCASENAME:
+      {
+        const string& name(
+            self->container_def->get_item_camelcase_name_fn(item));
+        return PyString_FromStringAndSize(name.c_str(), name.size());
+      }
     case PyContainer::KIND_BYNUMBER:
       {
         int value = self->container_def->get_item_number_fn(item);
@@ -276,6 +309,9 @@
     case PyContainer::KIND_BYNAME:
       kind = "mapping by name";
       break;
+    case PyContainer::KIND_BYCAMELCASENAME:
+      kind = "mapping by camelCase name";
+      break;
     case PyContainer::KIND_BYNUMBER:
       kind = "mapping by number";
       break;
@@ -319,7 +355,7 @@
       if (value2 == NULL) {
         return -1;
       }
-      int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
       if (cmp != 1)  // error or not equal
           return cmp;
     }
@@ -363,12 +399,12 @@
       if (value1 == NULL) {
         return -1;
       }
-      PyObject* value2 = PyDict_GetItem(other, key);
+      PyObject* value2 = PyDict_GetItem(other, key.get());
       if (value2 == NULL) {
         // Not found in the other dictionary
         return 0;
       }
-      int cmp = PyObject_RichCompareBool(value1, value2, Py_EQ);
+      int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
       if (cmp != 1)  // error or not equal
           return cmp;
     }
@@ -731,6 +767,18 @@
   return reinterpret_cast<PyObject*>(self);
 }
 
+static PyObject* NewMappingByCamelcaseName(
+    DescriptorContainerDef* container_def, const void* descriptor) {
+  PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+  if (self == NULL) {
+    return NULL;
+  }
+  self->descriptor = descriptor;
+  self->container_def = container_def;
+  self->kind = PyContainer::KIND_BYCAMELCASENAME;
+  return reinterpret_cast<PyObject*>(self);
+}
+
 static PyObject* NewMappingByNumber(
     DescriptorContainerDef* container_def, const void* descriptor) {
   if (container_def->get_by_number_fn == NULL ||
@@ -889,6 +937,11 @@
   return GetDescriptor(self)->FindFieldByName(name);
 }
 
+static ItemDescriptor GetByCamelcaseName(PyContainer* self,
+                                         const string& name) {
+  return GetDescriptor(self)->FindFieldByCamelcaseName(name);
+}
+
 static ItemDescriptor GetByNumber(PyContainer* self, int number) {
   return GetDescriptor(self)->FindFieldByNumber(number);
 }
@@ -905,6 +958,10 @@
   return item->name();
 }
 
+static const string& GetItemCamelcaseName(ItemDescriptor item) {
+  return item->camelcase_name();
+}
+
 static int GetItemNumber(ItemDescriptor item) {
   return item->number();
 }
@@ -918,9 +975,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)GetByCamelcaseName,
   (GetByNumberMethod)GetByNumber,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
   (GetItemNumberMethod)GetItemNumber,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -931,6 +990,11 @@
   return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
 }
 
+PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
+                                               descriptor);
+}
+
 PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
   return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
 }
@@ -972,9 +1036,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1022,9 +1088,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1094,9 +1162,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
@@ -1140,9 +1210,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1190,9 +1262,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1258,9 +1332,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)GetByNumber,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)GetItemNumber,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1314,9 +1390,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1370,9 +1448,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1416,9 +1496,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1462,9 +1544,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)GetItemIndex,
 };
@@ -1496,9 +1580,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
@@ -1530,9 +1616,11 @@
   (CountMethod)Count,
   (GetByIndexMethod)GetByIndex,
   (GetByNameMethod)NULL,
+  (GetByCamelcaseNameMethod)NULL,
   (GetByNumberMethod)NULL,
   (NewObjectFromItemMethod)NewObjectFromItem,
   (GetItemNameMethod)NULL,
+  (GetItemCamelcaseNameMethod)NULL,
   (GetItemNumberMethod)NULL,
   (GetItemIndexMethod)NULL,
 };
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index 8fbdaff..ce40747 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -54,6 +54,7 @@
 
 namespace message_descriptor {
 PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
 PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
 PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
 
diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc
new file mode 100644
index 0000000..514722b
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.cc
@@ -0,0 +1,145 @@
+// 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 file defines a C++ DescriptorDatabase, which wraps a Python Database
+// and delegate all its operations to Python methods.
+
+#include <google/protobuf/pyext/descriptor_database.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+PyDescriptorDatabase::PyDescriptorDatabase(PyObject* py_database)
+    : py_database_(py_database) {
+  Py_INCREF(py_database_);
+}
+
+PyDescriptorDatabase::~PyDescriptorDatabase() { Py_DECREF(py_database_); }
+
+// Convert a Python object to a FileDescriptorProto pointer.
+// Handles all kinds of Python errors, which are simply logged.
+static bool GetFileDescriptorProto(PyObject* py_descriptor,
+                                   FileDescriptorProto* output) {
+  if (py_descriptor == NULL) {
+    if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+      // Expected error: item was simply not found.
+      PyErr_Clear();
+    } else {
+      GOOGLE_LOG(ERROR) << "DescriptorDatabase method raised an error";
+      PyErr_Print();
+    }
+    return false;
+  }
+  const Descriptor* filedescriptor_descriptor =
+      FileDescriptorProto::default_instance().GetDescriptor();
+  CMessage* message = reinterpret_cast<CMessage*>(py_descriptor);
+  if (PyObject_TypeCheck(py_descriptor, &CMessage_Type) &&
+      message->message->GetDescriptor() == filedescriptor_descriptor) {
+    // Fast path: Just use the pointer.
+    FileDescriptorProto* file_proto =
+        static_cast<FileDescriptorProto*>(message->message);
+    *output = *file_proto;
+    return true;
+  } else {
+    // Slow path: serialize the message. This allows to use databases which
+    // use a different implementation of FileDescriptorProto.
+    ScopedPyObjectPtr serialized_pb(
+        PyObject_CallMethod(py_descriptor, "SerializeToString", NULL));
+    if (serialized_pb == NULL) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      PyErr_Print();
+      return false;
+    }
+    char* str;
+    Py_ssize_t len;
+    if (PyBytes_AsStringAndSize(serialized_pb.get(), &str, &len) < 0) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      PyErr_Print();
+      return false;
+    }
+    FileDescriptorProto file_proto;
+    if (!file_proto.ParseFromArray(str, len)) {
+      GOOGLE_LOG(ERROR)
+          << "DescriptorDatabase method did not return a FileDescriptorProto";
+      return false;
+    }
+    *output = file_proto;
+    return true;
+  }
+}
+
+// Find a file by file name.
+bool PyDescriptorDatabase::FindFileByName(const string& filename,
+                                          FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_descriptor(PyObject_CallMethod(
+      py_database_, "FindFileByName", "s#", filename.c_str(), filename.size()));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+// Find the file that declares the given fully-qualified symbol name.
+bool PyDescriptorDatabase::FindFileContainingSymbol(
+    const string& symbol_name, FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_descriptor(
+      PyObject_CallMethod(py_database_, "FindFileContainingSymbol", "s#",
+                          symbol_name.c_str(), symbol_name.size()));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+// Find the file which defines an extension extending the given message type
+// with the given field number.
+// Python DescriptorDatabases are not required to implement this method.
+bool PyDescriptorDatabase::FindFileContainingExtension(
+    const string& containing_type, int field_number,
+    FileDescriptorProto* output) {
+  ScopedPyObjectPtr py_method(
+      PyObject_GetAttrString(py_database_, "FindFileContainingExtension"));
+  if (py_method == NULL) {
+    // This method is not implemented, returns without error.
+    PyErr_Clear();
+    return false;
+  }
+  ScopedPyObjectPtr py_descriptor(
+      PyObject_CallFunction(py_method.get(), "s#i", containing_type.c_str(),
+                            containing_type.size(), field_number));
+  return GetFileDescriptorProto(py_descriptor.get(), output);
+}
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/descriptor_database.h b/python/google/protobuf/pyext/descriptor_database.h
new file mode 100644
index 0000000..fc71c4b
--- /dev/null
+++ b/python/google/protobuf/pyext/descriptor_database.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
+
+#include <Python.h>
+
+#include <google/protobuf/descriptor_database.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+class PyDescriptorDatabase : public DescriptorDatabase {
+ public:
+  explicit PyDescriptorDatabase(PyObject* py_database);
+  ~PyDescriptorDatabase();
+
+  // Implement the abstract interface. All these functions fill the output
+  // with a copy of FileDescriptorProto.
+
+  // Find a file by file name.
+  bool FindFileByName(const string& filename,
+                      FileDescriptorProto* output);
+
+  // Find the file that declares the given fully-qualified symbol name.
+  bool FindFileContainingSymbol(const string& symbol_name,
+                                FileDescriptorProto* output);
+
+  // Find the file which defines an extension extending the given message type
+  // with the given field number.
+  // Containing_type must be a fully-qualified type name.
+  // Python objects are not required to implement this method.
+  bool FindFileContainingExtension(const string& containing_type,
+                                   int field_number,
+                                   FileDescriptorProto* output);
+
+ private:
+  // The python object that implements the database. The reference is owned.
+  PyObject* py_database_;
+};
+
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index 7aed651..0bc76bc 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -34,8 +34,9 @@
 
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_database.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
@@ -60,38 +61,93 @@
 
 namespace cdescriptor_pool {
 
-static PyDescriptorPool* NewDescriptorPool() {
-  PyDescriptorPool* cdescriptor_pool = PyObject_New(
+// Create a Python DescriptorPool object, but does not fill the "pool"
+// attribute.
+static PyDescriptorPool* _CreateDescriptorPool() {
+  PyDescriptorPool* cpool = PyObject_New(
       PyDescriptorPool, &PyDescriptorPool_Type);
-  if (cdescriptor_pool == NULL) {
+  if (cpool == NULL) {
     return NULL;
   }
 
-  // Build a DescriptorPool for messages only declared in Python libraries.
-  // generated_pool() contains all messages linked in C++ libraries, and is used
-  // as underlay.
-  cdescriptor_pool->pool = new DescriptorPool(DescriptorPool::generated_pool());
+  cpool->underlay = NULL;
+  cpool->database = NULL;
 
   DynamicMessageFactory* message_factory = new DynamicMessageFactory();
   // This option might be the default some day.
   message_factory->SetDelegateToGeneratedFactory(true);
-  cdescriptor_pool->message_factory = message_factory;
+  cpool->message_factory = message_factory;
 
   // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same
   // storage.
-  cdescriptor_pool->classes_by_descriptor =
+  cpool->classes_by_descriptor =
       new PyDescriptorPool::ClassesByMessageMap();
-  cdescriptor_pool->descriptor_options =
+  cpool->descriptor_options =
       new hash_map<const void*, PyObject *>();
 
+  return cpool;
+}
+
+// Create a Python DescriptorPool, using the given pool as an underlay:
+// new messages will be added to a custom pool, not to the underlay.
+//
+// Ownership of the underlay is not transferred, its pointer should
+// stay alive.
+static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay(
+    const DescriptorPool* underlay) {
+  PyDescriptorPool* cpool = _CreateDescriptorPool();
+  if (cpool == NULL) {
+    return NULL;
+  }
+  cpool->pool = new DescriptorPool(underlay);
+  cpool->underlay = underlay;
+
   if (!descriptor_pool_map.insert(
-      std::make_pair(cdescriptor_pool->pool, cdescriptor_pool)).second) {
+      std::make_pair(cpool->pool, cpool)).second) {
     // Should never happen -- would indicate an internal error / bug.
     PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
     return NULL;
   }
 
-  return cdescriptor_pool;
+  return cpool;
+}
+
+static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
+    DescriptorDatabase* database) {
+  PyDescriptorPool* cpool = _CreateDescriptorPool();
+  if (cpool == NULL) {
+    return NULL;
+  }
+  if (database != NULL) {
+    cpool->pool = new DescriptorPool(database);
+    cpool->database = database;
+  } else {
+    cpool->pool = new DescriptorPool();
+  }
+
+  if (!descriptor_pool_map.insert(std::make_pair(cpool->pool, cpool)).second) {
+    // Should never happen -- would indicate an internal error / bug.
+    PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
+    return NULL;
+  }
+
+  return cpool;
+}
+
+// The public DescriptorPool constructor.
+static PyObject* New(PyTypeObject* type,
+                     PyObject* args, PyObject* kwargs) {
+  static char* kwlist[] = {"descriptor_db", 0};
+  PyObject* py_database = NULL;
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &py_database)) {
+    return NULL;
+  }
+  DescriptorDatabase* database = NULL;
+  if (py_database && py_database != Py_None) {
+    database = new PyDescriptorDatabase(py_database);
+  }
+  return reinterpret_cast<PyObject*>(
+      PyDescriptorPool_NewWithDatabase(database));
 }
 
 static void Dealloc(PyDescriptorPool* self) {
@@ -109,6 +165,8 @@
   }
   delete self->descriptor_options;
   delete self->message_factory;
+  delete self->database;
+  delete self->pool;
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
@@ -131,22 +189,9 @@
 }
 
 // Add a message class to our database.
-const Descriptor* RegisterMessageClass(
-    PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) {
-  ScopedPyObjectPtr full_message_name(
-      PyObject_GetAttrString(descriptor, "full_name"));
-  Py_ssize_t name_size;
-  char* name;
-  if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) {
-    return NULL;
-  }
-  const Descriptor *message_descriptor =
-      self->pool->FindMessageTypeByName(string(name, name_size));
-  if (!message_descriptor) {
-    PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'",
-                 name);
-    return NULL;
-  }
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor *message_descriptor,
+                         PyObject *message_class) {
   Py_INCREF(message_class);
   typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
   std::pair<iterator, bool> ret = self->classes_by_descriptor->insert(
@@ -156,7 +201,7 @@
     Py_DECREF(ret.first->second);
     ret.first->second = message_class;
   }
-  return message_descriptor;
+  return 0;
 }
 
 // Retrieve the message class added to our database.
@@ -260,6 +305,80 @@
   return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
 }
 
+PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FileDescriptor* file_descriptor =
+      self->pool->FindFileContainingSymbol(string(name, name_size));
+  if (file_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+// These functions should not exist -- the only valid way to create
+// descriptors is to call Add() or AddSerializedFile().
+// But these AddDescriptor() functions were created in Python and some people
+// call them, so we support them for now for compatibility.
+// However we do check that the existing descriptor already exists in the pool,
+// which appears to always be true for existing calls -- but then why do people
+// call a function that will just be a no-op?
+// TODO(amauryfa): Need to investigate further.
+
+PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const FileDescriptor* file_descriptor =
+      PyFileDescriptor_AsDescriptor(descriptor);
+  if (!file_descriptor) {
+    return NULL;
+  }
+  if (file_descriptor !=
+      self->pool->FindFileByName(file_descriptor->name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The file descriptor %s does not belong to this pool",
+                 file_descriptor->name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(descriptor);
+  if (!message_descriptor) {
+    return NULL;
+  }
+  if (message_descriptor !=
+      self->pool->FindMessageTypeByName(message_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The message descriptor %s does not belong to this pool",
+                 message_descriptor->full_name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
+PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+  const EnumDescriptor* enum_descriptor =
+      PyEnumDescriptor_AsDescriptor(descriptor);
+  if (!enum_descriptor) {
+    return NULL;
+  }
+  if (enum_descriptor !=
+      self->pool->FindEnumTypeByName(enum_descriptor->full_name())) {
+    PyErr_Format(PyExc_ValueError,
+                 "The enum descriptor %s does not belong to this pool",
+                 enum_descriptor->full_name().c_str());
+    return NULL;
+  }
+  Py_RETURN_NONE;
+}
+
 // The code below loads new Descriptors from a serialized FileDescriptorProto.
 
 
@@ -292,6 +411,14 @@
   char* message_type;
   Py_ssize_t message_len;
 
+  if (self->database != NULL) {
+    PyErr_SetString(
+        PyExc_ValueError,
+        "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
+        "Add your file to the underlying database.");
+    return NULL;
+  }
+
   if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
     return NULL;
   }
@@ -304,8 +431,10 @@
 
   // If the file was already part of a C++ library, all its descriptors are in
   // the underlying pool.  No need to do anything else.
-  const FileDescriptor* generated_file =
-      DescriptorPool::generated_pool()->FindFileByName(file_proto.name());
+  const FileDescriptor* generated_file = NULL;
+  if (self->underlay) {
+    generated_file = self->underlay->FindFileByName(file_proto.name());
+  }
   if (generated_file != NULL) {
     return PyFileDescriptor_FromDescriptorWithSerializedPb(
         generated_file, serialized_pb);
@@ -332,7 +461,7 @@
   if (serialized_pb == NULL) {
     return NULL;
   }
-  return AddSerializedFile(self, serialized_pb);
+  return AddSerializedFile(self, serialized_pb.get());
 }
 
 static PyMethodDef Methods[] = {
@@ -341,6 +470,15 @@
   { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O,
     "Adds a serialized FileDescriptorProto to this pool." },
 
+  // TODO(amauryfa): Understand why the Python implementation differs from
+  // this one, ask users to use another API and deprecate these functions.
+  { "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+  { "AddDescriptor", (PyCFunction)AddDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+  { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O,
+    "No-op. Add() must have been called before." },
+
   { "FindFileByName", (PyCFunction)FindFileByName, METH_O,
     "Searches for a file descriptor by its .proto name." },
   { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O,
@@ -353,6 +491,9 @@
     "Searches for enum type descriptor by full name." },
   { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
     "Searches for oneof descriptor by full name." },
+
+  { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
+    "Gets the FileDescriptor containing the specified symbol." },
   {NULL}
 };
 
@@ -396,7 +537,7 @@
   0,                                   // tp_dictoffset
   0,                                   // tp_init
   0,                                   // tp_alloc
-  0,                                   // tp_new
+  cdescriptor_pool::New,               // tp_new
   PyObject_Del,                        // tp_free
 };
 
@@ -408,7 +549,11 @@
   if (PyType_Ready(&PyDescriptorPool_Type) < 0)
     return false;
 
-  python_generated_pool = cdescriptor_pool::NewDescriptorPool();
+  // The Pool of messages declared in Python libraries.
+  // generated_pool() contains all messages already linked in C++ libraries, and
+  // is used as underlay.
+  python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
+      DescriptorPool::generated_pool());
   if (python_generated_pool == NULL) {
     return false;
   }
@@ -420,7 +565,11 @@
   return true;
 }
 
-PyDescriptorPool* GetDescriptorPool() {
+// The default DescriptorPool used everywhere in this module.
+// Today it's the python_generated_pool.
+// TODO(amauryfa): Remove all usages of this function: the pool should be
+// derived from the context.
+PyDescriptorPool* GetDefaultDescriptorPool() {
   return python_generated_pool;
 }
 
@@ -432,7 +581,7 @@
   }
   hash_map<const DescriptorPool*, PyDescriptorPool*>::iterator it =
       descriptor_pool_map.find(pool);
-  if (it != descriptor_pool_map.end()) {
+  if (it == descriptor_pool_map.end()) {
     PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
     return NULL;
   }
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 541d920..16bc910 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -55,8 +55,17 @@
 typedef struct PyDescriptorPool {
   PyObject_HEAD
 
+  // The C++ pool containing Descriptors.
   DescriptorPool* pool;
 
+  // The C++ pool acting as an underlay. Can be NULL.
+  // This pointer is not owned and must stay alive.
+  const DescriptorPool* underlay;
+
+  // The C++ descriptor database used to fetch unknown protos. Can be NULL.
+  // This pointer is owned.
+  const DescriptorDatabase* database;
+
   // DynamicMessageFactory used to create C++ instances of messages.
   // This object cache the descriptors that were used, so the DescriptorPool
   // needs to get rid of it before it can delete itself.
@@ -89,12 +98,10 @@
                                         const string& name);
 
 // Registers a new Python class for the given message descriptor.
-// Returns the message Descriptor.
-// On error, returns NULL with a Python exception set.
-const Descriptor* RegisterMessageClass(
-    PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor);
-
-// The function below are also exposed as methods of the DescriptorPool type.
+// On error, returns -1 with a Python exception set.
+int RegisterMessageClass(PyDescriptorPool* self,
+                         const Descriptor* message_descriptor,
+                         PyObject* message_class);
 
 // Retrieves the Python class registered with the given message descriptor.
 //
@@ -103,6 +110,8 @@
 PyObject* GetMessageClass(PyDescriptorPool* self,
                           const Descriptor* message_descriptor);
 
+// The functions below are also exposed as methods of the DescriptorPool type.
+
 // Looks up a message by name. Returns a PyMessageDescriptor corresponding to
 // the field on success, or NULL on failure.
 //
@@ -136,8 +145,10 @@
 }  // namespace cdescriptor_pool
 
 // Retrieve the global descriptor pool owned by the _message module.
+// This is the one used by pb2.py generated modules.
 // Returns a *borrowed* reference.
-PyDescriptorPool* GetDescriptorPool();
+// "Default" pool used to register messages from _pb2.py modules.
+PyDescriptorPool* GetDefaultDescriptorPool();
 
 // Retrieve the python descriptor pool owning a C++ descriptor pool.
 // Returns a *borrowed* reference.
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index 8ebbb27..555bd29 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -94,13 +94,13 @@
   if (descriptor == NULL) {
     return NULL;
   }
-  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
     return NULL;
   }
 
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
-    return cmessage::InternalGetScalar(self->parent->message, descriptor);
+    return cmessage::InternalGetScalar(self->message, descriptor);
   }
 
   PyObject* value = PyDict_GetItem(self->values, key);
@@ -109,6 +109,14 @@
     return value;
   }
 
+  if (self->parent == NULL) {
+    // We are in "detached" state. Don't allow further modifications.
+    // TODO(amauryfa): Support adding non-scalars to a detached extension dict.
+    // This probably requires to store the type of the main message.
+    PyErr_SetObject(PyExc_KeyError, key);
+    return NULL;
+  }
+
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     PyObject* sub_message = cmessage::InternalGetSubMessage(
@@ -123,7 +131,8 @@
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       PyObject *message_class = cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), descriptor->message_type());
+          cmessage::GetDescriptorPoolForMessage(self->parent),
+          descriptor->message_type());
       if (message_class == NULL) {
         return NULL;
       }
@@ -153,7 +162,7 @@
   if (descriptor == NULL) {
     return -1;
   }
-  if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
+  if (!CheckFieldBelongsToMessage(descriptor, self->message)) {
     return -1;
   }
 
@@ -163,9 +172,11 @@
                     "type");
     return -1;
   }
-  cmessage::AssureWritable(self->parent);
-  if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
-    return -1;
+  if (self->parent) {
+    cmessage::AssureWritable(self->parent);
+    if (cmessage::InternalSetScalar(self->parent, descriptor, value) < 0) {
+      return -1;
+    }
   }
   // TODO(tibell): We shouldn't write scalars to the cache.
   PyDict_SetItem(self->values, key, value);
@@ -179,15 +190,17 @@
     return NULL;
   }
   PyObject* value = PyDict_GetItem(self->values, extension);
-  if (value != NULL) {
-    if (ReleaseExtension(self, value, descriptor) < 0) {
+  if (self->parent) {
+    if (value != NULL) {
+      if (ReleaseExtension(self, value, descriptor) < 0) {
+        return NULL;
+      }
+    }
+    if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor(
+            self->parent, descriptor)) == NULL) {
       return NULL;
     }
   }
-  if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor(
-          self->parent, descriptor)) == NULL) {
-    return NULL;
-  }
   if (PyDict_DelItem(self->values, extension) < 0) {
     PyErr_Clear();
   }
@@ -200,8 +213,15 @@
   if (descriptor == NULL) {
     return NULL;
   }
-  PyObject* result = cmessage::HasFieldByDescriptor(self->parent, descriptor);
-  return result;
+  if (self->parent) {
+    return cmessage::HasFieldByDescriptor(self->parent, descriptor);
+  } else {
+    int exists = PyDict_Contains(self->values, extension);
+    if (exists < 0) {
+      return NULL;
+    }
+    return PyBool_FromLong(exists);
+  }
 }
 
 PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) {
@@ -210,7 +230,7 @@
   if (extensions_by_name == NULL) {
     return NULL;
   }
-  PyObject* result = PyDict_GetItem(extensions_by_name, name);
+  PyObject* result = PyDict_GetItem(extensions_by_name.get(), name);
   if (result == NULL) {
     Py_RETURN_NONE;
   } else {
diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h
index 7e1049f..d92cf95 100644
--- a/python/google/protobuf/pyext/extension_dict.h
+++ b/python/google/protobuf/pyext/extension_dict.h
@@ -47,7 +47,11 @@
 class Message;
 class FieldDescriptor;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
@@ -113,11 +117,6 @@
 PyObject* ClearExtension(ExtensionDict* self,
                                        PyObject* extension);
 
-// Checks if the dict has an extension.
-//
-// Returns a new python boolean reference.
-PyObject* HasExtension(ExtensionDict* self, PyObject* extension);
-
 // Gets an extension from the dict given the extension name as opposed to
 // descriptor.
 //
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
new file mode 100644
index 0000000..df9138a
--- /dev/null
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -0,0 +1,965 @@
+// 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.
+
+// Author: haberman@google.com (Josh Haberman)
+
+#include <google/protobuf/pyext/map_container.h>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
+#include <google/protobuf/map_field.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+#if PY_MAJOR_VERSION >= 3
+  #define PyInt_FromLong PyLong_FromLong
+  #define PyInt_FromSize_t PyLong_FromSize_t
+#endif
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+// Functions that need access to map reflection functionality.
+// They need to be contained in this class because it is friended.
+class MapReflectionFriend {
+ public:
+  // Methods that are in common between the map types.
+  static PyObject* Contains(PyObject* _self, PyObject* key);
+  static Py_ssize_t Length(PyObject* _self);
+  static PyObject* GetIterator(PyObject *_self);
+  static PyObject* IterNext(PyObject* _self);
+
+  // Methods that differ between the map types.
+  static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
+  static PyObject* MessageMapGetItem(PyObject* _self, PyObject* key);
+  static int ScalarMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
+  static int MessageMapSetItem(PyObject* _self, PyObject* key, PyObject* v);
+};
+
+struct MapIterator {
+  PyObject_HEAD;
+
+  scoped_ptr< ::google::protobuf::MapIterator> iter;
+
+  // A pointer back to the container, so we can notice changes to the version.
+  // We own a ref on this.
+  MapContainer* container;
+
+  // We need to keep a ref on the Message* too, because
+  // MapIterator::~MapIterator() accesses it.  Normally this would be ok because
+  // the ref on container (above) would guarantee outlive semantics.  However in
+  // the case of ClearField(), InitializeAndCopyToParentContainer() resets the
+  // message pointer (and the owner) to a different message, a copy of the
+  // original.  But our iterator still points to the original, which could now
+  // get deleted before us.
+  //
+  // To prevent this, we ensure that the Message will always stay alive as long
+  // as this iterator does.  This is solely for the benefit of the MapIterator
+  // destructor -- we should never actually access the iterator in this state
+  // except to delete it.
+  shared_ptr<Message> owner;
+
+  // The version of the map when we took the iterator to it.
+  //
+  // We store this so that if the map is modified during iteration we can throw
+  // an error.
+  uint64 version;
+
+  // True if the container is empty.  We signal this separately to avoid calling
+  // any of the iteration methods, which are non-const.
+  bool empty;
+};
+
+Message* MapContainer::GetMutableMessage() {
+  cmessage::AssureWritable(parent);
+  return const_cast<Message*>(message);
+}
+
+// Consumes a reference on the Python string object.
+static bool PyStringToSTL(PyObject* py_string, string* stl_string) {
+  char *value;
+  Py_ssize_t value_len;
+
+  if (!py_string) {
+    return false;
+  }
+  if (PyBytes_AsStringAndSize(py_string, &value, &value_len) < 0) {
+    Py_DECREF(py_string);
+    return false;
+  } else {
+    stl_string->assign(value, value_len);
+    Py_DECREF(py_string);
+    return true;
+  }
+}
+
+static bool PythonToMapKey(PyObject* obj,
+                           const FieldDescriptor* field_descriptor,
+                           MapKey* key) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      key->SetInt32Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(obj, value, false);
+      key->SetInt64Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(obj, value, false);
+      key->SetUInt32Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(obj, value, false);
+      key->SetUInt64Value(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(obj, value, false);
+      key->SetBoolValue(value);
+      break;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      string str;
+      if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
+        return false;
+      }
+      key->SetStringValue(str);
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Type %d cannot be a map key",
+          field_descriptor->cpp_type());
+      return false;
+  }
+  return true;
+}
+
+static PyObject* MapKeyToPython(const FieldDescriptor* field_descriptor,
+                                const MapKey& key) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyInt_FromLong(key.GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(key.GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyInt_FromSize_t(key.GetUInt32Value());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return PyLong_FromUnsignedLongLong(key.GetUInt64Value());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return PyBool_FromLong(key.GetBoolValue());
+    case FieldDescriptor::CPPTYPE_STRING:
+      return ToStringObject(field_descriptor, key.GetStringValue());
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Couldn't convert type %d to value",
+          field_descriptor->cpp_type());
+      return NULL;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+PyObject* MapValueRefToPython(const FieldDescriptor* field_descriptor,
+                              MapValueRef* value) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return PyInt_FromLong(value->GetInt32Value());
+    case FieldDescriptor::CPPTYPE_INT64:
+      return PyLong_FromLongLong(value->GetInt64Value());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return PyInt_FromSize_t(value->GetUInt32Value());
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return PyLong_FromUnsignedLongLong(value->GetUInt64Value());
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return PyFloat_FromDouble(value->GetFloatValue());
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return PyFloat_FromDouble(value->GetDoubleValue());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return PyBool_FromLong(value->GetBoolValue());
+    case FieldDescriptor::CPPTYPE_STRING:
+      return ToStringObject(field_descriptor, value->GetStringValue());
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return PyInt_FromLong(value->GetEnumValue());
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Couldn't convert type %d to value",
+          field_descriptor->cpp_type());
+      return NULL;
+  }
+}
+
+// This is only used for ScalarMap, so we don't need to handle the
+// CPPTYPE_MESSAGE case.
+static bool PythonToMapValueRef(PyObject* obj,
+                                const FieldDescriptor* field_descriptor,
+                                bool allow_unknown_enum_values,
+                                MapValueRef* value_ref) {
+  switch (field_descriptor->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      value_ref->SetInt32Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_INT64: {
+      GOOGLE_CHECK_GET_INT64(obj, value, false);
+      value_ref->SetInt64Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_UINT32: {
+      GOOGLE_CHECK_GET_UINT32(obj, value, false);
+      value_ref->SetUInt32Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      GOOGLE_CHECK_GET_UINT64(obj, value, false);
+      value_ref->SetUInt64Value(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_FLOAT: {
+      GOOGLE_CHECK_GET_FLOAT(obj, value, false);
+      value_ref->SetFloatValue(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_DOUBLE: {
+      GOOGLE_CHECK_GET_DOUBLE(obj, value, false);
+      value_ref->SetDoubleValue(value);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_BOOL: {
+      GOOGLE_CHECK_GET_BOOL(obj, value, false);
+      value_ref->SetBoolValue(value);
+      return true;;
+    }
+    case FieldDescriptor::CPPTYPE_STRING: {
+      string str;
+      if (!PyStringToSTL(CheckString(obj, field_descriptor), &str)) {
+        return false;
+      }
+      value_ref->SetStringValue(str);
+      return true;
+    }
+    case FieldDescriptor::CPPTYPE_ENUM: {
+      GOOGLE_CHECK_GET_INT32(obj, value, false);
+      if (allow_unknown_enum_values) {
+        value_ref->SetEnumValue(value);
+        return true;
+      } else {
+        const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
+        const EnumValueDescriptor* enum_value =
+            enum_descriptor->FindValueByNumber(value);
+        if (enum_value != NULL) {
+          value_ref->SetEnumValue(value);
+          return true;
+        } else {
+          PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
+          return false;
+        }
+      }
+      break;
+    }
+    default:
+      PyErr_Format(
+          PyExc_SystemError, "Setting value to a field of unknown type %d",
+          field_descriptor->cpp_type());
+      return false;
+  }
+}
+
+// Map methods common to ScalarMap and MessageMap //////////////////////////////
+
+static MapContainer* GetMap(PyObject* obj) {
+  return reinterpret_cast<MapContainer*>(obj);
+}
+
+Py_ssize_t MapReflectionFriend::Length(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  const google::protobuf::Message* message = self->message;
+  return message->GetReflection()->MapSize(*message,
+                                           self->parent_field_descriptor);
+}
+
+PyObject* Clear(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, self->parent_field_descriptor);
+
+  Py_RETURN_NONE;
+}
+
+PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) {
+  MapContainer* self = GetMap(_self);
+
+  const Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
+                                 map_key)) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
+// 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
+// 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).
+static int InitializeAndCopyToParentContainer(MapContainer* from,
+                                              MapContainer* to) {
+  // For now we require from == to, re-evaluate if we want to support deep copy
+  // as in repeated_scalar_container.cc.
+  GOOGLE_DCHECK(from == to);
+  Message* new_message = from->message->New();
+
+  if (MapReflectionFriend::Length(reinterpret_cast<PyObject*>(from)) > 0) {
+    // A somewhat roundabout way of copying just one field from old_message to
+    // new_message.  This is the best we can do with what Reflection gives us.
+    Message* mutable_old = from->GetMutableMessage();
+    vector<const FieldDescriptor*> fields;
+    fields.push_back(from->parent_field_descriptor);
+
+    // Move the map field into the new message.
+    mutable_old->GetReflection()->SwapFields(mutable_old, new_message, fields);
+
+    // If/when we support from != to, this will be required also to copy the
+    // map field back into the existing message:
+    // mutable_old->MergeFrom(*new_message);
+  }
+
+  // If from == to this could delete old_message.
+  to->owner.reset(new_message);
+
+  to->parent = NULL;
+  to->parent_field_descriptor = from->parent_field_descriptor;
+  to->message = new_message;
+
+  // Invalidate iterators, since they point to the old copy of the field.
+  to->version++;
+
+  return 0;
+}
+
+int MapContainer::Release() {
+  return InitializeAndCopyToParentContainer(this, this);
+}
+
+
+// ScalarMap ///////////////////////////////////////////////////////////////////
+
+PyObject *NewScalarMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+#if PY_MAJOR_VERSION >= 3
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(
+        reinterpret_cast<PyTypeObject *>(ScalarMapContainer_Type), 0));
+#else
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0));
+#endif
+  if (obj.get() == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  MapContainer* self = GetMap(obj.get());
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj.release();
+}
+
+PyObject* MapReflectionFriend::ScalarMapGetItem(PyObject* _self,
+                                                PyObject* key) {
+  MapContainer* self = GetMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return MapValueRefToPython(self->value_field_descriptor, &value);
+}
+
+int MapReflectionFriend::ScalarMapSetItem(PyObject* _self, PyObject* key,
+                                          PyObject* v) {
+  MapContainer* self = GetMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return -1;
+  }
+
+  self->version++;
+
+  if (v) {
+    // Set item to v.
+    reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                       map_key, &value);
+
+    return PythonToMapValueRef(v, self->value_field_descriptor,
+                               reflection->SupportsUnknownEnumValues(), &value)
+               ? 0
+               : -1;
+  } else {
+    // Delete key from map.
+    if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
+                                   map_key)) {
+      return 0;
+    } else {
+      PyErr_Format(PyExc_KeyError, "Key not present in map");
+      return -1;
+    }
+  }
+}
+
+static PyObject* ScalarMapGet(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::ScalarMapGetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static void ScalarMapDealloc(PyObject* _self) {
+  MapContainer* self = GetMap(_self);
+  self->owner.reset();
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef ScalarMapMethods[] = {
+  { "__contains__", MapReflectionFriend::Contains, METH_O,
+    "Tests whether a key is a member of the map." },
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map." },
+  { "get", ScalarMapGet, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+#if PY_MAJOR_VERSION >= 3
+  static PyType_Slot ScalarMapContainer_Type_slots[] = {
+      {Py_tp_dealloc, (void *)ScalarMapDealloc},
+      {Py_mp_length, (void *)MapReflectionFriend::Length},
+      {Py_mp_subscript, (void *)MapReflectionFriend::ScalarMapGetItem},
+      {Py_mp_ass_subscript, (void *)MapReflectionFriend::ScalarMapSetItem},
+      {Py_tp_methods, (void *)ScalarMapMethods},
+      {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
+      {0, 0},
+  };
+
+  PyType_Spec ScalarMapContainer_Type_spec = {
+      FULL_MODULE_NAME ".ScalarMapContainer",
+      sizeof(MapContainer),
+      0,
+      Py_TPFLAGS_DEFAULT,
+      ScalarMapContainer_Type_slots
+  };
+  PyObject *ScalarMapContainer_Type;
+#else
+  static PyMappingMethods ScalarMapMappingMethods = {
+    MapReflectionFriend::Length,             // mp_length
+    MapReflectionFriend::ScalarMapGetItem,   // mp_subscript
+    MapReflectionFriend::ScalarMapSetItem,   // mp_ass_subscript
+  };
+
+  PyTypeObject ScalarMapContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    FULL_MODULE_NAME ".ScalarMapContainer",  //  tp_name
+    sizeof(MapContainer),                //  tp_basicsize
+    0,                                   //  tp_itemsize
+    ScalarMapDealloc,                    //  tp_dealloc
+    0,                                   //  tp_print
+    0,                                   //  tp_getattr
+    0,                                   //  tp_setattr
+    0,                                   //  tp_compare
+    0,                                   //  tp_repr
+    0,                                   //  tp_as_number
+    0,                                   //  tp_as_sequence
+    &ScalarMapMappingMethods,            //  tp_as_mapping
+    0,                                   //  tp_hash
+    0,                                   //  tp_call
+    0,                                   //  tp_str
+    0,                                   //  tp_getattro
+    0,                                   //  tp_setattro
+    0,                                   //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  //  tp_flags
+    "A scalar map container",            //  tp_doc
+    0,                                   //  tp_traverse
+    0,                                   //  tp_clear
+    0,                                   //  tp_richcompare
+    0,                                   //  tp_weaklistoffset
+    MapReflectionFriend::GetIterator,    //  tp_iter
+    0,                                   //  tp_iternext
+    ScalarMapMethods,                    //  tp_methods
+    0,                                   //  tp_members
+    0,                                   //  tp_getset
+    0,                                   //  tp_base
+    0,                                   //  tp_dict
+    0,                                   //  tp_descr_get
+    0,                                   //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    0,                                   //  tp_init
+  };
+#endif
+
+
+// MessageMap //////////////////////////////////////////////////////////////////
+
+static MessageMapContainer* GetMessageMap(PyObject* obj) {
+  return reinterpret_cast<MessageMapContainer*>(obj);
+}
+
+static PyObject* GetCMessage(MessageMapContainer* self, Message* message) {
+  // Get or create the CMessage object corresponding to this message.
+  ScopedPyObjectPtr key(PyLong_FromVoidPtr(message));
+  PyObject* ret = PyDict_GetItem(self->message_dict, key.get());
+
+  if (ret == NULL) {
+    CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
+                                               message->GetDescriptor());
+    ret = reinterpret_cast<PyObject*>(cmsg);
+
+    if (cmsg == NULL) {
+      return NULL;
+    }
+    cmsg->owner = self->owner;
+    cmsg->message = message;
+    cmsg->parent = self->parent;
+
+    if (PyDict_SetItem(self->message_dict, key.get(), ret) < 0) {
+      Py_DECREF(ret);
+      return NULL;
+    }
+  } else {
+    Py_INCREF(ret);
+  }
+
+  return ret;
+}
+
+PyObject* NewMessageMapContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor,
+    PyObject* concrete_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+#if PY_MAJOR_VERSION >= 3
+  PyObject* obj = PyType_GenericAlloc(
+        reinterpret_cast<PyTypeObject *>(MessageMapContainer_Type), 0);
+#else
+  PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0);
+#endif
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  MessageMapContainer* self = GetMessageMap(obj);
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  self->message_dict = PyDict_New();
+  if (self->message_dict == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate message dict.");
+  }
+
+  Py_INCREF(concrete_class);
+  self->subclass_init = concrete_class;
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    Py_DECREF(obj);
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj;
+}
+
+int MapReflectionFriend::MessageMapSetItem(PyObject* _self, PyObject* key,
+                                           PyObject* v) {
+  if (v) {
+    PyErr_Format(PyExc_ValueError,
+                 "Direct assignment of submessage not allowed");
+    return -1;
+  }
+
+  // Now we know that this is a delete, not a set.
+
+  MessageMapContainer* self = GetMessageMap(_self);
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  self->version++;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return -1;
+  }
+
+  // Delete key from map.
+  if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
+                                 map_key)) {
+    return 0;
+  } else {
+    PyErr_Format(PyExc_KeyError, "Key not present in map");
+    return -1;
+  }
+}
+
+PyObject* MapReflectionFriend::MessageMapGetItem(PyObject* _self,
+                                                 PyObject* key) {
+  MessageMapContainer* self = GetMessageMap(_self);
+
+  Message* message = self->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+  MapKey map_key;
+  MapValueRef value;
+
+  if (!PythonToMapKey(key, self->key_field_descriptor, &map_key)) {
+    return NULL;
+  }
+
+  if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
+                                         map_key, &value)) {
+    self->version++;
+  }
+
+  return GetCMessage(self, value.MutableMessageValue());
+}
+
+PyObject* MessageMapGet(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return MapReflectionFriend::MessageMapGetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static void MessageMapDealloc(PyObject* _self) {
+  MessageMapContainer* self = GetMessageMap(_self);
+  self->owner.reset();
+  Py_DECREF(self->message_dict);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef MessageMapMethods[] = {
+  { "__contains__", (PyCFunction)MapReflectionFriend::Contains, METH_O,
+    "Tests whether the map contains this element."},
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map."},
+  { "get", MessageMapGet, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  { "get_or_create", MapReflectionFriend::MessageMapGetItem, METH_O,
+    "Alias for getitem, useful to make explicit that the map is mutated." },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+#if PY_MAJOR_VERSION >= 3
+  static PyType_Slot MessageMapContainer_Type_slots[] = {
+      {Py_tp_dealloc, (void *)MessageMapDealloc},
+      {Py_mp_length, (void *)MapReflectionFriend::Length},
+      {Py_mp_subscript, (void *)MapReflectionFriend::MessageMapGetItem},
+      {Py_mp_ass_subscript, (void *)MapReflectionFriend::MessageMapSetItem},
+      {Py_tp_methods, (void *)MessageMapMethods},
+      {Py_tp_iter, (void *)MapReflectionFriend::GetIterator},
+      {0, 0}
+  };
+
+  PyType_Spec MessageMapContainer_Type_spec = {
+      FULL_MODULE_NAME ".MessageMapContainer",
+      sizeof(MessageMapContainer),
+      0,
+      Py_TPFLAGS_DEFAULT,
+      MessageMapContainer_Type_slots
+  };
+
+  PyObject *MessageMapContainer_Type;
+#else
+  static PyMappingMethods MessageMapMappingMethods = {
+    MapReflectionFriend::Length,              // mp_length
+    MapReflectionFriend::MessageMapGetItem,   // mp_subscript
+    MapReflectionFriend::MessageMapSetItem,   // mp_ass_subscript
+  };
+
+  PyTypeObject MessageMapContainer_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    FULL_MODULE_NAME ".MessageMapContainer",  //  tp_name
+    sizeof(MessageMapContainer),         //  tp_basicsize
+    0,                                   //  tp_itemsize
+    MessageMapDealloc,                   //  tp_dealloc
+    0,                                   //  tp_print
+    0,                                   //  tp_getattr
+    0,                                   //  tp_setattr
+    0,                                   //  tp_compare
+    0,                                   //  tp_repr
+    0,                                   //  tp_as_number
+    0,                                   //  tp_as_sequence
+    &MessageMapMappingMethods,           //  tp_as_mapping
+    0,                                   //  tp_hash
+    0,                                   //  tp_call
+    0,                                   //  tp_str
+    0,                                   //  tp_getattro
+    0,                                   //  tp_setattro
+    0,                                   //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  //  tp_flags
+    "A map container for message",       //  tp_doc
+    0,                                   //  tp_traverse
+    0,                                   //  tp_clear
+    0,                                   //  tp_richcompare
+    0,                                   //  tp_weaklistoffset
+    MapReflectionFriend::GetIterator,    //  tp_iter
+    0,                                   //  tp_iternext
+    MessageMapMethods,                   //  tp_methods
+    0,                                   //  tp_members
+    0,                                   //  tp_getset
+    0,                                   //  tp_base
+    0,                                   //  tp_dict
+    0,                                   //  tp_descr_get
+    0,                                   //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    0,                                   //  tp_init
+  };
+#endif
+
+// MapIterator /////////////////////////////////////////////////////////////////
+
+static MapIterator* GetIter(PyObject* obj) {
+  return reinterpret_cast<MapIterator*>(obj);
+}
+
+PyObject* MapReflectionFriend::GetIterator(PyObject *_self) {
+  MapContainer* self = GetMap(_self);
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&MapIterator_Type, 0));
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
+  }
+
+  MapIterator* iter = GetIter(obj.get());
+
+  Py_INCREF(self);
+  iter->container = self;
+  iter->version = self->version;
+  iter->owner = self->owner;
+
+  if (MapReflectionFriend::Length(_self) > 0) {
+    Message* message = self->GetMutableMessage();
+    const Reflection* reflection = message->GetReflection();
+
+    iter->iter.reset(new ::google::protobuf::MapIterator(
+        reflection->MapBegin(message, self->parent_field_descriptor)));
+  }
+
+  return obj.release();
+}
+
+PyObject* MapReflectionFriend::IterNext(PyObject* _self) {
+  MapIterator* self = GetIter(_self);
+
+  // This won't catch mutations to the map performed by MergeFrom(); no easy way
+  // to address that.
+  if (self->version != self->container->version) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Map modified during iteration.");
+  }
+
+  if (self->iter.get() == NULL) {
+    return NULL;
+  }
+
+  Message* message = self->container->GetMutableMessage();
+  const Reflection* reflection = message->GetReflection();
+
+  if (*self->iter ==
+      reflection->MapEnd(message, self->container->parent_field_descriptor)) {
+    return NULL;
+  }
+
+  PyObject* ret = MapKeyToPython(self->container->key_field_descriptor,
+                                 self->iter->GetKey());
+
+  ++(*self->iter);
+
+  return ret;
+}
+
+static void DeallocMapIterator(PyObject* _self) {
+  MapIterator* self = GetIter(_self);
+  self->iter.reset();
+  self->owner.reset();
+  Py_XDECREF(self->container);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+PyTypeObject MapIterator_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MapIterator",     //  tp_name
+  sizeof(MapIterator),                 //  tp_basicsize
+  0,                                   //  tp_itemsize
+  DeallocMapIterator,                  //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  0,                                   //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A scalar map iterator",             //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  PyObject_SelfIter,                   //  tp_iter
+  MapReflectionFriend::IterNext,       //  tp_iternext
+  0,                                   //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/message_map_container.h b/python/google/protobuf/pyext/map_container.h
similarity index 68%
rename from python/google/protobuf/pyext/message_map_container.h
rename to python/google/protobuf/pyext/map_container.h
index 8286ba8..ddf94be 100644
--- a/python/google/protobuf/pyext/message_map_container.h
+++ b/python/google/protobuf/pyext/map_container.h
@@ -28,8 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
-#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
 
 #include <Python.h>
 
@@ -39,30 +39,40 @@
 #endif
 
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
 
 namespace google {
 namespace protobuf {
 
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
 struct CMessage;
 
-struct MessageMapContainer {
+// This struct is used directly for ScalarMap, and is the base class of
+// MessageMapContainer, which is used for MessageMap.
+struct MapContainer {
   PyObject_HEAD;
 
   // This is the top-level C++ Message object that owns the whole
-  // proto tree.  Every Python MessageMapContainer holds a
+  // proto tree.  Every Python MapContainer holds a
   // reference to it in order to keep it alive as long as there's a
   // Python object that references any part of the tree.
   shared_ptr<Message> owner;
 
   // Pointer to the C++ Message that contains this container.  The
-  // MessageMapContainer does not own this pointer.
-  Message* message;
+  // MapContainer does not own this pointer.
+  const Message* message;
+
+  // Use to get a mutable message when necessary.
+  Message* GetMutableMessage();
 
   // Weak reference to a parent CMessage object (i.e. may be NULL.)
   //
@@ -78,45 +88,54 @@
   const FieldDescriptor* key_field_descriptor;
   const FieldDescriptor* value_field_descriptor;
 
+  // We bump this whenever we perform a mutation, to invalidate existing
+  // iterators.
+  uint64 version;
+
+  // Releases the messages in the container to a new message.
+  //
+  // Returns 0 on success, -1 on failure.
+  int Release();
+
+  // Set the owner field of self and any children of self.
+  void SetOwner(const shared_ptr<Message>& new_owner) {
+    owner = new_owner;
+  }
+};
+
+struct MessageMapContainer : public MapContainer {
   // A callable that is used to create new child messages.
   PyObject* subclass_init;
 
   // A dict mapping Message* -> CMessage.
   PyObject* message_dict;
-
-  // We bump this whenever we perform a mutation, to invalidate existing
-  // iterators.
-  uint64 version;
 };
 
 #if PY_MAJOR_VERSION >= 3
   extern PyObject *MessageMapContainer_Type;
   extern PyType_Spec MessageMapContainer_Type_spec;
+  extern PyObject *ScalarMapContainer_Type;
+  extern PyType_Spec ScalarMapContainer_Type_spec;
 #else
   extern PyTypeObject MessageMapContainer_Type;
+  extern PyTypeObject ScalarMapContainer_Type;
 #endif
-extern PyTypeObject MessageMapIterator_Type;
 
-namespace message_map_container {
+extern PyTypeObject MapIterator_Type;  // Both map types use the same iterator.
 
-// Builds a MessageMapContainer object, from a parent message and a
+// Builds a MapContainer object, from a parent message and a
 // field descriptor.
-extern PyObject* NewContainer(CMessage* parent,
-                              const FieldDescriptor* parent_field_descriptor,
-                              PyObject* concrete_class);
+extern PyObject* NewScalarMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
 
-// Releases the messages in the container to a new message.
-//
-// Returns 0 on success, -1 on failure.
-int Release(MessageMapContainer* self);
+// Builds a MessageMap object, from a parent message and a
+// field descriptor.
+extern PyObject* NewMessageMapContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor,
+    PyObject* concrete_class);
 
-// Set the owner field of self and any children of self.
-void SetOwner(MessageMapContainer* self,
-              const shared_ptr<Message>& new_owner);
-
-}  // namespace message_map_container
 }  // namespace python
 }  // namespace protobuf
 
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 04544ca..60ec9c1 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -33,6 +33,7 @@
 
 #include <google/protobuf/pyext/message.h>
 
+#include <map>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
@@ -55,13 +56,13 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
+#include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/extension_dict.h>
 #include <google/protobuf/pyext/repeated_composite_container.h>
 #include <google/protobuf/pyext/repeated_scalar_container.h>
-#include <google/protobuf/pyext/message_map_container.h>
-#include <google/protobuf/pyext/scalar_map_container.h>
+#include <google/protobuf/pyext/map_container.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/strutil.h>
 
@@ -95,6 +96,7 @@
 PyObject* EnumTypeWrapper_class;
 static PyObject* PythonMessage_class;
 static PyObject* kEmptyWeakref;
+static PyObject* WKT_classes = NULL;
 
 // Defines the Metaclass of all Message classes.
 // It allows us to cache some C++ pointers in the class object itself, they are
@@ -107,8 +109,18 @@
 
   // C++ descriptor of this message.
   const Descriptor* message_descriptor;
+
   // Owned reference, used to keep the pointer above alive.
   PyObject* py_message_descriptor;
+
+  // The Python DescriptorPool used to create the class. It is needed to resolve
+  // fields descriptors, including extensions fields; its C++ MessageFactory is
+  // used to instantiate submessages.
+  // This can be different from DESCRIPTOR.file.pool, in the case of a custom
+  // DescriptorPool which defines new extensions.
+  // We own the reference, because it's important to keep the descriptors and
+  // factory alive.
+  PyDescriptorPool* py_descriptor_pool;
 };
 
 namespace message_meta {
@@ -131,7 +143,7 @@
   if (number == NULL) {
     return false;
   }
-  if (PyObject_SetAttr(cls, attr_name, number) == -1) {
+  if (PyObject_SetAttr(cls, attr_name.get(), number.get()) == -1) {
     return false;
   }
   return true;
@@ -139,31 +151,23 @@
 
 
 // Finalize the creation of the Message class.
-// Called from its metaclass: GeneratedProtocolMessageType.__init__().
-static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
-  const Descriptor* message_descriptor =
-      cdescriptor_pool::RegisterMessageClass(
-          GetDescriptorPool(), cls, descriptor);
-  if (message_descriptor == NULL) {
-    return -1;
-  }
-
+static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
   // If there are extension_ranges, the message is "extendable", and extension
   // classes will register themselves in this class.
-  if (message_descriptor->extension_range_count() > 0) {
+  if (descriptor->extension_range_count() > 0) {
     ScopedPyObjectPtr by_name(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) {
+    if (PyObject_SetAttr(cls, k_extensions_by_name, by_name.get()) < 0) {
       return -1;
     }
     ScopedPyObjectPtr by_number(PyDict_New());
-    if (PyObject_SetAttr(cls, k_extensions_by_number, by_number) < 0) {
+    if (PyObject_SetAttr(cls, k_extensions_by_number, by_number.get()) < 0) {
       return -1;
     }
   }
 
   // For each field set: cls.<field>_FIELD_NUMBER = <number>
-  for (int i = 0; i < message_descriptor->field_count(); ++i) {
-    if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) {
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    if (!AddFieldNumberToClass(cls, descriptor->field(i))) {
       return -1;
     }
   }
@@ -173,8 +177,8 @@
   // The enum descriptor we get from
   // <messagedescriptor>.enum_types_by_name[name]
   // which was built previously.
-  for (int i = 0; i < message_descriptor->enum_type_count(); ++i) {
-    const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i);
+  for (int i = 0; i < descriptor->enum_type_count(); ++i) {
+    const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
     ScopedPyObjectPtr enum_type(
         PyEnumDescriptor_FromDescriptor(enum_descriptor));
     if (enum_type == NULL) {
@@ -187,7 +191,7 @@
       return -1;
     }
     if (PyObject_SetAttrString(
-            cls, enum_descriptor->name().c_str(), wrapped) == -1) {
+            cls, enum_descriptor->name().c_str(), wrapped.get()) == -1) {
       return -1;
     }
 
@@ -200,8 +204,8 @@
       if (value_number == NULL) {
         return -1;
       }
-      if (PyObject_SetAttrString(
-              cls, enum_value_descriptor->name().c_str(), value_number) == -1) {
+      if (PyObject_SetAttrString(cls, enum_value_descriptor->name().c_str(),
+                                 value_number.get()) == -1) {
         return -1;
       }
     }
@@ -212,8 +216,8 @@
   // Extension descriptors come from
   // <message descriptor>.extensions_by_name[name]
   // which was defined previously.
-  for (int i = 0; i < message_descriptor->extension_count(); ++i) {
-    const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i);
+  for (int i = 0; i < descriptor->extension_count(); ++i) {
+    const google::protobuf::FieldDescriptor* field = descriptor->extension(i);
     ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field));
     if (extension_field == NULL) {
       return -1;
@@ -221,7 +225,7 @@
 
     // Add the extension field to the message class.
     if (PyObject_SetAttrString(
-            cls, field->name().c_str(), extension_field) == -1) {
+            cls, field->name().c_str(), extension_field.get()) == -1) {
       return -1;
     }
 
@@ -258,26 +262,50 @@
   }
 
   // Check dict['DESCRIPTOR']
-  PyObject* descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
-  if (descriptor == NULL) {
+  PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
+  if (py_descriptor == NULL) {
     PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
     return NULL;
   }
-  if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) {
+  if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
     PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
-                 descriptor->ob_type->tp_name);
+                 py_descriptor->ob_type->tp_name);
     return NULL;
   }
 
   // Build the arguments to the base metaclass.
   // We change the __bases__ classes.
-  ScopedPyObjectPtr new_args(Py_BuildValue(
-      "s(OO)O", name, &CMessage_Type, PythonMessage_class, dict));
+  ScopedPyObjectPtr new_args;
+  const Descriptor* message_descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (message_descriptor == NULL) {
+    return NULL;
+  }
+
+  if (WKT_classes == NULL) {
+    ScopedPyObjectPtr well_known_types(PyImport_ImportModule(
+        "google.protobuf.internal.well_known_types"));
+    GOOGLE_DCHECK(well_known_types != NULL);
+
+    WKT_classes = PyObject_GetAttrString(well_known_types.get(), "WKTBASES");
+    GOOGLE_DCHECK(WKT_classes != NULL);
+  }
+
+  PyObject* well_known_class = PyDict_GetItemString(
+      WKT_classes, message_descriptor->full_name().c_str());
+  if (well_known_class == NULL) {
+    new_args.reset(Py_BuildValue("s(OO)O", name, &CMessage_Type,
+                                 PythonMessage_class, dict));
+  } else {
+    new_args.reset(Py_BuildValue("s(OOO)O", name, &CMessage_Type,
+                                 PythonMessage_class, well_known_class, dict));
+  }
+
   if (new_args == NULL) {
     return NULL;
   }
   // Call the base metaclass.
-  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args, NULL));
+  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), NULL));
   if (result == NULL) {
     return NULL;
   }
@@ -291,17 +319,31 @@
   }
 
   // Cache the descriptor, both as Python object and as C++ pointer.
-  const Descriptor* message_descriptor =
-      PyMessageDescriptor_AsDescriptor(descriptor);
-  if (message_descriptor == NULL) {
+  const Descriptor* descriptor =
+      PyMessageDescriptor_AsDescriptor(py_descriptor);
+  if (descriptor == NULL) {
     return NULL;
   }
-  Py_INCREF(descriptor);
-  newtype->py_message_descriptor = descriptor;
-  newtype->message_descriptor = message_descriptor;
+  Py_INCREF(py_descriptor);
+  newtype->py_message_descriptor = py_descriptor;
+  newtype->message_descriptor = descriptor;
+  // TODO(amauryfa): Don't always use the canonical pool of the descriptor,
+  // use the MessageFactory optionally passed in the class dict.
+  newtype->py_descriptor_pool = GetDescriptorPool_FromPool(
+      descriptor->file()->pool());
+  if (newtype->py_descriptor_pool == NULL) {
+    return NULL;
+  }
+  Py_INCREF(newtype->py_descriptor_pool);
+
+  // Add the message to the DescriptorPool.
+  if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool,
+                                             descriptor, result.get()) < 0) {
+    return NULL;
+  }
 
   // Continue with type initialization: add other descriptors, enum values...
-  if (AddDescriptors(result, descriptor) < 0) {
+  if (AddDescriptors(result.get(), descriptor) < 0) {
     return NULL;
   }
   return result.release();
@@ -309,14 +351,10 @@
 
 static void Dealloc(PyMessageMeta *self) {
   Py_DECREF(self->py_message_descriptor);
+  Py_DECREF(self->py_descriptor_pool);
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
-static PyObject* GetDescriptor(PyMessageMeta *self, void *closure) {
-  Py_INCREF(self->py_message_descriptor);
-  return self->py_message_descriptor;
-}
-
 
 // This function inserts and empty weakref at the end of the list of
 // subclasses for the main protocol buffer Message class.
@@ -381,12 +419,20 @@
   message_meta::New,                   // tp_new
 };
 
-static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+static PyMessageMeta* CheckMessageClass(PyTypeObject* cls) {
   if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) {
     PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
     return NULL;
   }
-  return reinterpret_cast<PyMessageMeta*>(cls)->message_descriptor;
+  return reinterpret_cast<PyMessageMeta*>(cls);
+}
+
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+  PyMessageMeta* type = CheckMessageClass(cls);
+  if (type == NULL) {
+    return NULL;
+  }
+  return type->message_descriptor;
 }
 
 // Forward declarations
@@ -427,21 +473,9 @@
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       if (descriptor->is_map()) {
-        const Descriptor* entry_type = descriptor->message_type();
-        const FieldDescriptor* value_type =
-            entry_type->FindFieldByName("value");
-        if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-          MessageMapContainer* container =
-            reinterpret_cast<MessageMapContainer*>(child);
-          if (visitor.VisitMessageMapContainer(container) == -1) {
-            return -1;
-          }
-        } else {
-          ScalarMapContainer* container =
-            reinterpret_cast<ScalarMapContainer*>(child);
-          if (visitor.VisitScalarMapContainer(container) == -1) {
-            return -1;
-          }
+        MapContainer* container = reinterpret_cast<MapContainer*>(child);
+        if (visitor.VisitMapContainer(container) == -1) {
+          return -1;
         }
       } else {
         RepeatedCompositeContainer* container =
@@ -558,12 +592,14 @@
   if (PyObject_RichCompareBool(min, arg, Py_LE) != 1 ||
       PyObject_RichCompareBool(max, arg, Py_GE) != 1) {
 #endif
-    PyObject *s = PyObject_Str(arg);
-    if (s) {
-      PyErr_Format(PyExc_ValueError,
-                   "Value out of range: %s",
-                   PyString_AsString(s));
-      Py_DECREF(s);
+    if (!PyErr_Occurred()) {
+      PyObject *s = PyObject_Str(arg);
+      if (s) {
+        PyErr_Format(PyExc_ValueError,
+                     "Value out of range: %s",
+                     PyString_AsString(s));
+        Py_DECREF(s);
+      }
     }
     return false;
   }
@@ -621,38 +657,51 @@
   return true;
 }
 
-bool CheckAndSetString(
-    PyObject* arg, Message* message,
-    const FieldDescriptor* descriptor,
-    const Reflection* reflection,
-    bool append,
-    int index) {
+// Checks whether the given object (which must be "bytes" or "unicode") contains
+// valid UTF-8.
+bool IsValidUTF8(PyObject* obj) {
+  if (PyBytes_Check(obj)) {
+    PyObject* unicode = PyUnicode_FromEncodedObject(obj, "utf-8", NULL);
+
+    // Clear the error indicator; we report our own error when desired.
+    PyErr_Clear();
+
+    if (unicode) {
+      Py_DECREF(unicode);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    // Unicode object, known to be valid UTF-8.
+    return true;
+  }
+}
+
+bool AllowInvalidUTF8(const FieldDescriptor* field) { return false; }
+
+PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor) {
   GOOGLE_DCHECK(descriptor->type() == FieldDescriptor::TYPE_STRING ||
          descriptor->type() == FieldDescriptor::TYPE_BYTES);
   if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
     if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) {
       FormatTypeError(arg, "bytes, unicode");
-      return false;
+      return NULL;
     }
 
-    if (PyBytes_Check(arg)) {
-      PyObject* unicode = PyUnicode_FromEncodedObject(arg, "utf-8", NULL);
-      if (unicode == NULL) {
-        PyObject* repr = PyObject_Repr(arg);
-        PyErr_Format(PyExc_ValueError,
-                     "%s has type str, but isn't valid UTF-8 "
-                     "encoding. Non-UTF-8 strings must be converted to "
-                     "unicode objects before being added.",
-                     PyString_AsString(repr));
-        Py_DECREF(repr);
-        return false;
-      } else {
-        Py_DECREF(unicode);
-      }
+    if (!IsValidUTF8(arg) && !AllowInvalidUTF8(descriptor)) {
+      PyObject* repr = PyObject_Repr(arg);
+      PyErr_Format(PyExc_ValueError,
+                   "%s has type str, but isn't valid UTF-8 "
+                   "encoding. Non-UTF-8 strings must be converted to "
+                   "unicode objects before being added.",
+                   PyString_AsString(repr));
+      Py_DECREF(repr);
+      return NULL;
     }
   } else if (!PyBytes_Check(arg)) {
     FormatTypeError(arg, "bytes");
-    return false;
+    return NULL;
   }
 
   PyObject* encoded_string = NULL;
@@ -670,14 +719,24 @@
     Py_INCREF(encoded_string);
   }
 
-  if (encoded_string == NULL) {
+  return encoded_string;
+}
+
+bool CheckAndSetString(
+    PyObject* arg, Message* message,
+    const FieldDescriptor* descriptor,
+    const Reflection* reflection,
+    bool append,
+    int index) {
+  ScopedPyObjectPtr encoded_string(CheckString(arg, descriptor));
+
+  if (encoded_string.get() == NULL) {
     return false;
   }
 
   char* value;
   Py_ssize_t value_len;
-  if (PyBytes_AsStringAndSize(encoded_string, &value, &value_len) < 0) {
-    Py_DECREF(encoded_string);
+  if (PyBytes_AsStringAndSize(encoded_string.get(), &value, &value_len) < 0) {
     return false;
   }
 
@@ -689,7 +748,6 @@
   } else {
     reflection->SetRepeatedString(message, descriptor, index, value_string);
   }
-  Py_DECREF(encoded_string);
   return true;
 }
 
@@ -723,6 +781,17 @@
 
 namespace cmessage {
 
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) {
+  // No need to check the type: the type of instances of CMessage is always
+  // an instance of PyMessageMeta. Let's prove it with a debug-only check.
+  GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type));
+  return reinterpret_cast<PyMessageMeta*>(Py_TYPE(message))->py_descriptor_pool;
+}
+
+MessageFactory* GetFactoryForMessage(CMessage* message) {
+  return GetDescriptorPoolForMessage(message)->message_factory;
+}
+
 static int MaybeReleaseOverlappingOneofField(
     CMessage* cmessage,
     const FieldDescriptor* field) {
@@ -773,7 +842,7 @@
     return NULL;
   }
   return reflection->MutableMessage(
-      parent_message, parent_field, GetDescriptorPool()->message_factory);
+      parent_message, parent_field, GetFactoryForMessage(parent));
 }
 
 struct FixupMessageReference : public ChildVisitor {
@@ -791,12 +860,7 @@
     return 0;
   }
 
-  int VisitScalarMapContainer(ScalarMapContainer* container) {
-    container->message = message_;
-    return 0;
-  }
-
-  int VisitMessageMapContainer(MessageMapContainer* container) {
+  int VisitMapContainer(MapContainer* container) {
     container->message = message_;
     return 0;
   }
@@ -814,10 +878,7 @@
     // If parent is NULL but we are trying to modify a read-only message, this
     // is a reference to a constant default instance that needs to be replaced
     // with a mutable top-level message.
-    const Message* prototype =
-        GetDescriptorPool()->message_factory->GetPrototype(
-            self->message->GetDescriptor());
-    self->message = prototype->New();
+    self->message = self->message->New();
     self->owner.reset(self->message);
     // Cascade the new owner to eventual children: even if this message is
     // empty, some submessages or repeated containers might exist already.
@@ -828,7 +889,6 @@
       return -1;
 
     // Make self->message writable.
-    Message* parent_message = self->parent->message;
     Message* mutable_message = GetMutableMessage(
         self->parent,
         self->parent_field_descriptor);
@@ -842,9 +902,8 @@
   // When a CMessage is made writable its Message pointer is updated
   // to point to a new mutable Message.  When that happens we need to
   // update any references to the old, read-only CMessage.  There are
-  // five places such references occur: RepeatedScalarContainer,
-  // RepeatedCompositeContainer, ScalarMapContainer, MessageMapContainer,
-  // and ExtensionDict.
+  // four places such references occur: RepeatedScalarContainer,
+  // RepeatedCompositeContainer, MapContainer, and ExtensionDict.
   if (self->extensions != NULL)
     self->extensions->message = self->message;
   if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1)
@@ -1026,7 +1085,8 @@
     }
     const FieldDescriptor* descriptor = GetFieldDescriptor(self, name);
     if (descriptor == NULL) {
-      PyErr_Format(PyExc_ValueError, "Protocol message has no \"%s\" field.",
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.",
+                   self->message->GetDescriptor()->name().c_str(),
                    PyString_AsString(name));
       return -1;
     }
@@ -1072,8 +1132,8 @@
           return -1;
         }
         ScopedPyObjectPtr next;
-        while ((next.reset(PyIter_Next(iter))) != NULL) {
-          PyObject* kwargs = (PyDict_Check(next) ? next.get() : NULL);
+        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+          PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : NULL);
           ScopedPyObjectPtr new_msg(
               repeated_composite_container::Add(rc_container, NULL, kwargs));
           if (new_msg == NULL) {
@@ -1081,9 +1141,9 @@
           }
           if (kwargs == NULL) {
             // next was not a dict, it's a message we need to merge
-            ScopedPyObjectPtr merged(
-                MergeFrom(reinterpret_cast<CMessage*>(new_msg.get()), next));
-            if (merged == NULL) {
+            ScopedPyObjectPtr merged(MergeFrom(
+                reinterpret_cast<CMessage*>(new_msg.get()), next.get()));
+            if (merged.get() == NULL) {
               return -1;
             }
           }
@@ -1101,13 +1161,14 @@
           return -1;
         }
         ScopedPyObjectPtr next;
-        while ((next.reset(PyIter_Next(iter))) != NULL) {
-          ScopedPyObjectPtr enum_value(GetIntegerEnumValue(*descriptor, next));
+        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+          ScopedPyObjectPtr enum_value(
+              GetIntegerEnumValue(*descriptor, next.get()));
           if (enum_value == NULL) {
             return -1;
           }
-          ScopedPyObjectPtr new_msg(
-              repeated_scalar_container::Append(rs_container, enum_value));
+          ScopedPyObjectPtr new_msg(repeated_scalar_container::Append(
+              rs_container, enum_value.get()));
           if (new_msg == NULL) {
             return -1;
           }
@@ -1148,7 +1209,8 @@
           return -1;
         }
       }
-      if (SetAttr(self, name, (new_val == NULL) ? value : new_val) < 0) {
+      if (SetAttr(self, name, (new_val.get() == NULL) ? value : new_val.get()) <
+          0) {
         return -1;
       }
     }
@@ -1173,32 +1235,24 @@
 
   self->composite_fields = NULL;
 
-  // If there are extension_ranges, the message is "extendable". Allocate a
-  // dictionary to store the extension fields.
-  if (descriptor->extension_range_count() > 0) {
-    // TODO(amauryfa): Delay the construction of this dict until extensions are
-    // really used on the object.
-    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
-    if (extension_dict == NULL) {
-      return NULL;
-    }
-    self->extensions = extension_dict;
-  }
-
   return self;
 }
 
 // The __new__ method of Message classes.
 // Creates a new C++ message and takes ownership.
-static PyObject* New(PyTypeObject* type,
+static PyObject* New(PyTypeObject* cls,
                      PyObject* unused_args, PyObject* unused_kwargs) {
+  PyMessageMeta* type = CheckMessageClass(cls);
+  if (type == NULL) {
+    return NULL;
+  }
   // Retrieve the message descriptor and the default instance (=prototype).
-  const Descriptor* message_descriptor = GetMessageDescriptor(type);
+  const Descriptor* message_descriptor = type->message_descriptor;
   if (message_descriptor == NULL) {
     return NULL;
   }
-  const Message* default_message =
-      GetDescriptorPool()->message_factory->GetPrototype(message_descriptor);
+  const Message* default_message = type->py_descriptor_pool->message_factory
+                                   ->GetPrototype(message_descriptor);
   if (default_message == NULL) {
     PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
     return NULL;
@@ -1251,12 +1305,7 @@
     return 0;
   }
 
-  int VisitScalarMapContainer(ScalarMapContainer* container) {
-    container->parent = NULL;
-    return 0;
-  }
-
-  int VisitMessageMapContainer(MessageMapContainer* container) {
+  int VisitMapContainer(MapContainer* container) {
     container->parent = NULL;
     return 0;
   }
@@ -1271,6 +1320,9 @@
 static void Dealloc(CMessage* self) {
   // Null out all weak references from children to this message.
   GOOGLE_CHECK_EQ(0, ForEachCompositeField(self, ClearWeakReferences()));
+  if (self->extensions) {
+    self->extensions->parent = NULL;
+  }
 
   Py_CLEAR(self->extensions);
   Py_CLEAR(self->composite_fields);
@@ -1432,20 +1484,27 @@
   Py_RETURN_FALSE;
 }
 
-PyObject* ClearExtension(CMessage* self, PyObject* arg) {
+PyObject* ClearExtension(CMessage* self, PyObject* extension) {
   if (self->extensions != NULL) {
-    return extension_dict::ClearExtension(self->extensions, arg);
+    return extension_dict::ClearExtension(self->extensions, extension);
+  } else {
+    const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+    if (descriptor == NULL) {
+      return NULL;
+    }
+    if (ScopedPyObjectPtr(ClearFieldByDescriptor(self, descriptor)) == NULL) {
+      return NULL;
+    }
   }
-  PyErr_SetString(PyExc_TypeError, "Message is not extendable");
-  return NULL;
+  Py_RETURN_NONE;
 }
 
-PyObject* HasExtension(CMessage* self, PyObject* arg) {
-  if (self->extensions != NULL) {
-    return extension_dict::HasExtension(self->extensions, arg);
+PyObject* HasExtension(CMessage* self, PyObject* extension) {
+  const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
+  if (descriptor == NULL) {
+    return NULL;
   }
-  PyErr_SetString(PyExc_TypeError, "Message is not extendable");
-  return NULL;
+  return HasFieldByDescriptor(self, descriptor);
 }
 
 // ---------------------------------------------------------------------
@@ -1495,13 +1554,8 @@
     return 0;
   }
 
-  int VisitScalarMapContainer(ScalarMapContainer* container) {
-    scalar_map_container::SetOwner(container, new_owner_);
-    return 0;
-  }
-
-  int VisitMessageMapContainer(MessageMapContainer* container) {
-    message_map_container::SetOwner(container, new_owner_);
+  int VisitMapContainer(MapContainer* container) {
+    container->SetOwner(new_owner_);
     return 0;
   }
 
@@ -1528,7 +1582,7 @@
 Message* ReleaseMessage(CMessage* self,
                         const Descriptor* descriptor,
                         const FieldDescriptor* field_descriptor) {
-  MessageFactory* message_factory = GetDescriptorPool()->message_factory;
+  MessageFactory* message_factory = GetFactoryForMessage(self);
   Message* released_message = self->message->GetReflection()->ReleaseMessage(
       self->message, field_descriptor, message_factory);
   // ReleaseMessage will return NULL which differs from
@@ -1574,14 +1628,8 @@
         reinterpret_cast<RepeatedScalarContainer*>(container));
   }
 
-  int VisitScalarMapContainer(ScalarMapContainer* container) {
-    return scalar_map_container::Release(
-        reinterpret_cast<ScalarMapContainer*>(container));
-  }
-
-  int VisitMessageMapContainer(MessageMapContainer* container) {
-    return message_map_container::Release(
-        reinterpret_cast<MessageMapContainer*>(container));
+  int VisitMapContainer(MapContainer* container) {
+    return reinterpret_cast<MapContainer*>(container)->Release();
   }
 
   int VisitCMessage(CMessage* cmessage,
@@ -1673,17 +1721,7 @@
   AssureWritable(self);
   if (ForEachCompositeField(self, ReleaseChild(self)) == -1)
     return NULL;
-
-  // The old ExtensionDict still aliases this CMessage, but all its
-  // fields have been released.
-  if (self->extensions != NULL) {
-    Py_CLEAR(self->extensions);
-    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
-    if (extension_dict == NULL) {
-      return NULL;
-    }
-    self->extensions = extension_dict;
-  }
+  Py_CLEAR(self->extensions);
   if (self->composite_fields) {
     PyDict_Clear(self->composite_fields);
   }
@@ -1731,13 +1769,13 @@
     }
 
     ScopedPyObjectPtr encode_error(
-        PyObject_GetAttrString(message_module, "EncodeError"));
+        PyObject_GetAttrString(message_module.get(), "EncodeError"));
     if (encode_error.get() == NULL) {
       return NULL;
     }
     PyErr_Format(encode_error.get(),
                  "Message %s is missing required fields: %s",
-                 GetMessageName(self).c_str(), PyString_AsString(joined));
+                 GetMessageName(self).c_str(), PyString_AsString(joined.get()));
     return NULL;
   }
   int size = self->message->ByteSize();
@@ -1883,8 +1921,17 @@
   AssureWritable(self);
   io::CodedInputStream input(
       reinterpret_cast<const uint8*>(data), data_length);
-  input.SetExtensionRegistry(GetDescriptorPool()->pool,
-                             GetDescriptorPool()->message_factory);
+#if PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
+  // Protobuf has a 64MB limit built in, this code will override this. Please do
+  // not enable this unless you fully understand the implications: protobufs
+  // must all be kept in memory at the same time, so if they grow too big you
+  // may get OOM errors. The protobuf APIs do not provide any tools for
+  // processing protobufs in chunks.  If you have protos this big you should
+  // break them up if it is at all convenient to do so.
+  input.SetTotalBytesLimit(INT_MAX, INT_MAX);
+#endif  // PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
+  PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
+  input.SetExtensionRegistry(pool->pool, pool->message_factory);
   bool success = self->message->MergePartialFromCodedStream(&input);
   if (success) {
     return PyInt_FromLong(input.CurrentPosition());
@@ -1907,25 +1954,11 @@
 
 static PyObject* RegisterExtension(PyObject* cls,
                                    PyObject* extension_handle) {
-  ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
-  if (message_descriptor == NULL) {
-    return NULL;
-  }
-
   const FieldDescriptor* descriptor =
       GetExtensionDescriptor(extension_handle);
   if (descriptor == NULL) {
     return NULL;
   }
-  const Descriptor* cmessage_descriptor = GetMessageDescriptor(
-      reinterpret_cast<PyTypeObject*>(cls));
-
-  if (cmessage_descriptor != descriptor->containing_type()) {
-    if (PyObject_SetAttrString(extension_handle, "containing_type",
-                               message_descriptor) < 0) {
-      return NULL;
-    }
-  }
 
   ScopedPyObjectPtr extensions_by_name(
       PyObject_GetAttr(cls, k_extensions_by_name));
@@ -1939,7 +1972,8 @@
   }
 
   // If the extension was already registered, check that it is the same.
-  PyObject* existing_extension = PyDict_GetItem(extensions_by_name, full_name);
+  PyObject* existing_extension =
+      PyDict_GetItem(extensions_by_name.get(), full_name.get());
   if (existing_extension != NULL) {
     const FieldDescriptor* existing_extension_descriptor =
         GetExtensionDescriptor(existing_extension);
@@ -1951,7 +1985,8 @@
     Py_RETURN_NONE;
   }
 
-  if (PyDict_SetItem(extensions_by_name, full_name, extension_handle) < 0) {
+  if (PyDict_SetItem(extensions_by_name.get(), full_name.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
@@ -1966,7 +2001,8 @@
   if (number == NULL) {
     return NULL;
   }
-  if (PyDict_SetItem(extensions_by_number, number, extension_handle) < 0) {
+  if (PyDict_SetItem(extensions_by_number.get(), number.get(),
+                     extension_handle) < 0) {
     return NULL;
   }
 
@@ -1974,7 +2010,6 @@
   if (descriptor->is_extension() &&
       descriptor->containing_type()->options().message_set_wire_format() &&
       descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
-      descriptor->message_type() == descriptor->extension_scope() &&
       descriptor->label() == FieldDescriptor::LABEL_OPTIONAL) {
     ScopedPyObjectPtr message_name(PyString_FromStringAndSize(
         descriptor->message_type()->full_name().c_str(),
@@ -1982,7 +2017,8 @@
     if (message_name == NULL) {
       return NULL;
     }
-    PyDict_SetItem(extensions_by_name, message_name, extension_handle);
+    PyDict_SetItem(extensions_by_name.get(), message_name.get(),
+                   extension_handle);
   }
 
   Py_RETURN_NONE;
@@ -2018,6 +2054,8 @@
   }
 }
 
+static PyObject* GetExtensionDict(CMessage* self, void *closure);
+
 static PyObject* ListFields(CMessage* self) {
   vector<const FieldDescriptor*> fields;
   self->message->GetReflection()->ListFields(*self->message, &fields);
@@ -2032,7 +2070,7 @@
   // the field information.  Thus the actual size of the py list will be
   // smaller than the size of fields.  Set the actual size at the end.
   Py_ssize_t actual_size = 0;
-  for (Py_ssize_t i = 0; i < fields.size(); ++i) {
+  for (size_t i = 0; i < fields.size(); ++i) {
     ScopedPyObjectPtr t(PyTuple_New(2));
     if (t == NULL) {
       return NULL;
@@ -2050,16 +2088,18 @@
       // TODO(amauryfa): consider building the class on the fly!
       if (fields[i]->message_type() != NULL &&
           cdescriptor_pool::GetMessageClass(
-              GetDescriptorPool(), fields[i]->message_type()) == NULL) {
+              GetDescriptorPoolForMessage(self),
+              fields[i]->message_type()) == NULL) {
         PyErr_Clear();
         continue;
       }
-      PyObject* extensions = reinterpret_cast<PyObject*>(self->extensions);
+      ScopedPyObjectPtr extensions(GetExtensionDict(self, NULL));
       if (extensions == NULL) {
         return NULL;
       }
       // 'extension' reference later stolen by PyTuple_SET_ITEM.
-      PyObject* extension = PyObject_GetItem(extensions, extension_field);
+      PyObject* extension = PyObject_GetItem(
+          extensions.get(), extension_field.get());
       if (extension == NULL) {
         return NULL;
       }
@@ -2081,9 +2121,9 @@
         return NULL;
       }
 
-      PyObject* field_value = GetAttr(self, py_field_name);
+      PyObject* field_value = GetAttr(self, py_field_name.get());
       if (field_value == NULL) {
-        PyErr_SetObject(PyExc_ValueError, py_field_name);
+        PyErr_SetObject(PyExc_ValueError, py_field_name.get());
         return NULL;
       }
       PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
@@ -2105,7 +2145,7 @@
   if (error_list == NULL) {
     return NULL;
   }
-  for (Py_ssize_t i = 0; i < errors.size(); ++i) {
+  for (size_t i = 0; i < errors.size(); ++i) {
     const string& error = errors[i];
     PyObject* error_string = PyString_FromStringAndSize(
         error.c_str(), error.length());
@@ -2207,7 +2247,9 @@
             message->GetReflection()->GetUnknownFields(*message);
         for (int i = 0; i < unknown_field_set.field_count(); ++i) {
           if (unknown_field_set.field(i).number() ==
-              field_descriptor->number()) {
+              field_descriptor->number() &&
+              unknown_field_set.field(i).type() ==
+              google::protobuf::UnknownField::TYPE_VARINT) {
             result = PyInt_FromLong(unknown_field_set.field(i).varint());
             break;
           }
@@ -2233,11 +2275,12 @@
 PyObject* InternalGetSubMessage(
     CMessage* self, const FieldDescriptor* field_descriptor) {
   const Reflection* reflection = self->message->GetReflection();
+  PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
   const Message& sub_message = reflection->GetMessage(
-      *self->message, field_descriptor, GetDescriptorPool()->message_factory);
+      *self->message, field_descriptor, pool->message_factory);
 
   PyObject *message_class = cdescriptor_pool::GetMessageClass(
-      GetDescriptorPool(), field_descriptor->message_type());
+      pool, field_descriptor->message_type());
   if (message_class == NULL) {
     return NULL;
   }
@@ -2400,16 +2443,16 @@
     return NULL;
   }
   Py_INCREF(Py_True);
-  ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(text_format, method_name,
-                                                       self, Py_True, NULL));
+  ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(
+      text_format.get(), method_name.get(), self, Py_True, NULL));
   Py_DECREF(Py_True);
   if (encoded == NULL) {
     return NULL;
   }
 #if PY_MAJOR_VERSION < 3
-  PyObject* decoded = PyString_AsDecodedObject(encoded, "utf-8", NULL);
+  PyObject* decoded = PyString_AsDecodedObject(encoded.get(), "utf-8", NULL);
 #else
-  PyObject* decoded = PyUnicode_FromEncodedObject(encoded, "utf-8", NULL);
+  PyObject* decoded = PyUnicode_FromEncodedObject(encoded.get(), "utf-8", NULL);
 #endif
   if (decoded == NULL) {
     return NULL;
@@ -2432,7 +2475,7 @@
   if (serialized == NULL) {
     return NULL;
   }
-  if (PyDict_SetItemString(state, "serialized", serialized) < 0) {
+  if (PyDict_SetItemString(state.get(), "serialized", serialized.get()) < 0) {
     return NULL;
   }
   return Py_BuildValue("OOO", constructor.get(), args.get(), state.get());
@@ -2465,9 +2508,31 @@
   Py_RETURN_NONE;
 }
 
-static PyMemberDef Members[] = {
-  {"Extensions", T_OBJECT_EX, offsetof(CMessage, extensions), 0,
-   "Extension dict"},
+static PyObject* GetExtensionDict(CMessage* self, void *closure) {
+  if (self->extensions)  {
+    Py_INCREF(self->extensions);
+    return reinterpret_cast<PyObject*>(self->extensions);
+  }
+
+  // If there are extension_ranges, the message is "extendable". Allocate a
+  // dictionary to store the extension fields.
+  const Descriptor* descriptor = GetMessageDescriptor(Py_TYPE(self));
+  if (descriptor->extension_range_count() > 0) {
+    ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
+    if (extension_dict == NULL) {
+      return NULL;
+    }
+    self->extensions = extension_dict;
+    Py_INCREF(self->extensions);
+    return reinterpret_cast<PyObject*>(self->extensions);
+  }
+
+  PyErr_SetNone(PyExc_AttributeError);
+  return NULL;
+}
+
+static PyGetSetDef Getters[] = {
+  {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"},
   {NULL}
 };
 
@@ -2560,14 +2625,14 @@
     const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
     if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       PyObject* value_class = cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), value_type->message_type());
+          GetDescriptorPoolForMessage(self), value_type->message_type());
       if (value_class == NULL) {
         return NULL;
       }
-      py_container = message_map_container::NewContainer(self, field_descriptor,
-                                                         value_class);
+      py_container =
+          NewMessageMapContainer(self, field_descriptor, value_class);
     } else {
-      py_container = scalar_map_container::NewContainer(self, field_descriptor);
+      py_container = NewScalarMapContainer(self, field_descriptor);
     }
     if (py_container == NULL) {
       return NULL;
@@ -2583,7 +2648,7 @@
     PyObject* py_container = NULL;
     if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       PyObject *message_class = cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), field_descriptor->message_type());
+          GetDescriptorPoolForMessage(self), field_descriptor->message_type());
       if (message_class == NULL) {
         return NULL;
       }
@@ -2644,7 +2709,10 @@
     }
   }
 
-  PyErr_Format(PyExc_AttributeError, "Assignment not allowed");
+  PyErr_Format(PyExc_AttributeError,
+               "Assignment not allowed "
+               "(no field \"%s\"in protocol message object).",
+               PyString_AsString(name));
   return -1;
 }
 
@@ -2679,8 +2747,8 @@
   0,                                   //  tp_iter
   0,                                   //  tp_iternext
   cmessage::Methods,                   //  tp_methods
-  cmessage::Members,                   //  tp_members
-  0,                                   //  tp_getset
+  0,                                   //  tp_members
+  cmessage::Getters,                   //  tp_getset
   0,                                   //  tp_base
   0,                                   //  tp_dict
   0,                                   //  tp_descr_get
@@ -2787,16 +2855,16 @@
   if (empty_dict == NULL) {
     return false;
   }
-  ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict));
+  ScopedPyObjectPtr immutable_dict(PyDictProxy_New(empty_dict.get()));
   if (immutable_dict == NULL) {
     return false;
   }
   if (PyDict_SetItem(CMessage_Type.tp_dict,
-                     k_extensions_by_name, immutable_dict) < 0) {
+                     k_extensions_by_name, immutable_dict.get()) < 0) {
     return false;
   }
   if (PyDict_SetItem(CMessage_Type.tp_dict,
-                     k_extensions_by_number, immutable_dict) < 0) {
+                     k_extensions_by_number, immutable_dict.get()) < 0) {
     return false;
   }
 
@@ -2826,19 +2894,19 @@
     if (collections == NULL) {
       return false;
     }
-    ScopedPyObjectPtr mutable_sequence(PyObject_GetAttrString(
-        collections, "MutableSequence"));
+    ScopedPyObjectPtr mutable_sequence(
+        PyObject_GetAttrString(collections.get(), "MutableSequence"));
     if (mutable_sequence == NULL) {
       return false;
     }
-    if (ScopedPyObjectPtr(PyObject_CallMethod(mutable_sequence, "register", "O",
-                                              &RepeatedScalarContainer_Type))
-        == NULL) {
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedScalarContainer_Type)) == NULL) {
       return false;
     }
-    if (ScopedPyObjectPtr(PyObject_CallMethod(mutable_sequence, "register", "O",
-                                              &RepeatedCompositeContainer_Type))
-        == NULL) {
+    if (ScopedPyObjectPtr(
+            PyObject_CallMethod(mutable_sequence.get(), "register", "O",
+                                &RepeatedCompositeContainer_Type)) == NULL) {
       return false;
     }
   }
@@ -2853,16 +2921,16 @@
     }
 
     ScopedPyObjectPtr mutable_mapping(
-        PyObject_GetAttrString(containers, "MutableMapping"));
+        PyObject_GetAttrString(containers.get(), "MutableMapping"));
     if (mutable_mapping == NULL) {
       return false;
     }
 
-    if (!PyObject_TypeCheck(mutable_mapping, &PyType_Type)) {
+    if (!PyObject_TypeCheck(mutable_mapping.get(), &PyType_Type)) {
       return false;
     }
 
-    Py_INCREF(mutable_mapping);
+    Py_INCREF(mutable_mapping.get());
 #if PY_MAJOR_VERSION >= 3
     PyObject* bases = PyTuple_New(1);
     PyTuple_SET_ITEM(bases, 0, mutable_mapping.get());
@@ -2882,12 +2950,12 @@
                        reinterpret_cast<PyObject*>(&ScalarMapContainer_Type));
 #endif
 
-    if (PyType_Ready(&ScalarMapIterator_Type) < 0) {
+    if (PyType_Ready(&MapIterator_Type) < 0) {
       return false;
     }
 
-    PyModule_AddObject(m, "ScalarMapIterator",
-                       reinterpret_cast<PyObject*>(&ScalarMapIterator_Type));
+    PyModule_AddObject(m, "MapIterator",
+                       reinterpret_cast<PyObject*>(&MapIterator_Type));
 
 
 #if PY_MAJOR_VERSION >= 3
@@ -2895,7 +2963,7 @@
         PyType_FromSpecWithBases(&MessageMapContainer_Type_spec, bases);
     PyModule_AddObject(m, "MessageMapContainer", MessageMapContainer_Type);
 #else
-    Py_INCREF(mutable_mapping);
+    Py_INCREF(mutable_mapping.get());
     MessageMapContainer_Type.tp_base =
         reinterpret_cast<PyTypeObject*>(mutable_mapping.get());
 
@@ -2906,13 +2974,6 @@
     PyModule_AddObject(m, "MessageMapContainer",
                        reinterpret_cast<PyObject*>(&MessageMapContainer_Type));
 #endif
-
-    if (PyType_Ready(&MessageMapIterator_Type) < 0) {
-      return false;
-    }
-
-    PyModule_AddObject(m, "MessageMapIterator",
-                       reinterpret_cast<PyObject*>(&MessageMapIterator_Type));
   }
 
   if (PyType_Ready(&ExtensionDict_Type) < 0) {
@@ -2924,9 +2985,13 @@
 
   // Expose the DescriptorPool used to hold all descriptors added from generated
   // pb2.py files.
-  Py_INCREF(GetDescriptorPool());  // PyModule_AddObject steals a reference.
-  PyModule_AddObject(
-      m, "default_pool", reinterpret_cast<PyObject*>(GetDescriptorPool()));
+  // PyModule_AddObject steals a reference.
+  Py_INCREF(GetDefaultDescriptorPool());
+  PyModule_AddObject(m, "default_pool",
+                     reinterpret_cast<PyObject*>(GetDefaultDescriptorPool()));
+
+  PyModule_AddObject(m, "DescriptorPool", reinterpret_cast<PyObject*>(
+      &PyDescriptorPool_Type));
 
   // This implementation provides full Descriptor types, we advertise it so that
   // descriptor.py can use them in replacement of the Python classes.
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index f147d43..cc0012e 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -49,12 +49,20 @@
 class Reflection;
 class FieldDescriptor;
 class Descriptor;
+class DescriptorPool;
+class MessageFactory;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+using std::string;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
 struct ExtensionDict;
+struct PyDescriptorPool;
 
 typedef struct CMessage {
   PyObject_HEAD;
@@ -220,6 +228,16 @@
 int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
 
 int AssureWritable(CMessage* self);
+
+// Returns the "best" DescriptorPool for the given message.
+// This is often equivalent to message.DESCRIPTOR.pool, but not always, when
+// the message class was created from a MessageFactory using a custom pool which
+// uses the generated pool as an underlay.
+//
+// The returned pool is suitable for finding fields and building submessages,
+// even in the case of extensions.
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
+
 }  // namespace cmessage
 
 
@@ -289,6 +307,7 @@
 bool CheckAndGetDouble(PyObject* arg, double* value);
 bool CheckAndGetFloat(PyObject* arg, float* value);
 bool CheckAndGetBool(PyObject* arg, bool* value);
+PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor);
 bool CheckAndSetString(
     PyObject* arg, Message* message,
     const FieldDescriptor* descriptor,
diff --git a/python/google/protobuf/pyext/message_map_container.cc b/python/google/protobuf/pyext/message_map_container.cc
deleted file mode 100644
index f54d201..0000000
--- a/python/google/protobuf/pyext/message_map_container.cc
+++ /dev/null
@@ -1,569 +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.
-
-// Author: haberman@google.com (Josh Haberman)
-
-#include <google/protobuf/pyext/message_map_container.h>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/message.h>
-#include <google/protobuf/pyext/message.h>
-#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-struct MessageMapIterator {
-  PyObject_HEAD;
-
-  // This dict contains the full contents of what we want to iterate over.
-  // There's no way to avoid building this, because the list representation
-  // (which is canonical) can contain duplicate keys.  So at the very least we
-  // need a set that lets us skip duplicate keys.  And at the point that we're
-  // doing that, we might as well just build the actual dict we're iterating
-  // over and use dict's built-in iterator.
-  PyObject* dict;
-
-  // An iterator on dict.
-  PyObject* iter;
-
-  // A pointer back to the container, so we can notice changes to the version.
-  MessageMapContainer* container;
-
-  // The version of the map when we took the iterator to it.
-  //
-  // We store this so that if the map is modified during iteration we can throw
-  // an error.
-  uint64 version;
-};
-
-static MessageMapIterator* GetIter(PyObject* obj) {
-  return reinterpret_cast<MessageMapIterator*>(obj);
-}
-
-namespace message_map_container {
-
-static MessageMapContainer* GetMap(PyObject* obj) {
-  return reinterpret_cast<MessageMapContainer*>(obj);
-}
-
-// The private constructor of MessageMapContainer objects.
-PyObject* NewContainer(CMessage* parent,
-                       const google::protobuf::FieldDescriptor* parent_field_descriptor,
-                       PyObject* concrete_class) {
-  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
-    return NULL;
-  }
-
-#if PY_MAJOR_VERSION >= 3
-  PyObject* obj = PyType_GenericAlloc(
-        reinterpret_cast<PyTypeObject *>(MessageMapContainer_Type), 0);
-#else
-  PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0);
-#endif
-  if (obj == NULL) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Could not allocate new container.");
-  }
-
-  MessageMapContainer* self = GetMap(obj);
-
-  self->message = parent->message;
-  self->parent = parent;
-  self->parent_field_descriptor = parent_field_descriptor;
-  self->owner = parent->owner;
-  self->version = 0;
-
-  self->key_field_descriptor =
-      parent_field_descriptor->message_type()->FindFieldByName("key");
-  self->value_field_descriptor =
-      parent_field_descriptor->message_type()->FindFieldByName("value");
-
-  self->message_dict = PyDict_New();
-  if (self->message_dict == NULL) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Could not allocate message dict.");
-  }
-
-  Py_INCREF(concrete_class);
-  self->subclass_init = concrete_class;
-
-  if (self->key_field_descriptor == NULL ||
-      self->value_field_descriptor == NULL) {
-    Py_DECREF(obj);
-    return PyErr_Format(PyExc_KeyError,
-                        "Map entry descriptor did not have key/value fields");
-  }
-
-  return obj;
-}
-
-// 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
-// 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).
-static int InitializeAndCopyToParentContainer(
-    MessageMapContainer* from,
-    MessageMapContainer* to) {
-  // For now we require from == to, re-evaluate if we want to support deep copy
-  // as in repeated_composite_container.cc.
-  GOOGLE_DCHECK(from == to);
-  Message* old_message = from->message;
-  Message* new_message = old_message->New();
-  to->parent = NULL;
-  to->parent_field_descriptor = from->parent_field_descriptor;
-  to->message = new_message;
-  to->owner.reset(new_message);
-
-  vector<const FieldDescriptor*> fields;
-  fields.push_back(from->parent_field_descriptor);
-  old_message->GetReflection()->SwapFields(old_message, new_message, fields);
-  return 0;
-}
-
-static PyObject* GetCMessage(MessageMapContainer* self, Message* entry) {
-  // Get or create the CMessage object corresponding to this message.
-  Message* message = entry->GetReflection()->MutableMessage(
-      entry, self->value_field_descriptor);
-  ScopedPyObjectPtr key(PyLong_FromVoidPtr(message));
-  PyObject* ret = PyDict_GetItem(self->message_dict, key);
-
-  if (ret == NULL) {
-    CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
-                                               message->GetDescriptor());
-    ret = reinterpret_cast<PyObject*>(cmsg);
-
-    if (cmsg == NULL) {
-      return NULL;
-    }
-    cmsg->owner = self->owner;
-    cmsg->message = message;
-    cmsg->parent = self->parent;
-
-    if (PyDict_SetItem(self->message_dict, key, ret) < 0) {
-      Py_DECREF(ret);
-      return NULL;
-    }
-  } else {
-    Py_INCREF(ret);
-  }
-
-  return ret;
-}
-
-int Release(MessageMapContainer* self) {
-  InitializeAndCopyToParentContainer(self, self);
-  return 0;
-}
-
-void SetOwner(MessageMapContainer* self,
-              const shared_ptr<Message>& new_owner) {
-  self->owner = new_owner;
-}
-
-Py_ssize_t Length(PyObject* _self) {
-  MessageMapContainer* self = GetMap(_self);
-  google::protobuf::Message* message = self->message;
-  return message->GetReflection()->FieldSize(*message,
-                                             self->parent_field_descriptor);
-}
-
-int MapKeyMatches(MessageMapContainer* self, const Message* entry,
-                  PyObject* key) {
-  // TODO(haberman): do we need more strict type checking?
-  ScopedPyObjectPtr entry_key(
-      cmessage::InternalGetScalar(entry, self->key_field_descriptor));
-  int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ);
-  return ret;
-}
-
-int SetItem(PyObject *_self, PyObject *key, PyObject *v) {
-  if (v) {
-    PyErr_Format(PyExc_ValueError,
-                 "Direct assignment of submessage not allowed");
-    return -1;
-  }
-
-  // Now we know that this is a delete, not a set.
-
-  MessageMapContainer* self = GetMap(_self);
-  cmessage::AssureWritable(self->parent);
-
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.  We need to search from the end because the underlying
-  // representation can have duplicates if a user calls MergeFrom(); the last
-  // one needs to win.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  bool found = false;
-  for (int i = size - 1; i >= 0; i--) {
-    Message* entry = reflection->MutableRepeatedMessage(
-        message, self->parent_field_descriptor, i);
-    int matches = MapKeyMatches(self, entry, key);
-    if (matches < 0) return -1;
-    if (matches) {
-      found = true;
-      if (i != size - 1) {
-        reflection->SwapElements(message, self->parent_field_descriptor, i,
-                                 size - 1);
-      }
-      reflection->RemoveLast(message, self->parent_field_descriptor);
-
-      // Can't exit now, the repeated field representation of maps allows
-      // duplicate keys, and we have to be sure to remove all of them.
-    }
-  }
-
-  if (!found) {
-    PyErr_Format(PyExc_KeyError, "Key not present in map");
-    return -1;
-  }
-
-  self->version++;
-
-  return 0;
-}
-
-PyObject* GetIterator(PyObject *_self) {
-  MessageMapContainer* self = GetMap(_self);
-
-  ScopedPyObjectPtr obj(PyType_GenericAlloc(&MessageMapIterator_Type, 0));
-  if (obj == NULL) {
-    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
-  }
-
-  MessageMapIterator* iter = GetIter(obj);
-
-  Py_INCREF(self);
-  iter->container = self;
-  iter->version = self->version;
-  iter->dict = PyDict_New();
-  if (iter->dict == NULL) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Could not allocate dict for iterator.");
-  }
-
-  // Build the entire map into a dict right now.  Start from the beginning so
-  // that later entries win in the case of duplicates.
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.  We need to search from the end because the underlying
-  // representation can have duplicates if a user calls MergeFrom(); the last
-  // one needs to win.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = size - 1; i >= 0; i--) {
-    Message* entry = reflection->MutableRepeatedMessage(
-        message, self->parent_field_descriptor, i);
-    ScopedPyObjectPtr key(
-        cmessage::InternalGetScalar(entry, self->key_field_descriptor));
-    if (PyDict_SetItem(iter->dict, key.get(), GetCMessage(self, entry)) < 0) {
-      return PyErr_Format(PyExc_RuntimeError,
-                          "SetItem failed in iterator construction.");
-    }
-  }
-
-  iter->iter = PyObject_GetIter(iter->dict);
-
-  return obj.release();
-}
-
-PyObject* GetItem(PyObject* _self, PyObject* key) {
-  MessageMapContainer* self = GetMap(_self);
-  cmessage::AssureWritable(self->parent);
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.  We need to search from the end because the underlying
-  // representation can have duplicates if a user calls MergeFrom(); the last
-  // one needs to win.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = size - 1; i >= 0; i--) {
-    Message* entry = reflection->MutableRepeatedMessage(
-        message, self->parent_field_descriptor, i);
-    int matches = MapKeyMatches(self, entry, key);
-    if (matches < 0) return NULL;
-    if (matches) {
-      return GetCMessage(self, entry);
-    }
-  }
-
-  // Key is not already present; insert a new entry.
-  Message* entry =
-      reflection->AddMessage(message, self->parent_field_descriptor);
-
-  self->version++;
-
-  if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
-                                          key) < 0) {
-    reflection->RemoveLast(message, self->parent_field_descriptor);
-    return NULL;
-  }
-
-  return GetCMessage(self, entry);
-}
-
-PyObject* Contains(PyObject* _self, PyObject* key) {
-  MessageMapContainer* self = GetMap(_self);
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = 0; i < size; i++) {
-    Message* entry = reflection->MutableRepeatedMessage(
-        message, self->parent_field_descriptor, i);
-    int matches = MapKeyMatches(self, entry, key);
-    if (matches < 0) return NULL;
-    if (matches) {
-      Py_RETURN_TRUE;
-    }
-  }
-
-  Py_RETURN_FALSE;
-}
-
-PyObject* Clear(PyObject* _self) {
-  MessageMapContainer* self = GetMap(_self);
-  cmessage::AssureWritable(self->parent);
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  self->version++;
-  reflection->ClearField(message, self->parent_field_descriptor);
-
-  Py_RETURN_NONE;
-}
-
-PyObject* Get(PyObject* self, PyObject* args) {
-  PyObject* key;
-  PyObject* default_value = NULL;
-  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
-    return NULL;
-  }
-
-  ScopedPyObjectPtr is_present(Contains(self, key));
-  if (is_present.get() == NULL) {
-    return NULL;
-  }
-
-  if (PyObject_IsTrue(is_present.get())) {
-    return GetItem(self, key);
-  } else {
-    if (default_value != NULL) {
-      Py_INCREF(default_value);
-      return default_value;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-
-static PyMappingMethods MpMethods = {
-  Length,    // mp_length
-  GetItem,   // mp_subscript
-  SetItem,   // mp_ass_subscript
-};
-
-static void Dealloc(PyObject* _self) {
-  MessageMapContainer* self = GetMap(_self);
-  self->owner.reset();
-  Py_DECREF(self->message_dict);
-  Py_TYPE(_self)->tp_free(_self);
-}
-
-static PyMethodDef Methods[] = {
-  { "__contains__", (PyCFunction)Contains, METH_O,
-    "Tests whether the map contains this element."},
-  { "clear", (PyCFunction)Clear, METH_NOARGS,
-    "Removes all elements from the map."},
-  { "get", Get, METH_VARARGS,
-    "Gets the value for the given key if present, or otherwise a default" },
-  { "get_or_create", GetItem, METH_O,
-    "Alias for getitem, useful to make explicit that the map is mutated." },
-  /*
-  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
-    "Makes a deep copy of the class." },
-  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
-    "Outputs picklable representation of the repeated field." },
-  */
-  {NULL, NULL},
-};
-
-}  // namespace message_map_container
-
-namespace message_map_iterator {
-
-static void Dealloc(PyObject* _self) {
-  MessageMapIterator* self = GetIter(_self);
-  Py_DECREF(self->dict);
-  Py_DECREF(self->iter);
-  Py_DECREF(self->container);
-  Py_TYPE(_self)->tp_free(_self);
-}
-
-PyObject* IterNext(PyObject* _self) {
-  MessageMapIterator* self = GetIter(_self);
-
-  // This won't catch mutations to the map performed by MergeFrom(); no easy way
-  // to address that.
-  if (self->version != self->container->version) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Map modified during iteration.");
-  }
-
-  return PyIter_Next(self->iter);
-}
-
-}  // namespace message_map_iterator
-
-#if PY_MAJOR_VERSION >= 3
-  static PyType_Slot MessageMapContainer_Type_slots[] = {
-      {Py_tp_dealloc, (void *)message_map_container::Dealloc},
-      {Py_mp_length, (void *)message_map_container::Length},
-      {Py_mp_subscript, (void *)message_map_container::GetItem},
-      {Py_mp_ass_subscript, (void *)message_map_container::SetItem},
-      {Py_tp_methods, (void *)message_map_container::Methods},
-      {Py_tp_iter, (void *)message_map_container::GetIterator},
-      {0, 0}
-  };
-
-  PyType_Spec MessageMapContainer_Type_spec = {
-      FULL_MODULE_NAME ".MessageMapContainer",
-      sizeof(MessageMapContainer),
-      0,
-      Py_TPFLAGS_DEFAULT,
-      MessageMapContainer_Type_slots
-  };
-
-  PyObject *MessageMapContainer_Type;
-
-#else
-  PyTypeObject MessageMapContainer_Type = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    FULL_MODULE_NAME ".MessageMapContainer",  //  tp_name
-    sizeof(MessageMapContainer),         //  tp_basicsize
-    0,                                   //  tp_itemsize
-    message_map_container::Dealloc,      //  tp_dealloc
-    0,                                   //  tp_print
-    0,                                   //  tp_getattr
-    0,                                   //  tp_setattr
-    0,                                   //  tp_compare
-    0,                                   //  tp_repr
-    0,                                   //  tp_as_number
-    0,                                   //  tp_as_sequence
-    &message_map_container::MpMethods,   //  tp_as_mapping
-    0,                                   //  tp_hash
-    0,                                   //  tp_call
-    0,                                   //  tp_str
-    0,                                   //  tp_getattro
-    0,                                   //  tp_setattro
-    0,                                   //  tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                  //  tp_flags
-    "A map container for message",       //  tp_doc
-    0,                                   //  tp_traverse
-    0,                                   //  tp_clear
-    0,                                   //  tp_richcompare
-    0,                                   //  tp_weaklistoffset
-    message_map_container::GetIterator,  //  tp_iter
-    0,                                   //  tp_iternext
-    message_map_container::Methods,      //  tp_methods
-    0,                                   //  tp_members
-    0,                                   //  tp_getset
-    0,                                   //  tp_base
-    0,                                   //  tp_dict
-    0,                                   //  tp_descr_get
-    0,                                   //  tp_descr_set
-    0,                                   //  tp_dictoffset
-    0,                                   //  tp_init
-  };
-#endif
-
-PyTypeObject MessageMapIterator_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".MessageMapIterator",  //  tp_name
-  sizeof(MessageMapIterator),          //  tp_basicsize
-  0,                                   //  tp_itemsize
-  message_map_iterator::Dealloc,       //  tp_dealloc
-  0,                                   //  tp_print
-  0,                                   //  tp_getattr
-  0,                                   //  tp_setattr
-  0,                                   //  tp_compare
-  0,                                   //  tp_repr
-  0,                                   //  tp_as_number
-  0,                                   //  tp_as_sequence
-  0,                                   //  tp_as_mapping
-  0,                                   //  tp_hash
-  0,                                   //  tp_call
-  0,                                   //  tp_str
-  0,                                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  //  tp_flags
-  "A scalar map iterator",             //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  0,                                   //  tp_richcompare
-  0,                                   //  tp_weaklistoffset
-  PyObject_SelfIter,                   //  tp_iter
-  message_map_iterator::IterNext,       //  tp_iternext
-  0,                                   //  tp_methods
-  0,                                   //  tp_members
-  0,                                   //  tp_getset
-  0,                                   //  tp_base
-  0,                                   //  tp_dict
-  0,                                   //  tp_descr_get
-  0,                                   //  tp_descr_set
-  0,                                   //  tp_dictoffset
-  0,                                   //  tp_init
-};
-
-}  // namespace python
-}  // namespace protobuf
-}  // namespace google
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index fe2e600..b01123b 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -116,7 +116,7 @@
     cmsg->owner = self->owner;
     cmsg->message = const_cast<Message*>(&sub_message);
     cmsg->parent = self->parent;
-    if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+    if (PyList_Append(self->child_messages, py_cmsg.get()) < 0) {
       return -1;
     }
   }
@@ -202,8 +202,8 @@
     return NULL;
   }
   ScopedPyObjectPtr next;
-  while ((next.reset(PyIter_Next(iter))) != NULL) {
-    if (!PyObject_TypeCheck(next, &CMessage_Type)) {
+  while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+    if (!PyObject_TypeCheck(next.get(), &CMessage_Type)) {
       PyErr_SetString(PyExc_TypeError, "Not a cmessage");
       return NULL;
     }
@@ -212,7 +212,8 @@
       return NULL;
     }
     CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
-    if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next)) == NULL) {
+    if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next.get())) ==
+        NULL) {
       return NULL;
     }
   }
@@ -294,7 +295,7 @@
     return NULL;
   }
   ScopedPyObjectPtr py_index(PyLong_FromLong(index));
-  if (AssignSubscript(self, py_index, NULL) < 0) {
+  if (AssignSubscript(self, py_index.get(), NULL) < 0) {
     return NULL;
   }
   Py_RETURN_NONE;
@@ -318,17 +319,17 @@
     if (full_slice == NULL) {
       return NULL;
     }
-    ScopedPyObjectPtr list(Subscript(self, full_slice));
+    ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
     if (list == NULL) {
       return NULL;
     }
     ScopedPyObjectPtr other_list(
-        Subscript(
-            reinterpret_cast<RepeatedCompositeContainer*>(other), full_slice));
+        Subscript(reinterpret_cast<RepeatedCompositeContainer*>(other),
+                  full_slice.get()));
     if (other_list == NULL) {
       return NULL;
     }
-    return PyObject_RichCompare(list, other_list, opid);
+    return PyObject_RichCompare(list.get(), other_list.get(), opid);
   } else {
     Py_INCREF(Py_NotImplemented);
     return Py_NotImplemented;
@@ -365,7 +366,7 @@
   ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort"));
   if (m == NULL)
     return -1;
-  if (PyObject_Call(m, args, kwds) == NULL)
+  if (PyObject_Call(m.get(), args, kwds) == NULL)
     return -1;
   if (self->message != NULL) {
     ReorderAttached(self);
@@ -429,7 +430,7 @@
     return NULL;
   }
   ScopedPyObjectPtr py_index(PyLong_FromSsize_t(index));
-  if (AssignSubscript(self, py_index, NULL) < 0) {
+  if (AssignSubscript(self, py_index.get(), NULL) < 0) {
     return NULL;
   }
   return item;
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
index e0f2136..58d37b0 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.h
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -49,7 +49,11 @@
 class FieldDescriptor;
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
@@ -108,9 +112,6 @@
     const FieldDescriptor* parent_field_descriptor,
     PyObject *concrete_class);
 
-// Returns the number of items in this repeated composite container.
-static Py_ssize_t Length(RepeatedCompositeContainer* self);
-
 // Appends a new CMessage to the container and returns it.  The
 // CMessage is initialized using the content of kwargs.
 //
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index 7565c6f..95da85f 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -105,7 +105,7 @@
   if (arg == NULL) {
     ScopedPyObjectPtr py_index(PyLong_FromLong(index));
     return cmessage::InternalDeleteRepeatedField(self->parent, field_descriptor,
-                                                 py_index, NULL);
+                                                 py_index.get(), NULL);
   }
 
   if (PySequence_Check(arg) && !(PyBytes_Check(arg) || PyUnicode_Check(arg))) {
@@ -172,7 +172,7 @@
           ScopedPyObjectPtr s(PyObject_Str(arg));
           if (s != NULL) {
             PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                         PyString_AsString(s));
+                         PyString_AsString(s.get()));
           }
           return -1;
         }
@@ -334,7 +334,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   } else {
     if (step > 0) {
@@ -345,7 +345,7 @@
         break;
       }
       ScopedPyObjectPtr s(Item(self, index));
-      PyList_Append(list, s);
+      PyList_Append(list, s.get());
     }
   }
   return list;
@@ -414,7 +414,7 @@
           ScopedPyObjectPtr s(PyObject_Str(item));
           if (s != NULL) {
             PyErr_Format(PyExc_ValueError, "Unknown enum value: %s",
-                         PyString_AsString(s));
+                         PyString_AsString(s.get()));
           }
           return NULL;
         }
@@ -483,15 +483,15 @@
   if (full_slice == NULL) {
     return -1;
   }
-  ScopedPyObjectPtr new_list(Subscript(self, full_slice));
+  ScopedPyObjectPtr new_list(Subscript(self, full_slice.get()));
   if (new_list == NULL) {
     return -1;
   }
-  if (PySequence_SetSlice(new_list, from, to, value) < 0) {
+  if (PySequence_SetSlice(new_list.get(), from, to, value) < 0) {
     return -1;
   }
 
-  return InternalAssignRepeatedField(self, new_list);
+  return InternalAssignRepeatedField(self, new_list.get());
 }
 
 PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
@@ -511,8 +511,8 @@
     return NULL;
   }
   ScopedPyObjectPtr next;
-  while ((next.reset(PyIter_Next(iter))) != NULL) {
-    if (ScopedPyObjectPtr(Append(self, next)) == NULL) {
+  while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+    if (ScopedPyObjectPtr(Append(self, next.get())) == NULL) {
       return NULL;
     }
   }
@@ -529,11 +529,11 @@
     return NULL;
   }
   ScopedPyObjectPtr full_slice(PySlice_New(NULL, NULL, NULL));
-  ScopedPyObjectPtr new_list(Subscript(self, full_slice));
-  if (PyList_Insert(new_list, index, value) < 0) {
+  ScopedPyObjectPtr new_list(Subscript(self, full_slice.get()));
+  if (PyList_Insert(new_list.get(), index, value) < 0) {
     return NULL;
   }
-  int ret = InternalAssignRepeatedField(self, new_list);
+  int ret = InternalAssignRepeatedField(self, new_list.get());
   if (ret < 0) {
     return NULL;
   }
@@ -544,7 +544,7 @@
   Py_ssize_t match_index = -1;
   for (Py_ssize_t i = 0; i < Len(self); ++i) {
     ScopedPyObjectPtr elem(Item(self, i));
-    if (PyObject_RichCompareBool(elem, value, Py_EQ)) {
+    if (PyObject_RichCompareBool(elem.get(), value, Py_EQ)) {
       match_index = i;
       break;
     }
@@ -579,15 +579,15 @@
   ScopedPyObjectPtr other_list_deleter;
   if (PyObject_TypeCheck(other, &RepeatedScalarContainer_Type)) {
     other_list_deleter.reset(Subscript(
-        reinterpret_cast<RepeatedScalarContainer*>(other), full_slice));
+        reinterpret_cast<RepeatedScalarContainer*>(other), full_slice.get()));
     other = other_list_deleter.get();
   }
 
-  ScopedPyObjectPtr list(Subscript(self, full_slice));
+  ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
   if (list == NULL) {
     return NULL;
   }
-  return PyObject_RichCompare(list, other, opid);
+  return PyObject_RichCompare(list.get(), other, opid);
 }
 
 PyObject* Reduce(RepeatedScalarContainer* unused_self) {
@@ -618,19 +618,19 @@
   if (full_slice == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr list(Subscript(self, full_slice));
+  ScopedPyObjectPtr list(Subscript(self, full_slice.get()));
   if (list == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr m(PyObject_GetAttrString(list, "sort"));
+  ScopedPyObjectPtr m(PyObject_GetAttrString(list.get(), "sort"));
   if (m == NULL) {
     return NULL;
   }
-  ScopedPyObjectPtr res(PyObject_Call(m, args, kwds));
+  ScopedPyObjectPtr res(PyObject_Call(m.get(), args, kwds));
   if (res == NULL) {
     return NULL;
   }
-  int ret = InternalAssignRepeatedField(self, list);
+  int ret = InternalAssignRepeatedField(self, list.get());
   if (ret < 0) {
     return NULL;
   }
@@ -688,7 +688,7 @@
   if (full_slice == NULL) {
     return -1;
   }
-  ScopedPyObjectPtr values(Subscript(from, full_slice));
+  ScopedPyObjectPtr values(Subscript(from, full_slice.get()));
   if (values == NULL) {
     return -1;
   }
@@ -697,7 +697,7 @@
   to->parent_field_descriptor = from->parent_field_descriptor;
   to->message = new_message;
   to->owner.reset(new_message);
-  if (InternalAssignRepeatedField(to, values) < 0) {
+  if (InternalAssignRepeatedField(to, values.get()) < 0) {
     return -1;
   }
   return 0;
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h
index 5dfa21e..555e621 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.h
+++ b/python/google/protobuf/pyext/repeated_scalar_container.h
@@ -48,7 +48,11 @@
 
 class Message;
 
+#ifdef _SHARED_PTR_H
+using std::shared_ptr;
+#else
 using internal::shared_ptr;
+#endif
 
 namespace python {
 
diff --git a/python/google/protobuf/pyext/scalar_map_container.cc b/python/google/protobuf/pyext/scalar_map_container.cc
deleted file mode 100644
index a355edb..0000000
--- a/python/google/protobuf/pyext/scalar_map_container.cc
+++ /dev/null
@@ -1,542 +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.
-
-// Author: haberman@google.com (Josh Haberman)
-
-#include <google/protobuf/pyext/scalar_map_container.h>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/message.h>
-#include <google/protobuf/pyext/message.h>
-#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
-
-namespace google {
-namespace protobuf {
-namespace python {
-
-struct ScalarMapIterator {
-  PyObject_HEAD;
-
-  // This dict contains the full contents of what we want to iterate over.
-  // There's no way to avoid building this, because the list representation
-  // (which is canonical) can contain duplicate keys.  So at the very least we
-  // need a set that lets us skip duplicate keys.  And at the point that we're
-  // doing that, we might as well just build the actual dict we're iterating
-  // over and use dict's built-in iterator.
-  PyObject* dict;
-
-  // An iterator on dict.
-  PyObject* iter;
-
-  // A pointer back to the container, so we can notice changes to the version.
-  ScalarMapContainer* container;
-
-  // The version of the map when we took the iterator to it.
-  //
-  // We store this so that if the map is modified during iteration we can throw
-  // an error.
-  uint64 version;
-};
-
-static ScalarMapIterator* GetIter(PyObject* obj) {
-  return reinterpret_cast<ScalarMapIterator*>(obj);
-}
-
-namespace scalar_map_container {
-
-static ScalarMapContainer* GetMap(PyObject* obj) {
-  return reinterpret_cast<ScalarMapContainer*>(obj);
-}
-
-// The private constructor of ScalarMapContainer objects.
-PyObject *NewContainer(
-    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
-  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
-    return NULL;
-  }
-
-#if PY_MAJOR_VERSION >= 3
-  ScopedPyObjectPtr obj(PyType_GenericAlloc(
-        reinterpret_cast<PyTypeObject *>(ScalarMapContainer_Type), 0));
-#else
-  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0));
-#endif
-  if (obj.get() == NULL) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Could not allocate new container.");
-  }
-
-  ScalarMapContainer* self = GetMap(obj);
-
-  self->message = parent->message;
-  self->parent = parent;
-  self->parent_field_descriptor = parent_field_descriptor;
-  self->owner = parent->owner;
-  self->version = 0;
-
-  self->key_field_descriptor =
-      parent_field_descriptor->message_type()->FindFieldByName("key");
-  self->value_field_descriptor =
-      parent_field_descriptor->message_type()->FindFieldByName("value");
-
-  if (self->key_field_descriptor == NULL ||
-      self->value_field_descriptor == NULL) {
-    return PyErr_Format(PyExc_KeyError,
-                        "Map entry descriptor did not have key/value fields");
-  }
-
-  return obj.release();
-}
-
-// 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
-// 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).
-static int InitializeAndCopyToParentContainer(
-    ScalarMapContainer* from,
-    ScalarMapContainer* to) {
-  // For now we require from == to, re-evaluate if we want to support deep copy
-  // as in repeated_scalar_container.cc.
-  GOOGLE_DCHECK(from == to);
-  Message* old_message = from->message;
-  Message* new_message = old_message->New();
-  to->parent = NULL;
-  to->parent_field_descriptor = from->parent_field_descriptor;
-  to->message = new_message;
-  to->owner.reset(new_message);
-
-  vector<const FieldDescriptor*> fields;
-  fields.push_back(from->parent_field_descriptor);
-  old_message->GetReflection()->SwapFields(old_message, new_message, fields);
-  return 0;
-}
-
-int Release(ScalarMapContainer* self) {
-  return InitializeAndCopyToParentContainer(self, self);
-}
-
-void SetOwner(ScalarMapContainer* self,
-              const shared_ptr<Message>& new_owner) {
-  self->owner = new_owner;
-}
-
-Py_ssize_t Length(PyObject* _self) {
-  ScalarMapContainer* self = GetMap(_self);
-  google::protobuf::Message* message = self->message;
-  return message->GetReflection()->FieldSize(*message,
-                                             self->parent_field_descriptor);
-}
-
-int MapKeyMatches(ScalarMapContainer* self, const Message* entry,
-                  PyObject* key) {
-  // TODO(haberman): do we need more strict type checking?
-  ScopedPyObjectPtr entry_key(
-      cmessage::InternalGetScalar(entry, self->key_field_descriptor));
-  int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ);
-  return ret;
-}
-
-PyObject* GetItem(PyObject* _self, PyObject* key) {
-  ScalarMapContainer* self = GetMap(_self);
-
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size = reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = size - 1; i >= 0; i--) {
-    const Message& entry = reflection->GetRepeatedMessage(
-        *message, self->parent_field_descriptor, i);
-    int matches = MapKeyMatches(self, &entry, key);
-    if (matches < 0) return NULL;
-    if (matches) {
-      return cmessage::InternalGetScalar(&entry, self->value_field_descriptor);
-    }
-  }
-
-  // Need to add a new entry.
-  Message* entry =
-      reflection->AddMessage(message, self->parent_field_descriptor);
-  PyObject* ret = NULL;
-
-  if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
-                                          key) >= 0) {
-    ret = cmessage::InternalGetScalar(entry, self->value_field_descriptor);
-  }
-
-  self->version++;
-
-  // If there was a type error above, it set the Python exception.
-  return ret;
-}
-
-int SetItem(PyObject *_self, PyObject *key, PyObject *v) {
-  ScalarMapContainer* self = GetMap(_self);
-  cmessage::AssureWritable(self->parent);
-
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-  self->version++;
-
-  if (v) {
-    // Set item.
-    //
-    // Right now the Reflection API doesn't support map lookup, so we implement
-    // it via linear search.
-    //
-    // TODO(haberman): add lookup API to Reflection API.
-    for (int i = size - 1; i >= 0; i--) {
-      Message* entry = reflection->MutableRepeatedMessage(
-          message, self->parent_field_descriptor, i);
-      int matches = MapKeyMatches(self, entry, key);
-      if (matches < 0) return -1;
-      if (matches) {
-        return cmessage::InternalSetNonOneofScalar(
-            entry, self->value_field_descriptor, v);
-      }
-    }
-
-    // Key is not already present; insert a new entry.
-    Message* entry =
-        reflection->AddMessage(message, self->parent_field_descriptor);
-
-    if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
-                                            key) < 0 ||
-        cmessage::InternalSetNonOneofScalar(entry, self->value_field_descriptor,
-                                            v) < 0) {
-      reflection->RemoveLast(message, self->parent_field_descriptor);
-      return -1;
-    }
-
-    return 0;
-  } else {
-    bool found = false;
-    for (int i = size - 1; i >= 0; i--) {
-      Message* entry = reflection->MutableRepeatedMessage(
-          message, self->parent_field_descriptor, i);
-      int matches = MapKeyMatches(self, entry, key);
-      if (matches < 0) return -1;
-      if (matches) {
-        found = true;
-        if (i != size - 1) {
-          reflection->SwapElements(message, self->parent_field_descriptor, i,
-                                   size - 1);
-        }
-        reflection->RemoveLast(message, self->parent_field_descriptor);
-
-        // Can't exit now, the repeated field representation of maps allows
-        // duplicate keys, and we have to be sure to remove all of them.
-      }
-    }
-
-    if (found) {
-      return 0;
-    } else {
-      PyErr_Format(PyExc_KeyError, "Key not present in map");
-      return -1;
-    }
-  }
-}
-
-PyObject* GetIterator(PyObject *_self) {
-  ScalarMapContainer* self = GetMap(_self);
-
-  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapIterator_Type, 0));
-  if (obj == NULL) {
-    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
-  }
-
-  ScalarMapIterator* iter = GetIter(obj.get());
-
-  Py_INCREF(self);
-  iter->container = self;
-  iter->version = self->version;
-  iter->dict = PyDict_New();
-  if (iter->dict == NULL) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Could not allocate dict for iterator.");
-  }
-
-  // Build the entire map into a dict right now.  Start from the beginning so
-  // that later entries win in the case of duplicates.
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.  We need to search from the end because the underlying
-  // representation can have duplicates if a user calls MergeFrom(); the last
-  // one needs to win.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size =
-      reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = 0; i < size; i++) {
-    Message* entry = reflection->MutableRepeatedMessage(
-        message, self->parent_field_descriptor, i);
-    ScopedPyObjectPtr key(
-        cmessage::InternalGetScalar(entry, self->key_field_descriptor));
-    ScopedPyObjectPtr val(
-        cmessage::InternalGetScalar(entry, self->value_field_descriptor));
-    if (PyDict_SetItem(iter->dict, key.get(), val.get()) < 0) {
-      return PyErr_Format(PyExc_RuntimeError,
-                          "SetItem failed in iterator construction.");
-    }
-  }
-
-
-  iter->iter = PyObject_GetIter(iter->dict);
-
-
-  return obj.release();
-}
-
-PyObject* Clear(PyObject* _self) {
-  ScalarMapContainer* self = GetMap(_self);
-  cmessage::AssureWritable(self->parent);
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  reflection->ClearField(message, self->parent_field_descriptor);
-
-  Py_RETURN_NONE;
-}
-
-PyObject* Contains(PyObject* _self, PyObject* key) {
-  ScalarMapContainer* self = GetMap(_self);
-
-  Message* message = self->message;
-  const Reflection* reflection = message->GetReflection();
-
-  // Right now the Reflection API doesn't support map lookup, so we implement it
-  // via linear search.
-  //
-  // TODO(haberman): add lookup API to Reflection API.
-  size_t size = reflection->FieldSize(*message, self->parent_field_descriptor);
-  for (int i = size - 1; i >= 0; i--) {
-    const Message& entry = reflection->GetRepeatedMessage(
-        *message, self->parent_field_descriptor, i);
-    int matches = MapKeyMatches(self, &entry, key);
-    if (matches < 0) return NULL;
-    if (matches) {
-      Py_RETURN_TRUE;
-    }
-  }
-
-  Py_RETURN_FALSE;
-}
-
-PyObject* Get(PyObject* self, PyObject* args) {
-  PyObject* key;
-  PyObject* default_value = NULL;
-  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
-    return NULL;
-  }
-
-  ScopedPyObjectPtr is_present(Contains(self, key));
-  if (is_present.get() == NULL) {
-    return NULL;
-  }
-
-  if (PyObject_IsTrue(is_present.get())) {
-    return GetItem(self, key);
-  } else {
-    if (default_value != NULL) {
-      Py_INCREF(default_value);
-      return default_value;
-    } else {
-      Py_RETURN_NONE;
-    }
-  }
-}
-
-static PyMappingMethods MpMethods = {
-  Length,    // mp_length
-  GetItem,   // mp_subscript
-  SetItem,   // mp_ass_subscript
-};
-
-static void Dealloc(PyObject* _self) {
-  ScalarMapContainer* self = GetMap(_self);
-  self->owner.reset();
-  Py_TYPE(_self)->tp_free(_self);
-}
-
-static PyMethodDef Methods[] = {
-  { "__contains__", Contains, METH_O,
-    "Tests whether a key is a member of the map." },
-  { "clear", (PyCFunction)Clear, METH_NOARGS,
-    "Removes all elements from the map." },
-  { "get", Get, METH_VARARGS,
-    "Gets the value for the given key if present, or otherwise a default" },
-  /*
-  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
-    "Makes a deep copy of the class." },
-  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
-    "Outputs picklable representation of the repeated field." },
-  */
-  {NULL, NULL},
-};
-
-}  // namespace scalar_map_container
-
-namespace scalar_map_iterator {
-
-static void Dealloc(PyObject* _self) {
-  ScalarMapIterator* self = GetIter(_self);
-  Py_DECREF(self->dict);
-  Py_DECREF(self->iter);
-  Py_DECREF(self->container);
-  Py_TYPE(_self)->tp_free(_self);
-}
-
-PyObject* IterNext(PyObject* _self) {
-  ScalarMapIterator* self = GetIter(_self);
-
-  // This won't catch mutations to the map performed by MergeFrom(); no easy way
-  // to address that.
-  if (self->version != self->container->version) {
-    return PyErr_Format(PyExc_RuntimeError,
-                        "Map modified during iteration.");
-  }
-
-  return PyIter_Next(self->iter);
-}
-
-}  // namespace scalar_map_iterator
-
- 
-#if PY_MAJOR_VERSION >= 3
-  static PyType_Slot ScalarMapContainer_Type_slots[] = {
-      {Py_tp_dealloc, (void *)scalar_map_container::Dealloc},
-      {Py_mp_length, (void *)scalar_map_container::Length},
-      {Py_mp_subscript, (void *)scalar_map_container::GetItem},
-      {Py_mp_ass_subscript, (void *)scalar_map_container::SetItem},
-      {Py_tp_methods, (void *)scalar_map_container::Methods},
-      {Py_tp_iter, (void *)scalar_map_container::GetIterator},
-      {0, 0},
-  };
-
-  PyType_Spec ScalarMapContainer_Type_spec = {
-      FULL_MODULE_NAME ".ScalarMapContainer",
-      sizeof(ScalarMapContainer),
-      0,
-      Py_TPFLAGS_DEFAULT,
-      ScalarMapContainer_Type_slots
-  };
-  PyObject *ScalarMapContainer_Type;
-#else
-  PyTypeObject ScalarMapContainer_Type = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    FULL_MODULE_NAME ".ScalarMapContainer",  //  tp_name
-    sizeof(ScalarMapContainer),          //  tp_basicsize
-    0,                                   //  tp_itemsize
-    scalar_map_container::Dealloc,       //  tp_dealloc
-    0,                                   //  tp_print
-    0,                                   //  tp_getattr
-    0,                                   //  tp_setattr
-    0,                                   //  tp_compare
-    0,                                   //  tp_repr
-    0,                                   //  tp_as_number
-    0,                                   //  tp_as_sequence
-    &scalar_map_container::MpMethods,    //  tp_as_mapping
-    0,                                   //  tp_hash
-    0,                                   //  tp_call
-    0,                                   //  tp_str
-    0,                                   //  tp_getattro
-    0,                                   //  tp_setattro
-    0,                                   //  tp_as_buffer
-    Py_TPFLAGS_DEFAULT,                  //  tp_flags
-    "A scalar map container",            //  tp_doc
-    0,                                   //  tp_traverse
-    0,                                   //  tp_clear
-    0,                                   //  tp_richcompare
-    0,                                   //  tp_weaklistoffset
-    scalar_map_container::GetIterator,   //  tp_iter
-    0,                                   //  tp_iternext
-    scalar_map_container::Methods,       //  tp_methods
-    0,                                   //  tp_members
-    0,                                   //  tp_getset
-    0,                                   //  tp_base
-    0,                                   //  tp_dict
-    0,                                   //  tp_descr_get
-    0,                                   //  tp_descr_set
-    0,                                   //  tp_dictoffset
-    0,                                   //  tp_init
-  };
-#endif
-
-PyTypeObject ScalarMapIterator_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".ScalarMapIterator",  //  tp_name
-  sizeof(ScalarMapIterator),           //  tp_basicsize
-  0,                                   //  tp_itemsize
-  scalar_map_iterator::Dealloc,        //  tp_dealloc
-  0,                                   //  tp_print
-  0,                                   //  tp_getattr
-  0,                                   //  tp_setattr
-  0,                                   //  tp_compare
-  0,                                   //  tp_repr
-  0,                                   //  tp_as_number
-  0,                                   //  tp_as_sequence
-  0,                                   //  tp_as_mapping
-  0,                                   //  tp_hash
-  0,                                   //  tp_call
-  0,                                   //  tp_str
-  0,                                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  //  tp_flags
-  "A scalar map iterator",             //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  0,                                   //  tp_richcompare
-  0,                                   //  tp_weaklistoffset
-  PyObject_SelfIter,                   //  tp_iter
-  scalar_map_iterator::IterNext,       //  tp_iternext
-  0,                                   //  tp_methods
-  0,                                   //  tp_members
-  0,                                   //  tp_getset
-  0,                                   //  tp_base
-  0,                                   //  tp_dict
-  0,                                   //  tp_descr_get
-  0,                                   //  tp_descr_set
-  0,                                   //  tp_dictoffset
-  0,                                   //  tp_init
-};
-
-}  // namespace python
-}  // namespace protobuf
-}  // namespace google
diff --git a/python/google/protobuf/pyext/scalar_map_container.h b/python/google/protobuf/pyext/scalar_map_container.h
deleted file mode 100644
index aded8d4..0000000
--- a/python/google/protobuf/pyext/scalar_map_container.h
+++ /dev/null
@@ -1,115 +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.
-
-#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
-#define GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
-
-#include <Python.h>
-
-#include <memory>
-#ifndef _SHARED_PTR_H
-#include <google/protobuf/stubs/shared_ptr.h>
-#endif
-
-#include <google/protobuf/descriptor.h>
-
-namespace google {
-namespace protobuf {
-
-class Message;
-
-using internal::shared_ptr;
-
-namespace python {
-
-struct CMessage;
-
-struct ScalarMapContainer {
-  PyObject_HEAD;
-
-  // This is the top-level C++ Message object that owns the whole
-  // proto tree.  Every Python ScalarMapContainer holds a
-  // reference to it in order to keep it alive as long as there's a
-  // Python object that references any part of the tree.
-  shared_ptr<Message> owner;
-
-  // Pointer to the C++ Message that contains this container.  The
-  // ScalarMapContainer does not own this pointer.
-  Message* message;
-
-  // Weak reference to a parent CMessage object (i.e. may be NULL.)
-  //
-  // Used to make sure all ancestors are also mutable when first
-  // modifying the container.
-  CMessage* parent;
-
-  // Pointer to the parent's descriptor that describes this
-  // field.  Used together with the parent's message when making a
-  // default message instance mutable.
-  // The pointer is owned by the global DescriptorPool.
-  const FieldDescriptor* parent_field_descriptor;
-  const FieldDescriptor* key_field_descriptor;
-  const FieldDescriptor* value_field_descriptor;
-
-  // We bump this whenever we perform a mutation, to invalidate existing
-  // iterators.
-  uint64 version;
-};
-
-#if PY_MAJOR_VERSION >= 3
-  extern PyObject *ScalarMapContainer_Type;
-  extern PyType_Spec ScalarMapContainer_Type_spec;
-#else
-  extern PyTypeObject ScalarMapContainer_Type;
-#endif
-extern PyTypeObject ScalarMapIterator_Type;
-
-namespace scalar_map_container {
-
-// Builds a ScalarMapContainer object, from a parent message and a
-// field descriptor.
-extern PyObject *NewContainer(
-    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
-
-// Releases the messages in the container to a new message.
-//
-// Returns 0 on success, -1 on failure.
-int Release(ScalarMapContainer* self);
-
-// Set the owner field of self and any children of self.
-void SetOwner(ScalarMapContainer* self,
-              const shared_ptr<Message>& new_owner);
-
-}  // namespace scalar_map_container
-}  // namespace python
-}  // namespace protobuf
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
index 9979b83..a128cd4 100644
--- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -60,11 +60,6 @@
     return ptr_;
   }
 
-  // ScopedPyObjectPtr should not be copied.
-  // We explicitly list and delete this overload to avoid automatic conversion
-  // to PyObject*, which is wrong in this case.
-  PyObject* reset(const ScopedPyObjectPtr& other) = delete;
-
   // Releases ownership of the object.
   // The caller now owns the returned reference.
   PyObject* release() {
@@ -73,8 +68,6 @@
     return p;
   }
 
-  operator PyObject*() { return ptr_; }
-
   PyObject* operator->() const  {
     assert(ptr_ != NULL);
     return ptr_;
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
index 4c70b39..87760f2 100644
--- a/python/google/protobuf/symbol_database.py
+++ b/python/google/protobuf/symbol_database.py
@@ -72,12 +72,12 @@
   buffer types used within a program.
   """
 
-  def __init__(self):
+  def __init__(self, pool=None):
     """Constructor."""
 
     self._symbols = {}
     self._symbols_by_file = {}
-    self.pool = descriptor_pool.DescriptorPool()
+    self.pool = pool or descriptor_pool.Default()
 
   def RegisterMessage(self, message):
     """Registers the given message type in the local database.
@@ -177,7 +177,7 @@
       result.update(self._symbols_by_file[f])
     return result
 
-_DEFAULT = SymbolDatabase()
+_DEFAULT = SymbolDatabase(pool=descriptor_pool.Default())
 
 
 def Default():
diff --git a/python/google/protobuf/text_encoding.py b/python/google/protobuf/text_encoding.py
index a0728e3..9899563 100644
--- a/python/google/protobuf/text_encoding.py
+++ b/python/google/protobuf/text_encoding.py
@@ -27,6 +27,7 @@
 # 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.
+
 """Encoding related utilities."""
 import re
 
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 1399223..8d25607 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -28,9 +28,17 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Copyright 2007 Google Inc. All Rights Reserved.
+"""Contains routines for printing protocol messages in text format.
 
-"""Contains routines for printing protocol messages in text format."""
+Simple usage example:
+
+  # Create a proto object and serialize it to a text proto string.
+  message = my_proto_pb2.MyMessage(foo='bar')
+  text_proto = text_format.MessageToString(message)
+
+  # Parse a text proto string.
+  message = text_format.Parse(text_proto, my_proto_pb2.MyMessage())
+"""
 
 __author__ = 'kenton@google.com (Kenton Varda)'
 
@@ -58,6 +66,7 @@
 _FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
 _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
                           descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
+_QUOTES = frozenset(("'", '"'))
 
 
 class Error(Exception):
@@ -65,7 +74,8 @@
 
 
 class ParseError(Error):
-  """Thrown in case of ASCII parsing error."""
+  """Thrown in case of text parsing error."""
+
 
 class TextWriter(object):
   def __init__(self, as_utf8):
@@ -94,7 +104,8 @@
 
   Floating point values can be formatted compactly with 15 digits of
   precision (which is the most that IEEE 754 "double" can guarantee)
-  using float_format='.15g'.
+  using float_format='.15g'. To ensure that converting to text and back to a
+  proto will result in an identical value, float_format='.17g' should be used.
 
   Args:
     message: The protocol buffers message.
@@ -122,11 +133,13 @@
     return result.rstrip()
   return result
 
+
 def _IsMapEntry(field):
   return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
           field.message_type.has_options and
           field.message_type.GetOptions().map_entry)
 
+
 def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
                  pointy_brackets=False, use_index_order=False,
                  float_format=None):
@@ -158,17 +171,18 @@
                  use_index_order=use_index_order,
                  float_format=float_format)
 
+
 def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,
                pointy_brackets=False, use_index_order=False, float_format=None):
   """Print a single field name/value pair.  For repeated fields, the value
-  should be a single element."""
+  should be a single element.
+  """
 
   out.write(' ' * indent)
   if field.is_extension:
     out.write('[')
     if (field.containing_type.GetOptions().message_set_wire_format and
         field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
-        field.message_type == field.extension_scope and
         field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
       out.write(field.message_type.full_name)
     else:
@@ -254,95 +268,113 @@
     out.write(str(value))
 
 
-def Parse(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def Parse(text, message, allow_unknown_extension=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    text: Message ASCII representation.
+    text: Message text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  if not isinstance(text, str): text = text.decode('utf-8')
-  return ParseLines(text.split('\n'), message)
+  if not isinstance(text, str):
+    text = text.decode('utf-8')
+  return ParseLines(text.split('\n'), message, allow_unknown_extension)
 
 
-def Merge(text, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def Merge(text, message, allow_unknown_extension=False):
+  """Parses an text representation of a protocol message into a message.
 
   Like Parse(), but allows repeated values for a non-repeated field, and uses
   the last one.
 
   Args:
-    text: Message ASCII representation.
+    text: Message text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  return MergeLines(text.split('\n'), message)
+  return MergeLines(text.split('\n'), message, allow_unknown_extension)
 
 
-def ParseLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def ParseLines(lines, message, allow_unknown_extension=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    lines: An iterable of lines of a message's ASCII representation.
+    lines: An iterable of lines of a message's text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, False)
+  _ParseOrMerge(lines, message, False, allow_unknown_extension)
   return message
 
 
-def MergeLines(lines, message):
-  """Parses an ASCII representation of a protocol message into a message.
+def MergeLines(lines, message, allow_unknown_extension=False):
+  """Parses an text representation of a protocol message into a message.
 
   Args:
-    lines: An iterable of lines of a message's ASCII representation.
+    lines: An iterable of lines of a message's text representation.
     message: A protocol buffer message to merge into.
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Returns:
     The same message passed as argument.
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
-  _ParseOrMerge(lines, message, True)
+  _ParseOrMerge(lines, message, True, allow_unknown_extension)
   return message
 
 
-def _ParseOrMerge(lines, message, allow_multiple_scalars):
-  """Converts an ASCII representation of a protocol message into a message.
+def _ParseOrMerge(lines,
+                  message,
+                  allow_multiple_scalars,
+                  allow_unknown_extension=False):
+  """Converts an text representation of a protocol message into a message.
 
   Args:
-    lines: Lines of a message's ASCII representation.
+    lines: Lines of a message's text representation.
     message: A protocol buffer message to merge into.
     allow_multiple_scalars: Determines if repeated values for a non-repeated
       field are permitted, e.g., the string "foo: 1 foo: 2" for a
       required/optional field named "foo".
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Raises:
-    ParseError: On ASCII parsing problems.
+    ParseError: On text parsing problems.
   """
   tokenizer = _Tokenizer(lines)
   while not tokenizer.AtEnd():
-    _MergeField(tokenizer, message, allow_multiple_scalars)
+    _MergeField(tokenizer, message, allow_multiple_scalars,
+                allow_unknown_extension)
 
 
-def _MergeField(tokenizer, message, allow_multiple_scalars):
+def _MergeField(tokenizer,
+                message,
+                allow_multiple_scalars,
+                allow_unknown_extension=False):
   """Merges a single protocol message field into a message.
 
   Args:
@@ -351,9 +383,11 @@
     allow_multiple_scalars: Determines if repeated values for a non-repeated
       field are permitted, e.g., the string "foo: 1 foo: 2" for a
       required/optional field named "foo".
+    allow_unknown_extension: if True, skip over missing extensions and keep
+      parsing
 
   Raises:
-    ParseError: In case of ASCII parsing problems.
+    ParseError: In case of text parsing problems.
   """
   message_descriptor = message.DESCRIPTOR
   if (hasattr(message_descriptor, 'syntax') and
@@ -375,13 +409,18 @@
     field = message.Extensions._FindExtensionByName(name)
     # pylint: enable=protected-access
     if not field:
-      raise tokenizer.ParseErrorPreviousToken(
-          'Extension "%s" not registered.' % name)
+      if allow_unknown_extension:
+        field = None
+      else:
+        raise tokenizer.ParseErrorPreviousToken(
+            'Extension "%s" not registered.' % name)
     elif message_descriptor != field.containing_type:
       raise tokenizer.ParseErrorPreviousToken(
           'Extension "%s" does not extend message type "%s".' % (
               name, message_descriptor.full_name))
+
     tokenizer.Consume(']')
+
   else:
     name = tokenizer.ConsumeIdentifier()
     field = message_descriptor.fields_by_name.get(name, None)
@@ -403,7 +442,7 @@
           'Message type "%s" has no field named "%s".' % (
               message_descriptor.full_name, name))
 
-  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+  if field and field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
     is_map_entry = _IsMapEntry(field)
     tokenizer.TryConsume(':')
 
@@ -430,7 +469,8 @@
     while not tokenizer.TryConsume(end_token):
       if tokenizer.AtEnd():
         raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
-      _MergeField(tokenizer, sub_message, allow_multiple_scalars)
+      _MergeField(tokenizer, sub_message, allow_multiple_scalars,
+                  allow_unknown_extension)
 
     if is_map_entry:
       value_cpptype = field.message_type.fields_by_name['value'].cpp_type
@@ -439,8 +479,21 @@
         value.MergeFrom(sub_message.value)
       else:
         getattr(message, field.name)[sub_message.key] = sub_message.value
-  else:
-    _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+  elif field:
+    tokenizer.Consume(':')
+    if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
+        tokenizer.TryConsume('[')):
+      # Short repeated format, e.g. "foo: [1, 2, 3]"
+      while True:
+        _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+        if tokenizer.TryConsume(']'):
+          break
+        tokenizer.Consume(',')
+    else:
+      _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
+  else:  # Proto field is unknown.
+    assert allow_unknown_extension
+    _SkipFieldContents(tokenizer)
 
   # For historical reasons, fields may optionally be separated by commas or
   # semicolons.
@@ -448,6 +501,90 @@
     tokenizer.TryConsume(';')
 
 
+def _SkipFieldContents(tokenizer):
+  """Skips over contents (value or message) of a field.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+  # Try to guess the type of this field.
+  # If this field is not a message, there should be a ":" between the
+  # field name and the field value and also the field value should not
+  # start with "{" or "<" which indicates the beginning of a message body.
+  # If there is no ":" or there is a "{" or "<" after ":", this field has
+  # to be a message or the input is ill-formed.
+  if tokenizer.TryConsume(':') and not tokenizer.LookingAt(
+      '{') and not tokenizer.LookingAt('<'):
+    _SkipFieldValue(tokenizer)
+  else:
+    _SkipFieldMessage(tokenizer)
+
+
+def _SkipField(tokenizer):
+  """Skips over a complete field (name and value/message).
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+  if tokenizer.TryConsume('['):
+    # Consume extension name.
+    tokenizer.ConsumeIdentifier()
+    while tokenizer.TryConsume('.'):
+      tokenizer.ConsumeIdentifier()
+    tokenizer.Consume(']')
+  else:
+    tokenizer.ConsumeIdentifier()
+
+  _SkipFieldContents(tokenizer)
+
+  # For historical reasons, fields may optionally be separated by commas or
+  # semicolons.
+  if not tokenizer.TryConsume(','):
+    tokenizer.TryConsume(';')
+
+
+def _SkipFieldMessage(tokenizer):
+  """Skips over a field message.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+  """
+
+  if tokenizer.TryConsume('<'):
+    delimiter = '>'
+  else:
+    tokenizer.Consume('{')
+    delimiter = '}'
+
+  while not tokenizer.LookingAt('>') and not tokenizer.LookingAt('}'):
+    _SkipField(tokenizer)
+
+  tokenizer.Consume(delimiter)
+
+
+def _SkipFieldValue(tokenizer):
+  """Skips over a field value.
+
+  Args:
+    tokenizer: A tokenizer to parse the field name and values.
+
+  Raises:
+    ParseError: In case an invalid field value is found.
+  """
+  # String tokens can come in multiple adjacent string literals.
+  # If we can consume one, consume as many as we can.
+  if tokenizer.TryConsumeString():
+    while tokenizer.TryConsumeString():
+      pass
+    return
+
+  if (not tokenizer.TryConsumeIdentifier() and
+      not tokenizer.TryConsumeInt64() and
+      not tokenizer.TryConsumeUint64() and
+      not tokenizer.TryConsumeFloat()):
+    raise ParseError('Invalid field value: ' + tokenizer.token)
+
+
 def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):
   """Merges a single protocol message scalar field into a message.
 
@@ -460,10 +597,9 @@
       required/optional field named "foo".
 
   Raises:
-    ParseError: In case of ASCII parsing problems.
+    ParseError: In case of text parsing problems.
     RuntimeError: On runtime errors.
   """
-  tokenizer.Consume(':')
   value = None
 
   if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
@@ -517,7 +653,7 @@
 
 
 class _Tokenizer(object):
-  """Protocol buffer ASCII representation tokenizer.
+  """Protocol buffer text representation tokenizer.
 
   This class handles the lower level string parsing by splitting it into
   meaningful tokens.
@@ -526,11 +662,13 @@
   """
 
   _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
-  _TOKEN = re.compile(
-      '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier
-      '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number
-      '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string
-      '\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string
+  _TOKEN = re.compile('|'.join([
+      r'[a-zA-Z_][0-9a-zA-Z_+-]*',             # an identifier
+      r'([0-9+-]|(\.[0-9]))[0-9a-zA-Z_.+-]*',  # a number
+  ] + [                                        # quoted str for each quote mark
+      r'{qt}([^{qt}\n\\]|\\.)*({qt}|\\?$)'.format(qt=mark) for mark in _QUOTES
+  ]))
+
   _IDENTIFIER = re.compile(r'\w+')
 
   def __init__(self, lines):
@@ -547,6 +685,9 @@
     self._SkipWhitespace()
     self.NextToken()
 
+  def LookingAt(self, token):
+    return self.token == token
+
   def AtEnd(self):
     """Checks the end of the text was reached.
 
@@ -602,6 +743,13 @@
     if not self.TryConsume(token):
       raise self._ParseError('Expected "%s".' % token)
 
+  def TryConsumeIdentifier(self):
+    try:
+      self.ConsumeIdentifier()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeIdentifier(self):
     """Consumes protocol message field identifier.
 
@@ -649,6 +797,13 @@
     self.NextToken()
     return result
 
+  def TryConsumeInt64(self):
+    try:
+      self.ConsumeInt64()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeInt64(self):
     """Consumes a signed 64bit integer number.
 
@@ -665,6 +820,13 @@
     self.NextToken()
     return result
 
+  def TryConsumeUint64(self):
+    try:
+      self.ConsumeUint64()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeUint64(self):
     """Consumes an unsigned 64bit integer number.
 
@@ -681,6 +843,13 @@
     self.NextToken()
     return result
 
+  def TryConsumeFloat(self):
+    try:
+      self.ConsumeFloat()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeFloat(self):
     """Consumes an floating point number.
 
@@ -713,6 +882,13 @@
     self.NextToken()
     return result
 
+  def TryConsumeString(self):
+    try:
+      self.ConsumeString()
+      return True
+    except ParseError:
+      return False
+
   def ConsumeString(self):
     """Consumes a string value.
 
@@ -738,7 +914,7 @@
       ParseError: If a byte array value couldn't be consumed.
     """
     the_list = [self._ConsumeSingleByteString()]
-    while self.token and self.token[0] in ('\'', '"'):
+    while self.token and self.token[0] in _QUOTES:
       the_list.append(self._ConsumeSingleByteString())
     return b''.join(the_list)
 
@@ -749,11 +925,13 @@
     tokens which are automatically concatenated, like in C or Python.  This
     method only consumes one token.
 
+    Returns:
+      The token parsed.
     Raises:
       ParseError: When the wrong format data is found.
     """
     text = self.token
-    if len(text) < 1 or text[0] not in ('\'', '"'):
+    if len(text) < 1 or text[0] not in _QUOTES:
       raise self._ParseError('Expected string but found: %r' % (text,))
 
     if len(text) < 2 or text[-1] != text[0]:
diff --git a/python/setup.py b/python/setup.py
index 8269c4a..6ea3bad 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -88,6 +88,8 @@
   generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False)
   generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False)
   generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False)
+  generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False)
+  generate_proto("google/protobuf/internal/any_test.proto", False)
   generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False)
   generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
   generate_proto("google/protobuf/internal/factory_test1.proto", False)
@@ -112,7 +114,8 @@
         filepath = os.path.join(dirpath, filename)
         if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \
           filepath.endswith(".so") or filepath.endswith(".o") or \
-          filepath.endswith('google/protobuf/compiler/__init__.py'):
+          filepath.endswith('google/protobuf/compiler/__init__.py') or \
+          filepath.endswith('google/protobuf/util/__init__.py'):
           os.remove(filepath)
     # _clean is an old-style class, so super() doesn't work.
     _clean.run(self)
@@ -122,10 +125,20 @@
     # Generate necessary .proto file if it doesn't exist.
     generate_proto("../src/google/protobuf/descriptor.proto")
     generate_proto("../src/google/protobuf/compiler/plugin.proto")
+    generate_proto("../src/google/protobuf/any.proto")
+    generate_proto("../src/google/protobuf/api.proto")
+    generate_proto("../src/google/protobuf/duration.proto")
+    generate_proto("../src/google/protobuf/empty.proto")
+    generate_proto("../src/google/protobuf/field_mask.proto")
+    generate_proto("../src/google/protobuf/source_context.proto")
+    generate_proto("../src/google/protobuf/struct.proto")
+    generate_proto("../src/google/protobuf/timestamp.proto")
+    generate_proto("../src/google/protobuf/type.proto")
+    generate_proto("../src/google/protobuf/wrappers.proto")
     GenerateUnittestProtos()
 
     # Make sure google.protobuf/** are valid packages.
-    for path in ['', 'internal/', 'compiler/', 'pyext/']:
+    for path in ['', 'internal/', 'compiler/', 'pyext/', 'util/']:
       try:
         open('google/protobuf/%s__init__.py' % path, 'a').close()
       except EnvironmentError:
@@ -133,27 +146,48 @@
     # _build_py is an old-style class, so super() doesn't work.
     _build_py.run(self)
 
+class test_conformance(_build_py):
+  target = 'test_python'
+  def run(self):
+    if sys.version_info >= (2, 7):
+      # Python 2.6 dodges these extra failures.
+      os.environ["CONFORMANCE_PYTHON_EXTRA_FAILURES"] = (
+          "--failure_list failure_list_python-post26.txt")
+    cmd = 'cd ../conformance && make %s' % (test_conformance.target)
+    status = subprocess.check_call(cmd, shell=True)
+
 
 if __name__ == '__main__':
   ext_module_list = []
   cpp_impl = '--cpp_implementation'
+  warnings_as_errors = '--warnings_as_errors'
   if cpp_impl in sys.argv:
     sys.argv.remove(cpp_impl)
+    extra_compile_args = ['-Wno-write-strings', '-Wno-invalid-offsetof']
+    test_conformance.target = 'test_python_cpp'
+
+    if "clang" in os.popen('$CC --version 2> /dev/null').read():
+      extra_compile_args.append('-Wno-shorten-64-to-32')
+
+    if warnings_as_errors in sys.argv:
+      extra_compile_args.append('-Werror')
+      sys.argv.remove(warnings_as_errors)
+
     # C++ implementation extension
     ext_module_list.append(
         Extension(
             "google.protobuf.pyext._message",
             glob.glob('google/protobuf/pyext/*.cc'),
-            define_macros=[('GOOGLE_PROTOBUF_HAS_ONEOF', '1')],
             include_dirs=[".", "../src"],
             libraries=['protobuf'],
             library_dirs=['../src/.libs'],
+            extra_compile_args=extra_compile_args,
         )
     )
     os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp'
 
   # Keep this list of dependencies in sync with tox.ini.
-  install_requires = ['six', 'setuptools']
+  install_requires = ['six>=1.9', 'setuptools']
   if sys.version_info <= (2,7):
     install_requires.append('ordereddict')
     install_requires.append('unittest2')
@@ -186,6 +220,7 @@
       cmdclass={
           'clean': clean,
           'build_py': build_py,
+          'test_conformance': test_conformance,
       },
       install_requires=install_requires,
       ext_modules=ext_module_list,
diff --git a/python/tox.ini b/python/tox.ini
index a6352ef..cf8d540 100644
--- a/python/tox.ini
+++ b/python/tox.ini
@@ -1,11 +1,10 @@
 [tox]
 envlist =
-    # cpp implementation on py34 is currently broken due to
-    # changes introduced by http://bugs.python.org/issue22079.
     py{26,27,33,34}-{cpp,python}
 
 [testenv]
 usedevelop=true
+passenv = CC
 setenv =
     cpp: LD_LIBRARY_PATH={toxinidir}/../src/.libs
     cpp: DYLD_LIBRARY_PATH={toxinidir}/../src/.libs
@@ -13,11 +12,13 @@
 commands =
     python setup.py -q build_py
     python: python setup.py -q build
-    cpp: python setup.py -q build --cpp_implementation
+    cpp: python setup.py -q build --cpp_implementation --warnings_as_errors
     python: python setup.py -q test -q
     cpp: python setup.py -q test -q --cpp_implementation
+    python: python setup.py -q test_conformance
+    cpp: python setup.py -q test_conformance --cpp_implementation
 deps =
     # Keep this list of dependencies in sync with setup.py.
-    six
+    six>=1.9
     py26: ordereddict
     py26: unittest2
diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock
index 91e1666..27e5750 100644
--- a/ruby/Gemfile.lock
+++ b/ruby/Gemfile.lock
@@ -1,7 +1,7 @@
 PATH
   remote: .
   specs:
-    google-protobuf (3.0.0.alpha.4)
+    google-protobuf (3.0.0.alpha.5.0)
 
 GEM
   remote: https://rubygems.org/
@@ -10,6 +10,7 @@
     rake (10.4.2)
     rake-compiler (0.9.5)
       rake
+    rake-compiler-dock (0.5.1)
     rubygems-tasks (0.2.4)
     test-unit (3.0.9)
       power_assert
@@ -21,5 +22,9 @@
 DEPENDENCIES
   google-protobuf!
   rake-compiler
+  rake-compiler-dock
   rubygems-tasks
   test-unit
+
+BUNDLED WITH
+   1.11.2
diff --git a/ruby/Rakefile b/ruby/Rakefile
index c25103d..81c3119 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -20,6 +20,17 @@
   Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
     ext.ext_dir = "ext/google/protobuf_c"
     ext.lib_dir = "lib/google"
+    ext.cross_compile = true
+    ext.cross_platform = [
+      'x86-mingw32', 'x64-mingw32',
+      'x86_64-linux', 'x86-linux',
+      'universal-darwin'
+    ]
+  end
+
+  task 'gem:windows' do
+    require 'rake_compiler_dock'
+    RakeCompilerDock.sh "bundle && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.6"
   end
 end
 
diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c
index df4feac..1c48281 100644
--- a/ruby/ext/google/protobuf_c/encode_decode.c
+++ b/ruby/ext/google/protobuf_c/encode_decode.c
@@ -35,11 +35,13 @@
 // For more information, see:
 //   https://bugs.ruby-lang.org/issues/11328
 VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) {
+  char *p;
   size_t oldlen = RSTRING_LEN(rb_str);
   rb_str_modify_expand(rb_str, len);
-  char *p = RSTRING_PTR(rb_str);
+  p = RSTRING_PTR(rb_str);
   memcpy(p + oldlen, str, len);
   rb_str_set_len(rb_str, oldlen + len);
+  return rb_str;
 }
 
 // -----------------------------------------------------------------------------
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index ebe2f1a..283939c 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -166,7 +166,7 @@
                                           name, name_len);
 
   if (f == NULL) {
-    rb_raise(rb_eArgError, "Unknown field");
+    return rb_call_super(argc, argv);
   }
 
   if (setter) {
@@ -197,7 +197,7 @@
   f = upb_msgdef_ntofz(self->descriptor->msgdef, name);
   if (f == NULL) {
     rb_raise(rb_eArgError,
-             "Unknown field name in initialization map entry.");
+             "Unknown field name '%s' in initialization map entry.", name);
   }
 
   if (is_map_field(f)) {
@@ -205,7 +205,7 @@
 
     if (TYPE(val) != T_HASH) {
       rb_raise(rb_eArgError,
-               "Expected Hash object as initializer value for map field.");
+               "Expected Hash object as initializer value for map field '%s'.", name);
     }
     map = layout_get(self->descriptor->layout, Message_data(self), f);
     Map_merge_into_self(map, val);
@@ -214,7 +214,7 @@
 
     if (TYPE(val) != T_ARRAY) {
       rb_raise(rb_eArgError,
-               "Expected array as initializer value for repeated field.");
+               "Expected array as initializer value for repeated field '%s'.", name);
     }
     ary = layout_get(self->descriptor->layout, Message_data(self), f);
     for (int i = 0; i < RARRAY_LEN(val); i++) {
diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c
index 048a163..9e6aa67 100644
--- a/ruby/ext/google/protobuf_c/upb.c
+++ b/ruby/ext/google/protobuf_c/upb.c
@@ -8537,7 +8537,7 @@
 **       to perfectly match the output of reference encoders that always use the
 **       optimal amount of space for each length.
 **
-**   (2) requires guessing the the size upfront, and if multiple lengths are
+**   (2) requires guessing the size upfront, and if multiple lengths are
 **       guessed wrong the minimum required number of memmove() operations may
 **       be complicated to compute correctly.  Implemented properly, it may have
 **       a useful amortized or average cost, but more investigation is required
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index 3d53209..7b64ee7 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.4.0"
+  s.version     = "3.0.0.alpha.5.0"
   s.licenses    = ["BSD"]
   s.summary     = "Protocol Buffers"
   s.description = "Protocol Buffers are Google's data interchange format."
@@ -8,12 +8,13 @@
   s.authors     = ["Protobuf Authors"]
   s.email       = "protobuf@googlegroups.com"
   s.require_paths = ["lib"]
-  s.files       = `git ls-files -z`.split("\x0").find_all{|f| f =~ /lib\/.+\.rb/}
-  unless RUBY_PLATFORM == "java"
-    s.files     += `git ls-files "*.c" "*.h" extconf.rb Makefile`.split
-    s.extensions= ["ext/google/protobuf_c/extconf.rb"]
-  else
+  s.files       = Dir.glob('lib/**/*.rb')
+  if RUBY_PLATFORM == "java"
     s.files     += ["lib/google/protobuf_java.jar"]
+  else
+    s.files     += Dir.glob('ext/**/*')
+    s.extensions= ["ext/google/protobuf_c/extconf.rb"]
+    s.add_development_dependency "rake-compiler-dock"
   end
   s.test_files  = ["tests/basic.rb",
                   "tests/stress.rb",
diff --git a/ruby/lib/google/protobuf.rb b/ruby/lib/google/protobuf.rb
index f0eb626..62bdd1b 100644
--- a/ruby/lib/google/protobuf.rb
+++ b/ruby/lib/google/protobuf.rb
@@ -44,7 +44,11 @@
   require 'json'
   require 'google/protobuf_java'
 else
-  require 'google/protobuf_c'
+  begin
+    require "google/#{RUBY_VERSION.sub(/\.\d$/, '')}/protobuf_c"
+  rescue LoadError
+    require 'google/protobuf_c'
+  end
 end
 
 require 'google/protobuf/repeated_field'
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 547ab22..39213c4 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -86,14 +86,14 @@
 
                     if (Utils.isMapEntry(fieldDescriptor)) {
                         if (!(value instanceof RubyHash))
-                            throw runtime.newArgumentError("Expected Hash object as initializer value for map field.");
+                            throw runtime.newArgumentError("Expected Hash object as initializer value for map field '" +  key.asJavaString() + "'.");
 
                         final RubyMap map = newMapForField(context, fieldDescriptor);
                         map.mergeIntoSelf(context, value);
                         maps.put(fieldDescriptor, map);
                     } else if (fieldDescriptor.isRepeated()) {
                         if (!(value instanceof RubyArray))
-                            throw runtime.newTypeError("Expected array as initializer var for repeated field.");
+                            throw runtime.newArgumentError("Expected array as initializer value for repeated field '" +  key.asJavaString() + "'.");
                         RubyRepeatedField repeatedField = rubyToRepeatedField(context, fieldDescriptor, value);
                         addRepeatedField(fieldDescriptor, repeatedField);
                     } else {
@@ -217,6 +217,9 @@
             RubyDescriptor rubyDescriptor = (RubyDescriptor) getDescriptor(context, metaClass);
             IRubyObject oneofDescriptor = rubyDescriptor.lookupOneof(context, args[0]);
             if (oneofDescriptor.isNil()) {
+                if (!hasField(args[0])) {
+                    return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
+                }
                 return index(context, args[0]);
             }
             RubyOneofDescriptor rubyOneofDescriptor = (RubyOneofDescriptor) oneofDescriptor;
@@ -233,6 +236,10 @@
             if (field.end_with_p(context, equalSign).isTrue()) {
                 field.chomp_bang(context, equalSign);
             }
+
+            if (!hasField(field)) {
+                return Helpers.invokeSuper(context, this, metaClass, "method_missing", args, Block.NULL_BLOCK);
+            }
             return indexSet(context, field, args[1]);
         }
     }
@@ -435,6 +442,11 @@
         return ret;
     }
 
+    private boolean hasField(IRubyObject fieldName) {
+        String nameStr = fieldName.asJavaString();
+        return this.descriptor.findFieldByName(Utils.escapeIdentifier(nameStr)) != null;
+    }
+
     private void checkRepeatedFieldType(ThreadContext context, IRubyObject value,
                                         Descriptors.FieldDescriptor fieldDescriptor) {
         Ruby runtime = context.runtime;
diff --git a/ruby/src/main/sentinel.proto b/ruby/src/main/sentinel.proto
index 89a1ae1..722041b 100644
--- a/ruby/src/main/sentinel.proto
+++ b/ruby/src/main/sentinel.proto
@@ -3,13 +3,13 @@
 option optimize_for = CODE_SIZE;
 
 message Sentinel {
-  optional int32 default_int32 = 1;
-  optional int64 default_int64 = 2;
-  optional uint32 default_unit32 = 3;
-  optional uint64 default_uint64 = 4;
-  optional string default_string = 5;
-  optional bool default_bool = 6;
-  optional float default_float = 7;
-  optional double default_double = 8;
-  optional bytes default_bytes = 9;
+  int32 default_int32 = 1;
+  int64 default_int64 = 2;
+  uint32 default_unit32 = 3;
+  uint64 default_uint64 = 4;
+  string default_string = 5;
+  bool default_bool = 6;
+  float default_float = 7;
+  double default_double = 8;
+  bytes default_bytes = 9;
 }
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index 40c2007..da85520 100644
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -191,6 +191,35 @@
       assert m1.hash != m2.hash
     end
 
+    def test_unknown_field_errors
+      e = assert_raise NoMethodError do
+        TestMessage.new.hello
+      end
+      assert_match(/hello/, e.message)
+
+      e = assert_raise NoMethodError do
+        TestMessage.new.hello = "world"
+      end
+      assert_match(/hello/, e.message)
+    end
+
+    def test_initialization_map_errors
+      e = assert_raise ArgumentError do
+        TestMessage.new(:hello => "world")
+      end
+      assert_match(/hello/, e.message)
+
+      e = assert_raise ArgumentError do
+        MapMessage.new(:map_string_int32 => "hello")
+      end
+      assert_equal e.message, "Expected Hash object as initializer value for map field 'map_string_int32'."
+
+      e = assert_raise ArgumentError do
+        TestMessage.new(:repeated_uint32 => "hello")
+      end
+      assert_equal e.message, "Expected array as initializer value for repeated field 'repeated_uint32'."
+    end
+
     def test_type_errors
       m = TestMessage.new
       assert_raise TypeError do
diff --git a/ruby/travis-test.sh b/ruby/travis-test.sh
index 9ec7eb2..75db7d9 100755
--- a/ruby/travis-test.sh
+++ b/ruby/travis-test.sh
@@ -17,9 +17,8 @@
       "rvm install $version && rvm use $version && \
        which ruby && \
        gem install bundler && bundle && \
-       rake test && \
-       cd ../conformance && \
-       make test_ruby"
+       rake test &&
+       cd ../conformance && make test_ruby"
   fi
 }
 
diff --git a/six.BUILD b/six.BUILD
new file mode 100644
index 0000000..fb0b360
--- /dev/null
+++ b/six.BUILD
@@ -0,0 +1,13 @@
+genrule(
+  name = "copy_six",
+  srcs = ["six-1.10.0/six.py"],
+  outs = ["six.py"],
+  cmd = "cp $< $(@)",
+)
+
+py_library(
+  name = "six",
+  srcs = ["six.py"],
+  srcs_version = "PY2AND3",
+  visibility = ["//visibility:public"],
+)
diff --git a/src/Makefile.am b/src/Makefile.am
index caae293..073673a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,7 +58,7 @@
 nobase_include_HEADERS =                                        \
   google/protobuf/stubs/atomic_sequence_num.h                   \
   google/protobuf/stubs/atomicops.h                             \
-  google/protobuf/stubs/atomicops_internals_aix.h               \
+  google/protobuf/stubs/atomicops_internals_power.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           \
@@ -148,15 +148,16 @@
   google/protobuf/compiler/plugin.h                             \
   google/protobuf/compiler/plugin.pb.h                          \
   google/protobuf/compiler/cpp/cpp_generator.h                  \
+  google/protobuf/compiler/csharp/csharp_generator.h            \
+  google/protobuf/compiler/csharp/csharp_names.h                \
   google/protobuf/compiler/java/java_generator.h                \
   google/protobuf/compiler/java/java_names.h                    \
   google/protobuf/compiler/javanano/javanano_generator.h        \
+  google/protobuf/compiler/js/js_generator.h                    \
   google/protobuf/compiler/objectivec/objectivec_generator.h    \
   google/protobuf/compiler/objectivec/objectivec_helpers.h      \
   google/protobuf/compiler/python/python_generator.h            \
   google/protobuf/compiler/ruby/ruby_generator.h                \
-  google/protobuf/compiler/csharp/csharp_generator.h            \
-  google/protobuf/compiler/csharp/csharp_names.h                \
   google/protobuf/util/type_resolver.h                          \
   google/protobuf/util/field_comparator.h                       \
   google/protobuf/util/field_mask_util.h                        \
@@ -276,9 +277,9 @@
   google/protobuf/util/internal/protostream_objectsource.h     \
   google/protobuf/util/internal/protostream_objectwriter.cc    \
   google/protobuf/util/internal/protostream_objectwriter.h     \
-  google/protobuf/util/internal/snake2camel_objectwriter.h     \
+  google/protobuf/util/internal/proto_writer.cc                \
+  google/protobuf/util/internal/proto_writer.h                 \
   google/protobuf/util/internal/structured_objectwriter.h      \
-  google/protobuf/util/internal/testdata                       \
   google/protobuf/util/internal/type_info.cc                   \
   google/protobuf/util/internal/type_info.h                    \
   google/protobuf/util/internal/type_info_test_helper.cc       \
@@ -341,6 +342,8 @@
   google/protobuf/compiler/java/java_enum_lite.h               \
   google/protobuf/compiler/java/java_extension.cc              \
   google/protobuf/compiler/java/java_extension.h               \
+  google/protobuf/compiler/java/java_extension_lite.cc         \
+  google/protobuf/compiler/java/java_extension_lite.h          \
   google/protobuf/compiler/java/java_field.cc                  \
   google/protobuf/compiler/java/java_field.h                   \
   google/protobuf/compiler/java/java_file.cc                   \
@@ -386,6 +389,7 @@
   google/protobuf/compiler/java/java_string_field_lite.h       \
   google/protobuf/compiler/java/java_doc_comment.cc            \
   google/protobuf/compiler/java/java_doc_comment.h             \
+  google/protobuf/compiler/js/js_generator.cc                  \
   google/protobuf/compiler/javanano/javanano_enum.cc           \
   google/protobuf/compiler/javanano/javanano_enum.h            \
   google/protobuf/compiler/javanano/javanano_enum_field.cc     \
@@ -434,6 +438,8 @@
   google/protobuf/compiler/objectivec/objectivec_primitive_field.h \
   google/protobuf/compiler/python/python_generator.cc          \
   google/protobuf/compiler/ruby/ruby_generator.cc              \
+  google/protobuf/compiler/csharp/csharp_doc_comment.cc        \
+  google/protobuf/compiler/csharp/csharp_doc_comment.h         \
   google/protobuf/compiler/csharp/csharp_enum.cc               \
   google/protobuf/compiler/csharp/csharp_enum.h                \
   google/protobuf/compiler/csharp/csharp_enum_field.cc         \
@@ -451,6 +457,8 @@
   google/protobuf/compiler/csharp/csharp_message_field.h       \
   google/protobuf/compiler/csharp/csharp_primitive_field.cc    \
   google/protobuf/compiler/csharp/csharp_primitive_field.h     \
+  google/protobuf/compiler/csharp/csharp_reflection_class.cc     \
+  google/protobuf/compiler/csharp/csharp_reflection_class.h      \
   google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \
   google/protobuf/compiler/csharp/csharp_repeated_enum_field.h \
   google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \
@@ -459,8 +467,6 @@
   google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h \
   google/protobuf/compiler/csharp/csharp_source_generator_base.cc \
   google/protobuf/compiler/csharp/csharp_source_generator_base.h \
-  google/protobuf/compiler/csharp/csharp_umbrella_class.cc     \
-  google/protobuf/compiler/csharp/csharp_umbrella_class.h      \
   google/protobuf/compiler/csharp/csharp_wrapper_field.cc      \
   google/protobuf/compiler/csharp/csharp_wrapper_field.h
 
@@ -511,6 +517,7 @@
   google/protobuf/util/internal/testdata/struct.proto             \
   google/protobuf/util/internal/testdata/timestamp_duration.proto \
   google/protobuf/util/json_format_proto3.proto                   \
+  google/protobuf/util/message_differencer_unittest.proto         \
   google/protobuf/compiler/cpp/cpp_test_large_enum_value.proto
 
 EXTRA_DIST =                                                   \
@@ -622,7 +629,9 @@
   google/protobuf/util/internal/testdata/timestamp_duration.pb.cc \
   google/protobuf/util/internal/testdata/timestamp_duration.pb.h  \
   google/protobuf/util/json_format_proto3.pb.cc                   \
-  google/protobuf/util/json_format_proto3.pb.h
+  google/protobuf/util/json_format_proto3.pb.h                    \
+  google/protobuf/util/message_differencer_unittest.pb.cc         \
+  google/protobuf/util/message_differencer_unittest.pb.h
 
 BUILT_SOURCES = $(protoc_outputs)
 
@@ -720,6 +729,7 @@
   google/protobuf/compiler/cpp/cpp_unittest.h                  \
   google/protobuf/compiler/cpp/cpp_unittest.cc                 \
   google/protobuf/compiler/cpp/cpp_plugin_unittest.cc          \
+  google/protobuf/compiler/cpp/metadata_test.cc                \
   google/protobuf/compiler/java/java_plugin_unittest.cc        \
   google/protobuf/compiler/java/java_doc_comment_unittest.cc   \
   google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc \
@@ -735,6 +745,7 @@
   google/protobuf/util/internal/protostream_objectwriter_test.cc \
   google/protobuf/util/internal/type_info_test_helper.cc       \
   google/protobuf/util/json_util_test.cc                       \
+  google/protobuf/util/message_differencer_unittest.cc         \
   google/protobuf/util/time_util_test.cc                       \
   google/protobuf/util/type_resolver_util_test.cc              \
   $(COMMON_TEST_SOURCES)
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..4e312c0
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,209 @@
+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)
+
+Copyright 2008 Google Inc.
+
+https://developers.google.com/protocol-buffers/
+
+C++ Installation - Unix
+-----------------------
+
+To build protobuf from source, the following tools are needed:
+
+  * autoconf
+  * automake
+  * libtool
+  * curl (used to download gmock)
+
+On Ubuntu, you can install them with:
+
+  $ sudo apt-get install autoconf automake libtool curl
+
+On other platforms, please use the corresponding package managing tool to
+install them before proceeding.
+
+If you get the source from github, you need to generate the configure script
+first:
+
+    $ ./autogen.sh
+
+This will download gmock source (which is used for C++ Protocol Buffer
+unit-tests) to the current directory and run automake, autoconf, etc.
+to generate the configure script and various template makefiles.
+
+You can skip this step if you are using a release package (which already
+contains gmock and the configure script).
+
+To build and install the C++ Protocol Buffer runtime and the Protocol
+Buffer compiler (protoc) execute the following:
+
+    $ ./configure
+    $ make
+    $ make check
+    $ sudo make install
+    $ sudo ldconfig # refresh shared library cache.
+
+If "make check" fails, you can still install, but it is likely that
+some features of this library will not work correctly on your system.
+Proceed at your own risk.
+
+For advanced usage information on configure and make, please refer to the
+autoconf documentation:
+
+  http://www.gnu.org/software/autoconf/manual/autoconf.html#Running-configure-Scripts
+
+**Hint on install location**
+
+  By default, the package will be installed to /usr/local.  However,
+  on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
+  You can add it, but it may be easier to just install to /usr
+  instead.  To do this, invoke configure as follows:
+
+    ./configure --prefix=/usr
+
+  If you already built the package with a different prefix, make sure
+  to run "make clean" before building again.
+
+**Compiling dependent packages**
+
+  To compile a package that uses Protocol Buffers, you need to pass
+  various flags to your compiler and linker.  As of version 2.2.0,
+  Protocol Buffers integrates with pkg-config to manage this.  If you
+  have pkg-config installed, then you can invoke it to get a list of
+  flags like so:
+
+    pkg-config --cflags protobuf         # print compiler flags
+    pkg-config --libs protobuf           # print linker flags
+    pkg-config --cflags --libs protobuf  # print both
+
+  For example:
+
+    c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
+
+  Note that packages written prior to the 2.2.0 release of Protocol
+  Buffers may not yet integrate with pkg-config to get flags, and may
+  not pass the correct set of flags to correctly link against
+  libprotobuf.  If the package in question uses autoconf, you can
+  often fix the problem by invoking its configure script like:
+
+    configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
+              LIBS="$(pkg-config --libs protobuf)"
+
+  This will force it to use the correct flags.
+
+  If you are writing an autoconf-based package that uses Protocol
+  Buffers, you should probably use the PKG_CHECK_MODULES macro in your
+  configure script like:
+
+    PKG_CHECK_MODULES([protobuf], [protobuf])
+
+  See the pkg-config man page for more info.
+
+  If you only want protobuf-lite, substitute "protobuf-lite" in place
+  of "protobuf" in these examples.
+
+**Note for Mac users**
+
+  For a Mac system, Unix tools are not available by default. You will first need
+  to install Xcode from the Mac AppStore and then run the following command from
+  a terminal:
+
+    $ sudo xcode-select --install
+
+  To install Unix tools, you can install "port" following the instructions at
+  https://www.macports.org . This will reside in /opt/local/bin/port for most
+  Mac installations.
+
+    $ sudo /opt/local/bin/port install autoconf automake libtool
+
+  Then follow the Unix instructions above.
+
+**Note for cross-compiling**
+
+  The makefiles normally invoke the protoc executable that they just
+  built in order to build tests.  When cross-compiling, the protoc
+  executable may not be executable on the host machine.  In this case,
+  you must build a copy of protoc for the host machine first, then use
+  the --with-protoc option to tell configure to use it instead.  For
+  example:
+
+    ./configure --with-protoc=protoc
+
+  This will use the installed protoc (found in your $PATH) instead of
+  trying to execute the one built during the build process.  You can
+  also use an executable that hasn't been installed.  For example, if
+  you built the protobuf package for your host machine in ../host,
+  you might do:
+
+    ./configure --with-protoc=../host/src/protoc
+
+  Either way, you must make sure that the protoc executable you use
+  has the same version as the protobuf source code you are trying to
+  use it with.
+
+**Note for Solaris users**
+
+  Solaris 10 x86 has a bug that will make linking fail, complaining
+  about libstdc++.la being invalid.  We have included a work-around
+  in this package.  To use the work-around, run configure as follows:
+
+    ./configure LDFLAGS=-L$PWD/src/solaris
+
+  See src/solaris/libstdc++.la for more info on this bug.
+
+**Note for HP C++ Tru64 users**
+
+  To compile invoke configure as follows:
+
+    ./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
+
+  Also, you will need to use gmake instead of make.
+
+**Note for AIX users**
+
+  Compile using the IBM xlC C++ compiler as follows:
+
+    ./configure CXX=xlC
+
+  Also, you will need to use GNU `make` (`gmake`) instead of AIX `make`.
+
+C++ Installation - Windows
+--------------------------
+
+If you only need the protoc binary, you can download it from the release
+page:
+
+  https://github.com/google/protobuf/releases
+
+In the downloads section, download the zip file protoc-$VERSION-win32.zip.
+It contains the protoc binary as well as public proto files of protobuf
+library.
+
+To build from source using Microsoft Visual C++, see cmake/README.md.
+
+To build from source using Cygwin or MinGW, follow the Unix installation
+instructions, above.
+
+Binary Compatibility Warning
+----------------------------
+
+Due to the nature of C++, it is unlikely that any two versions of the
+Protocol Buffers C++ runtime libraries will have compatible ABIs.
+That is, if you linked an executable against an older version of
+libprotobuf, it is unlikely to work with a newer version without
+re-compiling.  This problem, when it occurs, will normally be detected
+immediately on startup of your app.  Still, you may want to consider
+using static linkage.  You can configure this package to install
+static libraries only using:
+
+    ./configure --disable-shared
+
+Usage
+-----
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+    https://developers.google.com/protocol-buffers/
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index c6ed37a..f3ca06b 100644
--- a/src/google/protobuf/any.cc
+++ b/src/google/protobuf/any.cc
@@ -43,6 +43,7 @@
 
 const char kAnyFullTypeName[] = "google.protobuf.Any";
 const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
 
 AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
     : type_url_(type_url), value_(value) {
@@ -64,17 +65,30 @@
 }
 
 bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
-  return type_url_->GetNoArena(
-             &::google::protobuf::internal::GetEmptyString()) ==
-         GetTypeUrl(descriptor);
+  const string type_url = type_url_->GetNoArena(
+             &::google::protobuf::internal::GetEmptyString());
+  const string full_name = descriptor->full_name();
+  if (type_url.length() < full_name.length()) {
+      return false;
+  }
+  return (0 == type_url.compare(
+    type_url.length() - full_name.length(),
+    full_name.length(),
+    full_name));
 }
 
 bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
-  const int prefix_len = strlen(kTypeGoogleApisComPrefix);
-  if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) {
-    full_type_name->assign(type_url.data() + prefix_len,
-                           type_url.size() - prefix_len);
-    return true;
+  static const char* prefix[] = {
+    kTypeGoogleApisComPrefix,
+    kTypeGoogleProdComPrefix
+  };
+  for (int i = 0; i < 2; i++) {
+    const int prefix_len = strlen(prefix[i]);
+    if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) {
+      full_type_name->assign(type_url.data() + prefix_len,
+                             type_url.size() - prefix_len);
+      return true;
+    }
   }
   return false;
 }
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
index 7eeb6b7..c8dbef1 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -70,11 +70,12 @@
 
 extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
 extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
 
 // Get the proto type name from Any::type_url value. For example, passing
 // "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
 // *full_type_name. Returns false if type_url does not start with
-// "type.googleapis.com".
+// "type.googleapis.com" or "type.googleprod.com".
 bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
 
 // See if message is of type google.protobuf.Any, if so, return the descriptors
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index cbb5d23..0bf523b 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/any.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/any.pb.h"
+#include <google/protobuf/any.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -119,10 +120,10 @@
   return _any_metadata_.UnpackTo(message);
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Any::kTypeUrlFieldNumber;
 const int Any::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Any::Any()
   : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index c324c4a..97982ec 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -27,7 +27,7 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/any.h"
+#include <google/protobuf/any.h>
 // @@protoc_insertion_point(includes)
 
 namespace google {
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
index 423699b..e8a18bc 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -27,21 +27,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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "AnyProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
-
 // `Any` contains an arbitrary serialized message along with a URL
 // that describes the type of the serialized message.
 //
+//
 // JSON
 // ====
 // The JSON representation of an `Any` value uses the regular
@@ -62,8 +63,8 @@
 //
 // If the embedded message type is well-known and has a custom JSON
 // representation, that representation will be embedded adding a field
-// `value` which holds the custom JSON in addition to the the `@type`
-// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
+// `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",
@@ -80,7 +81,7 @@
   // * If no schema is provided, `https` is assumed.
   // * The last segment of the URL's path must represent the fully
   //   qualified name of the type (as in `path/google.protobuf.Duration`).
-  // * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
+  // * 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
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 0a2c4ec..e589a89 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/api.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/api.pb.h"
+#include <google/protobuf/api.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -186,7 +187,7 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Api::kNameFieldNumber;
 const int Api::kMethodsFieldNumber;
 const int Api::kOptionsFieldNumber;
@@ -194,7 +195,7 @@
 const int Api::kSourceContextFieldNumber;
 const int Api::kMixinsFieldNumber;
 const int Api::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Api::Api()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -904,7 +905,7 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Method::kNameFieldNumber;
 const int Method::kRequestTypeUrlFieldNumber;
 const int Method::kRequestStreamingFieldNumber;
@@ -912,7 +913,7 @@
 const int Method::kResponseStreamingFieldNumber;
 const int Method::kOptionsFieldNumber;
 const int Method::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Method::Method()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1608,10 +1609,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Mixin::kNameFieldNumber;
 const int Mixin::kRootFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Mixin::Mixin()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 3c5a6f3..e1dca4e 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -27,8 +27,8 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/source_context.pb.h"
-#include "google/protobuf/type.pb.h"
+#include <google/protobuf/source_context.pb.h>
+#include <google/protobuf/type.pb.h>
 // @@protoc_insertion_point(includes)
 
 namespace google {
diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto
index 597a649..dbe87b8 100644
--- a/src/google/protobuf/api.proto
+++ b/src/google/protobuf/api.proto
@@ -27,6 +27,7 @@
 // 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.
+
 syntax = "proto3";
 
 package google.protobuf;
@@ -34,11 +35,11 @@
 import "google/protobuf/source_context.proto";
 import "google/protobuf/type.proto";
 
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 option java_package = "com.google.protobuf";
 option java_outer_classname = "ApiProto";
 option java_multiple_files = true;
 option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 option objc_class_prefix = "GPB";
 
 // Api is a light-weight descriptor for a protocol buffer service.
@@ -75,6 +76,7 @@
   // be omitted. Zero major versions must only be used for
   // experimental, none-GA apis.
   //
+  //
   string version = 4;
 
   // Source context for the protocol buffer service represented by this
@@ -141,7 +143,6 @@
 //
 //     package google.storage.v2;
 //     service Storage {
-//       // (-- see AccessControl.GetAcl --)
 //       rpc GetAcl(GetAclRequest) returns (Acl);
 //
 //       // Get a data record.
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 907a6a2..cd0b21a 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -38,17 +38,17 @@
 namespace protobuf {
 
 google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
-Arena::ThreadCache& Arena::thread_cache() {
-  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
-  return thread_cache_;
-}
-#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
 Arena::ThreadCache& Arena::thread_cache() {
   static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
       new internal::ThreadLocalStorage<ThreadCache>();
   return *thread_cache_->Get();
 }
+#elif defined(PROTOBUF_USE_DLLS)
+Arena::ThreadCache& Arena::thread_cache() {
+  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
+  return thread_cache_;
+}
 #else
 GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
 #endif
@@ -61,6 +61,9 @@
   cleanup_list_ = 0;
 
   if (options_.initial_block != NULL && options_.initial_block_size > 0) {
+    GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
+        << ": Initial block size too small for header.";
+
     // Add first unowned block to list.
     Block* first_block = reinterpret_cast<Block*>(options_.initial_block);
     first_block->size = options_.initial_block_size;
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 074a9e5..5ad94fa 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -38,7 +38,16 @@
 #if __cplusplus >= 201103L
 #include <google/protobuf/stubs/type_traits.h>
 #endif
+#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
+// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
+#include <exception>
 #include <typeinfo>
+namespace std {
+using type_info = ::type_info;
+}
+#else
+#include <typeinfo>
+#endif
 
 #include <google/protobuf/stubs/atomic_sequence_num.h>
 #include <google/protobuf/stubs/atomicops.h>
@@ -67,7 +76,7 @@
 template<typename T> void arena_delete_object(void* object) {
   delete reinterpret_cast<T*>(object);
 }
-inline void arena_free(void* object, size_t size) {
+inline void arena_free(void* object, size_t /* size */) {
   free(object);
 }
 
@@ -481,27 +490,28 @@
     return GetArenaInternal(value, static_cast<T*>(0));
   }
 
-  // Helper typetrait that indicates support for arenas in a type T at compile
-  // time. This is public only to allow construction of higher-level templated
-  // utilities. is_arena_constructable<T>::value is an instance of
-  // google::protobuf::internal::true_type if the message type T has arena support enabled, and
-  // google::protobuf::internal::false_type otherwise.
-  //
-  // This is inside Arena because only Arena has the friend relationships
-  // necessary to see the underlying generated code traits.
-  template<typename T>
-  struct is_arena_constructable {
+ private:
+  struct InternalIsArenaConstructableHelper {
     template<typename U>
     static char ArenaConstructable(
         const typename U::InternalArenaConstructable_*);
     template<typename U>
     static double ArenaConstructable(...);
+  };
 
-    // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
-    typedef google::protobuf::internal::integral_constant<bool,
-              sizeof(ArenaConstructable<const T>(static_cast<const T*>(0))) ==
-              sizeof(char)> type;
-    static const type value;
+ public:
+  // Helper typetrait that indicates support for arenas in a type T at compile
+  // time. This is public only to allow construction of higher-level templated
+  // utilities. is_arena_constructable<T>::value is true if the message type T
+  // has arena support enabled, and false otherwise.
+  //
+  // This is inside Arena because only Arena has the friend relationships
+  // necessary to see the underlying generated code traits.
+  template<typename T>
+  struct is_arena_constructable :
+      public google::protobuf::internal::integral_constant<bool,
+          sizeof(InternalIsArenaConstructableHelper::ArenaConstructable<
+                 const T>(static_cast<const T*>(0))) == sizeof(char)> {
   };
 
  private:
@@ -533,15 +543,15 @@
 
   static const size_t kHeaderSize = sizeof(Block);
   static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
-  // Thread local variables cannot be exposed through DLL interface but we can
-  // wrap them in static functions.
-  static ThreadCache& thread_cache();
-#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
   // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
   // local storage class we implemented.
   // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
   static ThreadCache& thread_cache();
+#elif defined(PROTOBUF_USE_DLLS)
+  // Thread local variables cannot be exposed through DLL interface but we can
+  // wrap them in static functions.
+  static ThreadCache& thread_cache();
 #else
   static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
   static ThreadCache& thread_cache() { return thread_cache_; }
@@ -563,32 +573,30 @@
     return google::protobuf::internal::has_trivial_destructor<T>::value;
   }
 
-  // Helper typetrait that indicates whether the desctructor of type T should be
-  // called when arena is destroyed at compile time. This is only to allow
-  // construction of higher-level templated utilities.
-  // is_destructor_skippable<T>::value is an instance of google::protobuf::internal::true_type if the
-  // destructor of the message type T should not be called when arena is
-  // destroyed or google::protobuf::internal::has_trivial_destructor<T>::value == true, and
-  // google::protobuf::internal::false_type otherwise.
-  //
-  // This is inside Arena because only Arena has the friend relationships
-  // necessary to see the underlying generated code traits.
-  template<typename T>
-  struct is_destructor_skippable {
+ private:
+  struct InternalIsDestructorSkippableHelper {
     template<typename U>
     static char DestructorSkippable(
         const typename U::DestructorSkippable_*);
     template<typename U>
     static double DestructorSkippable(...);
-
-    // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
-    typedef google::protobuf::internal::integral_constant<bool,
-              sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) ==
-              sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true>
-              type;
-    static const type value;
   };
 
+ public:
+  // Helper typetrait that indicates whether the desctructor of type T should be
+  // called when arena is destroyed at compile time. This is only to allow
+  // construction of higher-level templated utilities.
+  // is_destructor_skippable<T>::value is true if the destructor of the message
+  // type T should not be called when arena is destroyed or false otherwise.
+  // This is inside Arena because only Arena has the friend relationships
+  // necessary to see the underlying generated code traits.
+  template<typename T>
+  struct is_destructor_skippable
+      : public google::protobuf::internal::integral_constant<
+            bool,
+            sizeof(InternalIsDestructorSkippableHelper::DestructorSkippable<
+                   const T>(static_cast<const T*>(0))) == sizeof(char) ||
+                google::protobuf::internal::has_trivial_destructor<T>::value> {};
 
   // CreateMessage<T> requires that T supports arenas, but this private method
   // works whether or not T supports arenas. These are not exposed to user code
@@ -769,8 +777,10 @@
   // which needs to declare google::protobuf::Map as friend of generated message.
   template <typename T>
   static void CreateInArenaStorage(T* ptr, Arena* arena) {
-    CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
-    RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>::value);
+    CreateInArenaStorageInternal(ptr, arena,
+                                 typename is_arena_constructable<T>::type());
+    RegisterDestructorInternal(ptr, arena,
+                               typename is_destructor_skippable<T>::type());
   }
 
   template <typename T>
@@ -899,16 +909,6 @@
 // Defined above for supporting environments without RTTI.
 #undef RTTI_TYPE_ID
 
-template<typename T>
-const typename Arena::is_arena_constructable<T>::type
-    Arena::is_arena_constructable<T>::value =
-        typename Arena::is_arena_constructable<T>::type();
-
-template<typename T>
-const typename Arena::is_destructor_skippable<T>::type
-    Arena::is_destructor_skippable<T>::value =
-        typename Arena::is_destructor_skippable<T>::type();
-
 }  // namespace protobuf
 
 }  // namespace google
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index c9ca1fd..6b67f44 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -362,7 +362,7 @@
   Arena arena;
   TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   arena_message->mutable_optional_nested_message()->set_bb(118);
-  scoped_ptr<TestAllTypes::NestedMessage> nested(
+  google::protobuf::scoped_ptr<TestAllTypes::NestedMessage> nested(
       arena_message->release_optional_nested_message());
   EXPECT_EQ(118, nested->bb());
 
@@ -383,7 +383,7 @@
   Arena arena;
   TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
   arena_message->set_optional_string("hello");
-  scoped_ptr<string> released_str(
+  google::protobuf::scoped_ptr<string> released_str(
       arena_message->release_optional_string());
   EXPECT_EQ("hello", *released_str);
 
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index 1dacdc6..e2e2f25 100755
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -36,7 +36,6 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/fastmem.h>
-
 #include <google/protobuf/arena.h>
 #include <google/protobuf/generated_message_util.h>
 
@@ -65,7 +64,7 @@
   }
 
   // Basic accessors.
-  inline const ::std::string& Get(const ::std::string* default_value) const {
+  inline const ::std::string& Get(const ::std::string* /* default_value */) const {
     return *ptr_;
   }
 
@@ -103,7 +102,7 @@
   // state. Used to implement unsafe_arena_release_<field>() methods on
   // generated classes.
   inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
-                                      ::google::protobuf::Arena* arena) {
+                                      ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       return NULL;
     }
@@ -135,7 +134,7 @@
   // UnsafeArenaRelease() on another field of a message in the same arena. Used
   // to implement unsafe_arena_set_allocated_<field> in generated classes.
   inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
-                                      ::std::string* value, ::google::protobuf::Arena* arena) {
+                                      ::std::string* value, ::google::protobuf::Arena* /* arena */) {
     if (value != NULL) {
       ptr_ = value;
     } else {
@@ -164,7 +163,7 @@
   // the user) will always be the empty string. Assumes that |default_value|
   // is an empty string.
   inline void ClearToEmpty(const ::std::string* default_value,
-                           ::google::protobuf::Arena* arena) {
+                           ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       // Already set to default (which is empty) -- do nothing.
     } else {
@@ -176,7 +175,7 @@
   // overhead of heap operations. After this returns, the content (as seen by
   // the user) will always be equal to |default_value|.
   inline void ClearToDefault(const ::std::string* default_value,
-                             ::google::protobuf::Arena* arena) {
+                             ::google::protobuf::Arena* /* arena */) {
     if (ptr_ == default_value) {
       // Already set to default -- do nothing.
     } else {
@@ -216,7 +215,7 @@
 
   void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
 
-  inline const ::std::string& GetNoArena(const ::std::string* default_value) const {
+  inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const {
     return *ptr_;
   }
 
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 26a4f0b..3a816b0 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -33,6 +33,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/stubs/platform_macros.h>
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -48,6 +49,10 @@
 #include <iostream>
 #include <ctype.h>
 
+#ifdef GOOGLE_PROTOBUF_ARCH_SPARC 
+#include <limits.h> //For PATH_MAX
+#endif
+
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
@@ -271,15 +276,35 @@
   // implements MultiFileErrorCollector ------------------------------
   void AddError(const string& filename, int line, int column,
                 const string& message) {
+    AddErrorOrWarning(filename, line, column, message, "error", std::cerr);
+  }
 
+  void AddWarning(const string& filename, int line, int column,
+                  const string& message) {
+    AddErrorOrWarning(filename, line, column, message, "warning", std::clog);
+  }
+
+  // implements io::ErrorCollector -----------------------------------
+  void AddError(int line, int column, const string& message) {
+    AddError("input", line, column, message);
+  }
+
+  void AddWarning(int line, int column, const string& message) {
+    AddErrorOrWarning("input", line, column, message, "warning", std::clog);
+  }
+
+ private:
+  void AddErrorOrWarning(
+      const string& filename, int line, int column,
+      const string& message, const string& type, ostream& out) {
     // Print full path when running under MSVS
     string dfile;
     if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
         tree_ != NULL &&
         tree_->VirtualFileToDiskFile(filename, &dfile)) {
-      std::cerr << dfile;
+      out << dfile;
     } else {
-      std::cerr << filename;
+      out << filename;
     }
 
     // Users typically expect 1-based line/column numbers, so we add 1
@@ -288,24 +313,22 @@
       // Allow for both GCC- and Visual-Studio-compatible output.
       switch (format_) {
         case CommandLineInterface::ERROR_FORMAT_GCC:
-          std::cerr << ":" << (line + 1) << ":" << (column + 1);
+          out << ":" << (line + 1) << ":" << (column + 1);
           break;
         case CommandLineInterface::ERROR_FORMAT_MSVS:
-          std::cerr << "(" << (line + 1)
-                    << ") : error in column=" << (column + 1);
+          out << "(" << (line + 1) << ") : "
+              << type << " in column=" << (column + 1);
           break;
       }
     }
 
-    std::cerr << ": " << message << std::endl;
+    if (type == "warning") {
+      out << ": warning: " << message << std::endl;
+    } else {
+      out << ": " << message << std::endl;
+    }
   }
 
-  // implements io::ErrorCollector -----------------------------------
-  void AddError(int line, int column, const string& message) {
-    AddError("input", line, column, message);
-  }
-
- private:
   const ErrorFormat format_;
   DiskSourceTree *tree_;
 };
@@ -1353,7 +1376,7 @@
 "                              defined in the given proto files. Groups share\n"
 "                              the same field number space with the parent \n"
 "                              message. Extension ranges are counted as \n"
-"                              occupied fields numbers."
+"                              occupied fields numbers.\n"
       << std::endl;
   if (!plugin_prefix_.empty()) {
     std::cerr <<
@@ -1443,6 +1466,7 @@
   for (int i = 0; i < parsed_files.size(); i++) {
     GetTransitiveDependencies(parsed_files[i],
                               false,
+                              false,
                               &already_seen,
                               file_set.mutable_file());
   }
@@ -1522,6 +1546,7 @@
   for (int i = 0; i < parsed_files.size(); i++) {
     request.add_file_to_generate(parsed_files[i]->name());
     GetTransitiveDependencies(parsed_files[i],
+                              true,  // Include json_name for plugins.
                               true,  // Include source code info.
                               &already_seen, request.mutable_proto_file());
   }
@@ -1654,6 +1679,7 @@
     set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
       GetTransitiveDependencies(parsed_files[i],
+                                true,  // Include json_name
                                 source_info_in_descriptor_set_,
                                 &already_seen, file_set.mutable_file());
     }
@@ -1665,6 +1691,7 @@
       }
       FileDescriptorProto* file_proto = file_set.add_file();
       parsed_files[i]->CopyTo(file_proto);
+      parsed_files[i]->CopyJsonNameTo(file_proto);
       if (source_info_in_descriptor_set_) {
         parsed_files[i]->CopySourceCodeInfoTo(file_proto);
       }
@@ -1699,7 +1726,9 @@
 }
 
 void CommandLineInterface::GetTransitiveDependencies(
-    const FileDescriptor* file, bool include_source_code_info,
+    const FileDescriptor* file,
+    bool include_json_name,
+    bool include_source_code_info,
     set<const FileDescriptor*>* already_seen,
     RepeatedPtrField<FileDescriptorProto>* output) {
   if (!already_seen->insert(file).second) {
@@ -1709,13 +1738,18 @@
 
   // Add all dependencies.
   for (int i = 0; i < file->dependency_count(); i++) {
-    GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+    GetTransitiveDependencies(file->dependency(i),
+                              include_json_name,
+                              include_source_code_info,
                               already_seen, output);
   }
 
   // Add this file.
   FileDescriptorProto* new_descriptor = output->Add();
   file->CopyTo(new_descriptor);
+  if (include_json_name) {
+    file->CopyJsonNameTo(new_descriptor);
+  }
   if (include_source_code_info) {
     file->CopySourceCodeInfoTo(new_descriptor);
   }
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 7e611c4..f196ffc 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -262,8 +262,11 @@
   // in order.  Any files in *already_seen will not be added, and each file
   // added will be inserted into *already_seen.  If include_source_code_info is
   // true then include the source code information in the FileDescriptorProtos.
+  // If include_json_name is true, populate the json_name field of
+  // FieldDescriptorProto for all fields.
   static void GetTransitiveDependencies(
       const FileDescriptor* file,
+      bool include_json_name,
       bool include_source_code_info,
       set<const FileDescriptor*>* already_seen,
       RepeatedPtrField<FileDescriptorProto>* output);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 9560d0e..dda007d 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -294,6 +294,10 @@
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
 #ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+    string plugin_path;
+#ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
+    plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
+#else
     const char* possible_paths[] = {
       // When building with shared libraries, libtool hides the real executable
       // in .libs and puts a fake wrapper in the current directory.
@@ -311,15 +315,13 @@
       "test_plugin.exe",        // Other Win32 (MSVC)
       "test_plugin",            // Unix
     };
-
-    string plugin_path;
-
     for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) {
       if (access(possible_paths[i], F_OK) == 0) {
         plugin_path = possible_paths[i];
         break;
       }
     }
+#endif
 
     if (plugin_path.empty()) {
 #else
@@ -884,6 +886,10 @@
   EXPECT_EQ("bar.proto", descriptor_set.file(0).name());
   // Descriptor set should not have source code info.
   EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+  // Descriptor set should have json_name.
+  EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+  EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
 }
 
 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) {
@@ -917,6 +923,10 @@
   EXPECT_EQ("baz.proto", descriptor_set.file(2).name());
   // Descriptor set should not have source code info.
   EXPECT_FALSE(descriptor_set.file(0).has_source_code_info());
+  // Descriptor set should have json_name.
+  EXPECT_EQ("Bar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo", descriptor_set.file(0).message_type(0).field(0).name());
+  EXPECT_TRUE(descriptor_set.file(0).message_type(0).field(0).has_json_name());
 }
 
 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
@@ -1411,6 +1421,18 @@
       "Saw message type MockCodeGenerator_HasSourceCodeInfo: 1.");
 }
 
+TEST_F(CommandLineInterfaceTest, PluginReceivesJsonName) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message MockCodeGenerator_HasJsonName {\n"
+    "  optional int32 value = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --plug_out=$tmpdir --proto_path=$tmpdir foo.proto");
+
+  ExpectErrorSubstring("Saw json_name: 1");
+}
+
 TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) {
   // Test what happens if the plugin isn't found.
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index c3e9fe7..47729e1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -107,7 +107,7 @@
 
   virtual io::ZeroCopyOutputStream* Open(const string& filename) {
     string** map_slot = &files_[filename];
-    if (*map_slot != NULL) delete *map_slot;
+    delete *map_slot;
     *map_slot = new string;
 
     return new io::StringOutputStream(*map_slot);
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index de4d7cc..1a11bce 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -278,9 +278,9 @@
   if (descriptor_->containing_type() != NULL) {
     // We need to "define" the static constants which were declared in the
     // header, to give the linker a place to put them.  Or at least the C++
-    // standard says we have to.  MSVC actually insists tha we do _not_ define
-    // them again in the .cc file.
-    printer->Print("#ifndef _MSC_VER\n");
+    // standard says we have to.  MSVC actually insists that we do _not_ define
+    // them again in the .cc file, prior to VC++ 2015.
+    printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
 
     vars["parent"] = ClassName(descriptor_->containing_type(), false);
     vars["nested_name"] = descriptor_->name();
@@ -297,7 +297,7 @@
         "const int $parent$::$nested_name$_ARRAYSIZE;\n");
     }
 
-    printer->Print("#endif  // _MSC_VER\n");
+    printer->Print("#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 468ca48..c42f162 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -155,7 +155,7 @@
   // Likewise, class members need to declare the field constant variable.
   if (descriptor_->extension_scope() != NULL) {
     printer->Print(vars,
-      "#ifndef _MSC_VER\n"
+      "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
       "const int $scope$$constant_name$;\n"
       "#endif\n");
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 8e8bd8b..37e4bae 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -237,6 +237,7 @@
 }
 
 void FileGenerator::GenerateSource(io::Printer* printer) {
+  bool well_known = IsWellKnownMessage(file_);
   string header =
       StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
   printer->Print(
@@ -246,16 +247,19 @@
     // The generated code calls accessors that might be deprecated. We don't
     // want the compiler to warn in generated code.
     "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
-    "#include \"$header$\"\n"
+    "#include $left$$header$$right$\n"
     "\n"
     "#include <algorithm>\n"    // for swap()
     "\n"
     "#include <google/protobuf/stubs/common.h>\n"
+    "#include <google/protobuf/stubs/port.h>\n"
     "#include <google/protobuf/stubs/once.h>\n"
     "#include <google/protobuf/io/coded_stream.h>\n"
     "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "filename", file_->name(),
-    "header", header);
+    "header", header,
+    "left", well_known ? "<" : "\"",
+    "right", well_known ? ">" : "\"");
 
   // Unknown fields implementation in lite mode uses StringOutputStream
   if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -846,7 +850,7 @@
 
   if (IsAnyMessage(file_)) {
     printer->Print(
-      "#include \"google/protobuf/any.h\"\n");
+      "#include <google/protobuf/any.h>\n");
   }
 }
 
@@ -857,14 +861,16 @@
   }
 
   for (int i = 0; i < file_->dependency_count(); i++) {
+    bool well_known = IsWellKnownMessage(file_->dependency(i));
     const string& name = file_->dependency(i)->name();
     bool public_import = (public_import_names.count(name) != 0);
 
-
     printer->Print(
-      "#include \"$dependency$.pb.h\"$iwyu$\n",
+      "#include $left$$dependency$.pb.h$right$$iwyu$\n",
       "dependency", StripProto(name),
-      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
+      "iwyu", (public_import) ? "  // IWYU pragma: export" : "",
+      "left", well_known ? "<" : "\"",
+      "right", well_known ? ">" : "\"");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 0984545..fb46e38 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -54,6 +54,7 @@
 
 static const char kAnyMessageName[] = "Any";
 static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+static const char kGoogleProtobufPrefix[] = "google/protobuf/";
 
 string DotsToUnderscores(const string& name) {
   return StringReplace(name, ".", "_", true);
@@ -600,6 +601,10 @@
          descriptor->file()->name() == kAnyProtoFile;
 }
 
+bool IsWellKnownMessage(const FileDescriptor* descriptor) {
+  return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix);
+}
+
 enum Utf8CheckMode {
   STRICT = 0,  // Parsing will fail if non UTF-8 data is in string fields.
   VERIFY = 1,  // Only log an error but parsing will succeed.
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 985cb04..a22d414 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -265,6 +265,8 @@
 bool IsAnyMessage(const FileDescriptor* descriptor);
 bool IsAnyMessage(const Descriptor* descriptor);
 
+bool IsWellKnownMessage(const FileDescriptor* descriptor);
+
 void GenerateUtf8CheckCodeForString(
     const FieldDescriptor* field,
     bool for_parse,
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 25acc61..e5e2f07 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -66,7 +66,7 @@
       (*variables)["wrapper"] = "EntryWrapper";
       break;
     case FieldDescriptor::CPPTYPE_ENUM:
-      (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
+      (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
       (*variables)["wrapper"] = "EnumEntryWrapper";
       break;
     default:
@@ -200,7 +200,7 @@
       case FieldDescriptor::CPPTYPE_ENUM:
         printer->Print(variables_,
             "(*mutable_$name$())[entry->key()] =\n"
-            "    static_cast<$val_cpp$>(*entry->mutable_value());\n");
+            "    static_cast< $val_cpp$ >(*entry->mutable_value());\n");
         break;
       default:
         printer->Print(variables_,
@@ -215,7 +215,7 @@
         "  DO_(entry->ParseFromString(data));\n"
         "  if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
         "    (*mutable_$name$())[entry->key()] =\n"
-        "        static_cast<$val_cpp$>(*entry->mutable_value());\n"
+        "        static_cast< $val_cpp$ >(*entry->mutable_value());\n"
         "  } else {\n");
     if (HasDescriptorMethods(descriptor_->file())) {
       printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index fc1ce96..8304ebb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -350,7 +350,7 @@
       (*variables)["val"] = FieldMessageTypeName(val);
       break;
     case FieldDescriptor::CPPTYPE_ENUM:
-      (*variables)["val"] = ClassName(val->enum_type(), false);
+      (*variables)["val"] = ClassName(val->enum_type(), true);
       break;
     default:
       (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
@@ -1772,6 +1772,17 @@
 
 void MessageGenerator::
 GenerateClassMethods(io::Printer* printer) {
+  // mutable_unknown_fields wrapper function for LazyStringOutputStream
+  // callback.
+  if (!UseUnknownFieldSet(descriptor_->file())) {
+    printer->Print(
+        "static ::std::string* MutableUnknownFieldsFor$classname$(\n"
+        "    $classname$* ptr) {\n"
+        "  return ptr->mutable_unknown_fields();\n"
+        "}\n"
+        "\n",
+        "classname", classname_);
+  }
   if (IsAnyMessage(descriptor_)) {
     printer->Print(
       "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
@@ -1807,7 +1818,7 @@
   }
 
   // Generate field number constants.
-  printer->Print("#ifndef _MSC_VER\n");
+  printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor *field = descriptor_->field(i);
     printer->Print(
@@ -1816,7 +1827,7 @@
       "constant_name", FieldConstantName(field));
   }
   printer->Print(
-    "#endif  // !_MSC_VER\n"
+    "#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n"
     "\n");
 
   // Define extension identifiers.
@@ -2814,7 +2825,9 @@
         "}\n");
     } else {
       printer->Print(
-        "mutable_unknown_fields()->append(from.unknown_fields());\n");
+        "if (!from.unknown_fields().empty()) {\n"
+        "  mutable_unknown_fields()->append(from.unknown_fields());\n"
+        "}\n");
     }
   }
 
@@ -2889,11 +2902,16 @@
     "classname", classname_);
 
   if (!UseUnknownFieldSet(descriptor_->file())) {
+    // Use LazyStringOutputString to avoid initializing unknown fields string
+    // unless it is actually needed. For the same reason, disable eager refresh
+    // on the CodedOutputStream.
     printer->Print(
-      "  ::google::protobuf::io::StringOutputStream unknown_fields_string(\n"
-      "      mutable_unknown_fields());\n"
+      "  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
+      "      ::google::protobuf::internal::NewPermanentCallback(\n"
+      "          &MutableUnknownFieldsFor$classname$, this));\n"
       "  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
-      "      &unknown_fields_string);\n");
+      "      &unknown_fields_string, false);\n",
+      "classname", classname_);
   }
 
   printer->Print(
@@ -3364,7 +3382,7 @@
     } else {
       printer->Print(
         "output->WriteRaw(unknown_fields().data(),\n"
-        "                 unknown_fields().size());\n");
+        "                 static_cast<int>(unknown_fields().size()));\n");
     }
   }
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index b7b6039..9942a34 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -82,6 +82,7 @@
 
 namespace google {
 namespace protobuf {
+using internal::NewPermanentCallback;
 namespace compiler {
 namespace cpp {
 
diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
similarity index 71%
rename from src/google/protobuf/proto_cast_test.cc
rename to src/google/protobuf/compiler/cpp/metadata_test.cc
index a8f43ae..422eb73 100644
--- a/src/google/protobuf/proto_cast_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -28,33 +28,31 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <google/protobuf/util/proto_cast.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
-#include <google/protobuf/util/unknown_enum_test.pb.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_generator.h>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+
+#include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <gmock/gmock.h>
+#include <google/protobuf/testing/file.h>
 
 namespace google {
-using google::protobuf::util::UpRevision;
-using google::protobuf::util::DownRevision;
-
+namespace protobuf {
+namespace compiler {
+namespace cpp {
 namespace {
 
-TEST(ProtoCastTest, V2KnownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NONDEFAULT_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::NONDEFAULT_VALUE, receiver.value());
-}
-
-TEST(ProtoCastTest, V2UnknownValue) {
-  UpRevision sender;
-  sender.set_value(UpRevision::NEW_VALUE);
-
-  DownRevision receiver = proto_cast<DownRevision>(sender);
-  ASSERT_EQ(DownRevision::DEFAULT_VALUE, receiver.value());
-}
-
 }  // namespace
+}  // namespace cpp
+}  // namespace compiler
+}  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
new file mode 100644
index 0000000..587e022
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
@@ -0,0 +1,114 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace csharp {
+
+// Functions to create C# XML documentation comments.
+// Currently this only includes documentation comments containing text specified as comments
+// in the .proto file; documentation comments generated just from field/message/enum/proto names
+// is inlined in the relevant code. If more control is required, that code can be moved here.
+
+void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
+    string comments = location.leading_comments.empty() ?
+        location.trailing_comments : location.leading_comments;
+    if (comments.empty()) {
+        return;
+    }
+    // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+    // node of a summary element, not part of an attribute.
+    comments = StringReplace(comments, "&", "&amp;", true);
+    comments = StringReplace(comments, "<", "&lt;", true);
+    vector<string> lines = Split(comments, "\n", false /* skip_empty */);
+    // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+    // but that needs to be part of a bigger effort to understand the markdown better anyway.
+    printer->Print("/// <summary>\n");
+    bool last_was_empty = false;
+    // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+    // to preserve the blank lines themselves, as this is relevant in the markdown.
+    // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+    // (We don't skip "just whitespace" lines, either.)
+    for (std::vector<string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+        string line = *it;
+        if (line.empty()) {
+            last_was_empty = true;
+        } else {
+            if (last_was_empty) {
+                printer->Print("///\n");
+            }
+            last_was_empty = false;
+            printer->Print("/// $line$\n", "line", *it);
+        }
+    }
+    printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+static void WriteDocCommentBody(
+    io::Printer* printer, const DescriptorType* descriptor) {
+    SourceLocation location;
+    if (descriptor->GetSourceLocation(&location)) {
+        WriteDocCommentBodyImpl(printer, location);
+    }
+}
+
+void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
+    WriteDocCommentBody(printer, message);
+}
+
+void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) {
+    WriteDocCommentBody(printer, field);
+}
+
+void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) {
+    WriteDocCommentBody(printer, enumDescriptor);
+}
+void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) {
+    WriteDocCommentBody(printer, value);
+}
+
+void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) {
+    WriteDocCommentBody(printer, method);
+}
+
+}  // namespace csharp
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
similarity index 68%
rename from src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc
rename to src/google/protobuf/compiler/csharp/csharp_doc_comment.h
index e5db844..75eb0ea 100644
--- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
@@ -28,30 +28,24 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <google/protobuf/util/internal/snake2camel_objectwriter.h>
-#include <google/protobuf/util/internal/expecting_objectwriter.h>
-#include <gtest/gtest.h>
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
 
 namespace google {
 namespace protobuf {
-namespace util {
-namespace converter {
-
-class Snake2CamelObjectWriterTest : public ::testing::Test {
- protected:
-  Snake2CamelObjectWriterTest() : mock_(), expects_(&mock_), testing_(&mock_) {}
-  virtual ~Snake2CamelObjectWriterTest() {}
-
-  MockObjectWriter mock_;
-  ExpectingObjectWriter expects_;
-  Snake2CamelObjectWriter testing_;
-};
-
-// All tests are deleted as they are no longer needed. This file will be removed
-// after the component dependecies are cleaned up.
-// TODO(skarvaje): Remove this file.
-
-}  // namespace converter
-}  // namespace util
+namespace compiler {
+namespace csharp {
+    void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
+    void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field);
+    void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor);
+    void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value);
+    void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method);
+}  // namespace csharp
+}  // namespace compiler
 }  // namespace protobuf
 }  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc
index 0e8f983..5668198 100644
--- a/src/google/protobuf/compiler/csharp/csharp_enum.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/stubs/strutil.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_enum.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 
@@ -57,13 +58,15 @@
 }
 
 void EnumGenerator::Generate(io::Printer* printer) {
+  WriteEnumDocComment(printer, descriptor_);
   WriteGeneratedCodeAttributes(printer);
   printer->Print("$access_level$ enum $name$ {\n",
                  "access_level", class_access_level(),
                  "name", descriptor_->name());
   printer->Indent();
   for (int i = 0; i < descriptor_->value_count(); i++) {
-    printer->Print("$name$ = $number$,\n",
+      WriteEnumValueDocComment(printer, descriptor_->value(i));
+      printer->Print("$name$ = $number$,\n",
                    "name", descriptor_->value(i)->name(),
                    "number", SimpleItoa(descriptor_->value(i)->number()));
   }
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc
index e0a6c83..825de54 100644
--- a/src/google/protobuf/compiler/csharp/csharp_generator.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc
@@ -36,10 +36,12 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
 
 #include <google/protobuf/compiler/csharp/csharp_generator.h>
-#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
 
 using google::protobuf::internal::scoped_ptr;
 
@@ -48,15 +50,10 @@
 namespace compiler {
 namespace csharp {
 
-std::string GetOutputFile(const google::protobuf::FileDescriptor* file, const std::string file_extension)
-{
-  return GetUmbrellaClassUnqualifiedName(file) + file_extension;
-}
-
 void GenerateFile(const google::protobuf::FileDescriptor* file,
                   io::Printer* printer) {
-  UmbrellaClassGenerator umbrellaGenerator(file);
-  umbrellaGenerator.Generate(printer);
+  ReflectionClassGenerator reflectionClassGenerator(file);
+  reflectionClassGenerator.Generate(printer);
 }
 
 bool Generator::Generate(
@@ -75,16 +72,26 @@
   }
 
   std::string file_extension = ".cs";
+  std::string base_namespace = "";
+  bool generate_directories = false;
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "file_extension") {
       file_extension = options[i].second;
+    } else if (options[i].first == "base_namespace") {
+      base_namespace = options[i].second;
+      generate_directories = true;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
     }
   }
 
-  std::string filename = GetOutputFile(file, file_extension);
+  string filename_error = "";
+  std::string filename = GetOutputFile(file, file_extension, generate_directories, base_namespace, &filename_error);
+  if (filename.empty()) {
+    *error = filename_error;
+    return false;
+  }
   scoped_ptr<io::ZeroCopyOutputStream> output(
       generator_context->Open(filename));
   io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
index 333b491..c51fe44 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -117,43 +117,18 @@
   return UnderscoresToCamelCase(descriptor->package(), true, true);
 }
 
-std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor) {
-  // We manually rename Descriptor to DescriptorProtoFile to avoid collisions with
-  // the static Descriptor property. It would be nice to be able to do this with an
-  // option, but it would be rarely used.
-  if (IsDescriptorProto(descriptor)) {
-    return "DescriptorProtoFile";
-  }
-  // umbrella_classname can no longer be set using message option.
-  std::string proto_file = descriptor->name();
-  int lastslash = proto_file.find_last_of("/");
-  std::string base = proto_file.substr(lastslash + 1);
-  return UnderscoresToPascalCase(StripDotProto(base));
+// Returns the Pascal-cased last part of the proto file. For example,
+// input of "google/protobuf/foo_bar.proto" would result in "FooBar".
+std::string GetFileNameBase(const FileDescriptor* descriptor) {
+    std::string proto_file = descriptor->name();
+    int lastslash = proto_file.find_last_of("/");
+    std::string base = proto_file.substr(lastslash + 1);
+    return UnderscoresToPascalCase(StripDotProto(base));
 }
 
-std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor) {
-  // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option
-  bool collision = false;
-  std::string umbrella_classname = GetUmbrellaClassUnqualifiedName(descriptor);
-  for(int i = 0; i < descriptor->message_type_count(); i++) {
-    if (descriptor->message_type(i)->name() == umbrella_classname) {
-      collision = true;
-      break;
-    }
-  }
-  for (int i = 0; i < descriptor->service_count(); i++) {
-    if (descriptor->service(i)->name() == umbrella_classname) {
-      collision = true;
-      break;
-    }
-  }
-  for (int i = 0; i < descriptor->enum_type_count(); i++) {
-    if (descriptor->enum_type(i)->name() == umbrella_classname) {
-      collision = true;
-      break;
-    }
-  }
-  return collision ? "Proto" : "";
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) {
+  // TODO: Detect collisions with existing messages, and append an underscore if necessary.
+  return GetFileNameBase(descriptor) + "Reflection";
 }
 
 // TODO(jtattermusch): can we reuse a utility function?
@@ -218,16 +193,12 @@
   return "global::" + result;
 }
 
-std::string GetUmbrellaClassName(const FileDescriptor* descriptor) {
+std::string GetReflectionClassName(const FileDescriptor* descriptor) {
   std::string result = GetFileNamespace(descriptor);
   if (!result.empty()) {
     result += '.';
   }
-  std::string umbrellaNamespace = GetUmbrellaClassNestedNamespace(descriptor);
-  if (!umbrellaNamespace.empty()) {
-      result += umbrellaNamespace + ".";
-  }
-  result += GetUmbrellaClassUnqualifiedName(descriptor);
+  result += GetReflectionClassUnqualifiedName(descriptor);
   return "global::" + result;
 }
 
@@ -269,6 +240,41 @@
   return property_name;
 }
 
+std::string GetOutputFile(
+    const google::protobuf::FileDescriptor* descriptor,
+    const std::string file_extension,
+    const bool generate_directories,
+    const std::string base_namespace,
+    string* error) {
+  string relative_filename = GetFileNameBase(descriptor) + file_extension;
+  if (!generate_directories) {
+    return relative_filename;
+  }
+  string ns = GetFileNamespace(descriptor);
+  string namespace_suffix = ns;
+  if (!base_namespace.empty()) {
+    // Check that the base_namespace is either equal to or a leading part of
+    // the file namespace. This isn't just a simple prefix; "Foo.B" shouldn't
+    // be regarded as a prefix of "Foo.Bar". The simplest option is to add "."
+    // to both.
+    string extended_ns = ns + ".";
+    if (extended_ns.find(base_namespace + ".") != 0) {
+      *error = "Namespace " + ns + " is not a prefix namespace of base namespace " + base_namespace;
+      return ""; // This will be ignored, because we've set an error.
+    }
+    namespace_suffix = ns.substr(base_namespace.length());
+    if (namespace_suffix.find(".") == 0) {
+      namespace_suffix = namespace_suffix.substr(1);
+    }
+  }
+
+  string namespace_dir = StringReplace(namespace_suffix, ".", "/", true);
+  if (!namespace_dir.empty()) {
+    namespace_dir += "/";
+  }
+  return namespace_dir + relative_filename;
+}
+
 // TODO: c&p from Java protoc plugin
 // For encodings with fixed sizes, returns that size in bytes.  Otherwise
 // returns -1.
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
index 4ed17a8..e96e793 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.h
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -69,14 +69,8 @@
 
 std::string StripDotProto(const std::string& proto_file);
 
-// Gets unqualified name of the umbrella class
-std::string GetUmbrellaClassUnqualifiedName(const FileDescriptor* descriptor);
-
-// Gets name of the nested for umbrella class (just the nested part,
-// not including the GetFileNamespace part).
-std::string GetUmbrellaClassNestedNamespace(const FileDescriptor* descriptor);
-
-std::string GetClassName(const Descriptor* descriptor);
+// Gets unqualified name of the reflection class
+std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor);
 
 std::string GetClassName(const EnumDescriptor* descriptor);
 
@@ -101,8 +95,6 @@
 
 std::string FileDescriptorToBase64(const FileDescriptor* descriptor);
 
-uint FixedMakeTag(const FieldDescriptor* descriptor);
-
 FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
 
 // Determines whether the given message is a map entry message, i.e. one implicitly created
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
index f84ad6f..15c68b3 100644
--- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/stubs/strutil.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_map_field.h>
 
@@ -61,7 +62,6 @@
       descriptor_->message_type()->FindFieldByName("value");
   variables_["key_type_name"] = type_name(key_descriptor);
   variables_["value_type_name"] = type_name(value_descriptor);
-  variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
   scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));  
   scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
 
@@ -75,7 +75,8 @@
   printer->Print(
     variables_,
     ", $tag$);\n"
-    "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n");
+    "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
index a71a790..e0230a2 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -42,6 +42,7 @@
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_enum.h>
 #include <google/protobuf/compiler/csharp/csharp_field_base.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
@@ -101,6 +102,7 @@
   vars["class_name"] = class_name();
   vars["access_level"] = class_access_level();
 
+  WriteMessageDocComment(printer, descriptor_);
   printer->Print(
     "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
   WriteGeneratedCodeAttributes(printer);
@@ -117,7 +119,7 @@
 
   // Access the message descriptor via the relevant file descriptor or containing message descriptor.
   if (!descriptor_->containing_type()) {
-    vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file())
+    vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file())
         + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
   } else {
     vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
@@ -152,7 +154,9 @@
 
     // Rats: we lose the debug comment here :(
     printer->Print(
+      "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
       "public const int $field_constant_name$ = $index$;\n",
+      "field_name", fieldDescriptor->name(),
       "field_constant_name", GetFieldConstantName(fieldDescriptor),
       "index", SimpleItoa(fieldDescriptor->number()));
     scoped_ptr<FieldGeneratorBase> generator(
@@ -169,6 +173,7 @@
     printer->Print(
       vars,
       "private object $name$_;\n"
+      "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
       "public enum $property_name$OneofCase {\n");
     printer->Indent();
     printer->Print("None = 0,\n");
@@ -180,6 +185,7 @@
     }
     printer->Outdent();
     printer->Print("}\n");
+    // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go.
     printer->Print(
       vars,
       "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"
@@ -199,8 +205,11 @@
 
   // Nested messages and enums
   if (HasNestedGeneratedTypes()) {
-    printer->Print("#region Nested types\n"
-		   "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+    printer->Print(
+      vars,
+      "#region Nested types\n"
+      "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n"
+      "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
     WriteGeneratedCodeAttributes(printer);
     printer->Print("public static partial class Types {\n");
     printer->Indent();
@@ -314,6 +323,10 @@
             CreateFieldGeneratorInternal(descriptor_->field(i)));
         generator->WriteEquals(printer);
     }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+        printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n",
+            "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
+    }
     printer->Outdent();
     printer->Print(
         "  return true;\n"
@@ -330,13 +343,17 @@
             CreateFieldGeneratorInternal(descriptor_->field(i)));
         generator->WriteHash(printer);
     }
+    for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+        printer->Print("hash ^= (int) $name$Case_;\n",
+            "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false));
+    }
     printer->Print("return hash;\n");
     printer->Outdent();
     printer->Print("}\n\n");
 
     printer->Print(
         "public override string ToString() {\n"
-        "  return pb::JsonFormatter.Default.Format(this);\n"
+        "  return pb::JsonFormatter.ToDiagnosticString(this);\n"
         "}\n\n");
 }
 
diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
index 4f576cd..f81f769 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/stubs/strutil.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_message_field.h>
 
@@ -61,6 +62,7 @@
   printer->Print(
     variables_,
     "private $type_name$ $name$_;\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
@@ -152,6 +154,7 @@
 }
 
 void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_names.h b/src/google/protobuf/compiler/csharp/csharp_names.h
index ccd2e72..3080518 100644
--- a/src/google/protobuf/compiler/csharp/csharp_names.h
+++ b/src/google/protobuf/compiler/csharp/csharp_names.h
@@ -72,7 +72,28 @@
 //   The fully-qualified name of the C# class that provides
 //   access to the file descriptor. Proto compiler generates
 //   such class for each .proto file processed.
-std::string GetUmbrellaClassName(const FileDescriptor* descriptor);
+string GetReflectionClassName(const FileDescriptor* descriptor);
+
+// Generates output file name for given file descriptor. If generate_directories
+// is true, the output file will be put under directory corresponding to file's
+// namespace. base_namespace can be used to strip some of the top level
+// directories. E.g. for file with namespace "Bar.Foo" and base_namespace="Bar",
+// the resulting file will be put under directory "Foo" (and not "Bar/Foo").
+//
+// Requires:
+//   descriptor != NULL
+//   error != NULL
+//
+//  Returns:
+//    The file name to use as output file for given file descriptor. In case
+//    of failure, this function will return empty string and error parameter
+//    will contain the error message.
+string GetOutputFile(
+    const google::protobuf::FileDescriptor* descriptor,
+    const string file_extension,
+    const bool generate_directories,
+    const string base_namespace,
+    string* error);
 
 }  // namespace csharp
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
index fc043ec..60afd89 100644
--- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/stubs/strutil.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
 
@@ -68,6 +69,7 @@
   printer->Print(
     variables_,
     "private $type_name$ $name_def_message$;\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
@@ -81,7 +83,7 @@
   } else {
     printer->Print(
       variables_,
-      "    $name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
+      "    $name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
   }
   printer->Print(
     "  }\n"
@@ -170,6 +172,7 @@
 }
 
 void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
@@ -183,7 +186,7 @@
     } else {
       printer->Print(
         variables_,
-        "    $oneof_name$_ = pb::Preconditions.CheckNotNull(value, \"value\");\n");
+        "    $oneof_name$_ = pb::ProtoPreconditions.CheckNotNull(value, \"value\");\n");
     }
     printer->Print(
       variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
similarity index 83%
rename from src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
rename to src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
index 399c64e..22dae43 100644
--- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
@@ -43,25 +43,24 @@
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_message.h>
 #include <google/protobuf/compiler/csharp/csharp_names.h>
-#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h>
+#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
 
 namespace google {
 namespace protobuf {
 namespace compiler {
 namespace csharp {
 
-UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file)
+ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file)
     : SourceGeneratorBase(file),
       file_(file) {
   namespace_ = GetFileNamespace(file);
-  umbrellaClassname_ = GetUmbrellaClassUnqualifiedName(file);
-  umbrellaNamespace_ = GetUmbrellaClassNestedNamespace(file);
+  reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
 }
 
-UmbrellaClassGenerator::~UmbrellaClassGenerator() {
+ReflectionClassGenerator::~ReflectionClassGenerator() {
 }
 
-void UmbrellaClassGenerator::Generate(io::Printer* printer) {
+void ReflectionClassGenerator::Generate(io::Printer* printer) {
   WriteIntroduction(printer);
 
   WriteDescriptor(printer);
@@ -69,12 +68,6 @@
   printer->Outdent();
   printer->Print("}\n");
 
-  // Close the namespace around the umbrella class if defined
-  if (!umbrellaNamespace_.empty()) {
-    printer->Outdent();
-    printer->Print("}\n");
-  }
-
   // write children: Enums
   if (file_->enum_type_count() > 0) {
     printer->Print("#region Enums\n");
@@ -107,7 +100,7 @@
   printer->Print("#endregion Designer generated code\n");
 }
 
-void UmbrellaClassGenerator::WriteIntroduction(io::Printer* printer) {
+void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "// source: $file_name$\n"
@@ -126,35 +119,31 @@
     printer->Print("\n");
   }
 
-  // Add the namespace around the umbrella class if defined
-  if (!umbrellaNamespace_.empty()) {
-    printer->Print("namespace $umbrella_namespace$ {\n",
-                   "umbrella_namespace", umbrellaNamespace_);
-    printer->Indent();
-    printer->Print("\n");
-  }
-
   printer->Print(
-    "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
+    "/// <summary>Holder for reflection information generated from $file_name$</summary>\n"
+    "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n",
+    "file_name", file_->name());
   WriteGeneratedCodeAttributes(printer);
   printer->Print(
-    "$access_level$ static partial class $umbrella_class_name$ {\n"
+    "$access_level$ static partial class $reflection_class_name$ {\n"
     "\n",
     "access_level", class_access_level(),
-    "umbrella_class_name", umbrellaClassname_);
+    "reflection_class_name", reflectionClassname_);
   printer->Indent();
 }
 
-void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
+void ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
   printer->Print(
     "#region Descriptor\n"
+    "/// <summary>File descriptor for $file_name$</summary>\n"
     "public static pbr::FileDescriptor Descriptor {\n"
     "  get { return descriptor; }\n"
     "}\n"
     "private static pbr::FileDescriptor descriptor;\n"
     "\n"
-    "static $umbrella_class_name$() {\n",
-    "umbrella_class_name", umbrellaClassname_);
+    "static $reflection_class_name$() {\n",
+    "file_name", file_->name(),
+    "reflection_class_name", reflectionClassname_);
   printer->Indent();
   printer->Print(
     "byte[] descriptorData = global::System.Convert.FromBase64String(\n");
@@ -166,7 +155,7 @@
   // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
   std::string base64 = FileDescriptorToBase64(file_);
   while (base64.size() > 60) {
-    printer->Print("\"$base64$\", \n", "base64", base64.substr(0, 60));
+    printer->Print("\"$base64$\",\n", "base64", base64.substr(0, 60));
     base64 = base64.substr(60);
   }
   printer->Print("\"$base64$\"));\n", "base64", base64);
@@ -177,7 +166,7 @@
   // -----------------------------------------------------------------
   // Invoke InternalBuildGeneratedFileFrom() to build the file.
   printer->Print(
-      "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
+      "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n");
   printer->Print("    new pbr::FileDescriptor[] { ");
   for (int i = 0; i < file_->dependency_count(); i++) {
     // descriptor.proto is special: we don't allow access to the generated code, but there's
@@ -187,13 +176,13 @@
       printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, ");
     } else {
       printer->Print(
-      "$full_umbrella_class_name$.Descriptor, ",
-      "full_umbrella_class_name",
-      GetUmbrellaClassName(file_->dependency(i)));
+      "$full_reflection_class_name$.Descriptor, ",
+      "full_reflection_class_name",
+      GetReflectionClassName(file_->dependency(i)));
     }
   }
   printer->Print("},\n"
-      "    new pbr::GeneratedCodeInfo(");
+      "    new pbr::GeneratedClrTypeInfo(");
   // Specify all the generated code information, recursively.
   if (file_->enum_type_count() > 0) {
       printer->Print("new[] {");
@@ -206,7 +195,7 @@
       printer->Print("null, ");
   }
   if (file_->message_type_count() > 0) {
-      printer->Print("new pbr::GeneratedCodeInfo[] {\n");
+      printer->Print("new pbr::GeneratedClrTypeInfo[] {\n");
       printer->Indent();
       printer->Indent();
       printer->Indent();
@@ -237,13 +226,13 @@
 // The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
 // context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
 // just controlling the formatting in the generated code.
-void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
+void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
   if (IsMapEntryMessage(descriptor)) {
     printer->Print("null, ");
     return;
   }
   // Generated message type
-  printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), ", "type_name", GetClassName(descriptor));
+  printer->Print("new pbr::GeneratedClrTypeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor));
   
   // Fields
   if (descriptor->field_count() > 0) {
@@ -284,7 +273,7 @@
   // Nested types
   if (descriptor->nested_type_count() > 0) {
       // Need to specify array type explicitly here, as all elements may be null. 
-      printer->Print("new pbr::GeneratedCodeInfo[] { ");
+      printer->Print("new pbr::GeneratedClrTypeInfo[] { ");
       for (int i = 0; i < descriptor->nested_type_count(); i++) {
           WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1);
       }
diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
similarity index 83%
rename from src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
rename to src/google/protobuf/compiler/csharp/csharp_reflection_class.h
index b8bd213..0a5b8ed 100644
--- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
+++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
@@ -28,8 +28,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
-#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
+#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
 
 #include <string>
 
@@ -41,10 +41,10 @@
 namespace compiler {
 namespace csharp {
 
-class UmbrellaClassGenerator : public SourceGeneratorBase {
+class ReflectionClassGenerator : public SourceGeneratorBase {
  public:
-  UmbrellaClassGenerator(const FileDescriptor* file);
-  ~UmbrellaClassGenerator();
+  ReflectionClassGenerator(const FileDescriptor* file);
+  ~ReflectionClassGenerator();
 
   void Generate(io::Printer* printer);
 
@@ -52,14 +52,13 @@
   const FileDescriptor* file_;
 
   std::string namespace_;
-  std::string umbrellaClassname_;
-  std::string umbrellaNamespace_;
+  std::string reflectionClassname_;
 
   void WriteIntroduction(io::Printer* printer);
   void WriteDescriptor(io::Printer* printer);
   void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last);
 
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator);
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator);
 };
 
 }  // namespace csharp
@@ -67,4 +66,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__
+#endif  // GOOGLE_PROTOBUF_COMPILER_CSHARP_REFLECTION_CLASS_H__
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
index 625631d..3a11b75 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/wire_format.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
 
@@ -62,6 +63,7 @@
     "    = pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x);\n");
   printer->Print(variables_,
     "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
index 7fbab68..fc12fae 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
 #include <google/protobuf/compiler/csharp/csharp_message_field.h>
@@ -75,6 +76,7 @@
   printer->Print(
     variables_,
     "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
index 1163ce7..5fe0b20 100644
--- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/wire_format.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
 
@@ -62,6 +63,7 @@
     "    = pb::FieldCodec.For$capitalized_type_name$($tag$);\n");
   printer->Print(variables_,
     "private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
index 44f832b..6a3750e 100644
--- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
 #include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
 
@@ -70,6 +71,7 @@
     variables_,
     ";\n"
     "private $type_name$ $name$_;\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
@@ -165,6 +167,7 @@
         "private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
   GenerateCodecCode(printer);
   printer->Print(";\n");
+  WritePropertyDocComment(printer, descriptor_);
   AddDeprecatedFlag(printer);
   printer->Print(
     variables_,
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 8333684..0d9093c 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -185,6 +185,19 @@
   owner_->error_collector_->AddError(filename, line, column, message);
 }
 
+void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
+    const string& filename,
+    const string& element_name,
+    const Message* descriptor,
+    ErrorLocation location,
+    const string& message) {
+  if (owner_->error_collector_ == NULL) return;
+
+  int line, column;
+  owner_->source_locations_.Find(descriptor, location, &line, &column);
+  owner_->error_collector_->AddWarning(filename, line, column, message);
+}
+
 // ===================================================================
 
 Importer::Importer(SourceTree* source_tree,
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index f010fd0..cc8fcc3 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -121,6 +121,12 @@
                   ErrorLocation location,
                   const string& message);
 
+    virtual void AddWarning(const string& filename,
+                            const string& element_name,
+                            const Message* descriptor,
+                            ErrorLocation location,
+                            const string& message);
+
    private:
     SourceTreeDescriptorDatabase* owner_;
   };
@@ -188,6 +194,9 @@
   virtual void AddError(const string& filename, int line, int column,
                         const string& message) = 0;
 
+  virtual void AddWarning(const string& filename, int line, int column,
+                          const string& message) {}
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
 };
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index 33c9328..be19aa2 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -71,6 +71,7 @@
   ~MockErrorCollector() {}
 
   string text_;
+  string warning_text_;
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const string& filename, int line, int column,
@@ -78,6 +79,12 @@
     strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n",
                                  filename, line, column, message);
   }
+
+  void AddWarning(const string& filename, int line, int column,
+                  const string& message) {
+    strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n",
+                                 filename, line, column, message);
+  }
 };
 
 // -------------------------------------------------------------------
@@ -123,6 +130,7 @@
 
   // Return the collected error text
   string error() const { return error_collector_.text_; }
+  string warning() const { return error_collector_.warning_text_; }
 
   MockErrorCollector error_collector_;
   MockSourceTree source_tree_;
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 8a09f3a..5fc9b00 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -85,17 +85,10 @@
 
 void EnumGenerator::Generate(io::Printer* printer) {
   WriteEnumDocComment(printer, descriptor_);
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
-      "classname", descriptor_->name());
-  } else {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.Internal.EnumLite {\n",
-      "classname", descriptor_->name());
-  }
+  printer->Print(
+    "public enum $classname$\n"
+    "    implements com.google.protobuf.ProtocolMessageEnum {\n",
+    "classname", descriptor_->name());
   printer->Indent();
 
   for (int i = 0; i < canonical_values_.size(); i++) {
@@ -311,7 +304,6 @@
       "}\n"
       "\n");
 
-    // index is only used for reflection; lite implementation does not need it
     printer->Print("private final int index;\n");
   }
 
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index 2c3608c..e3e87c5 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -299,7 +299,7 @@
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
-        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+        "  super.mergeVarintField($number$, rawValue);\n");
     }
     printer->Print(variables_,
       "} else {\n"
@@ -492,7 +492,7 @@
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
-        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+        "  super.mergeVarintField($number$, rawValue);\n");
     }
     printer->Print(variables_,
       "} else {\n"
@@ -596,9 +596,7 @@
 void RepeatedImmutableEnumFieldLiteGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    // TODO(dweis): Switch to IntList?
-    "private com.google.protobuf.Internal.ProtobufList<\n"
-    "    java.lang.Integer> $name$_;\n"
+    "private com.google.protobuf.Internal.IntList $name$_;\n"
     "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
     "    java.lang.Integer, $type$> $name$_converter_ =\n"
     "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
@@ -623,7 +621,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
-    "  return $name$_converter_.convert($name$_.get(index));\n"
+    "  return $name$_converter_.convert($name$_.getInt(index));\n"
     "}\n");
   if (SupportUnknownEnumValue(descriptor_->file())) {
     WriteFieldDocComment(printer, descriptor_);
@@ -635,7 +633,7 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
       "$deprecation$public int get$capitalized_name$Value(int index) {\n"
-      "  return $name$_.get(index);\n"
+      "  return $name$_.getInt(index);\n"
       "}\n");
   }
 
@@ -649,7 +647,7 @@
   printer->Print(variables_,
     "private void ensure$capitalized_name$IsMutable() {\n"
     "  if (!$is_mutable$) {\n"
-    "    $name$_ = newProtobufList($name$_);\n"
+    "    $name$_ = newIntList($name$_);\n"
     "  }\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
@@ -660,7 +658,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  ensure$capitalized_name$IsMutable();\n"
-    "  $name$_.set(index, value.getNumber());\n"
+    "  $name$_.setInt(index, value.getNumber());\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -669,7 +667,7 @@
     "    throw new NullPointerException();\n"
     "  }\n"
     "  ensure$capitalized_name$IsMutable();\n"
-    "  $name$_.add(value.getNumber());\n"
+    "  $name$_.addInt(value.getNumber());\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
@@ -677,13 +675,13 @@
     "    java.lang.Iterable<? extends $type$> values) {\n"
     "  ensure$capitalized_name$IsMutable();\n"
     "  for ($type$ value : values) {\n"
-    "    $name$_.add(value.getNumber());\n"
+    "    $name$_.addInt(value.getNumber());\n"
     "  }\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "private void clear$capitalized_name$() {\n"
-    "  $name$_ = emptyProtobufList();\n"
+    "  $name$_ = emptyIntList();\n"
     "}\n");
 
   if (SupportUnknownEnumValue(descriptor_->file())) {
@@ -692,13 +690,13 @@
       "private void set$capitalized_name$Value(\n"
       "    int index, int value) {\n"
       "  ensure$capitalized_name$IsMutable();\n"
-      "  $name$_.set(index, value);\n"
+      "  $name$_.setInt(index, value);\n"
       "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
       "private void add$capitalized_name$Value(int value) {\n"
       "  ensure$capitalized_name$IsMutable();\n"
-      "  $name$_.add(value);\n"
+      "  $name$_.addInt(value);\n"
       "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -706,7 +704,7 @@
       "    java.lang.Iterable<java.lang.Integer> values) {\n"
       "  ensure$capitalized_name$IsMutable();\n"
       "  for (int value : values) {\n"
-      "    $name$_.add(value);\n"
+      "    $name$_.addInt(value);\n"
       "  }\n"
       "}\n");
   }
@@ -805,7 +803,7 @@
 
 void RepeatedImmutableEnumFieldLiteGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+  printer->Print(variables_, "$name$_ = emptyIntList();\n");
 }
 
 void RepeatedImmutableEnumFieldLiteGenerator::
@@ -840,9 +838,9 @@
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
       "if (!$is_mutable$) {\n"
-      "  $name$_ = newProtobufList();\n"
+      "  $name$_ = newIntList();\n"
       "}\n"
-      "$name$_.add(rawValue);\n");
+      "$name$_.addInt(rawValue);\n");
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
@@ -850,14 +848,14 @@
         "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
-        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+        "  super.mergeVarintField($number$, rawValue);\n");
     }
     printer->Print(variables_,
       "} else {\n"
       "  if (!$is_mutable$) {\n"
-      "    $name$_ = newProtobufList();\n"
+      "    $name$_ = newIntList();\n"
       "  }\n"
-      "  $name$_.add(rawValue);\n"
+      "  $name$_.addInt(rawValue);\n"
       "}\n");
   }
 }
@@ -897,12 +895,12 @@
       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeEnumNoTag($name$_.get(i));\n"
+      "  output.writeEnumNoTag($name$_.getInt(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeEnum($number$, $name$_.get(i));\n"
+      "  output.writeEnum($number$, $name$_.getInt(i));\n"
       "}\n");
   }
 }
@@ -917,7 +915,7 @@
   printer->Print(variables_,
     "for (int i = 0; i < $name$_.size(); i++) {\n"
     "  dataSize += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSizeNoTag($name$_.get(i));\n"
+    "    .computeEnumSizeNoTag($name$_.getInt(i));\n"
     "}\n");
   printer->Print(
     "size += dataSize;\n");
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index 6218638..ed415ee 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -85,34 +85,26 @@
 
 void EnumLiteGenerator::Generate(io::Printer* printer) {
   WriteEnumDocComment(printer, descriptor_);
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
-      "classname", descriptor_->name());
-  } else {
-    printer->Print(
-      "public enum $classname$\n"
-      "    implements com.google.protobuf.Internal.EnumLite {\n",
-      "classname", descriptor_->name());
-  }
+  printer->Print(
+    "public enum $classname$\n"
+    "    implements com.google.protobuf.Internal.EnumLite {\n",
+    "classname", descriptor_->name());
   printer->Indent();
 
   for (int i = 0; i < canonical_values_.size(); i++) {
     map<string, string> vars;
     vars["name"] = canonical_values_[i]->name();
-    vars["index"] = SimpleItoa(canonical_values_[i]->index());
     vars["number"] = SimpleItoa(canonical_values_[i]->number());
     WriteEnumValueDocComment(printer, canonical_values_[i]);
     if (canonical_values_[i]->options().deprecated()) {
       printer->Print("@java.lang.Deprecated\n");
     }
     printer->Print(vars,
-      "$name$($index$, $number$),\n");
+      "$name$($number$),\n");
   }
 
   if (SupportUnknownEnumValue(descriptor_->file())) {
-    printer->Print("UNRECOGNIZED(-1, -1),\n");
+    printer->Print("UNRECOGNIZED(-1),\n");
   }
 
   printer->Print(
@@ -145,15 +137,7 @@
 
   printer->Print(
     "\n"
-    "public final int getNumber() {\n");
-  if (SupportUnknownEnumValue(descriptor_->file())) {
-    printer->Print(
-      "  if (index == -1) {\n"
-      "    throw new java.lang.IllegalArgumentException(\n"
-      "        \"Can't get the number of an unknown enum value.\");\n"
-      "  }\n");
-  }
-  printer->Print(
+    "public final int getNumber() {\n"
     "  return value;\n"
     "}\n"
     "\n"
@@ -193,7 +177,7 @@
 
   printer->Print(
     "private final int value;\n\n"
-    "private $classname$(int index, int value) {\n",
+    "private $classname$(int value) {\n",
     "classname", descriptor_->name());
   printer->Print(
     "  this.value = value;\n"
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_extension_lite.h
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 68b47ee..c817233 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -42,6 +42,7 @@
 
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
 #include <google/protobuf/compiler/java/java_extension.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
@@ -281,8 +282,13 @@
 
   if (!MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
-          .Generate(printer);
+      if (HasDescriptorMethods(file_)) {
+        EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      } else {
+        EnumLiteGenerator(file_->enum_type(i), immutable_api_, context_.get())
+            .Generate(printer);
+      }
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       message_generators_[i]->GenerateInterface(printer);
@@ -543,13 +549,23 @@
                                      vector<string>* file_list) {
   if (MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      EnumGenerator generator(file_->enum_type(i), immutable_api_,
-                              context_.get());
-      GenerateSibling<EnumGenerator>(package_dir, java_package_,
-                                     file_->enum_type(i),
-                                     context, file_list, "",
-                                     &generator,
-                                     &EnumGenerator::Generate);
+      if (HasDescriptorMethods(file_)) {
+        EnumGenerator generator(file_->enum_type(i), immutable_api_,
+                                context_.get());
+        GenerateSibling<EnumGenerator>(package_dir, java_package_,
+                                       file_->enum_type(i),
+                                       context, file_list, "",
+                                       &generator,
+                                       &EnumGenerator::Generate);
+      } else {
+        EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
+                                    context_.get());
+        GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
+                                           file_->enum_type(i),
+                                           context, file_list, "",
+                                           &generator,
+                                           &EnumLiteGenerator::Generate);
+      }
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       if (immutable_api_) {
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index 4fe656d..d203940 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -405,7 +405,7 @@
     printer->Print(
         variables_,
         "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
-        "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
+        "  super.mergeLengthDelimitedField($number$, bytes);\n"
         "} else {\n"
         "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
         "}\n");
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 19ba070..22a70c3 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -664,34 +664,34 @@
     "}\n"
     "public static $classname$ parseFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
     "}\n"
     "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseDelimitedFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);"
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -1217,9 +1217,8 @@
       "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
       "  throw new RuntimeException(e.setUnfinishedMessage(this));\n"
       "} catch (java.io.IOException e) {\n"
-      "  throw new RuntimeException(\n"
-      "      new com.google.protobuf.InvalidProtocolBufferException(\n"
-      "          e.getMessage()).setUnfinishedMessage(this));\n"
+      "  throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n"
+      "      .setUnfinishedMessage(this));\n"
       "} finally {\n");
   printer->Indent();
 
@@ -1356,7 +1355,7 @@
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
     "  if (!is(clazz)) {\n"
     "    throw new com.google.protobuf.InvalidProtocolBufferException(\n"
-    "        \"Type of the Any messsage does not match the given class.\");\n"
+    "        \"Type of the Any message does not match the given class.\");\n"
     "  }\n"
     "  if (cachedUnpackValue != null) {\n"
     "    return (T) cachedUnpackValue;\n"
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index 7269411..5d53503 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -538,7 +538,7 @@
     "    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
     "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
     "    parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
-    "    throw e;\n"
+    "    throw e.unwrapIOException();\n"
     "  } finally {\n"
     "    if (parsedMessage != null) {\n"
     "      mergeFrom(parsedMessage);\n"
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 8b6c75b..94ed2c3 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -1029,12 +1029,6 @@
       "bit_field_name", GetBitFieldName(i));
   }
 
-  if (PreserveUnknownFields(descriptor_)) {
-    printer->Print(
-      "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
-      "    com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
-  }
-
   printer->Print(
       "try {\n");
   printer->Indent();
@@ -1056,13 +1050,10 @@
 
   if (PreserveUnknownFields(descriptor_)) {
     if (descriptor_->extension_range_count() > 0) {
-      // Lite runtime directly invokes parseUnknownField to reduce method
-      // counts.
       printer->Print(
         "default: {\n"
-        "  if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
-        "                         input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
+        "  if (!parseUnknownField(getDefaultInstanceForType(),\n"
+        "                         input, extensionRegistry, tag)) {\n"
         "    done = true;\n"  // it's an endgroup tag
         "  }\n"
         "  break;\n"
@@ -1070,8 +1061,7 @@
     } else {
       printer->Print(
         "default: {\n"
-        "  if (!parseUnknownField(input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
+        "  if (!parseUnknownField(tag, input)) {\n"
         "    done = true;\n"  // it's an endgroup tag
         "  }\n"
         "  break;\n"
@@ -1146,16 +1136,8 @@
     field_generators_.get(field).GenerateParsingDoneCode(printer);
   }
 
-  if (PreserveUnknownFields(descriptor_)) {
-    // Make unknown fields immutable.
-    printer->Print("this.unknownFields = unknownFields.build();\n");
-  }
-
-  if (descriptor_->extension_range_count() > 0) {
-    // Make extensions immutable.
-    printer->Print(
-        "makeExtensionsImmutable(extensions);\n");
-  }
+  printer->Print(
+      "doneParsing();\n");
 
   printer->Outdent();
   printer->Outdent();
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 392333b..5a7bf82 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -87,11 +87,13 @@
       (*variables)["field_list_type"] =
           "com.google.protobuf.Internal." + capitalized_type + "List";
       (*variables)["new_list"] = "new" + capitalized_type + "List";
+      (*variables)["new_list_with_capacity"] =
+          "new" + capitalized_type + "ListWithCapacity";
       (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
       (*variables)["make_name_unmodifiable"] =
           (*variables)["name"] + "_.makeImmutable()";
-      (*variables)["repeated_index_get"] =
-          (*variables)["name"] + "_.get" + capitalized_type + "(index)";
+      (*variables)["repeated_get"] =
+          (*variables)["name"] + "_.get" + capitalized_type;
       (*variables)["repeated_add"] =
           (*variables)["name"] + "_.add" + capitalized_type;
       (*variables)["repeated_set"] =
@@ -102,11 +104,11 @@
           "com.google.protobuf.Internal.ProtobufList<" +
           (*variables)["boxed_type"] + ">";
       (*variables)["new_list"] = "newProtobufList";
+      (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity";
       (*variables)["empty_list"] = "emptyProtobufList()";
       (*variables)["make_name_unmodifiable"] =
           (*variables)["name"] + "_.makeImmutable()";
-      (*variables)["repeated_index_get"] =
-          (*variables)["name"] + "_.get(index)";
+      (*variables)["repeated_get"] = (*variables)["name"] + "_.get";
       (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
       (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
   }
@@ -629,7 +631,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
-    "  return $repeated_index_get$;\n"
+    "  return $repeated_get$(index);\n"
     "}\n");
 
   if (descriptor_->options().packed() &&
@@ -773,6 +775,9 @@
 
 void RepeatedImmutablePrimitiveFieldLiteGenerator::
 GenerateParsingCode(io::Printer* printer) const {
+  // TODO(dweis): Scan the input buffer to count, then initialize
+  // appropriately.
+  // TODO(dweis): Scan the input buffer to count and ensure capacity.
   printer->Print(variables_,
     "if (!$is_mutable$) {\n"
     "  $name$_ = $new_list$();\n"
@@ -785,8 +790,21 @@
   printer->Print(variables_,
     "int length = input.readRawVarint32();\n"
     "int limit = input.pushLimit(length);\n"
-    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
-    "  $name$_ = $new_list$();\n"
+    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n");
+
+  int fixed_size = FixedSize(GetType(descriptor_));
+  if (fixed_size == -1) {
+    // TODO(dweis): Scan the input buffer to count, then initialize
+    // appropriately.
+    printer->Print(variables_,
+      "  $name$_ = $new_list$();\n");
+  } else {
+    printer->Print(variables_,
+      "  $name$_ = $new_list_with_capacity$(length/$fixed_size$);\n");
+  }
+
+  // TODO(dweis): Scan the input buffer to count and ensure capacity.
+  printer->Print(variables_,
     "}\n"
     "while (input.getBytesUntilLimit() > 0) {\n"
     "  $repeated_add$(input.read$capitalized_type$());\n"
@@ -814,12 +832,12 @@
       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.write$capitalized_type$NoTag($name$_.get(i));\n"
+      "  output.write$capitalized_type$NoTag($repeated_get$(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
       "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.write$capitalized_type$($number$, $name$_.get(i));\n"
+      "  output.write$capitalized_type$($number$, $repeated_get$(i));\n"
       "}\n");
   }
 }
@@ -835,7 +853,7 @@
     printer->Print(variables_,
       "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  dataSize += com.google.protobuf.CodedOutputStream\n"
-      "    .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
+      "    .compute$capitalized_type$SizeNoTag($repeated_get$(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 72ebaec..7f757e4 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -405,7 +405,7 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-      "String s = input.readStringRequireUtf8();\n"
+      "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_has_field_bit_message$\n"
       "$name$_ = s;\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
@@ -414,7 +414,7 @@
     // spurious intermediary ByteString allocations, cutting overall allocations
     // in half.
     printer->Print(variables_,
-      "String s = input.readString();\n"
+      "java.lang.String s = input.readString();\n"
       "$set_has_field_bit_message$\n"
       "$name$_ = s;\n");
   } else {
@@ -665,7 +665,7 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-      "String s = input.readStringRequireUtf8();\n"
+      "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_oneof_case_message$;\n"
       "$oneof_name$_ = s;\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
@@ -674,7 +674,7 @@
     // spurious intermediary ByteString allocations, cutting overall allocations
     // in half.
     printer->Print(variables_,
-      "String s = input.readString();\n"
+      "java.lang.String s = input.readString();\n"
       "$set_oneof_case_message$;\n"
       "$oneof_name$_ = s;\n");
   } else {
@@ -773,12 +773,6 @@
     "    get$capitalized_name$Bytes(int index) {\n"
     "  return $name$_.getByteString(index);\n"
     "}\n");
-
-  if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      "private int $name$MemoizedSerializedSize = -1;\n");
-  }
 }
 
 void RepeatedImmutableStringFieldGenerator::
@@ -939,14 +933,14 @@
 GenerateParsingCode(io::Printer* printer) const {
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
-    "String s = input.readStringRequireUtf8();\n");
+    "java.lang.String s = input.readStringRequireUtf8();\n");
   } else if (!HasDescriptorMethods(descriptor_->file())) {
     // Lite runtime should attempt to reduce allocations by attempting to
     // construct the string directly from the input stream buffer. This avoids
     // spurious intermediary ByteString allocations, cutting overall allocations
     // in half.
     printer->Print(variables_,
-    "String s = input.readString();\n");
+    "java.lang.String s = input.readString();\n");
   } else {
     printer->Print(variables_,
     "com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -966,30 +960,6 @@
 }
 
 void RepeatedImmutableStringFieldGenerator::
-GenerateParsingCodeFromPacked(io::Printer* printer) const {
-  printer->Print(variables_,
-    "int length = input.readRawVarint32();\n"
-    "int limit = input.pushLimit(length);\n"
-    "if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n"
-    "  $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
-    "  $set_mutable_bit_parser$;\n"
-    "}\n"
-    "while (input.getBytesUntilLimit() > 0) {\n");
-  if (CheckUtf8(descriptor_)) {
-    printer->Print(variables_,
-      "  String s = input.readStringRequireUtf8();\n");
-  } else {
-    printer->Print(variables_,
-      "  String s = input.readString();\n");
-  }
-  printer->Print(variables_,
-    "  $name$.add(s);\n");
-  printer->Print(variables_,
-    "}\n"
-    "input.popLimit(limit);\n");
-}
-
-void RepeatedImmutableStringFieldGenerator::
 GenerateParsingDoneCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($get_mutable_bit_parser$) {\n"
@@ -999,21 +969,10 @@
 
 void RepeatedImmutableStringFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
-      "}\n"
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  writeStringNoTag(output, $name$_.getRaw(i));\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  $writeString$(output, $number$, $name$_.getRaw(i));\n"
-      "}\n");
-  }
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  $writeString$(output, $number$, $name$_.getRaw(i));\n"
+    "}\n");
 }
 
 void RepeatedImmutableStringFieldGenerator::
@@ -1031,23 +990,8 @@
   printer->Print(
       "size += dataSize;\n");
 
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (!get$capitalized_name$List().isEmpty()) {\n"
-      "  size += $tag_size$;\n"
-      "  size += com.google.protobuf.CodedOutputStream\n"
-      "      .computeInt32SizeNoTag(dataSize);\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "size += $tag_size$ * get$capitalized_name$List().size();\n");
-  }
-
-  // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "$name$MemoizedSerializedSize = dataSize;\n");
-  }
+  printer->Print(variables_,
+    "size += $tag_size$ * get$capitalized_name$List().size();\n");
 
   printer->Outdent();
   printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 1ea44de..a3b5735 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -131,7 +131,6 @@
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateBuildingCode(io::Printer* printer) const;
   void GenerateParsingCode(io::Printer* printer) const;
-  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
   void GenerateParsingDoneCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index 092e3c2..eb5964b 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -647,12 +647,6 @@
     "      $name$_.get(index));\n"
     "}\n");
 
-  if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      "private int $name$MemoizedSerializedSize = -1;\n");
-  }
-
   printer->Print(variables_,
     "private void ensure$capitalized_name$IsMutable() {\n"
     "  if (!$is_mutable$) {\n"
@@ -835,29 +829,6 @@
 }
 
 void RepeatedImmutableStringFieldLiteGenerator::
-GenerateParsingCodeFromPacked(io::Printer* printer) const {
-  printer->Print(variables_,
-    "int length = input.readRawVarint32();\n"
-    "int limit = input.pushLimit(length);\n"
-    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
-    "  $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n"
-    "}\n"
-    "while (input.getBytesUntilLimit() > 0) {\n");
-  if (CheckUtf8(descriptor_)) {
-    printer->Print(variables_,
-      "  String s = input.readStringRequireUtf8();\n");
-  } else {
-    printer->Print(variables_,
-      "  String s = input.readString();\n");
-  }
-  printer->Print(variables_,
-    "  $name$.add(s);\n");
-  printer->Print(variables_,
-    "}\n"
-    "input.popLimit(limit);\n");
-}
-
-void RepeatedImmutableStringFieldLiteGenerator::
 GenerateParsingDoneCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if ($is_mutable$) {\n"
@@ -870,21 +841,10 @@
   // Lite runtime should reduce allocations by serializing the string directly.
   // This avoids spurious intermediary ByteString allocations, cutting overall
   // allocations in half.
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
-      "}\n"
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeStringNoTag($name$_.get(i));\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "for (int i = 0; i < $name$_.size(); i++) {\n"
-      "  output.writeString($number$, $name$_.get(i));\n"
-      "}\n");
-  }
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.writeString($number$, $name$_.get(i));\n"
+    "}\n");
 }
 
 void RepeatedImmutableStringFieldLiteGenerator::
@@ -906,23 +866,9 @@
   printer->Print(
       "size += dataSize;\n");
 
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "if (!get$capitalized_name$List().isEmpty()) {\n"
-      "  size += $tag_size$;\n"
-      "  size += com.google.protobuf.CodedOutputStream\n"
-      "      .computeInt32SizeNoTag(dataSize);\n"
-      "}\n");
-  } else {
-    printer->Print(variables_,
-      "size += $tag_size$ * get$capitalized_name$List().size();\n");
-  }
 
-  // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
-    printer->Print(variables_,
-      "$name$MemoizedSerializedSize = dataSize;\n");
-  }
+  printer->Print(variables_,
+    "size += $tag_size$ * get$capitalized_name$List().size();\n");
 
   printer->Outdent();
   printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
index 9d93b30..4d9b4bd 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -129,7 +129,6 @@
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
   void GenerateParsingCode(io::Printer* printer) const;
-  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
   void GenerateParsingDoneCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
new file mode 100755
index 0000000..351c396
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -0,0 +1,2785 @@
+// 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.
+
+#include <google/protobuf/compiler/js/js_generator.h>
+
+#include <assert.h>
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace js {
+
+// Sorted list of JavaScript keywords. These cannot be used as names. If they
+// appear, we prefix them with "pb_".
+const char* kKeyword[] = {
+  "abstract",
+  "boolean",
+  "break",
+  "byte",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "const",
+  "continue",
+  "debugger",
+  "default",
+  "delete",
+  "do",
+  "double",
+  "else",
+  "enum",
+  "export",
+  "extends",
+  "false",
+  "final",
+  "finally",
+  "float",
+  "for",
+  "function",
+  "goto",
+  "if",
+  "implements",
+  "import",
+  "in",
+  "instanceof",
+  "int",
+  "interface",
+  "long",
+  "native",
+  "new",
+  "null",
+  "package",
+  "private",
+  "protected",
+  "public",
+  "return",
+  "short",
+  "static",
+  "super",
+  "switch",
+  "synchronized",
+  "this",
+  "throw",
+  "throws",
+  "transient",
+  "try",
+  "typeof",
+  "var",
+  "void",
+  "volatile",
+  "while",
+  "with",
+};
+
+static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
+
+namespace {
+
+bool IsReserved(const string& ident) {
+  for (int i = 0; i < kNumKeyword; i++) {
+    if (ident == kKeyword[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
+// suffix stripped.
+// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc.
+string StripProto(const string& filename) {
+  const char* suffix = HasSuffixString(filename, ".protodevel")
+      ? ".protodevel" : ".proto";
+  return StripSuffixString(filename, suffix);
+}
+
+// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
+// file foo/bar/baz.js.
+string GetJSFilename(const string& filename) {
+  const char* suffix = HasSuffixString(filename, ".protodevel")
+      ? ".protodevel" : ".proto";
+  return StripSuffixString(filename, suffix) + "_pb.js";
+}
+
+// Returns the alias we assign to the module of the given .proto filename
+// when importing.
+string ModuleAlias(const string& filename) {
+  // This scheme could technically cause problems if a file includes any 2 of:
+  //   foo/bar_baz.proto
+  //   foo_bar_baz.proto
+  //   foo_bar/baz.proto
+  //
+  // We'll worry about this problem if/when we actually see it.  This name isn't
+  // exposed to users so we can change it later if we need to.
+  string basename = StripProto(filename);
+  StripString(&basename, "-", '$');
+  StripString(&basename, "/", '_');
+  return basename + "_pb";
+}
+
+// Returns the fully normalized JavaScript path for the given
+// file descriptor's package.
+string GetPath(const GeneratorOptions& options,
+               const FileDescriptor* file) {
+  if (!options.namespace_prefix.empty()) {
+    return options.namespace_prefix;
+  } else if (!file->package().empty()) {
+    return "proto." + file->package();
+  } else {
+    return "proto";
+  }
+}
+
+// Forward declare, so that GetPrefix can call this method,
+// which in turn, calls GetPrefix.
+string GetPath(const GeneratorOptions& options,
+               const Descriptor* descriptor);
+
+// Returns the path prefix for a message or enumeration that
+// lives under the given file and containing type.
+string GetPrefix(const GeneratorOptions& options,
+                 const FileDescriptor* file_descriptor,
+                 const Descriptor* containing_type) {
+  string prefix = "";
+
+  if (containing_type == NULL) {
+    prefix = GetPath(options, file_descriptor);
+  } else {
+    prefix = GetPath(options, containing_type);
+  }
+
+  if (!prefix.empty()) {
+    prefix += ".";
+  }
+
+  return prefix;
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// message descriptor.
+string GetPath(const GeneratorOptions& options,
+               const Descriptor* descriptor) {
+  return GetPrefix(
+      options, descriptor->file(),
+      descriptor->containing_type()) + descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// field's containing message descriptor.
+string GetPath(const GeneratorOptions& options,
+               const FieldDescriptor* descriptor) {
+  return GetPath(options, descriptor->containing_type());
+}
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration descriptor.
+string GetPath(const GeneratorOptions& options,
+               const EnumDescriptor* enum_descriptor) {
+  return GetPrefix(
+      options, enum_descriptor->file(),
+      enum_descriptor->containing_type()) + enum_descriptor->name();
+}
+
+
+// Returns the fully normalized JavaScript path for the given
+// enumeration value descriptor.
+string GetPath(const GeneratorOptions& options,
+               const EnumValueDescriptor* value_descriptor) {
+  return GetPath(
+      options,
+      value_descriptor->type()) + "." + value_descriptor->name();
+}
+
+string MaybeCrossFileRef(const GeneratorOptions& options,
+                         const FileDescriptor* from_file,
+                         const Descriptor* to_message) {
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS &&
+      from_file != to_message->file()) {
+    // Cross-file ref in CommonJS needs to use the module alias instead of
+    // the global name.
+    return ModuleAlias(to_message->file()->name()) + "." + to_message->name();
+  } else {
+    // Within a single file we use a full name.
+    return GetPath(options, to_message);
+  }
+}
+
+string SubmessageTypeRef(const GeneratorOptions& options,
+                         const FieldDescriptor* field) {
+  GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+  return MaybeCrossFileRef(options, field->file(), field->message_type());
+}
+
+// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
+// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
+// and with reserved words triggering a "pb_" prefix.
+// - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
+// (use the name directly), then append "List" if appropriate, then append "$"
+// if resulting name is equal to a reserved word.
+// - Enums: just uppercase.
+
+// Locale-independent version of ToLower that deals only with ASCII A-Z.
+char ToLowerASCII(char c) {
+  if (c >= 'A' && c <= 'Z') {
+    return (c - 'A') + 'a';
+  } else {
+    return c;
+  }
+}
+
+vector<string> ParseLowerUnderscore(const string& input) {
+  vector<string> words;
+  string running = "";
+  for (int i = 0; i < input.size(); i++) {
+    if (input[i] == '_') {
+      if (!running.empty()) {
+        words.push_back(running);
+        running.clear();
+      }
+    } else {
+      running += ToLowerASCII(input[i]);
+    }
+  }
+  if (!running.empty()) {
+    words.push_back(running);
+  }
+  return words;
+}
+
+vector<string> ParseUpperCamel(const string& input) {
+  vector<string> words;
+  string running = "";
+  for (int i = 0; i < input.size(); i++) {
+    if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
+      words.push_back(running);
+      running.clear();
+    }
+    running += ToLowerASCII(input[i]);
+  }
+  if (!running.empty()) {
+    words.push_back(running);
+  }
+  return words;
+}
+
+string ToLowerCamel(const vector<string>& words) {
+  string result;
+  for (int i = 0; i < words.size(); i++) {
+    string word = words[i];
+    if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) {
+      word[0] = (word[0] - 'A') + 'a';
+    } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) {
+      word[0] = (word[0] - 'a') + 'A';
+    }
+    result += word;
+  }
+  return result;
+}
+
+string ToUpperCamel(const vector<string>& words) {
+  string result;
+  for (int i = 0; i < words.size(); i++) {
+    string word = words[i];
+    if (word[0] >= 'a' && word[0] <= 'z') {
+      word[0] = (word[0] - 'a') + 'A';
+    }
+    result += word;
+  }
+  return result;
+}
+
+// Based on code from descriptor.cc (Thanks Kenton!)
+// Uppercases the entire string, turning ValueName into
+// VALUENAME.
+string ToEnumCase(const string& input) {
+  string result;
+  result.reserve(input.size());
+
+  for (int i = 0; i < input.size(); i++) {
+    if ('a' <= input[i] && input[i] <= 'z') {
+      result.push_back(input[i] - 'a' + 'A');
+    } else {
+      result.push_back(input[i]);
+    }
+  }
+
+  return result;
+}
+
+string ToFileName(const string& input) {
+  string result;
+  result.reserve(input.size());
+
+  for (int i = 0; i < input.size(); i++) {
+    if ('A' <= input[i] && input[i] <= 'Z') {
+      result.push_back(input[i] - 'A' + 'a');
+    } else {
+      result.push_back(input[i]);
+    }
+  }
+
+  return result;
+}
+
+// Returns the message/response ID, if set.
+string GetMessageId(const Descriptor* desc) {
+  return string();
+}
+
+
+// Used inside Google only -- do not remove.
+bool IsResponse(const Descriptor* desc) { return false; }
+bool IgnoreField(const FieldDescriptor* field) { return false; }
+
+
+// Does JSPB ignore this entire oneof? True only if all fields are ignored.
+bool IgnoreOneof(const OneofDescriptor* oneof) {
+  for (int i = 0; i < oneof->field_count(); i++) {
+    if (!IgnoreField(oneof->field(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+string JSIdent(const FieldDescriptor* field,
+               bool is_upper_camel,
+               bool is_map) {
+  string result;
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    result = is_upper_camel ?
+        ToUpperCamel(ParseUpperCamel(field->message_type()->name())) :
+        ToLowerCamel(ParseUpperCamel(field->message_type()->name()));
+  } else {
+    result = is_upper_camel ?
+        ToUpperCamel(ParseLowerUnderscore(field->name())) :
+        ToLowerCamel(ParseLowerUnderscore(field->name()));
+  }
+  if (is_map) {
+    result += "Map";
+  } else if (field->is_repeated()) {
+    result += "List";
+  }
+  return result;
+}
+
+string JSObjectFieldName(const FieldDescriptor* field) {
+  string name = JSIdent(
+      field,
+      /* is_upper_camel = */ false,
+      /* is_map = */ false);
+  if (IsReserved(name)) {
+    name = "pb_" + name;
+  }
+  return name;
+}
+
+// Returns the field name as a capitalized portion of a getter/setter method
+// name, e.g. MyField for .getMyField().
+string JSGetterName(const FieldDescriptor* field) {
+  string name = JSIdent(field,
+                        /* is_upper_camel = */ true,
+                        /* is_map = */ false);
+  if (name == "Extension" || name == "JsPbMessageId") {
+    // Avoid conflicts with base-class names.
+    name += "$";
+  }
+  return name;
+}
+
+string JSMapGetterName(const FieldDescriptor* field) {
+  return JSIdent(field,
+                 /* is_upper_camel = */ true,
+                 /* is_map = */ true);
+}
+
+
+
+string JSOneofName(const OneofDescriptor* oneof) {
+  return ToUpperCamel(ParseLowerUnderscore(oneof->name()));
+}
+
+// Returns the index corresponding to this field in the JSPB array (underlying
+// data storage array).
+string JSFieldIndex(const FieldDescriptor* field) {
+  // Determine whether this field is a member of a group. Group fields are a bit
+  // wonky: their "containing type" is a message type created just for the
+  // group, and that type's parent type has a field with the group-message type
+  // as its message type and TYPE_GROUP as its field type. For such fields, the
+  // index we use is relative to the field number of the group submessage field.
+  // For all other fields, we just use the field number.
+  const Descriptor* containing_type = field->containing_type();
+  const Descriptor* parent_type = containing_type->containing_type();
+  if (parent_type != NULL) {
+    for (int i = 0; i < parent_type->field_count(); i++) {
+      if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP &&
+          parent_type->field(i)->message_type() == containing_type) {
+        return SimpleItoa(field->number() - parent_type->field(i)->number());
+      }
+    }
+  }
+  return SimpleItoa(field->number());
+}
+
+string JSOneofIndex(const OneofDescriptor* oneof) {
+  int index = -1;
+  for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) {
+    const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i);
+    // If at least one field in this oneof is not JSPB-ignored, count the oneof.
+    for (int j = 0; j < o->field_count(); j++) {
+      const FieldDescriptor* f = o->field(j);
+      if (!IgnoreField(f)) {
+        index++;
+        break;  // inner loop
+      }
+    }
+    if (o == oneof) {
+      break;
+    }
+  }
+  return SimpleItoa(index);
+}
+
+// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only
+// need to handle the BMP (16-bit range) here.
+uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
+  if (*length == 0) {
+    return 0;
+  }
+  size_t expected = 0;
+  if ((*bytes & 0x80) == 0) {
+    expected = 1;
+  } else if ((*bytes & 0xe0) == 0xc0) {
+    expected = 2;
+  } else if ((*bytes & 0xf0) == 0xe0) {
+    expected = 3;
+  } else {
+    // Too long -- don't accept.
+    *length = 0;
+    return 0;
+  }
+
+  if (*length < expected) {
+    // Not enough bytes -- don't accept.
+    *length = 0;
+    return 0;
+  }
+
+  *length = expected;
+  switch (expected) {
+    case 1: return bytes[0];
+    case 2: return ((bytes[0] & 0x1F) << 6)  |
+                   ((bytes[1] & 0x3F) << 0);
+    case 3: return ((bytes[0] & 0x0F) << 12) |
+                   ((bytes[1] & 0x3F) << 6)  |
+                   ((bytes[2] & 0x3F) << 0);
+    default: return 0;
+  }
+}
+
+// Escapes the contents of a string to be included within double-quotes ("") in
+// JavaScript. |is_utf8| determines whether the input data (in a C++ string of
+// chars) is UTF-8 encoded (in which case codepoints become JavaScript string
+// characters, escaped with 16-bit hex escapes where necessary) or raw binary
+// (in which case bytes become JavaScript string characters 0 -- 255).
+string EscapeJSString(const string& in, bool is_utf8) {
+  string result;
+  size_t decoded = 0;
+  for (size_t i = 0; i < in.size(); i += decoded) {
+    uint16 codepoint = 0;
+    if (is_utf8) {
+      // Decode the next UTF-8 codepoint.
+      size_t have_bytes = in.size() - i;
+      uint8 bytes[3] = {
+        static_cast<uint8>(in[i]),
+        static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
+        static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
+      };
+      codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
+      if (have_bytes == 0) {
+        break;
+      }
+      decoded = have_bytes;
+    } else {
+      codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
+      decoded = 1;
+    }
+
+    // Next byte -- used for minimal octal escapes below.
+    char next_byte = (i + decoded) < in.size() ?
+        in[i + decoded] : 0;
+    bool pad_octal = (next_byte >= '0' && next_byte <= '7');
+
+    switch (codepoint) {
+      case '\0': result += pad_octal ? "\\000" : "\\0";   break;
+      case '\b': result += "\\\b";  break;
+      case '\t': result += "\\\t";  break;
+      case '\n': result += "\\\n";  break;
+      case '\r': result += "\\\r";  break;
+      case '\f': result += "\\\f";  break;
+      case '\\': result += "\\\\";  break;
+      case '"':  result += pad_octal ? "\\042" : "\\42"; break;
+      case '&':  result += pad_octal ? "\\046" : "\\46"; break;
+      case '\'': result += pad_octal ? "\\047" : "\\47"; break;
+      case '<':  result += pad_octal ? "\\074" : "\\74"; break;
+      case '=':  result += pad_octal ? "\\075" : "\\75"; break;
+      case '>':  result += pad_octal ? "\\076" : "\\76"; break;
+      default:
+        // All other non-ASCII codepoints are escaped.
+        // Original codegen uses hex for >= 0x100 and octal for others.
+        if (codepoint >= 0x20 && codepoint <= 0x7e) {
+          result += static_cast<char>(codepoint);
+        } else {
+          if (codepoint >= 0x100) {
+            result += StringPrintf("\\u%04x", codepoint);
+          } else {
+            if (pad_octal || codepoint >= 0100) {
+              result += "\\";
+              result += ('0' + ((codepoint >> 6) & 07));
+              result += ('0' + ((codepoint >> 3) & 07));
+              result += ('0' + ((codepoint >> 0) & 07));
+            } else if (codepoint >= 010) {
+              result += "\\";
+              result += ('0' + ((codepoint >> 3) & 07));
+              result += ('0' + ((codepoint >> 0) & 07));
+            } else {
+              result += "\\";
+              result += ('0' + ((codepoint >> 0) & 07));
+            }
+          }
+        }
+        break;
+    }
+  }
+  return result;
+}
+
+string EscapeBase64(const string& in) {
+  static const char* kAlphabet =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  string result;
+
+  for (size_t i = 0; i < in.size(); i += 3) {
+    int value = (in[i] << 16) |
+        (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
+        (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0);
+    result += kAlphabet[(value >> 18) & 0x3f];
+    result += kAlphabet[(value >> 12) & 0x3f];
+    if ((i + 1) < in.size()) {
+      result += kAlphabet[(value >>  6) & 0x3f];
+    } else {
+      result += '=';
+    }
+    if ((i + 2) < in.size()) {
+      result += kAlphabet[(value >>  0) & 0x3f];
+    } else {
+      result += '=';
+    }
+  }
+
+  return result;
+}
+
+// Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the
+// original codegen's formatting (which is just .toString() on java.lang.Double
+// or java.lang.Float).
+string PostProcessFloat(string result) {
+  // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN.
+  if (result == "inf") {
+    return "Infinity";
+  } else if (result == "-inf") {
+    return "-Infinity";
+  } else if (result == "nan") {
+    return "NaN";
+  }
+
+  // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii)
+  // ensure that the mantissa (portion prior to the "e") has at least one
+  // fractional digit (after the decimal point), and (iii) strip any unnecessary
+  // leading zeroes and/or '+' signs from the exponent.
+  string::size_type exp_pos = result.find('e');
+  if (exp_pos != string::npos) {
+    string mantissa = result.substr(0, exp_pos);
+    string exponent = result.substr(exp_pos + 1);
+
+    // Add ".0" to mantissa if no fractional part exists.
+    if (mantissa.find('.') == string::npos) {
+      mantissa += ".0";
+    }
+
+    // Strip the sign off the exponent and store as |exp_neg|.
+    bool exp_neg = false;
+    if (!exponent.empty() && exponent[0] == '+') {
+      exponent = exponent.substr(1);
+    } else if (!exponent.empty() && exponent[0] == '-') {
+      exp_neg = true;
+      exponent = exponent.substr(1);
+    }
+
+    // Strip any leading zeroes off the exponent.
+    while (exponent.size() > 1 && exponent[0] == '0') {
+      exponent = exponent.substr(1);
+    }
+
+    return mantissa + "E" + string(exp_neg ? "-" : "") + exponent;
+  }
+
+  // Otherwise, this is an ordinary decimal number. Append ".0" if result has no
+  // decimal/fractional part in order to match output of original codegen.
+  if (result.find('.') == string::npos) {
+    result += ".0";
+  }
+
+  return result;
+}
+
+string FloatToString(float value) {
+  string result = SimpleFtoa(value);
+  return PostProcessFloat(result);
+}
+
+string DoubleToString(double value) {
+  string result = SimpleDtoa(value);
+  return PostProcessFloat(result);
+}
+
+string MaybeNumberString(const FieldDescriptor* field, const string& orig) {
+  return orig;
+}
+
+string JSFieldDefault(const FieldDescriptor* field) {
+  assert(field->has_default_value());
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return MaybeNumberString(
+          field, SimpleItoa(field->default_value_int32()));
+    case FieldDescriptor::CPPTYPE_UINT32:
+      // The original codegen is in Java, and Java protobufs store unsigned
+      // integer values as signed integer values. In order to exactly match the
+      // output, we need to reinterpret as base-2 signed. Ugh.
+      return MaybeNumberString(
+          field, SimpleItoa(static_cast<int32>(field->default_value_uint32())));
+    case FieldDescriptor::CPPTYPE_INT64:
+      return MaybeNumberString(
+          field, SimpleItoa(field->default_value_int64()));
+    case FieldDescriptor::CPPTYPE_UINT64:
+      // See above note for uint32 -- reinterpreting as signed.
+      return MaybeNumberString(
+          field, SimpleItoa(static_cast<int64>(field->default_value_uint64())));
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return SimpleItoa(field->default_value_enum()->number());
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return FloatToString(field->default_value_float());
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return DoubleToString(field->default_value_double());
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->type() == FieldDescriptor::TYPE_STRING) {
+        return "\"" + EscapeJSString(field->default_value_string(), true) +
+               "\"";
+      } else {
+        return "\"" + EscapeBase64(field->default_value_string()) +
+               "\"";
+      }
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return "null";
+  }
+  GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
+  return "";
+}
+
+string ProtoTypeName(const GeneratorOptions& options,
+                     const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::TYPE_INT32:
+      return "int32";
+    case FieldDescriptor::TYPE_UINT32:
+      return "uint32";
+    case FieldDescriptor::TYPE_SINT32:
+      return "sint32";
+    case FieldDescriptor::TYPE_FIXED32:
+      return "fixed32";
+    case FieldDescriptor::TYPE_SFIXED32:
+      return "sfixed32";
+    case FieldDescriptor::TYPE_INT64:
+      return "int64";
+    case FieldDescriptor::TYPE_UINT64:
+      return "uint64";
+    case FieldDescriptor::TYPE_SINT64:
+      return "sint64";
+    case FieldDescriptor::TYPE_FIXED64:
+      return "fixed64";
+    case FieldDescriptor::TYPE_SFIXED64:
+      return "sfixed64";
+    case FieldDescriptor::TYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::TYPE_DOUBLE:
+      return "double";
+    case FieldDescriptor::TYPE_STRING:
+      return "string";
+    case FieldDescriptor::TYPE_BYTES:
+      return "bytes";
+    case FieldDescriptor::TYPE_GROUP:
+      return GetPath(options, field->message_type());
+    case FieldDescriptor::TYPE_ENUM:
+      return GetPath(options, field->enum_type());
+    case FieldDescriptor::TYPE_MESSAGE:
+      return GetPath(options, field->message_type());
+    default:
+      return "";
+  }
+}
+
+string JSIntegerTypeName(const FieldDescriptor* field) {
+  return "number";
+}
+
+string JSTypeName(const GeneratorOptions& options,
+                  const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "boolean";
+    case FieldDescriptor::CPPTYPE_INT32:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_INT64:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return JSIntegerTypeName(field);
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "number";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "number";
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "string";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return GetPath(options, field->enum_type());
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return GetPath(options, field->message_type());
+    default:
+      return "";
+  }
+}
+
+bool HasFieldPresence(const FieldDescriptor* field);
+
+string JSFieldTypeAnnotation(const GeneratorOptions& options,
+                             const FieldDescriptor* field,
+                             bool force_optional,
+                             bool force_present,
+                             bool singular_if_not_packed,
+                             bool always_singular) {
+  bool is_primitive =
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
+       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE);
+
+  string jstype = JSTypeName(options, field);
+
+  if (field->is_repeated() &&
+      !always_singular &&
+      (field->is_packed() || !singular_if_not_packed)) {
+    if (!is_primitive) {
+      jstype = "!" + jstype;
+    }
+    jstype = "Array.<" + jstype + ">";
+    if (!force_optional) {
+      jstype = "!" + jstype;
+    }
+  }
+
+  if (field->is_optional() && is_primitive &&
+      (!field->has_default_value() || force_optional) && !force_present) {
+    jstype += "?";
+  } else if (field->is_required() && !is_primitive && !force_optional) {
+    jstype = "!" + jstype;
+  }
+
+  if (force_optional && HasFieldPresence(field)) {
+    jstype += "|undefined";
+  }
+  if (force_present && jstype[0] != '!' && !is_primitive) {
+    jstype = "!" + jstype;
+  }
+
+  return jstype;
+}
+
+string JSBinaryReaderMethodType(const FieldDescriptor* field) {
+  string name = field->type_name();
+  if (name[0] >= 'a' && name[0] <= 'z') {
+    name[0] = (name[0] - 'a') + 'A';
+  }
+
+  return name;
+}
+
+string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
+                                   bool is_writer) {
+  string name = JSBinaryReaderMethodType(field);
+  if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
+    // Override for `bytes` fields: treat string as raw bytes, not base64.
+    name = "BytesRawString";
+  }
+  if (field->is_packed()) {
+    name = "Packed" + name;
+  } else if (is_writer && field->is_repeated()) {
+    name = "Repeated" + name;
+  }
+  return name;
+}
+
+string JSBinaryReaderMethodName(const FieldDescriptor* field) {
+  return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+}
+
+string JSBinaryWriterMethodName(const FieldDescriptor* field) {
+  return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+}
+
+string JSReturnClause(const FieldDescriptor* desc) {
+  return "";
+}
+
+string JSReturnDoc(const GeneratorOptions& options,
+                   const FieldDescriptor* desc) {
+  return "";
+}
+
+bool HasRepeatedFields(const Descriptor* desc) {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->is_repeated()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static const char* kRepeatedFieldArrayName = ".repeatedFields_";
+
+string RepeatedFieldsArrayName(const GeneratorOptions& options,
+                               const Descriptor* desc) {
+  return HasRepeatedFields(desc) ?
+      (GetPath(options, desc) + kRepeatedFieldArrayName) : "null";
+}
+
+bool HasOneofFields(const Descriptor* desc) {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->containing_oneof()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static const char* kOneofGroupArrayName = ".oneofGroups_";
+
+string OneofFieldsArrayName(const GeneratorOptions& options,
+                            const Descriptor* desc) {
+  return HasOneofFields(desc) ?
+      (GetPath(options, desc) + kOneofGroupArrayName) : "null";
+}
+
+string RepeatedFieldNumberList(const Descriptor* desc) {
+  std::vector<string> numbers;
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (desc->field(i)->is_repeated()) {
+      numbers.push_back(JSFieldIndex(desc->field(i)));
+    }
+  }
+  return "[" + Join(numbers, ",") + "]";
+}
+
+string OneofGroupList(const Descriptor* desc) {
+  // List of arrays (one per oneof), each of which is a list of field indices
+  std::vector<string> oneof_entries;
+  for (int i = 0; i < desc->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = desc->oneof_decl(i);
+    if (IgnoreOneof(oneof)) {
+      continue;
+    }
+
+    std::vector<string> oneof_fields;
+    for (int j = 0; j < oneof->field_count(); j++) {
+      if (IgnoreField(oneof->field(j))) {
+        continue;
+      }
+      oneof_fields.push_back(JSFieldIndex(oneof->field(j)));
+    }
+    oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]");
+  }
+  return "[" + Join(oneof_entries, ",") + "]";
+}
+
+string JSOneofArray(const GeneratorOptions& options,
+                    const FieldDescriptor* field) {
+  return OneofFieldsArrayName(options, field->containing_type()) + "[" +
+      JSOneofIndex(field->containing_oneof()) + "]";
+}
+
+string RelativeTypeName(const FieldDescriptor* field) {
+  assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
+         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
+  // For a field with an enum or message type, compute a name relative to the
+  // path name of the message type containing this field.
+  string package = field->file()->package();
+  string containing_type = field->containing_type()->full_name() + ".";
+  string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) ?
+      field->enum_type()->full_name() : field->message_type()->full_name();
+
+  // |prefix| is advanced as we find separators '.' past the common package
+  // prefix that yield common prefixes in the containing type's name and this
+  // type's name.
+  int prefix = 0;
+  for (int i = 0; i < type.size() && i < containing_type.size(); i++) {
+    if (type[i] != containing_type[i]) {
+      break;
+    }
+    if (type[i] == '.' && i >= package.size()) {
+      prefix = i + 1;
+    }
+  }
+
+  return type.substr(prefix);
+}
+
+string JSExtensionsObjectName(const GeneratorOptions& options,
+                              const FileDescriptor* from_file,
+                              const Descriptor* desc) {
+  if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
+    // TODO(haberman): fix this for the IMPORT_COMMONJS case.
+    return "jspb.Message.messageSetExtensions";
+  } else {
+    return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
+  }
+}
+
+string FieldDefinition(const GeneratorOptions& options,
+                       const FieldDescriptor* field) {
+  string qualifier = field->is_repeated() ? "repeated" :
+      (field->is_optional() ? "optional" : "required");
+  string type, name;
+  if (field->type() == FieldDescriptor::TYPE_ENUM ||
+      field->type() == FieldDescriptor::TYPE_MESSAGE) {
+    type = RelativeTypeName(field);
+    name = field->name();
+  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    type = "group";
+    name = field->message_type()->name();
+  } else {
+    type = ProtoTypeName(options, field);
+    name = field->name();
+  }
+  return StringPrintf("%s %s %s = %d;",
+                      qualifier.c_str(),
+                      type.c_str(),
+                      name.c_str(),
+                      field->number());
+}
+
+string FieldComments(const FieldDescriptor* field) {
+  string comments;
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
+    comments +=
+        " * Note that Boolean fields may be set to 0/1 when serialized from "
+        "a Java server.\n"
+        " * You should avoid comparisons like {@code val === true/false} in "
+        "those cases.\n";
+  }
+  if (field->is_repeated()) {
+    comments +=
+        " * If you change this array by adding, removing or replacing "
+        "elements, or if you\n"
+        " * replace the array itself, then you must call the setter to "
+        "update it.\n";
+  }
+  return comments;
+}
+
+bool ShouldGenerateExtension(const FieldDescriptor* field) {
+  return
+      field->is_extension() &&
+      !IgnoreField(field);
+}
+
+bool HasExtensions(const Descriptor* desc) {
+  if (desc->extension_count() > 0) {
+    return true;
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    if (HasExtensions(desc->nested_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool HasExtensions(const FileDescriptor* file) {
+  for (int i = 0; i < file->extension_count(); i++) {
+    if (ShouldGenerateExtension(file->extension(i))) {
+      return true;
+    }
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
+    if (HasExtensions(file->message_type(i))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsExtendable(const Descriptor* desc) {
+  return desc->extension_range_count() > 0;
+}
+
+// Returns the max index in the underlying data storage array beyond which the
+// extension object is used.
+string GetPivot(const Descriptor* desc) {
+  static const int kDefaultPivot = (1 << 29);  // max field number (29 bits)
+
+  // Find the max field number
+  int max_field_number = 0;
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (!IgnoreField(desc->field(i)) &&
+        desc->field(i)->number() > max_field_number) {
+      max_field_number = desc->field(i)->number();
+    }
+  }
+
+  int pivot = -1;
+  if (IsExtendable(desc)) {
+    pivot = ((max_field_number + 1) < kDefaultPivot) ?
+        (max_field_number + 1) : kDefaultPivot;
+  }
+
+  return SimpleItoa(pivot);
+}
+
+// Returns true for fields that represent "null" as distinct from the default
+// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information.
+bool HasFieldPresence(const FieldDescriptor* field) {
+  return
+      (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
+      (field->containing_oneof() != NULL) ||
+      (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3);
+}
+
+// For proto3 fields without presence, returns a string representing the default
+// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more
+// information.
+string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_UINT64: {
+      return "0";
+    }
+
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return "0";
+
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "false";
+
+    case FieldDescriptor::CPPTYPE_STRING:
+      return "\"\"";
+
+    default:
+      // BYTES and MESSAGE are handled separately.
+      assert(false);
+      return "";
+  }
+}
+
+}  // anonymous namespace
+
+void Generator::GenerateHeader(const GeneratorOptions& options,
+                               io::Printer* printer) const {
+  printer->Print("/**\n"
+                 " * @fileoverview\n"
+                 " * @enhanceable\n"
+                 " * @public\n"
+                 " */\n"
+                 "// GENERATED CODE -- DO NOT EDIT!\n"
+                 "\n");
+}
+
+void Generator::FindProvidesForFile(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const FileDescriptor* file,
+                                    std::set<string>* provided) const {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    FindProvidesForMessage(options, printer, file->message_type(i), provided);
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    FindProvidesForEnum(options, printer, file->enum_type(i), provided);
+  }
+}
+
+void Generator::FindProvides(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const vector<const FileDescriptor*>& files,
+                             std::set<string>* provided) const {
+  for (int i = 0; i < files.size(); i++) {
+    FindProvidesForFile(options, printer, files[i], provided);
+  }
+
+  printer->Print("\n");
+}
+
+void Generator::FindProvidesForMessage(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const Descriptor* desc,
+    std::set<string>* provided) const {
+  string name = GetPath(options, desc);
+  provided->insert(name);
+
+  for (int i = 0; i < desc->enum_type_count(); i++) {
+    FindProvidesForEnum(options, printer, desc->enum_type(i),
+                        provided);
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    FindProvidesForMessage(options, printer, desc->nested_type(i),
+                           provided);
+  }
+}
+
+void Generator::FindProvidesForEnum(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const EnumDescriptor* enumdesc,
+                                    std::set<string>* provided) const {
+  string name = GetPath(options, enumdesc);
+  provided->insert(name);
+}
+
+void Generator::FindProvidesForFields(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const vector<const FieldDescriptor*>& fields,
+    std::set<string>* provided) const {
+  for (int i = 0; i < fields.size(); i++) {
+    const FieldDescriptor* field = fields[i];
+
+    if (IgnoreField(field)) {
+      continue;
+    }
+
+    string name =
+        GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+    provided->insert(name);
+  }
+}
+
+void Generator::GenerateProvides(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 std::set<string>* provided) const {
+  for (std::set<string>::iterator it = provided->begin();
+       it != provided->end(); ++it) {
+    printer->Print("goog.provide('$name$');\n",
+                   "name", *it);
+  }
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const Descriptor* desc,
+                                 std::set<string>* provided) const {
+  std::set<string> required;
+  std::set<string> forwards;
+  bool have_message = false;
+  FindRequiresForMessage(options, desc,
+                         &required, &forwards, &have_message);
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ have_message,
+                       /* require_extension = */ HasExtensions(desc));
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const vector<const FileDescriptor*>& files,
+                                 std::set<string>* provided) const {
+  if (options.import_style == GeneratorOptions::IMPORT_BROWSER) {
+    return;
+  } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
+    // For Closure imports we need to import every message type individually.
+    std::set<string> required;
+    std::set<string> forwards;
+    bool have_extensions = false;
+    bool have_message = false;
+
+    for (int i = 0; i < files.size(); i++) {
+      for (int j = 0; j < files[i]->message_type_count(); j++) {
+        FindRequiresForMessage(options,
+                               files[i]->message_type(j),
+                               &required, &forwards, &have_message);
+      }
+      if (!have_extensions && HasExtensions(files[i])) {
+        have_extensions = true;
+      }
+
+      for (int j = 0; j < files[i]->extension_count(); j++) {
+        const FieldDescriptor* extension = files[i]->extension(j);
+        if (IgnoreField(extension)) {
+          continue;
+        }
+        if (extension->containing_type()->full_name() !=
+            "google.protobuf.bridge.MessageSet") {
+          required.insert(GetPath(options, extension->containing_type()));
+        }
+        FindRequiresForField(options, extension, &required, &forwards);
+        have_extensions = true;
+      }
+    }
+
+    GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                         /* require_jspb = */ have_message,
+                         /* require_extension = */ have_extensions);
+  } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
+    // CommonJS imports are based on files
+  }
+}
+
+void Generator::GenerateRequires(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const vector<const FieldDescriptor*>& fields,
+                                 std::set<string>* provided) const {
+  std::set<string> required;
+  std::set<string> forwards;
+  for (int i = 0; i < fields.size(); i++) {
+    const FieldDescriptor* field = fields[i];
+    if (IgnoreField(field)) {
+      continue;
+    }
+    FindRequiresForExtension(options, field, &required, &forwards);
+  }
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ false,
+                       /* require_extension = */ fields.size() > 0);
+}
+
+void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
+                                     io::Printer* printer,
+                                     std::set<string>* required,
+                                     std::set<string>* forwards,
+                                     std::set<string>* provided,
+                                     bool require_jspb,
+                                     bool require_extension) const {
+  if (require_jspb) {
+    printer->Print(
+        "goog.require('jspb.Message');\n");
+    if (options.binary) {
+      printer->Print(
+          "goog.require('jspb.BinaryReader');\n"
+          "goog.require('jspb.BinaryWriter');\n");
+    }
+  }
+  if (require_extension) {
+    printer->Print(
+        "goog.require('jspb.ExtensionFieldInfo');\n");
+  }
+
+  std::set<string>::iterator it;
+  for (it = required->begin(); it != required->end(); ++it) {
+    if (provided->find(*it) != provided->end()) {
+      continue;
+    }
+    printer->Print("goog.require('$name$');\n",
+                   "name", *it);
+  }
+
+  printer->Print("\n");
+
+  for (it = forwards->begin(); it != forwards->end(); ++it) {
+    if (provided->find(*it) != provided->end()) {
+      continue;
+    }
+    printer->Print("goog.forwardDeclare('$name$');\n",
+                   "name", *it);
+  }
+}
+
+bool NamespaceOnly(const Descriptor* desc) {
+  return false;
+}
+
+void Generator::FindRequiresForMessage(
+    const GeneratorOptions& options,
+    const Descriptor* desc,
+    std::set<string>* required,
+    std::set<string>* forwards,
+    bool* have_message) const {
+
+
+  if (!NamespaceOnly(desc)) {
+    *have_message = true;
+    for (int i = 0; i < desc->field_count(); i++) {
+      const FieldDescriptor* field = desc->field(i);
+      if (IgnoreField(field)) {
+        continue;
+      }
+      FindRequiresForField(options, field, required, forwards);
+    }
+  }
+
+  for (int i = 0; i < desc->extension_count(); i++) {
+    const FieldDescriptor* field = desc->extension(i);
+    if (IgnoreField(field)) {
+      continue;
+    }
+    FindRequiresForExtension(options, field, required, forwards);
+  }
+
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    FindRequiresForMessage(options, desc->nested_type(i), required, forwards,
+                           have_message);
+  }
+}
+
+void Generator::FindRequiresForField(const GeneratorOptions& options,
+                                     const FieldDescriptor* field,
+                                     std::set<string>* required,
+                                     std::set<string>* forwards) const {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+        // N.B.: file-level extensions with enum type do *not* create
+        // dependencies, as per original codegen.
+        !(field->is_extension() && field->extension_scope() == NULL)) {
+      if (options.add_require_for_enums) {
+        required->insert(GetPath(options, field->enum_type()));
+      } else {
+        forwards->insert(GetPath(options, field->enum_type()));
+      }
+    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      required->insert(GetPath(options, field->message_type()));
+    }
+}
+
+void Generator::FindRequiresForExtension(const GeneratorOptions& options,
+                                         const FieldDescriptor* field,
+                                         std::set<string>* required,
+                                         std::set<string>* forwards) const {
+    if (field->containing_type()->full_name() != "google.protobuf.bridge.MessageSet") {
+      required->insert(GetPath(options, field->containing_type()));
+    }
+    FindRequiresForField(options, field, required, forwards);
+}
+
+void Generator::GenerateTestOnly(const GeneratorOptions& options,
+                                 io::Printer* printer) const {
+  if (options.testonly) {
+    printer->Print("goog.setTestOnly();\n\n");
+  }
+  printer->Print("\n");
+}
+
+void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
+                                        io::Printer* printer,
+                                        const FileDescriptor* file) const {
+  for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateClass(options, printer, file->message_type(i));
+  }
+  for (int i = 0; i < file->enum_type_count(); i++) {
+    GenerateEnum(options, printer, file->enum_type(i));
+  }
+}
+
+void Generator::GenerateClass(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc) const {
+  if (!NamespaceOnly(desc)) {
+    printer->Print("\n");
+    GenerateClassConstructor(options, printer, desc);
+    GenerateClassFieldInfo(options, printer, desc);
+
+
+    GenerateClassToObject(options, printer, desc);
+    if (options.binary) {
+      // These must come *before* the extension-field info generation in
+      // GenerateClassRegistration so that references to the binary
+      // serialization/deserialization functions may be placed in the extension
+      // objects.
+      GenerateClassDeserializeBinary(options, printer, desc);
+      GenerateClassSerializeBinary(options, printer, desc);
+    }
+    GenerateClassClone(options, printer, desc);
+    GenerateClassRegistration(options, printer, desc);
+    GenerateClassFields(options, printer, desc);
+    if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
+      GenerateClassExtensionFieldInfo(options, printer, desc);
+    }
+
+    if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) {
+      for (int i = 0; i < desc->extension_count(); i++) {
+        GenerateExtension(options, printer, desc->extension(i));
+      }
+    }
+  }
+
+  // Recurse on nested types.
+  for (int i = 0; i < desc->enum_type_count(); i++) {
+    GenerateEnum(options, printer, desc->enum_type(i));
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    GenerateClass(options, printer, desc->nested_type(i));
+  }
+}
+
+void Generator::GenerateClassConstructor(const GeneratorOptions& options,
+                                         io::Printer* printer,
+                                         const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Generated by JsPbCodeGenerator.\n"
+      " * @param {Array=} opt_data Optional initial data array, typically "
+      "from a\n"
+      " * server response, or constructed directly in Javascript. The array "
+      "is used\n"
+      " * in place and becomes part of the constructed object. It is not "
+      "cloned.\n"
+      " * If no data is provided, the constructed object will be empty, but "
+      "still\n"
+      " * valid.\n"
+      " * @extends {jspb.Message}\n"
+      " * @constructor\n"
+      " */\n"
+      "$classname$ = function(opt_data) {\n",
+      "classname", GetPath(options, desc));
+  string message_id = GetMessageId(desc);
+  printer->Print(
+      "  jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, "
+      "$rptfields$, $oneoffields$);\n",
+      "messageId", !message_id.empty() ?
+                   ("'" + message_id + "'") :
+                   (IsResponse(desc) ? "''" : "0"),
+      "pivot", GetPivot(desc),
+      "rptfields", RepeatedFieldsArrayName(options, desc),
+      "oneoffields", OneofFieldsArrayName(options, desc));
+  printer->Print(
+      "};\n"
+      "goog.inherits($classname$, jspb.Message);\n"
+      "if (goog.DEBUG && !COMPILED) {\n"
+      "  $classname$.displayName = '$classname$';\n"
+      "}\n",
+      "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
+                                       io::Printer* printer,
+                                       const Descriptor* desc) const {
+  if (HasRepeatedFields(desc)) {
+    printer->Print(
+        "/**\n"
+        " * List of repeated fields within this message type.\n"
+        " * @private {!Array<number>}\n"
+        " * @const\n"
+        " */\n"
+        "$classname$$rptfieldarray$ = $rptfields$;\n"
+        "\n",
+        "classname", GetPath(options, desc),
+        "rptfieldarray", kRepeatedFieldArrayName,
+        "rptfields", RepeatedFieldNumberList(desc));
+  }
+
+  if (HasOneofFields(desc)) {
+    printer->Print(
+        "/**\n"
+        " * Oneof group definitions for this message. Each group defines the "
+        "field\n"
+        " * numbers belonging to that group. When of these fields' value is "
+        "set, all\n"
+        " * other fields in the group are cleared. During deserialization, if "
+        "multiple\n"
+        " * fields are encountered for a group, only the last value seen will "
+        "be kept.\n"
+        " * @private {!Array<!Array<number>>}\n"
+        " * @const\n"
+        " */\n"
+        "$classname$$oneofgrouparray$ = $oneofgroups$;\n"
+        "\n",
+        "classname", GetPath(options, desc),
+        "oneofgrouparray", kOneofGroupArrayName,
+        "oneofgroups", OneofGroupList(desc));
+
+    for (int i = 0; i < desc->oneof_decl_count(); i++) {
+      if (IgnoreOneof(desc->oneof_decl(i))) {
+        continue;
+      }
+      GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i));
+    }
+  }
+}
+
+void Generator::GenerateClassXid(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const Descriptor* desc) const {
+  printer->Print(
+      "\n"
+      "\n"
+      "$class$.prototype.messageXid = xid('$class$');\n",
+      "class", GetPath(options, desc));
+}
+
+void Generator::GenerateOneofCaseDefinition(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const OneofDescriptor* oneof) const {
+  printer->Print(
+      "/**\n"
+      " * @enum {number}\n"
+      " */\n"
+      "$classname$.$oneof$Case = {\n"
+      "  $upcase$_NOT_SET: 0",
+      "classname", GetPath(options, oneof->containing_type()),
+      "oneof", JSOneofName(oneof),
+      "upcase", ToEnumCase(oneof->name()));
+
+  for (int i = 0; i < oneof->field_count(); i++) {
+    if (IgnoreField(oneof->field(i))) {
+      continue;
+    }
+
+    printer->Print(
+        ",\n"
+        "  $upcase$: $number$",
+        "upcase", ToEnumCase(oneof->field(i)->name()),
+        "number", JSFieldIndex(oneof->field(i)));
+  }
+
+  printer->Print(
+      "\n"
+      "};\n"
+      "\n"
+      "/**\n"
+      " * @return {$class$.$oneof$Case}\n"
+      " */\n"
+      "$class$.prototype.get$oneof$Case = function() {\n"
+      "  return /** @type {$class$.$oneof$Case} */(jspb.Message."
+      "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n"
+      "};\n"
+      "\n",
+      "class", GetPath(options, oneof->containing_type()),
+      "oneof", JSOneofName(oneof),
+      "oneofindex", JSOneofIndex(oneof));
+}
+
+void Generator::GenerateClassToObject(const GeneratorOptions& options,
+                                      io::Printer* printer,
+                                      const Descriptor* desc) const {
+  printer->Print(
+      "\n"
+      "\n"
+      "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
+      "/**\n"
+      " * Creates an object representation of this proto suitable for use in "
+      "Soy templates.\n"
+      " * Field names that are reserved in JavaScript and will be renamed to "
+      "pb_name.\n"
+      " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
+      " * For the list of reserved names please see:\n"
+      " *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.\n"
+      " * @param {boolean=} opt_includeInstance Whether to include the JSPB "
+      "instance\n"
+      " *     for transitional soy proto support: http://goto/soy-param-"
+      "migration\n"
+      " * @return {!Object}\n"
+      " */\n"
+      "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
+      "  return $classname$.toObject(opt_includeInstance, this);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Static version of the {@see toObject} method.\n"
+      " * @param {boolean|undefined} includeInstance Whether to include the "
+      "JSPB\n"
+      " *     instance for transitional soy proto support:\n"
+      " *     http://goto/soy-param-migration\n"
+      " * @param {!$classname$} msg The msg instance to transform.\n"
+      " * @return {!Object}\n"
+      " */\n"
+      "$classname$.toObject = function(includeInstance, msg) {\n"
+      "  var f, obj = {",
+      "classname", GetPath(options, desc));
+
+  bool first = true;
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    if (IgnoreField(field)) {
+      continue;
+    }
+
+    if (!first) {
+      printer->Print(",\n    ");
+    } else {
+      printer->Print("\n    ");
+      first = false;
+    }
+
+    GenerateClassFieldToObject(options, printer, field);
+  }
+
+  if (!first) {
+    printer->Print("\n  };\n\n");
+  } else {
+    printer->Print("\n\n  };\n\n");
+  }
+
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "  jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
+        "obj,\n"
+        "      $extObject$, $class$.prototype.getExtension,\n"
+        "      includeInstance);\n",
+        "extObject", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  }
+
+  printer->Print(
+      "  if (includeInstance) {\n"
+      "    obj.$$jspbMessageInstance = msg\n"
+      "  }\n"
+      "  return obj;\n"
+      "};\n"
+      "}\n"
+      "\n"
+      "\n",
+      "classname", GetPath(options, desc));
+}
+
+void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const FieldDescriptor* field) const {
+  printer->Print("$fieldname$: ",
+                 "fieldname", JSObjectFieldName(field));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message field.
+    if (field->is_repeated()) {
+      {
+        printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
+                       "    $type$.toObject, includeInstance)",
+                       "getter", JSGetterName(field),
+                       "type", SubmessageTypeRef(options, field));
+      }
+    } else {
+      printer->Print("(f = msg.get$getter$()) && "
+                     "$type$.toObject(includeInstance, f)",
+                     "getter", JSGetterName(field),
+                     "type", SubmessageTypeRef(options, field));
+    }
+  } else {
+    // Simple field (singular or repeated).
+    if (!HasFieldPresence(field) && !field->is_repeated()) {
+      // Delegate to the generated get<field>() method in order not to duplicate
+      // the proto3-field-default-value logic here.
+      printer->Print("msg.get$getter$()",
+                     "getter", JSGetterName(field));
+    } else {
+      if (field->has_default_value()) {
+        printer->Print("jspb.Message.getField(msg, $index$) != null ? "
+                       "jspb.Message.getField(msg, $index$) : $defaultValue$",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(field));
+      } else {
+        printer->Print("jspb.Message.getField(msg, $index$)",
+                       "index", JSFieldIndex(field));
+      }
+    }
+  }
+}
+
+void Generator::GenerateClassFromObject(const GeneratorOptions& options,
+                                        io::Printer* printer,
+                                        const Descriptor* desc) const {
+  printer->Print(
+      "if (jspb.Message.GENERATE_FROM_OBJECT) {\n"
+      "/**\n"
+      " * Loads data from an object into a new instance of this proto.\n"
+      " * @param {!Object} obj The object representation of this proto to\n"
+      " *     load the data from.\n"
+      " * @return {!$classname$}\n"
+      " */\n"
+      "$classname$.fromObject = function(obj) {\n"
+      "  var f, msg = new $classname$();\n",
+      "classname", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    const FieldDescriptor* field = desc->field(i);
+    GenerateClassFieldFromObject(options, printer, field);
+  }
+
+  printer->Print(
+      "  return msg;\n"
+      "};\n"
+      "}\n");
+}
+
+void Generator::GenerateClassFieldFromObject(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message field (singular or repeated)
+    if (field->is_repeated()) {
+      {
+        printer->Print(
+            "  goog.isDef(obj.$name$) && "
+            "jspb.Message.setRepeatedWrapperField(\n"
+            "      msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
+            "        return $fieldclass$.fromObject(i);\n"
+            "      }));\n",
+            "name", JSObjectFieldName(field),
+            "index", JSFieldIndex(field),
+            "fieldclass", SubmessageTypeRef(options, field));
+      }
+    } else {
+      printer->Print(
+          "  goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
+          "      msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
+          "name", JSObjectFieldName(field),
+          "index", JSFieldIndex(field),
+          "fieldclass", SubmessageTypeRef(options, field));
+    }
+  } else {
+    // Simple (primitive) field.
+    printer->Print(
+        "  goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
+        "obj.$name$);\n",
+        "name", JSObjectFieldName(field),
+        "index", JSFieldIndex(field));
+  }
+}
+
+void Generator::GenerateClassClone(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Creates a deep clone of this proto. No data is shared with the "
+      "original.\n"
+      " * @return {!$name$} The clone.\n"
+      " */\n"
+      "$name$.prototype.cloneMessage = function() {\n"
+      "  return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n"
+      "};\n\n\n",
+      "name", GetPath(options, desc));
+}
+
+void Generator::GenerateClassRegistration(const GeneratorOptions& options,
+                                          io::Printer* printer,
+                                          const Descriptor* desc) const {
+  // Register any extensions defined inside this message type.
+  for (int i = 0; i < desc->extension_count(); i++) {
+    const FieldDescriptor* extension = desc->extension(i);
+    if (ShouldGenerateExtension(extension)) {
+      GenerateExtension(options, printer, extension);
+    }
+  }
+
+}
+
+void Generator::GenerateClassFields(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const Descriptor* desc) const {
+  for (int i = 0; i < desc->field_count(); i++) {
+    if (!IgnoreField(desc->field(i))) {
+      GenerateClassField(options, printer, desc->field(i));
+    }
+  }
+}
+
+void Generator::GenerateClassField(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const FieldDescriptor* field) const {
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "/**\n"
+        " * $fielddef$\n"
+        "$comment$"
+        " * @return {$type$}\n"
+        " */\n",
+        "fielddef", FieldDefinition(options, field),
+        "comment", FieldComments(field),
+        "type", JSFieldTypeAnnotation(options, field,
+                                      /* force_optional = */ false,
+                                      /* force_present = */ false,
+                                      /* singular_if_not_packed = */ false,
+                                      /* always_singular = */ false));
+    printer->Print(
+        "$class$.prototype.get$name$ = function() {\n"
+        "  return /** @type{$type$} */ (\n"
+        "    jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
+        "$index$$required$));\n"
+        "};\n"
+        "\n"
+        "\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "type", JSFieldTypeAnnotation(options, field,
+                                      /* force_optional = */ false,
+                                      /* force_present = */ false,
+                                      /* singular_if_not_packed = */ false,
+                                      /* always_singular = */ false),
+        "rpt", (field->is_repeated() ? "Repeated" : ""),
+        "index", JSFieldIndex(field),
+        "wrapperclass", SubmessageTypeRef(options, field),
+        "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
+                     ", 1" : ""));
+    printer->Print(
+        "/** @param {$optionaltype$} value $returndoc$ */\n"
+        "$class$.prototype.set$name$ = function(value) {\n"
+        "  jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
+        "optionaltype",
+        JSFieldTypeAnnotation(options, field,
+                              /* force_optional = */ true,
+                              /* force_present = */ false,
+                              /* singular_if_not_packed = */ false,
+                              /* always_singular = */ false),
+        "returndoc", JSReturnDoc(options, field),
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+        "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
+
+    printer->Print(
+        "this, $index$$oneofgroup$, value);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "index", JSFieldIndex(field),
+        "oneofgroup", (field->containing_oneof() ?
+                       (", " + JSOneofArray(options, field)) : ""),
+        "returnvalue", JSReturnClause(field));
+
+    printer->Print(
+        "$class$.prototype.clear$name$ = function() {\n"
+        "  this.set$name$($clearedvalue$);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+        "returnvalue", JSReturnClause(field));
+
+  } else {
+    string typed_annotation;
+
+    // Simple (primitive) field, either singular or repeated.
+    {
+      typed_annotation = JSFieldTypeAnnotation(options, field,
+                              /* force_optional = */ false,
+                              /* force_present = */ !HasFieldPresence(field),
+                              /* singular_if_not_packed = */ false,
+                              /* always_singular = */ false),
+      printer->Print(
+          "/**\n"
+          " * $fielddef$\n"
+          "$comment$"
+          " * @return {$type$}\n"
+          " */\n",
+          "fielddef", FieldDefinition(options, field),
+          "comment", FieldComments(field),
+          "type", typed_annotation);
+    }
+
+    printer->Print(
+        "$class$.prototype.get$name$ = function() {\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field));
+
+    {
+      printer->Print(
+          "  return /** @type {$type$} */ (",
+          "type", typed_annotation);
+    }
+
+    // For proto3 fields without presence, use special getters that will return
+    // defaults when the field is unset, possibly constructing a value if
+    // required.
+    if (!HasFieldPresence(field) && !field->is_repeated()) {
+      printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)",
+                     "index", JSFieldIndex(field),
+                     "default", Proto3PrimitiveFieldDefault(field));
+    } else {
+      if (field->has_default_value()) {
+        printer->Print("jspb.Message.getField(this, $index$) != null ? "
+                       "jspb.Message.getField(this, $index$) : $defaultValue$",
+                       "index", JSFieldIndex(field),
+                       "defaultValue", JSFieldDefault(field));
+      } else {
+        printer->Print("jspb.Message.getField(this, $index$)",
+                       "index", JSFieldIndex(field));
+      }
+    }
+
+    {
+      printer->Print(
+          ");\n"
+          "};\n"
+          "\n"
+          "\n");
+    }
+
+    {
+      printer->Print(
+          "/** @param {$optionaltype$} value $returndoc$ */\n",
+          "optionaltype",
+          JSFieldTypeAnnotation(options, field,
+                                /* force_optional = */ true,
+                                /* force_present = */ !HasFieldPresence(field),
+                                /* singular_if_not_packed = */ false,
+                                /* always_singular = */ false),
+          "returndoc", JSReturnDoc(options, field));
+    }
+
+    printer->Print(
+        "$class$.prototype.set$name$ = function(value) {\n"
+        "  jspb.Message.set$oneoftag$Field(this, $index$",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(field),
+        "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+        "index", JSFieldIndex(field));
+    printer->Print(
+        "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
+        "};\n"
+        "\n"
+        "\n",
+        "type", "",
+        "typeclose", "",
+        "oneofgroup",
+        (field->containing_oneof() ? (", " + JSOneofArray(options, field))
+                                   : ""),
+        "returnvalue", JSReturnClause(field), "rptvalueinit",
+        (field->is_repeated() ? " || []" : ""));
+
+
+    if (HasFieldPresence(field)) {
+      printer->Print(
+          "$class$.prototype.clear$name$ = function() {\n"
+          "  jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
+          "class", GetPath(options, field->containing_type()),
+          "name", JSGetterName(field),
+          "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+          "oneofgroup", (field->containing_oneof() ?
+                         (", " + JSOneofArray(options, field)) : ""),
+          "index", JSFieldIndex(field));
+      printer->Print(
+          "$clearedvalue$);$returnvalue$\n"
+          "};\n"
+          "\n"
+          "\n",
+          "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+          "returnvalue", JSReturnClause(field));
+    }
+  }
+}
+
+void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+                                                io::Printer* printer,
+                                                const Descriptor* desc) const {
+  if (IsExtendable(desc)) {
+    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$.extensions = {};\n"
+        "\n",
+        "class", GetPath(options, desc));
+  }
+}
+
+
+void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
+                                               io::Printer* printer,
+                                               const Descriptor* desc) const {
+  // TODO(cfallin): Handle lazy decoding when requested by field option and/or
+  // by default for 'bytes' fields and packed repeated fields.
+
+  printer->Print(
+      "/**\n"
+      " * Deserializes binary data (in protobuf wire format).\n"
+      " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n"
+      " * @return {!$class$}\n"
+      " */\n"
+      "$class$.deserializeBinary = function(bytes) {\n"
+      "  var reader = new jspb.BinaryReader(bytes);\n"
+      "  var msg = new $class$;\n"
+      "  return $class$.deserializeBinaryFromReader(msg, reader);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Deserializes binary data (in protobuf wire format) from the\n"
+      " * given reader into the given message object.\n"
+      " * @param {!$class$} msg The message object to deserialize into.\n"
+      " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n"
+      " * @return {!$class$}\n"
+      " */\n"
+      "$class$.deserializeBinaryFromReader = function(msg, reader) {\n"
+      "  while (reader.nextField()) {\n"
+      "    if (reader.isEndGroup()) {\n"
+      "      break;\n"
+      "    }\n"
+      "    var field = reader.getFieldNumber();\n"
+      "    switch (field) {\n",
+      "class", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
+  }
+
+  printer->Print(
+      "    default:\n");
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "      jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
+        "        $class$.prototype.getExtension,\n"
+        "        $class$.prototype.setExtension);\n"
+        "      break;\n",
+        "extobj", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  } else {
+    printer->Print(
+        "      reader.skipField();\n"
+        "      break;\n");
+  }
+
+  printer->Print(
+      "    }\n"
+      "  }\n"
+      "  return msg;\n"
+      "};\n"
+      "\n"
+      "\n");
+}
+
+void Generator::GenerateClassDeserializeBinaryField(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+
+  printer->Print("    case $num$:\n",
+                 "num", SimpleItoa(field->number()));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        "      var value = new $fieldclass$;\n"
+        "      reader.read$msgOrGroup$($grpfield$value,"
+        "$fieldclass$.deserializeBinaryFromReader);\n",
+        "fieldclass", SubmessageTypeRef(options, field),
+        "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                      "Group" : "Message",
+        "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                    (SimpleItoa(field->number()) + ", ") : "");
+  } else {
+    printer->Print(
+        "      var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
+        "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+                                           /* singular_if_not_packed = */ true,
+                                           /* always_singular = */ false),
+        "reader", JSBinaryReaderMethodName(field));
+  }
+
+  if (field->is_repeated() && !field->is_packed()) {
+    // Repeated fields receive a |value| one at at a time; append to array
+    // returned by get$name$().
+    printer->Print(
+        "      msg.get$name$().push(value);\n",
+        "name", JSGetterName(field));
+  } else {
+    // Singular fields, and packed repeated fields, receive a |value| either as
+    // the field's value or as the array of all the field's values; set this as
+    // the field's value directly.
+    printer->Print(
+        "      msg.set$name$(value);\n",
+        "name", JSGetterName(field));
+  }
+
+  printer->Print("      break;\n");
+}
+
+void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
+                                             io::Printer* printer,
+                                             const Descriptor* desc) const {
+  printer->Print(
+      "/**\n"
+      " * Class method variant: serializes the given message to binary data\n"
+      " * (in protobuf wire format), writing to the given BinaryWriter.\n"
+      " * @param {!$class$} message\n"
+      " * @param {!jspb.BinaryWriter} writer\n"
+      " */\n"
+      "$class$.serializeBinaryToWriter = function(message, "
+      "writer) {\n"
+      "  message.serializeBinaryToWriter(writer);\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Serializes the message to binary data (in protobuf wire format).\n"
+      " * @return {!Uint8Array}\n"
+      " */\n"
+      "$class$.prototype.serializeBinary = function() {\n"
+      "  var writer = new jspb.BinaryWriter();\n"
+      "  this.serializeBinaryToWriter(writer);\n"
+      "  return writer.getResultBuffer();\n"
+      "};\n"
+      "\n"
+      "\n"
+      "/**\n"
+      " * Serializes the message to binary data (in protobuf wire format),\n"
+      " * writing to the given BinaryWriter.\n"
+      " * @param {!jspb.BinaryWriter} writer\n"
+      " */\n"
+      "$class$.prototype.serializeBinaryToWriter = function (writer) {\n"
+      "  var f = undefined;\n",
+      "class", GetPath(options, desc));
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    GenerateClassSerializeBinaryField(options, printer, desc->field(i));
+  }
+
+  if (IsExtendable(desc)) {
+    printer->Print(
+        "  jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
+        "    $class$.prototype.getExtension);\n",
+        "extobj", JSExtensionsObjectName(options, desc->file(), desc),
+        "class", GetPath(options, desc));
+  }
+
+  printer->Print(
+      "};\n"
+      "\n"
+      "\n");
+}
+
+void Generator::GenerateClassSerializeBinaryField(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FieldDescriptor* field) const {
+  printer->Print(
+      "  f = this.get$name$();\n",
+      "name", JSGetterName(field));
+
+  if (field->is_repeated()) {
+    printer->Print(
+        "  if (f.length > 0) {\n");
+  } else {
+    if (HasFieldPresence(field)) {
+      printer->Print(
+          "  if (f != null) {\n");
+    } else {
+      // No field presence: serialize onto the wire only if value is
+      // non-default.  Defaults are documented here:
+      // https://goto.google.com/lhdfm
+      switch (field->cpp_type()) {
+        case FieldDescriptor::CPPTYPE_INT32:
+        case FieldDescriptor::CPPTYPE_INT64:
+        case FieldDescriptor::CPPTYPE_UINT32:
+        case FieldDescriptor::CPPTYPE_UINT64: {
+          {
+            printer->Print("  if (f !== 0) {\n");
+          }
+          break;
+        }
+
+        case FieldDescriptor::CPPTYPE_ENUM:
+        case FieldDescriptor::CPPTYPE_FLOAT:
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+          printer->Print(
+              "  if (f !== 0.0) {\n");
+          break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+          printer->Print(
+              "  if (f) {\n");
+          break;
+        case FieldDescriptor::CPPTYPE_STRING:
+          printer->Print(
+              "  if (f.length > 0) {\n");
+          break;
+        default:
+          assert(false);
+          break;
+      }
+    }
+  }
+
+  printer->Print(
+      "    writer.$writer$(\n"
+      "      $index$,\n"
+      "      f",
+      "writer", JSBinaryWriterMethodName(field),
+      "name", JSGetterName(field),
+      "index", SimpleItoa(field->number()));
+
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    printer->Print(
+        ",\n"
+        "      $submsg$.serializeBinaryToWriter\n",
+        "submsg", SubmessageTypeRef(options, field));
+  } else {
+    printer->Print("\n");
+  }
+  printer->Print(
+      "    );\n"
+      "  }\n");
+}
+
+void Generator::GenerateEnum(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const EnumDescriptor* enumdesc) const {
+  printer->Print(
+      "/**\n"
+      " * @enum {number}\n"
+      " */\n"
+      "$name$ = {\n",
+      "name", GetPath(options, enumdesc));
+
+  for (int i = 0; i < enumdesc->value_count(); i++) {
+    const EnumValueDescriptor* value = enumdesc->value(i);
+    printer->Print(
+        "  $name$: $value$$comma$\n",
+        "name", ToEnumCase(value->name()),
+        "value", SimpleItoa(value->number()),
+        "comma", (i == enumdesc->value_count() - 1) ? "" : ",");
+  }
+
+  printer->Print(
+      "};\n"
+      "\n");
+}
+
+void Generator::GenerateExtension(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const FieldDescriptor* field) const {
+  string extension_scope =
+      (field->extension_scope() ?
+       GetPath(options, field->extension_scope()) :
+       GetPath(options, field->file()));
+
+  printer->Print(
+      "\n"
+      "/**\n"
+      " * A tuple of {field number, class constructor} for the extension\n"
+      " * field named `$name$`.\n"
+      " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
+      " */\n"
+      "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
+      "name", JSObjectFieldName(field),
+      "class", extension_scope,
+      "extensionType", JSFieldTypeAnnotation(
+          options, field,
+          /* force_optional = */ false,
+          /* force_present = */ true,
+          /* singular_if_not_packed = */ false,
+          /* always_singular = */ false));
+  printer->Print(
+      "    $index$,\n"
+      "    {$name$: 0},\n"
+      "    $ctor$,\n"
+      "     /** @type {?function((boolean|undefined),!jspb.Message=): "
+      "!Object} */ (\n"
+      "         $toObject$),\n"
+      "    $repeated$",
+      "index", SimpleItoa(field->number()),
+      "name", JSObjectFieldName(field),
+      "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+               SubmessageTypeRef(options, field) : string("null")),
+      "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
+                   (SubmessageTypeRef(options, field) + ".toObject") :
+                   string("null")),
+      "repeated", (field->is_repeated() ? "1" : "0"));
+
+  if (options.binary) {
+    printer->Print(
+        ",\n"
+        "    jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
+        "    jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+        "    $binaryMessageSerializeFn$,\n"
+        "    $binaryMessageDeserializeFn$,\n"
+        "    $isPacked$);\n",
+        "binaryReaderFn", JSBinaryReaderMethodName(field),
+        "binaryWriterFn", JSBinaryWriterMethodName(field),
+        "binaryMessageSerializeFn",
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+        (SubmessageTypeRef(options, field) +
+         ".serializeBinaryToWriter") : "null",
+        "binaryMessageDeserializeFn",
+        (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+        (SubmessageTypeRef(options, field) +
+         ".deserializeBinaryFromReader") : "null",
+        "isPacked", (field->is_packed() ? "true" : "false"));
+  } else {
+    printer->Print(");\n");
+  }
+
+  printer->Print(
+      "// This registers the extension field with the extended class, so that\n"
+      "// toObject() will function correctly.\n"
+      "$extendName$[$index$] = $class$.$name$;\n"
+      "\n",
+      "extendName", JSExtensionsObjectName(options, field->file(),
+                                           field->containing_type()),
+      "index", SimpleItoa(field->number()),
+      "class", extension_scope,
+      "name", JSObjectFieldName(field));
+}
+
+bool GeneratorOptions::ParseFromOptions(
+    const vector< pair< string, string > >& options,
+    string* error) {
+  for (int i = 0; i < options.size(); i++) {
+    if (options[i].first == "add_require_for_enums") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for add_require_for_enums";
+        return false;
+      }
+      add_require_for_enums = true;
+    } else if (options[i].first == "binary") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for binary";
+        return false;
+      }
+      binary = true;
+    } else if (options[i].first == "testonly") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for testonly";
+        return false;
+      }
+      testonly = true;
+    } else if (options[i].first == "error_on_name_conflict") {
+      if (options[i].second != "") {
+        *error = "Unexpected option value for error_on_name_conflict";
+        return false;
+      }
+      error_on_name_conflict = true;
+    } else if (options[i].first == "output_dir") {
+      output_dir = options[i].second;
+    } else if (options[i].first == "namespace_prefix") {
+      namespace_prefix = options[i].second;
+    } else if (options[i].first == "library") {
+      library = options[i].second;
+    } else if (options[i].first == "import_style") {
+      if (options[i].second == "closure") {
+        import_style = IMPORT_CLOSURE;
+      } else if (options[i].second == "commonjs") {
+        import_style = IMPORT_COMMONJS;
+      } else if (options[i].second == "browser") {
+        import_style = IMPORT_BROWSER;
+      } else if (options[i].second == "es6") {
+        import_style = IMPORT_ES6;
+      } else {
+        *error = "Unknown import style " + options[i].second + ", expected " +
+                 "one of: closure, commonjs, browser, es6.";
+      }
+    } else {
+      // Assume any other option is an output directory, as long as it is a bare
+      // `key` rather than a `key=value` option.
+      if (options[i].second != "") {
+        *error = "Unknown option: " + options[i].first;
+        return false;
+      }
+      output_dir = options[i].first;
+    }
+  }
+
+  if (!library.empty() && import_style != IMPORT_CLOSURE) {
+    *error = "The library option should only be used for "
+             "import_style=closure";
+  }
+
+  return true;
+}
+
+void Generator::GenerateFilesInDepOrder(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const vector<const FileDescriptor*>& files) const {
+  // Build a std::set over all files so that the DFS can detect when it recurses
+  // into a dep not specified in the user's command line.
+  std::set<const FileDescriptor*> all_files(files.begin(), files.end());
+  // Track the in-progress set of files that have been generated already.
+  std::set<const FileDescriptor*> generated;
+  for (int i = 0; i < files.size(); i++) {
+    GenerateFileAndDeps(options, printer, files[i], &all_files, &generated);
+  }
+}
+
+void Generator::GenerateFileAndDeps(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const FileDescriptor* root,
+    std::set<const FileDescriptor*>* all_files,
+    std::set<const FileDescriptor*>* generated) const {
+  // Skip if already generated.
+  if (generated->find(root) != generated->end()) {
+    return;
+  }
+  generated->insert(root);
+
+  // Generate all dependencies before this file's content.
+  for (int i = 0; i < root->dependency_count(); i++) {
+    const FileDescriptor* dep = root->dependency(i);
+    GenerateFileAndDeps(options, printer, dep, all_files, generated);
+  }
+
+  // Generate this file's content.  Only generate if the file is part of the
+  // original set requested to be generated; i.e., don't take all transitive
+  // deps down to the roots.
+  if (all_files->find(root) != all_files->end()) {
+    GenerateClassesAndEnums(options, printer, root);
+  }
+}
+
+void Generator::GenerateFile(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const FileDescriptor* file) const {
+  GenerateHeader(options, printer);
+
+  // Generate "require" statements.
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
+    printer->Print("var jspb = require('google-protobuf');\n");
+    printer->Print("var goog = jspb;\n");
+    printer->Print("var global = Function('return this')();\n\n");
+
+    for (int i = 0; i < file->dependency_count(); i++) {
+      const std::string& name = file->dependency(i)->name();
+      printer->Print(
+          "var $alias$ = require('$file$');\n",
+          "alias", ModuleAlias(name),
+          "file", GetJSFilename(name));
+    }
+  }
+
+  // We aren't using Closure's import system, but we use goog.exportSymbol()
+  // to construct the expected tree of objects, eg.
+  //
+  //   goog.exportSymbol('foo.bar.Baz', null, this);
+  //
+  //   // Later generated code expects foo.bar = {} to exist:
+  //   foo.bar.Baz = function() { /* ... */ }
+  std::set<std::string> provided;
+
+  // Cover the case where this file declares extensions but no messages.
+  // This will ensure that the file-level object will be declared to hold
+  // the extensions.
+  for (int i = 0; i < file->extension_count(); i++) {
+    provided.insert(file->extension(i)->full_name());
+  }
+
+  FindProvidesForFile(options, printer, file, &provided);
+  for (std::set<string>::iterator it = provided.begin();
+       it != provided.end(); ++it) {
+    printer->Print("goog.exportSymbol('$name$', null, global);\n",
+                   "name", *it);
+  }
+
+  GenerateClassesAndEnums(options, printer, file);
+
+  // Extensions nested inside messages are emitted inside
+  // GenerateClassesAndEnums().
+  for (int i = 0; i < file->extension_count(); i++) {
+    GenerateExtension(options, printer, file->extension(i));
+  }
+
+  if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
+    printer->Print("goog.object.extend(exports, $package$);\n",
+                   "package", GetPath(options, file));
+  }
+}
+
+bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
+                            const string& parameter,
+                            GeneratorContext* context,
+                            string* error) const {
+  vector< pair< string, string > > option_pairs;
+  ParseGeneratorParameter(parameter, &option_pairs);
+  GeneratorOptions options;
+  if (!options.ParseFromOptions(option_pairs, error)) {
+    return false;
+  }
+
+
+  // There are three schemes for where output files go:
+  //
+  // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file
+  // - import_style = IMPORT_CLOSURE, library empty: one output file per type
+  // - import_style != IMPORT_CLOSURE: one output file per .proto file
+  if (options.import_style == GeneratorOptions::IMPORT_CLOSURE &&
+      options.library != "") {
+    // All output should go in a single file.
+    string filename = options.output_dir + "/" + options.library + ".js";
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+    GOOGLE_CHECK(output.get());
+    io::Printer printer(output.get(), '$');
+
+    // Pull out all extensions -- we need these to generate all
+    // provides/requires.
+    vector<const FieldDescriptor*> extensions;
+    for (int i = 0; i < files.size(); i++) {
+      for (int j = 0; j < files[i]->extension_count(); j++) {
+        const FieldDescriptor* extension = files[i]->extension(j);
+        extensions.push_back(extension);
+      }
+    }
+
+    GenerateHeader(options, &printer);
+
+    std::set<string> provided;
+    FindProvides(options, &printer, files, &provided);
+    FindProvidesForFields(options, &printer, extensions, &provided);
+    GenerateProvides(options, &printer, &provided);
+    GenerateTestOnly(options, &printer);
+    GenerateRequires(options, &printer, files, &provided);
+
+    GenerateFilesInDepOrder(options, &printer, files);
+
+    for (int i = 0; i < extensions.size(); i++) {
+      if (ShouldGenerateExtension(extensions[i])) {
+        GenerateExtension(options, &printer, extensions[i]);
+      }
+    }
+
+    if (printer.failed()) {
+      return false;
+    }
+  } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
+    // Collect all types, and print each type to a separate file. Pull out
+    // free-floating extensions while we make this pass.
+    map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
+
+    // If we're generating code in file-per-type mode, avoid overwriting files
+    // by choosing the last descriptor that writes each filename and permitting
+    // only those to generate code.
+
+    // Current descriptor that will generate each filename, indexed by filename.
+    map<string, const void*> desc_by_filename;
+    // Set of descriptors allowed to generate files.
+    set<const void*> allowed_descs;
+
+    for (int i = 0; i < files.size(); i++) {
+      // Collect all (descriptor, filename) pairs.
+      map<const void*, string> descs_in_file;
+      for (int j = 0; j < files[i]->message_type_count(); j++) {
+        const Descriptor* desc = files[i]->message_type(j);
+        string filename =
+            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+        descs_in_file[desc] = filename;
+      }
+      for (int j = 0; j < files[i]->enum_type_count(); j++) {
+        const EnumDescriptor* desc = files[i]->enum_type(j);
+        string filename =
+            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+        descs_in_file[desc] = filename;
+      }
+
+      // For each (descriptor, filename) pair, update the
+      // descriptors-by-filename map, and if a previous descriptor was already
+      // writing the filename, remove it from the allowed-descriptors set.
+      map<const void*, string>::iterator it;
+      for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
+        const void* desc = it->first;
+        const string& filename = it->second;
+        if (desc_by_filename.find(filename) != desc_by_filename.end()) {
+          if (options.error_on_name_conflict) {
+            *error = "Name conflict: file name " + filename +
+                     " would be generated by two descriptors";
+            return false;
+          }
+          allowed_descs.erase(desc_by_filename[filename]);
+        }
+        desc_by_filename[filename] = desc;
+        allowed_descs.insert(desc);
+      }
+    }
+
+    // Generate code.
+    for (int i = 0; i < files.size(); i++) {
+      const FileDescriptor* file = files[i];
+      for (int j = 0; j < file->message_type_count(); j++) {
+        const Descriptor* desc = file->message_type(j);
+        if (allowed_descs.find(desc) == allowed_descs.end()) {
+          continue;
+        }
+
+        string filename = options.output_dir + "/" +
+            ToFileName(desc->name()) + ".js";
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
+
+        GenerateHeader(options, &printer);
+
+        std::set<string> provided;
+        FindProvidesForMessage(options, &printer, desc, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+        GenerateRequires(options, &printer, desc, &provided);
+
+        GenerateClass(options, &printer, desc);
+
+        if (printer.failed()) {
+          return false;
+        }
+      }
+      for (int j = 0; j < file->enum_type_count(); j++) {
+        const EnumDescriptor* enumdesc = file->enum_type(j);
+        if (allowed_descs.find(enumdesc) == allowed_descs.end()) {
+          continue;
+        }
+
+        string filename = options.output_dir + "/" +
+            ToFileName(enumdesc->name()) + ".js";
+
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
+
+        GenerateHeader(options, &printer);
+
+        std::set<string> provided;
+        FindProvidesForEnum(options, &printer, enumdesc, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+
+        GenerateEnum(options, &printer, enumdesc);
+
+        if (printer.failed()) {
+          return false;
+        }
+      }
+      // Pull out all free-floating extensions and generate files for those too.
+      for (int j = 0; j < file->extension_count(); j++) {
+        const FieldDescriptor* extension = file->extension(j);
+        extensions_by_namespace[GetPath(options, files[i])]
+            .push_back(extension);
+      }
+    }
+
+    // Generate extensions in separate files.
+    map< string, vector<const FieldDescriptor*> >::iterator it;
+    for (it = extensions_by_namespace.begin();
+         it != extensions_by_namespace.end();
+         ++it) {
+      string filename = options.output_dir + "/" +
+          ToFileName(it->first) + ".js";
+
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filename));
+      GOOGLE_CHECK(output.get());
+      io::Printer printer(output.get(), '$');
+
+      GenerateHeader(options, &printer);
+
+      std::set<string> provided;
+      FindProvidesForFields(options, &printer, it->second, &provided);
+      GenerateProvides(options, &printer, &provided);
+      GenerateTestOnly(options, &printer);
+      GenerateRequires(options, &printer, it->second, &provided);
+
+      for (int j = 0; j < it->second.size(); j++) {
+        if (ShouldGenerateExtension(it->second[j])) {
+          GenerateExtension(options, &printer, it->second[j]);
+        }
+      }
+    }
+  } else {
+    // Generate one output file per input (.proto) file.
+
+    for (int i = 0; i < files.size(); i++) {
+      const google::protobuf::FileDescriptor* file = files[i];
+
+      string filename = options.output_dir + "/" + GetJSFilename(file->name());
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filename));
+      GOOGLE_CHECK(output.get());
+      io::Printer printer(output.get(), '$');
+
+      GenerateFile(options, &printer, file);
+
+      if (printer.failed()) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+}  // namespace js
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
new file mode 100755
index 0000000..db9178d
--- /dev/null
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -0,0 +1,281 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
+
+#include <string>
+#include <set>
+
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class OneofDescriptor;
+class FileDescriptor;
+
+namespace io { class Printer; }
+
+namespace compiler {
+namespace js {
+
+struct GeneratorOptions {
+  // Add a `goog.requires()` call for each enum type used. If not set, a forward
+  // declaration with `goog.forwardDeclare` is produced instead.
+  bool add_require_for_enums;
+  // Set this as a test-only module via `goog.setTestOnly();`.
+  bool testonly;
+  // Output path.
+  string output_dir;
+  // Namespace prefix.
+  string namespace_prefix;
+  // Create a library with name <name>_lib.js rather than a separate .js file
+  // per type?
+  string library;
+  // Error if there are two types that would generate the same output file?
+  bool error_on_name_conflict;
+  // Enable binary-format support?
+  bool binary;
+  // What style of imports should be used.
+  enum ImportStyle {
+    IMPORT_CLOSURE,    // goog.require()
+    IMPORT_COMMONJS,   // require()
+    IMPORT_BROWSER,    // no import statements
+    IMPORT_ES6,        // import { member } from ''
+  } import_style;
+
+  GeneratorOptions()
+      : add_require_for_enums(false),
+        testonly(false),
+        output_dir("."),
+        namespace_prefix(""),
+        library(""),
+        error_on_name_conflict(false),
+        binary(false),
+        import_style(IMPORT_CLOSURE) {}
+
+  bool ParseFromOptions(
+      const vector< pair< string, string > >& options,
+      string* error);
+};
+
+class LIBPROTOC_EXPORT Generator : public CodeGenerator {
+ public:
+  Generator() {}
+  virtual ~Generator() {}
+
+  virtual bool Generate(const FileDescriptor* file,
+                        const string& parameter,
+                        GeneratorContext* context,
+                        string* error) const {
+    *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
+    return false;
+  }
+
+  virtual bool HasGenerateAll() const { return true; }
+
+  virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+                           const string& parameter,
+                           GeneratorContext* context,
+                           string* error) const;
+
+ private:
+  void GenerateHeader(const GeneratorOptions& options,
+                      io::Printer* printer) const;
+
+  // Generate goog.provides() calls.
+  void FindProvides(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const vector<const FileDescriptor*>& file,
+                    std::set<string>* provided) const;
+  void FindProvidesForFile(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const FileDescriptor* file,
+                           std::set<string>* provided) const;
+  void FindProvidesForMessage(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc,
+                              std::set<string>* provided) const;
+  void FindProvidesForEnum(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const EnumDescriptor* enumdesc,
+                           std::set<string>* provided) const;
+  // For extension fields at file scope.
+  void FindProvidesForFields(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const vector<const FieldDescriptor*>& fields,
+                             std::set<string>* provided) const;
+  // Print the goog.provides() found by the methods above.
+  void GenerateProvides(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        std::set<string>* provided) const;
+
+  // Generate goog.setTestOnly() if indicated.
+  void GenerateTestOnly(const GeneratorOptions& options,
+                        io::Printer* printer) const;
+
+  // Generate goog.requires() calls.
+  void GenerateRequires(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const vector<const FileDescriptor*>& file,
+                        std::set<string>* provided) const;
+  void GenerateRequires(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const Descriptor* desc,
+                        std::set<string>* provided) const;
+  // For extension fields at file scope.
+  void GenerateRequires(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const vector<const FieldDescriptor*>& fields,
+                        std::set<string>* provided) const;
+  void GenerateRequiresImpl(const GeneratorOptions& options,
+                            io::Printer* printer,
+                            std::set<string>* required,
+                            std::set<string>* forwards,
+                            std::set<string>* provided,
+                            bool require_jspb,
+                            bool require_extension) const;
+  void FindRequiresForMessage(const GeneratorOptions& options,
+                              const Descriptor* desc,
+                              std::set<string>* required,
+                              std::set<string>* forwards,
+                              bool* have_message) const;
+  void FindRequiresForField(const GeneratorOptions& options,
+                            const FieldDescriptor* field,
+                            std::set<string>* required,
+                            std::set<string>* forwards) const;
+  void FindRequiresForExtension(const GeneratorOptions& options,
+                                const FieldDescriptor* field,
+                                std::set<string>* required,
+                                std::set<string>* forwards) const;
+
+  void GenerateFile(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const FileDescriptor* file) const;
+
+  // Generate definitions for all message classes and enums in all files,
+  // processing the files in dependence order.
+  void GenerateFilesInDepOrder(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const vector<const FileDescriptor*>& file) const;
+  // Helper for above.
+  void GenerateFileAndDeps(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const FileDescriptor* root,
+                           std::set<const FileDescriptor*>* all_files,
+                           std::set<const FileDescriptor*>* generated) const;
+
+  // Generate definitions for all message classes and enums.
+  void GenerateClassesAndEnums(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const FileDescriptor* file) const;
+
+  // Generate definition for one class.
+  void GenerateClass(const GeneratorOptions& options,
+                     io::Printer* printer,
+                     const Descriptor* desc) const;
+  void GenerateClassConstructor(const GeneratorOptions& options,
+                                io::Printer* printer,
+                                const Descriptor* desc) const;
+  void GenerateClassFieldInfo(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const Descriptor* desc) const;
+  void GenerateClassXid(const GeneratorOptions& options,
+                        io::Printer* printer,
+                        const Descriptor* desc) const;
+  void GenerateOneofCaseDefinition(const GeneratorOptions& options,
+                                   io::Printer* printer,
+                                   const OneofDescriptor* oneof) const;
+  void GenerateClassToObject(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const Descriptor* desc) const;
+  void GenerateClassFieldToObject(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const FieldDescriptor* field) const;
+  void GenerateClassFromObject(const GeneratorOptions& options,
+                               io::Printer* printer,
+                               const Descriptor* desc) const;
+  void GenerateClassFieldFromObject(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const FieldDescriptor* field) const;
+  void GenerateClassClone(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const Descriptor* desc) const;
+  void GenerateClassRegistration(const GeneratorOptions& options,
+                                 io::Printer* printer,
+                                 const Descriptor* desc) const;
+  void GenerateClassFields(const GeneratorOptions& options,
+                           io::Printer* printer,
+                           const Descriptor* desc) const;
+  void GenerateClassField(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const FieldDescriptor* desc) const;
+  void GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
+                                       io::Printer* printer,
+                                       const Descriptor* desc) const;
+  void GenerateClassDeserialize(const GeneratorOptions& options,
+                                io::Printer* printer,
+                                const Descriptor* desc) const;
+  void GenerateClassDeserializeBinary(const GeneratorOptions& options,
+                                      io::Printer* printer,
+                                      const Descriptor* desc) const;
+  void GenerateClassDeserializeBinaryField(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const FieldDescriptor* field) const;
+  void GenerateClassSerializeBinary(const GeneratorOptions& options,
+                                    io::Printer* printer,
+                                    const Descriptor* desc) const;
+  void GenerateClassSerializeBinaryField(const GeneratorOptions& options,
+                                         io::Printer* printer,
+                                         const FieldDescriptor* field) const;
+
+  // Generate definition for one enum.
+  void GenerateEnum(const GeneratorOptions& options,
+                    io::Printer* printer,
+                    const EnumDescriptor* enumdesc) const;
+
+  // Generate an extension definition.
+  void GenerateExtension(const GeneratorOptions& options,
+                         io::Printer* printer,
+                         const FieldDescriptor* field) const;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator);
+};
+
+}  // namespace js
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JS_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 4815a72..66ad13b 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/compiler/ruby/ruby_generator.h>
 #include <google/protobuf/compiler/csharp/csharp_generator.h>
 #include <google/protobuf/compiler/objectivec/objectivec_generator.h>
+#include <google/protobuf/compiler/js/js_generator.h>
 
 int main(int argc, char* argv[]) {
 
@@ -72,13 +73,18 @@
 
   // CSharp
   google::protobuf::compiler::csharp::Generator csharp_generator;
-  cli.RegisterGenerator("--csharp_out", &csharp_generator,
+  cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator,
                         "Generate C# source file.");
 
   // Objective C
   google::protobuf::compiler::objectivec::ObjectiveCGenerator objc_generator;
-  cli.RegisterGenerator("--objc_out", &objc_generator,
+  cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator,
                         "Generate Objective C header and source.");
 
+  // JavaScript
+  google::protobuf::compiler::js::Generator js_generator;
+  cli.RegisterGenerator("--js_out", &js_generator,
+                        "Generate JavaScript source.");
+
   return cli.Run(argc, argv);
 }
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 9826143..121d917 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -147,6 +147,12 @@
         std::cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: "
                   << has_source_code_info << "." << std::endl;
         abort();
+      } else if (command == "HasJsonName") {
+        FieldDescriptorProto field_descriptor_proto;
+        file->message_type(i)->field(0)->CopyTo(&field_descriptor_proto);
+        std::cerr << "Saw json_name: "
+                  << field_descriptor_proto.has_json_name() << std::endl;
+        abort();
       } else {
         GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
       }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
index 30a13dd..ecc77f6 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
@@ -44,6 +44,7 @@
 namespace objectivec {
 
 namespace {
+
 void SetEnumVariables(const FieldDescriptor* descriptor,
                       map<string, string>* variables) {
   string type = EnumName(descriptor->enum_type());
@@ -63,8 +64,9 @@
 }
 }  // namespace
 
-EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor)
-    : SingleFieldGenerator(descriptor) {
+EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
+                                       const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
   SetEnumVariables(descriptor, &variables_);
 }
 
@@ -112,6 +114,7 @@
 
 void EnumFieldGenerator::DetermineForwardDeclarations(
     set<string>* fwd_decls) const {
+  SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls);
   // If it is an enum defined in a different file, then we'll need a forward
   // declaration for it.  When it is in our file, all the enums are output
   // before the message, so it will be declared before it is needed.
@@ -123,14 +126,20 @@
 }
 
 RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : RepeatedFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
   SetEnumVariables(descriptor, &variables_);
   variables_["array_storage_type"] = "GPBEnumArray";
 }
 
 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
 
+void RepeatedEnumFieldGenerator::FinishInitialization(void) {
+  RepeatedFieldGenerator::FinishInitialization();
+  variables_["array_comment"] =
+      "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+}
+
 void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific(
     io::Printer* printer) const {
   printer->Print(
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
index b629eae..ae2f57e 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
@@ -41,7 +41,8 @@
 namespace objectivec {
 
 class EnumFieldGenerator : public SingleFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  public:
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
@@ -50,7 +51,7 @@
   virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
 
  protected:
-  explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+  EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
   virtual ~EnumFieldGenerator();
 
  private:
@@ -58,13 +59,16 @@
 };
 
 class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  public:
+  virtual void FinishInitialization();
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
 
  protected:
-  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
   virtual ~RepeatedEnumFieldGenerator();
 
  private:
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
index cf5d8cf..0934182 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc
@@ -45,6 +45,7 @@
 namespace objectivec {
 
 namespace {
+
 void SetCommonFieldVariables(const FieldDescriptor* descriptor,
                              map<string, string>* variables) {
   string camel_case_name = FieldName(descriptor);
@@ -117,39 +118,40 @@
 
 }  // namespace
 
-FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) {
+FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                     const Options& options) {
   FieldGenerator* result = NULL;
   if (field->is_repeated()) {
     switch (GetObjectiveCType(field)) {
       case OBJECTIVECTYPE_MESSAGE: {
         if (field->is_map()) {
-          result = new MapFieldGenerator(field);
+          result = new MapFieldGenerator(field, options);
         } else {
-          result = new RepeatedMessageFieldGenerator(field);
+          result = new RepeatedMessageFieldGenerator(field, options);
         }
         break;
       }
       case OBJECTIVECTYPE_ENUM:
-        result = new RepeatedEnumFieldGenerator(field);
+        result = new RepeatedEnumFieldGenerator(field, options);
         break;
       default:
-        result = new RepeatedPrimitiveFieldGenerator(field);
+        result = new RepeatedPrimitiveFieldGenerator(field, options);
         break;
     }
   } else {
     switch (GetObjectiveCType(field)) {
       case OBJECTIVECTYPE_MESSAGE: {
-        result = new MessageFieldGenerator(field);
+        result = new MessageFieldGenerator(field, options);
         break;
       }
       case OBJECTIVECTYPE_ENUM:
-        result = new EnumFieldGenerator(field);
+        result = new EnumFieldGenerator(field, options);
         break;
       default:
         if (IsReferenceType(field)) {
-          result = new PrimitiveObjFieldGenerator(field);
+          result = new PrimitiveObjFieldGenerator(field, options);
         } else {
-          result = new PrimitiveFieldGenerator(field);
+          result = new PrimitiveFieldGenerator(field, options);
         }
         break;
     }
@@ -158,8 +160,8 @@
   return result;
 }
 
-
-FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor)
+FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor,
+                               const Options& options)
     : descriptor_(descriptor) {
   SetCommonFieldVariables(descriptor, &variables_);
 }
@@ -252,9 +254,9 @@
   }
 }
 
-SingleFieldGenerator::SingleFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : FieldGenerator(descriptor) {
+SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor,
+                                           const Options& options)
+    : FieldGenerator(descriptor, options) {
   // Nothing
 }
 
@@ -300,9 +302,9 @@
   return false;
 }
 
-ObjCObjFieldGenerator::ObjCObjFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : SingleFieldGenerator(descriptor) {
+ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
   variables_["property_storage_attribute"] = "strong";
   if (IsRetainedName(variables_["name"])) {
     variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
@@ -342,18 +344,21 @@
 }
 
 RepeatedFieldGenerator::RepeatedFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : ObjCObjFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
   // Repeated fields don't use the has index.
   variables_["has_index"] = "GPBNoHasBit";
+  // Default to no comment and let the cases needing it fill it in.
+  variables_["array_comment"] = "";
 }
 
 RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
 
 void RepeatedFieldGenerator::FinishInitialization(void) {
   FieldGenerator::FinishInitialization();
-  variables_["array_comment"] =
-      "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n";
+  if (variables_.find("array_property_type") == variables_.end()) {
+    variables_["array_property_type"] = variable("array_storage_type");
+  }
 }
 
 void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
@@ -379,13 +384,13 @@
       variables_,
       "$comments$"
       "$array_comment$"
-      "@property(nonatomic, readwrite, strong, null_resettable) $array_storage_type$ *$name$$storage_attribute$;\n"
+      "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$;\n"
       "@property(nonatomic, readonly) NSUInteger $name$_Count;\n");
   if (IsInitName(variables_.find("name")->second)) {
     // If property name starts with init we need to annotate it to get past ARC.
     // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
     printer->Print(variables_,
-                   "- ($array_storage_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
+                   "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n");
   }
   printer->Print("\n");
 }
@@ -395,7 +400,8 @@
   return false;
 }
 
-FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
+                                     const Options& options)
     : descriptor_(descriptor),
       field_generators_(
           new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
@@ -403,10 +409,12 @@
           new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
   // Construct all the FieldGenerators.
   for (int i = 0; i < descriptor->field_count(); i++) {
-    field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i)));
+    field_generators_[i].reset(
+        FieldGenerator::Make(descriptor->field(i), options));
   }
   for (int i = 0; i < descriptor->extension_count(); i++) {
-    extension_generators_[i].reset(FieldGenerator::Make(descriptor->extension(i)));
+    extension_generators_[i].reset(
+        FieldGenerator::Make(descriptor->extension(i), options));
   }
 }
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h
index 130a52d..e8a20a7 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h
@@ -49,24 +49,31 @@
 
 class FieldGenerator {
  public:
-  static FieldGenerator* Make(const FieldDescriptor* field);
+  static FieldGenerator* Make(const FieldDescriptor* field,
+                              const Options& options);
 
   virtual ~FieldGenerator();
 
+  // Exposed for subclasses to fill in.
   virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const = 0;
   virtual void GeneratePropertyDeclaration(io::Printer* printer) const = 0;
-
   virtual void GeneratePropertyImplementation(io::Printer* printer) const = 0;
 
-  virtual void GenerateFieldDescription(io::Printer* printer) const;
+  // Called by GenerateFieldDescription, exposed for classes that need custom
+  // generation.
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
-  virtual void GenerateFieldNumberConstant(io::Printer* printer) const;
 
+  // Exposed for subclasses to extend, base does nothing.
   virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
   virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
 
+  // Exposed for subclasses, should always call it on the parent class also.
   virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
 
+  // Used during generation, not intended to be extended by subclasses.
+  void GenerateFieldDescription(io::Printer* printer) const;
+  void GenerateFieldNumberConstant(io::Printer* printer) const;
+
   void SetOneofIndexBase(int index_base);
 
   string variable(const char* key) const {
@@ -81,7 +88,7 @@
   string raw_field_name() const { return variable("raw_field_name"); }
 
  protected:
-  explicit FieldGenerator(const FieldDescriptor* descriptor);
+  FieldGenerator(const FieldDescriptor* descriptor, const Options& options);
 
   virtual void FinishInitialization(void);
   virtual bool WantsHasProperty(void) const = 0;
@@ -103,7 +110,8 @@
   virtual void GeneratePropertyImplementation(io::Printer* printer) const;
 
  protected:
-  explicit SingleFieldGenerator(const FieldDescriptor* descriptor);
+  SingleFieldGenerator(const FieldDescriptor* descriptor,
+                       const Options& options);
   virtual bool WantsHasProperty(void) const;
 
  private:
@@ -119,7 +127,8 @@
   virtual void GeneratePropertyDeclaration(io::Printer* printer) const;
 
  protected:
-  explicit ObjCObjFieldGenerator(const FieldDescriptor* descriptor);
+  ObjCObjFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options);
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjCObjFieldGenerator);
@@ -135,7 +144,8 @@
   virtual void GeneratePropertyImplementation(io::Printer* printer) const;
 
  protected:
-  explicit RepeatedFieldGenerator(const FieldDescriptor* descriptor);
+  RepeatedFieldGenerator(const FieldDescriptor* descriptor,
+                         const Options& options);
   virtual void FinishInitialization(void);
   virtual bool WantsHasProperty(void) const;
 
@@ -146,7 +156,7 @@
 // Convenience class which constructs FieldGenerators for a Descriptor.
 class FieldGeneratorMap {
  public:
-  explicit FieldGeneratorMap(const Descriptor* descriptor);
+  FieldGeneratorMap(const Descriptor* descriptor, const Options& options);
   ~FieldGeneratorMap();
 
   const FieldGenerator& get(const FieldDescriptor* field) const;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index 184a84a..cdf9ebb 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -50,17 +50,18 @@
 namespace compiler {
 namespace objectivec {
 
-FileGenerator::FileGenerator(const FileDescriptor *file)
+FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
     : file_(file),
       root_class_name_(FileClassName(file)),
-      is_public_dep_(false) {
+      is_public_dep_(false),
+      options_(options) {
   for (int i = 0; i < file_->enum_type_count(); i++) {
     EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
     enum_generators_.push_back(generator);
   }
   for (int i = 0; i < file_->message_type_count(); i++) {
     MessageGenerator *generator =
-        new MessageGenerator(root_class_name_, file_->message_type(i));
+        new MessageGenerator(root_class_name_, file_->message_type(i), options_);
     message_generators_.push_back(generator);
   }
   for (int i = 0; i < file_->extension_count(); i++) {
@@ -95,7 +96,7 @@
   // code is being compiled with.
   printer->Print(
       "#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
-      "#error This file was generated by a different version of protoc-gen-objc which is incompatible with your Protocol Buffer sources.\n"
+      "#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
       "#endif\n"
       "\n",
       "protoc_gen_objc_version",
@@ -352,7 +353,8 @@
       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));
+      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);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h
index 1bb4f0e..4c0fcd3 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h
@@ -55,7 +55,7 @@
 
 class FileGenerator {
  public:
-  explicit FileGenerator(const FileDescriptor* file);
+  FileGenerator(const FileDescriptor* file, const Options& options);
   ~FileGenerator();
 
   void GenerateSource(io::Printer* printer);
@@ -84,6 +84,8 @@
   vector<ExtensionGenerator*> extension_generators_;
   bool is_public_dep_;
 
+  const Options options_;
+
   const vector<FileGenerator*>& DependencyGenerators();
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index 375b4e0..72e295d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -49,21 +49,31 @@
                                    const string& parameter,
                                    OutputDirectory* output_directory,
                                    string* error) const {
-  // ObjC doesn't have any options at the moment, error if passed one.
+  // -----------------------------------------------------------------
+  // Parse generator options.
+
+  Options generation_options;
+
   vector<pair<string, string> > options;
   ParseGeneratorParameter(parameter, &options);
   for (int i = 0; i < options.size(); i++) {
-    *error = "error:: Unknown generator option: " + options[i].first;
-    return false;
+    if (options[i].first == "expected_prefixes_path") {
+      generation_options.expected_prefixes_path = options[i].second;
+    } else {
+      *error = "error: Unknown generator option: " + options[i].first;
+      return false;
+    }
   }
 
+  // -----------------------------------------------------------------
+
   // Validate the objc prefix/package pairing.
-  if (!ValidateObjCClassPrefix(file, error)) {
+  if (!ValidateObjCClassPrefix(file, generation_options, error)) {
     // *error will have been filled in.
     return false;
   }
 
-  FileGenerator file_generator(file);
+  FileGenerator file_generator(file, generation_options);
   string filepath = FilePath(file);
 
   // Generate header.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index b724d35..77a378c 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -58,6 +58,14 @@
 namespace compiler {
 namespace objectivec {
 
+Options::Options() {
+  // Default is the value of the env for the package prefixes.
+  const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
+  if (file_path) {
+    expected_prefixes_path = file_path;
+  }
+}
+
 namespace {
 
 hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) {
@@ -883,33 +891,33 @@
     StringPiece prefix(line, offset + 1, line.length() - offset - 1);
     TrimWhitespace(&package);
     TrimWhitespace(&prefix);
-    // Don't really worry about error checking the the package/prefix for
+    // Don't really worry about error checking the package/prefix for
     // being valid.  Assume the file is validated when it is created/edited.
     (*prefix_map_)[package.ToString()] = prefix.ToString();
   }
   return true;
 }
 
-bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map,
-                                 string* out_expect_file_path,
+bool LoadExpectedPackagePrefixes(const Options &generation_options,
+                                 map<string, string>* prefix_map,
                                  string* out_error) {
-  const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
-  if (file_path == NULL) {
+  if (generation_options.expected_prefixes_path.empty()) {
     return true;
   }
 
   int fd;
   do {
-    fd = open(file_path, O_RDONLY);
+    fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY);
   } while (fd < 0 && errno == EINTR);
   if (fd < 0) {
     *out_error =
-        string(file_path) + ":0:0: error: Unable to open." + strerror(errno);
+        string("error: Unable to open \"") +
+        generation_options.expected_prefixes_path +
+        "\", " + strerror(errno);
     return false;
   }
   io::FileInputStream file_stream(fd);
   file_stream.SetCloseOnDelete(true);
-  *out_expect_file_path = file_path;
 
   Parser parser(prefix_map);
   const void* buf;
@@ -920,8 +928,9 @@
     }
 
     if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
-      *out_error = string(file_path) + ":" + SimpleItoa(parser.last_line()) +
-                   ":0: error: " + parser.error_str();
+      *out_error =
+          string("error: ") + generation_options.expected_prefixes_path +
+          " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
       return false;
     }
   }
@@ -930,48 +939,25 @@
 
 }  // namespace
 
-bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) {
+bool ValidateObjCClassPrefix(const FileDescriptor* file,
+                             const Options& generation_options,
+                             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.
 
-  // First Check: Warning - if there is a prefix, ensure it is is a reasonable
-  // value according to Apple's rules.
-  if (prefix.length()) {
-    if (!ascii_isupper(prefix[0])) {
-      cerr << endl
-           << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
-           << prefix << "\";' in '" << file->name() << "';"
-           << " it should start with a capital letter." << endl;
-      cerr.flush();
-    }
-    if (prefix.length() < 3) {
-      cerr << endl
-           << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
-           << prefix << "\";' in '" << file->name() << "';"
-           << " Apple recommends they should be at least 3 characters long."
-           << endl;
-      cerr.flush();
-    }
-  }
-
   // Load any expected package prefixes to validate against those.
   map<string, string> expected_package_prefixes;
-  string expect_file_path;
-  if (!LoadExpectedPackagePrefixes(&expected_package_prefixes,
-                                   &expect_file_path, out_error)) {
+  if (!LoadExpectedPackagePrefixes(generation_options,
+                                   &expected_package_prefixes,
+                                   out_error)) {
     return false;
   }
 
-  // If there are no expected prefixes, out of here.
-  if (expected_package_prefixes.size() == 0) {
-    return true;
-  }
-
-  // Second Check: Error - See if there was an expected prefix for the package
-  // and report if it doesn't match.
+  // 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 =
       expected_package_prefixes.find(package);
   if (package_match != expected_package_prefixes.end()) {
@@ -981,7 +967,7 @@
       return true;
     } else {
       // ...it didn't match!
-      *out_error = "protoc:0: error: Expected 'option objc_class_prefix = \"" +
+      *out_error = "error: Expected 'option objc_class_prefix = \"" +
                    package_match->second + "\";' in '" + file->name() + "'";
       if (prefix.length()) {
         *out_error += "; but found '" + prefix + "' instead";
@@ -991,32 +977,57 @@
     }
   }
 
-  // Third Check: Error - If there was a prefix make sure it wasn't expected
-  // for a different package instead (overlap is allowed, but it has to be
-  // listed as an expected overlap).
-  if (prefix.length()) {
-    for (map<string, string>::iterator i = expected_package_prefixes.begin();
-         i != expected_package_prefixes.end(); ++i) {
-      if (i->second == prefix) {
-        *out_error =
-            "protoc:0: 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 (" +
-            expect_file_path + ").";
-        return false;  // Only report first usage of the prefix.
-      }
+  // If there was no prefix option, we're done at this point.
+  if (prefix.length() == 0) {
+    // 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.
     }
   }
 
-  // Fourth Check: Warning - If there was a prefix, and it wasn't expected,
-  // issue a warning suggesting it gets added to the file.
-  if (prefix.length()) {
+  // 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).
+  if (!ascii_isupper(prefix[0])) {
     cerr << endl
-         << "protoc:0: warning: Found 'option objc_class_prefix = \"" << prefix
-         << "\";' in '" << file->name() << "';"
-         << " should you add it to the expected prefixes file ("
-         << expect_file_path << ")?" << endl;
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " it should start with a capital letter." << endl;
+    cerr.flush();
+  }
+  if (prefix.length() < 3) {
+    // Apple reserves 2 character prefixes for themselves. They do use some
+    // 3 character prefixes, but they haven't updated the rules/docs.
+    cerr << endl
+         << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
+         << prefix << "\";' in '" << file->name() << "';"
+         << " Apple recommends they should be at least 3 characters long."
+         << endl;
+    cerr.flush();
+  }
+
+  // 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()) {
+    cerr << endl
+         << "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;
     cerr.flush();
   }
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index 072a2e5..5b2dd19 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -42,6 +42,12 @@
 namespace compiler {
 namespace objectivec {
 
+// Generator options (see objectivec_generator.cc for a description of each):
+struct Options {
+  Options();
+  string expected_prefixes_path;
+};
+
 // Strips ".proto" or ".protodevel" from the end of a filename.
 string StripProto(const string& filename);
 
@@ -64,7 +70,7 @@
 
 // Gets the name of the root class we'll generate in the file.  This class
 // is not meant for external consumption, but instead contains helpers that
-// the rest of the the classes need
+// the rest of the classes need
 string FileClassName(const FileDescriptor* file);
 
 // These return the fully-qualified class name corresponding to the given
@@ -145,10 +151,12 @@
 // 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, string *out_error);
+bool ValidateObjCClassPrefix(const FileDescriptor* file,
+                             const Options& generation_options,
+                             string* out_error);
 
 // Generate decode data needed for ObjC's GPBDecodeTextFormatName() to transform
-// the input into the the expected output.
+// the input into the expected output.
 class LIBPROTOC_EXPORT TextFormatDecodeData {
  public:
   TextFormatDecodeData() {}
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
index 2987f3d..2751e93 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -84,13 +84,14 @@
 
 }  // namespace
 
-MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor)
-    : RepeatedFieldGenerator(descriptor) {
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+                                     const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
   const FieldDescriptor* key_descriptor =
       descriptor->message_type()->FindFieldByName("key");
   const FieldDescriptor* value_descriptor =
       descriptor->message_type()->FindFieldByName("value");
-  value_field_generator_.reset(FieldGenerator::Make(value_descriptor));
+  value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options));
 
   // Pull over some variables_ from the value.
   variables_["field_type"] = value_field_generator_->variable("field_type");
@@ -117,16 +118,27 @@
   variables_["fieldflags"] = BuildFlagsString(field_flags);
 
   ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
-  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+  const bool value_is_object_type =
       ((value_objc_type == OBJECTIVECTYPE_STRING) ||
        (value_objc_type == OBJECTIVECTYPE_DATA) ||
-       (value_objc_type == OBJECTIVECTYPE_MESSAGE))) {
+       (value_objc_type == OBJECTIVECTYPE_MESSAGE));
+  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
+      value_is_object_type) {
     variables_["array_storage_type"] = "NSMutableDictionary";
+    variables_["array_property_type"] =
+        "NSMutableDictionary<NSString*, " +
+        value_field_generator_->variable("storage_type") + "*>";
   } else {
-    string base_name = MapEntryTypeName(key_descriptor, true);
-    base_name += MapEntryTypeName(value_descriptor, false);
-    base_name += "Dictionary";
-    variables_["array_storage_type"] = "GPB" + base_name;
+    string class_name("GPB");
+    class_name += MapEntryTypeName(key_descriptor, true);
+    class_name += MapEntryTypeName(value_descriptor, false);
+    class_name += "Dictionary";
+    variables_["array_storage_type"] = class_name;
+    if (value_is_object_type) {
+      variables_["array_property_type"] =
+          class_name + "<" +
+          value_field_generator_->variable("storage_type") + "*>";
+    }
   }
 }
 
@@ -138,15 +150,9 @@
   // values in the map are.
   const FieldDescriptor* value_descriptor =
       descriptor_->message_type()->FindFieldByName("value");
-  ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
-  if ((value_objc_type == OBJECTIVECTYPE_MESSAGE) ||
-      (value_objc_type == OBJECTIVECTYPE_DATA) ||
-      (value_objc_type == OBJECTIVECTYPE_STRING) ||
-      (value_objc_type == OBJECTIVECTYPE_ENUM)) {
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
     variables_["array_comment"] =
         "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
-  } else {
-    variables_["array_comment"] = "";
   }
 }
 
@@ -157,6 +163,19 @@
   value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer);
 }
 
+void MapFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  const FieldDescriptor* value_descriptor =
+      descriptor_->message_type()->FindFieldByName("value");
+  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
+    const string& value_storage_type =
+        value_field_generator_->variable("storage_type");
+    fwd_decls->insert("@class " + value_storage_type);
+  }
+}
+
+
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
index 173541f..7351ea0 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
@@ -41,18 +41,22 @@
 namespace objectivec {
 
 class MapFieldGenerator : public RepeatedFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  public:
   virtual void FinishInitialization(void);
   virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const;
 
  protected:
-  explicit MapFieldGenerator(const FieldDescriptor* descriptor);
+  MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
   virtual ~MapFieldGenerator();
 
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
  private:
   scoped_ptr<FieldGenerator> value_field_generator_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index 32671d4..e0ea8bd 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -174,10 +174,11 @@
 }  // namespace
 
 MessageGenerator::MessageGenerator(const string& root_classname,
-                                   const Descriptor* descriptor)
+                                   const Descriptor* descriptor,
+                                   const Options& options)
     : root_classname_(root_classname),
       descriptor_(descriptor),
-      field_generators_(descriptor),
+      field_generators_(descriptor, options),
       class_name_(ClassName(descriptor_)) {
   for (int i = 0; i < descriptor_->extension_count(); i++) {
     extension_generators_.push_back(
@@ -196,7 +197,9 @@
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     MessageGenerator* generator =
-        new MessageGenerator(root_classname_, descriptor_->nested_type(i));
+        new MessageGenerator(root_classname_,
+                             descriptor_->nested_type(i),
+                             options);
     nested_message_generators_.push_back(generator);
   }
 }
@@ -230,11 +233,6 @@
   if (!IsMapEntryMessage(descriptor_)) {
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
-      // If it is a the field is repeated, the type will be and *Array, and we
-      // don't need any forward decl.
-      if (fieldDescriptor->is_repeated()) {
-        continue;
-      }
       field_generators_.get(fieldDescriptor)
           .DetermineForwardDeclarations(fwd_decls);
     }
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h
index 06b536f..8565e76 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h
@@ -54,7 +54,9 @@
 
 class MessageGenerator {
  public:
-  MessageGenerator(const string& root_classname, const Descriptor* descriptor);
+  MessageGenerator(const string& root_classname,
+                   const Descriptor* descriptor,
+                   const Options& options);
   ~MessageGenerator();
 
   void GenerateStaticVariablesInitialization(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
index f2ce4e5..d6ccd6d 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
@@ -58,8 +58,9 @@
 
 }  // namespace
 
-MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor)
-    : ObjCObjFieldGenerator(descriptor) {
+MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
+                                             const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
   SetMessageVariables(descriptor, &variables_);
 }
 
@@ -67,6 +68,7 @@
 
 void MessageFieldGenerator::DetermineForwardDeclarations(
     set<string>* fwd_decls) const {
+  ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls);
   // Class name is already in "storage_type".
   fwd_decls->insert("@class " + variable("storage_type"));
 }
@@ -82,14 +84,24 @@
 }
 
 RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : RepeatedFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
   SetMessageVariables(descriptor, &variables_);
   variables_["array_storage_type"] = "NSMutableArray";
+  variables_["array_property_type"] =
+      "NSMutableArray<" + variables_["storage_type"] + "*>";
 }
 
 RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
 
+void RepeatedMessageFieldGenerator::DetermineForwardDeclarations(
+    set<string>* fwd_decls) const {
+  RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
+  // Class name is already in "storage_type".
+  fwd_decls->insert("@class " + variable("storage_type"));
+}
+
+
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
index 708ea56..d2dba15 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
@@ -41,10 +41,12 @@
 namespace objectivec {
 
 class MessageFieldGenerator : public ObjCObjFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  protected:
-  explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+  MessageFieldGenerator(const FieldDescriptor* descriptor,
+                        const Options& options);
   virtual ~MessageFieldGenerator();
   virtual bool WantsHasProperty(void) const;
 
@@ -56,12 +58,17 @@
 };
 
 class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  protected:
-  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+  RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                                const Options& options);
   virtual ~RepeatedMessageFieldGenerator();
 
+ public:
+  virtual void DetermineForwardDeclarations(set<string>* fwd_decls) const;
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
 };
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
index c185b66..ea7f1b9 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
@@ -74,7 +74,7 @@
     case OBJECTIVECTYPE_ENUM:
       return "int32_t";
     case OBJECTIVECTYPE_MESSAGE:
-      return NULL;
+      return NULL;  // Messages go through objectivec_message_field.cc|h.
   }
 
   // Some compilers report reaching end of function even though all cases of
@@ -107,7 +107,8 @@
     case OBJECTIVECTYPE_ENUM:
       return "Enum";
     case OBJECTIVECTYPE_MESSAGE:
-      return "";  // Want NSArray
+      // Want NSArray (but goes through objectivec_message_field.cc|h).
+      return "";
   }
 
   // Some compilers report reaching end of function even though all cases of
@@ -126,16 +127,16 @@
 }  // namespace
 
 PrimitiveFieldGenerator::PrimitiveFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : SingleFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : SingleFieldGenerator(descriptor, options) {
   SetPrimitiveVariables(descriptor, &variables_);
 }
 
 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
 
 PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : ObjCObjFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : ObjCObjFieldGenerator(descriptor, options) {
   SetPrimitiveVariables(descriptor, &variables_);
   variables_["property_storage_attribute"] = "copy";
 }
@@ -143,8 +144,8 @@
 PrimitiveObjFieldGenerator::~PrimitiveObjFieldGenerator() {}
 
 RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
-    const FieldDescriptor* descriptor)
-    : RepeatedFieldGenerator(descriptor) {
+    const FieldDescriptor* descriptor, const Options& options)
+    : RepeatedFieldGenerator(descriptor, options) {
   SetPrimitiveVariables(descriptor, &variables_);
 
   string base_name = PrimitiveArrayTypeName(descriptor);
@@ -152,19 +153,13 @@
     variables_["array_storage_type"] = "GPB" + base_name + "Array";
   } else {
     variables_["array_storage_type"] = "NSMutableArray";
+    variables_["array_property_type"] =
+        "NSMutableArray<" + variables_["storage_type"] + "*>";
   }
 }
 
 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
 
-void RepeatedPrimitiveFieldGenerator::FinishInitialization(void) {
-  RepeatedFieldGenerator::FinishInitialization();
-  if (IsPrimitiveType(descriptor_)) {
-    // No comment needed for primitive types.
-    variables_["array_comment"] = "";
-  }
-}
-
 }  // namespace objectivec
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
index 9bb7934..87139af 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
@@ -41,10 +41,12 @@
 namespace objectivec {
 
 class PrimitiveFieldGenerator : public SingleFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  protected:
-  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                          const Options& options);
   virtual ~PrimitiveFieldGenerator();
 
  private:
@@ -52,10 +54,12 @@
 };
 
 class PrimitiveObjFieldGenerator : public ObjCObjFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  protected:
-  explicit PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor);
+  PrimitiveObjFieldGenerator(const FieldDescriptor* descriptor,
+                             const Options& options);
   virtual ~PrimitiveObjFieldGenerator();
 
  private:
@@ -63,12 +67,13 @@
 };
 
 class RepeatedPrimitiveFieldGenerator : public RepeatedFieldGenerator {
-  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field);
+  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
+                                              const Options& options);
 
  protected:
-  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                  const Options& options);
   virtual ~RepeatedPrimitiveFieldGenerator();
-  virtual void FinishInitialization(void);
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 4d01842..90ded4d 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -458,6 +458,61 @@
 
 // ===================================================================
 
+bool Parser::ValidateEnum(const EnumDescriptorProto* proto) {
+  bool has_allow_alias = false;
+  bool allow_alias = false;
+
+  for (int i = 0; i < proto->options().uninterpreted_option_size(); i++) {
+    const UninterpretedOption option = proto->options().uninterpreted_option(i);
+    if (option.name_size() > 1) {
+      continue;
+    }
+    if (!option.name(0).is_extension() &&
+        option.name(0).name_part() == "allow_alias") {
+      has_allow_alias = true;
+      if (option.identifier_value() == "true") {
+        allow_alias = true;
+      }
+      break;
+    }
+  }
+
+  if (has_allow_alias && !allow_alias) {
+    string error =
+        "\"" + proto->name() +
+        "\" declares 'option allow_alias = false;' which has no effect. "
+        "Please remove the declaration.";
+    // This needlessly clutters declarations with nops.
+    AddError(error);
+    return false;
+  }
+
+  set<int> used_values;
+  bool has_duplicates = false;
+  for (int i = 0; i < proto->value_size(); ++i) {
+    const EnumValueDescriptorProto enum_value = proto->value(i);
+    if (used_values.find(enum_value.number()) != used_values.end()) {
+      has_duplicates = true;
+      break;
+    } else {
+      used_values.insert(enum_value.number());
+    }
+  }
+  if (allow_alias && !has_duplicates) {
+    string error =
+        "\"" + proto->name() +
+        "\" declares support for enum aliases but no enum values share field "
+        "numbers. Please remove the unnecessary 'option allow_alias = true;' "
+        "declaration.";
+    // Generate an error if an enum declares support for duplicate enum values
+    // and does not use it protect future authors.
+    AddError(error);
+    return false;
+  }
+
+  return true;
+}
+
 bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
   input_ = input;
   had_errors_ = false;
@@ -489,9 +544,9 @@
       // Store the syntax into the file.
       if (file != NULL) file->set_syntax(syntax_identifier_);
     } else if (!stop_after_syntax_identifier_) {
-      GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
-                   << "Please use 'syntax = \"proto2\";' or "
-                   << "'syntax = \"proto3\";' to specify a syntax "
+      GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: "
+                   << file->name() << ". Please use 'syntax = \"proto2\";' "
+                   << "or 'syntax = \"proto3\";' to specify a syntax "
                    << "version. (Defaulted to proto2 syntax.)";
       syntax_identifier_ = "proto2";
     }
@@ -993,6 +1048,9 @@
       // We intentionally pass field_location rather than location here, since
       // the default value is not actually an option.
       DO(ParseDefaultAssignment(field, field_location, containing_file));
+    } else if (LookingAt("json_name")) {
+      // Like default value, this "json_name" is not an actual option.
+      DO(ParseJsonName(field, field_location, containing_file));
     } else {
       DO(ParseOption(field->mutable_options(), location,
                      containing_file, OPTION_ASSIGNMENT));
@@ -1140,6 +1198,28 @@
   return true;
 }
 
+bool Parser::ParseJsonName(
+    FieldDescriptorProto* field,
+    const LocationRecorder& field_location,
+    const FileDescriptorProto* containing_file) {
+  if (field->has_json_name()) {
+    AddError("Already set option \"json_name\".");
+    field->clear_json_name();
+  }
+
+  DO(Consume("json_name"));
+  DO(Consume("="));
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kJsonNameFieldNumber);
+  location.RecordLegacyLocation(
+      field, DescriptorPool::ErrorCollector::OPTION_VALUE);
+  DO(ConsumeString(field->mutable_json_name(),
+                   "Expected string for JSON name."));
+  return true;
+}
+
+
 bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
                                  const LocationRecorder& part_location,
                                  const FileDescriptorProto* containing_file) {
@@ -1602,6 +1682,9 @@
   }
 
   DO(ParseEnumBlock(enum_type, enum_location, containing_file));
+
+  DO(ValidateEnum(enum_type));
+
   return true;
 }
 
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 007b001..2c561c2 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -439,6 +439,10 @@
                               const LocationRecorder& field_location,
                               const FileDescriptorProto* containing_file);
 
+  bool ParseJsonName(FieldDescriptorProto* field,
+                     const LocationRecorder& field_location,
+                     const FileDescriptorProto* containing_file);
+
   enum OptionStyle {
     OPTION_ASSIGNMENT,  // just "name = value"
     OPTION_STATEMENT    // "option name = value;"
@@ -494,6 +498,8 @@
   }
 
 
+  bool ValidateEnum(const EnumDescriptorProto* proto);
+
   // =================================================================
 
   io::Tokenizer* input_;
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index cc6f1ef..1d623dd 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -452,6 +452,20 @@
 #undef ETC
 }
 
+TEST_F(ParseMessageTest, FieldJsonName) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  optional string foo = 1 [json_name = \"@type\"];\n"
+    "}\n",
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field {\n"
+    "    name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
+    "    json_name: \"@type\"\n"
+    "  }\n"
+    "}\n");
+}
+
 TEST_F(ParseMessageTest, FieldOptions) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -1126,6 +1140,22 @@
     "6:36: Integer out of range.\n");
 }
 
+TEST_F(ParseErrorTest, JsonNameNotString) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  optional string foo = 1 [json_name=1];\n"
+    "}\n",
+    "1:37: Expected string for JSON name.\n");
+}
+
+TEST_F(ParseErrorTest, DuplicateJsonName) {
+  ExpectHasErrors(
+    "message TestMessage {\n"
+    "  optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
+    "}\n",
+    "1:41: Already set option \"json_name\".\n");
+}
+
 TEST_F(ParseErrorTest, EnumValueOutOfRange) {
   ExpectHasErrors(
     "enum TestEnum {\n"
@@ -1140,6 +1170,29 @@
     "4:19: Integer out of range.\n");
 }
 
+TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
+  ExpectHasErrors(
+    "enum Foo {\n"
+    "  option allow_alias = false;\n"
+    "  BAR = 1;\n"
+    "  BAZ = 2;\n"
+    "}\n",
+    "5:0: \"Foo\" declares 'option allow_alias = false;' which has no effect. "
+    "Please remove the declaration.\n");
+}
+
+TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
+  ExpectHasErrors(
+    "enum Foo {\n"
+    "  option allow_alias = true;\n"
+    "  BAR = 1;\n"
+    "  BAZ = 2;\n"
+    "}\n",
+    "5:0: \"Foo\" declares support for enum aliases but no enum values share "
+    "field numbers. Please remove the unnecessary 'option allow_alias = true;' "
+    "declaration.\n");
+}
+
 TEST_F(ParseErrorTest, DefaultValueMissing) {
   ExpectHasErrors(
     "message TestMessage {\n"
@@ -1809,6 +1862,8 @@
       "// Detached comment before TestMessage1.\n"
       "\n"
       "// Message comment.\n"
+      "//\n"
+      "// More detail in message comment.\n"
       "message TestMessage1 {\n"
       "\n"
       "  // Detached comment before foo.\n"
@@ -1860,11 +1915,6 @@
       pool_.BuildFileCollectingErrors(parsed_desc, &collector);
   ASSERT_TRUE(descriptor != NULL);
 
-  DebugStringOptions debug_string_options;
-  debug_string_options.include_comments = true;
-  const string debug_string =
-      descriptor->DebugStringWithOptions(debug_string_options);
-
   // Ensure that each of the comments appears somewhere in the DebugString().
   // We don't test the exact comment placement or formatting, because we do not
   // want to be too fragile here.
@@ -1875,6 +1925,7 @@
     "Package comment.",
     "Detached comment before TestMessage1.",
     "Message comment.",
+    "More detail in message comment.",
     "Detached comment before foo.",
     "Field comment",
     "Detached comment before NestedMessage.",
@@ -1889,11 +1940,28 @@
     "RPC comment",
   };
 
-  for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
-    string::size_type found_pos = debug_string.find(expected_comments[i]);
-    EXPECT_TRUE(found_pos != string::npos)
-        << "\"" << expected_comments[i] << "\" not found.";
+  DebugStringOptions debug_string_options;
+  debug_string_options.include_comments = true;
+
+  {
+    const string debug_string =
+        descriptor->DebugStringWithOptions(debug_string_options);
+
+    for (int i = 0; i < GOOGLE_ARRAYSIZE(expected_comments); ++i) {
+      string::size_type found_pos = debug_string.find(expected_comments[i]);
+      EXPECT_TRUE(found_pos != string::npos)
+          << "\"" << expected_comments[i] << "\" not found.";
+    }
+
+    // Result of DebugStringWithOptions should be parseable.
+    SetupParser(debug_string.c_str());
+    FileDescriptorProto parsed;
+    parser_->Parse(input_.get(), &parsed);
+    EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
+    ASSERT_EQ("", error_collector_.text_)
+        << "Failed to parse:\n" << debug_string;
   }
+
 }
 
 TEST_F(ParseDescriptorDebugTest, TestMaps) {
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 0792d87..a2da8ee 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/compiler/plugin.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/compiler/plugin.pb.h"
+#include <google/protobuf/compiler/plugin.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -172,11 +173,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
 const int CodeGeneratorRequest::kParameterFieldNumber;
 const int CodeGeneratorRequest::kProtoFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorRequest::CodeGeneratorRequest()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -656,11 +657,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorResponse_File::kNameFieldNumber;
 const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
 const int CodeGeneratorResponse_File::kContentFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorResponse_File::CodeGeneratorResponse_File()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1021,10 +1022,10 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int CodeGeneratorResponse::kErrorFieldNumber;
 const int CodeGeneratorResponse::kFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 CodeGeneratorResponse::CodeGeneratorResponse()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ab79bda..0a03e97 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -27,7 +27,7 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
 // @@protoc_insertion_point(includes)
 
 namespace google {
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index e81af70..4d500f9 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -28,6 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+//#PY25 compatible generated code for GAE.
 // Copyright 2007 Google Inc. All Rights Reserved.
 // Author: robinson@google.com (Will Robinson)
 //
@@ -166,6 +167,7 @@
   printer->Print(
       "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
       "# source: $filename$\n"
+      "\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))"  //##PY25
       "\n",
       "filename", file->name());
   if (HasTopLevelEnums(file)) {
@@ -257,9 +259,12 @@
     case FieldDescriptor::CPPTYPE_ENUM:
       return SimpleItoa(field.default_value_enum()->number());
     case FieldDescriptor::CPPTYPE_STRING:
-      return "b\"" + CEscape(field.default_value_string()) +
-             (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
-               "\".decode('utf-8')");
+//##!PY25      return "b\"" + CEscape(field.default_value_string()) +
+//##!PY25             (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
+//##!PY25               "\".decode('utf-8')");
+      return "_b(\"" + CEscape(field.default_value_string()) +  //##PY25
+             (field.type() != FieldDescriptor::TYPE_STRING ? "\")" :  //##PY25
+               "\").decode('utf-8')");  //##PY25
     case FieldDescriptor::CPPTYPE_MESSAGE:
       return "None";
   }
@@ -385,7 +390,8 @@
   printer_->Print(m, file_descriptor_template);
   printer_->Indent();
   printer_->Print(
-      "serialized_pb=b'$value$'\n",
+//##!PY25      "serialized_pb=b'$value$'\n",
+      "serialized_pb=_b('$value$')\n",  //##PY25
       "value", strings::CHexEscape(file_descriptor_serialized_));
   if (file_->dependency_count() != 0) {
     printer_->Print(",\ndependencies=[");
@@ -1029,8 +1035,10 @@
     return "None";
   } else {
     string full_class_name = "descriptor_pb2." + class_name;
-    return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
-        + CEscape(serialized_options)+ "')";
+//##!PY25    return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
+//##!PY25        + CEscape(serialized_options)+ "')";
+    return "_descriptor._ParseOptions(" + full_class_name + "(), _b('"  //##PY25
+        + CEscape(serialized_options)+ "'))";  //##PY25
   }
 }
 
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 8542992..a30ac30 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -47,6 +47,7 @@
 #include <google/protobuf/message.h>
 #include <google/protobuf/stubs/substitute.h>
 
+
 namespace google {
 namespace protobuf {
 namespace compiler {
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 5256b83..78a3461 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -34,6 +34,10 @@
 
 #include <google/protobuf/stubs/hash.h>
 #include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <set>
 #include <string>
 #include <vector>
@@ -152,7 +156,7 @@
 
 static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
 
-#ifndef _MSC_VER  // MSVC doesn't need these and won't even accept them.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldDescriptor::kMaxNumber;
 const int FieldDescriptor::kFirstReservedNumber;
 const int FieldDescriptor::kLastReservedNumber;
@@ -556,7 +560,7 @@
   ~FileDescriptorTables();
 
   // Empty table, used with placeholder files.
-  static const FileDescriptorTables kEmpty;
+  inline static const FileDescriptorTables& GetEmptyInstance();
 
   // -----------------------------------------------------------------
   // Finding items.
@@ -661,7 +665,32 @@
 
 FileDescriptorTables::~FileDescriptorTables() {}
 
-const FileDescriptorTables FileDescriptorTables::kEmpty;
+namespace {
+
+FileDescriptorTables* file_descriptor_tables_ = NULL;
+GOOGLE_PROTOBUF_DECLARE_ONCE(file_descriptor_tables_once_init_);
+
+void DeleteFileDescriptorTables() {
+  delete file_descriptor_tables_;
+  file_descriptor_tables_ = NULL;
+}
+
+void InitFileDescriptorTables() {
+  file_descriptor_tables_ = new FileDescriptorTables();
+  internal::OnShutdown(&DeleteFileDescriptorTables);
+}
+
+inline void InitFileDescriptorTablesOnce() {
+  ::google::protobuf::GoogleOnceInit(
+      &file_descriptor_tables_once_init_, &InitFileDescriptorTables);
+}
+
+}  // anonymous namespace
+
+inline const FileDescriptorTables& FileDescriptorTables::GetEmptyInstance() {
+  InitFileDescriptorTablesOnce();
+  return *file_descriptor_tables_;
+}
 
 void DescriptorPool::Tables::AddCheckpoint() {
   checkpoints_.push_back(CheckPoint(this));
@@ -1726,6 +1755,20 @@
   }
 }
 
+void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const {
+  if (message_type_count() != proto->message_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < message_type_count(); i++) {
+    message_type(i)->CopyJsonNameTo(proto->mutable_message_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
 void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
   if (source_code_info_ &&
       source_code_info_ != &SourceCodeInfo::default_instance()) {
@@ -1770,9 +1813,30 @@
   }
 }
 
+void Descriptor::CopyJsonNameTo(DescriptorProto* proto) const {
+  if (field_count() != proto->field_size() ||
+      nested_type_count() != proto->nested_type_size() ||
+      extension_count() != proto->extension_size()) {
+    GOOGLE_LOG(ERROR) << "Cannot copy json_name to a proto of a different size.";
+    return;
+  }
+  for (int i = 0; i < field_count(); i++) {
+    field(i)->CopyJsonNameTo(proto->mutable_field(i));
+  }
+  for (int i = 0; i < nested_type_count(); i++) {
+    nested_type(i)->CopyJsonNameTo(proto->mutable_nested_type(i));
+  }
+  for (int i = 0; i < extension_count(); i++) {
+    extension(i)->CopyJsonNameTo(proto->mutable_extension(i));
+  }
+}
+
 void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
   proto->set_name(name());
   proto->set_number(number());
+  if (has_json_name_) {
+    proto->set_json_name(json_name());
+  }
 
   // Some compilers do not allow static_cast directly between two enum types,
   // so we must cast to int first.
@@ -1819,6 +1883,10 @@
   }
 }
 
+void FieldDescriptor::CopyJsonNameTo(FieldDescriptorProto* proto) const {
+  proto->set_json_name(json_name());
+}
+
 void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
   proto->set_name(name());
 }
@@ -2007,6 +2075,7 @@
   }
 
  private:
+
   bool have_source_loc_;
   SourceLocation source_loc_;
   DebugStringOptions options_;
@@ -2908,7 +2977,8 @@
                    const ServiceDescriptor* parent,
                    MethodDescriptor* result);
 
-  void LogUnusedDependency(const FileDescriptor* result);
+  void LogUnusedDependency(const FileDescriptorProto& proto,
+                           const FileDescriptor* result);
 
   // Must be run only after building.
   //
@@ -3492,7 +3562,7 @@
   placeholder->package_ = &internal::GetEmptyString();
   placeholder->pool_ = pool_;
   placeholder->options_ = &FileOptions::default_instance();
-  placeholder->tables_ = &FileDescriptorTables::kEmpty;
+  placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
   placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
   placeholder->is_placeholder_ = true;
   placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2;
@@ -3953,7 +4023,7 @@
 
 
   if (!unused_dependency_.empty()) {
-    LogUnusedDependency(result);
+    LogUnusedDependency(proto, result);
   }
 
   if (had_errors_) {
@@ -4100,6 +4170,7 @@
   }
 }
 
+
 void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
                                               const Descriptor* parent,
                                               FieldDescriptor* result,
@@ -4136,6 +4207,14 @@
       tables_->AllocateString(ToCamelCase(proto.name(),
                                           /* lower_first = */ true));
 
+  if (proto.has_json_name()) {
+    result->has_json_name_ = true;
+    result->json_name_ = tables_->AllocateString(proto.json_name());
+  } else {
+    result->has_json_name_ = false;
+    result->json_name_ = result->camelcase_name_;
+  }
+
   // Some compilers do not allow static_cast directly between two enum types,
   // so we must cast to int first.
   result->type_  = static_cast<FieldDescriptor::Type>(
@@ -4197,8 +4276,8 @@
           } else if (proto.default_value() == "nan") {
             result->default_value_float_ = numeric_limits<float>::quiet_NaN();
           } else  {
-            result->default_value_float_ =
-              io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
+            result->default_value_float_ = io::SafeDoubleToFloat(
+                io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos));
           }
           break;
         case FieldDescriptor::CPPTYPE_DOUBLE:
@@ -4370,6 +4449,7 @@
     AllocateOptions(proto.options(), result);
   }
 
+
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 }
@@ -5040,6 +5120,20 @@
   }
 }
 
+static string ToLowercaseWithoutUnderscores(const string& name) {
+  string result;
+  for (int i = 0; i < name.size(); ++i) {
+    if (name[i] != '_') {
+      if (name[i] >= 'A' && name[i] <= 'Z') {
+        result.push_back(name[i] - 'A' + 'a');
+      } else {
+        result.push_back(name[i]);
+      }
+    }
+  }
+  return result;
+}
+
 void DescriptorBuilder::ValidateProto3Message(
     Descriptor* message, const DescriptorProto& proto) {
   for (int i = 0; i < message->nested_type_count(); ++i) {
@@ -5067,6 +5161,25 @@
              DescriptorPool::ErrorCollector::OTHER,
              "MessageSet is not supported in proto3.");
   }
+
+  // In proto3, we reject field names if they conflict in camelCase.
+  // Note that we currently enforce a stricter rule: Field names must be
+  // unique after being converted to lowercase with underscores removed.
+  map<string, const FieldDescriptor*> name_to_field;
+  for (int i = 0; i < message->field_count(); ++i) {
+    string lowercase_name = ToLowercaseWithoutUnderscores(
+        message->field(i)->name());
+    if (name_to_field.find(lowercase_name) != name_to_field.end()) {
+      AddError(message->full_name(), proto,
+               DescriptorPool::ErrorCollector::OTHER,
+               "The JSON camcel-case name of field \"" +
+               message->field(i)->name() + "\" conflicts with field \"" +
+               name_to_field[lowercase_name]->name() + "\". This is not " +
+               "allowed in proto3.");
+    } else {
+      name_to_field[lowercase_name] = message->field(i);
+    }
+  }
 }
 
 void DescriptorBuilder::ValidateProto3Field(
@@ -5449,11 +5562,19 @@
     // UnknownFieldSet and wait there until the message is parsed by something
     // that does know about the options.
     string buf;
-    options->AppendToString(&buf);
-    GOOGLE_CHECK(options->ParseFromString(buf))
+    GOOGLE_CHECK(options->AppendPartialToString(&buf))
+        << "Protocol message could not be serialized.";
+    GOOGLE_CHECK(options->ParsePartialFromString(buf))
         << "Protocol message serialized itself in invalid fashion.";
+    if (!options->IsInitialized()) {
+      builder_->AddWarning(
+          options_to_interpret->element_name, *original_options,
+          DescriptorPool::ErrorCollector::OTHER,
+          "Options could not be fully parsed using the proto descriptors "
+          "compiled into this binary. Missing required fields: " +
+          options->InitializationErrorString());
+    }
   }
-
   return !failed;
 }
 
@@ -5602,7 +5723,7 @@
 
   // First set the value on the UnknownFieldSet corresponding to the
   // innermost message.
-  scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
+  google::protobuf::scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
   if (!SetOptionValue(field, unknown_fields.get())) {
     return false;  // SetOptionValue() already added the error.
   }
@@ -5612,7 +5733,8 @@
   for (vector<const FieldDescriptor*>::reverse_iterator iter =
            intermediate_fields.rbegin();
        iter != intermediate_fields.rend(); ++iter) {
-    scoped_ptr<UnknownFieldSet> parent_unknown_fields(new UnknownFieldSet());
+    google::protobuf::scoped_ptr<UnknownFieldSet> parent_unknown_fields(
+        new UnknownFieldSet());
     switch ((*iter)->type()) {
       case FieldDescriptor::TYPE_MESSAGE: {
         io::StringOutputStream outstr(
@@ -5998,7 +6120,7 @@
   }
 
   const Descriptor* type = option_field->message_type();
-  scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
+  google::protobuf::scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
   GOOGLE_CHECK(dynamic.get() != NULL)
       << "Could not create an instance of " << option_field->DebugString();
 
@@ -6106,7 +6228,8 @@
   }
 }
 
-void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
+void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
+                                            const FileDescriptor* result) {
 
   if (!unused_dependency_.empty()) {
     std::set<string> annotation_extensions;
@@ -6132,9 +6255,9 @@
       }
       // Log warnings for unused imported files.
       if (i == (*it)->extension_count()) {
-        GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name()
-                     << "\" imports \"" << (*it)->name()
-                     << "\" which is not used.";
+        string error_message = "Import " + (*it)->name() + " but not used.";
+        AddWarning((*it)->name(), proto, DescriptorPool::ErrorCollector::OTHER,
+                   error_message);
       }
     }
   }
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 2ab316a..7e3a749 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -54,6 +54,10 @@
 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
 #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <set>
 #include <string>
 #include <vector>
@@ -111,8 +115,17 @@
 
 // Defined in generated_message_reflection.h.
 namespace internal {
-  class GeneratedMessageReflection;
-}
+class GeneratedMessageReflection;
+}  // namespace internal
+
+// Defined in command_line_interface.cc
+namespace compiler {
+class CommandLineInterface;
+}  // namespace compiler
+
+namespace descriptor_unittest {
+class DescriptorTest;
+}  // namespace descriptor_unittest
 
 // NB, all indices are zero-based.
 struct SourceLocation {
@@ -343,6 +356,12 @@
  private:
   typedef MessageOptions OptionsType;
 
+  // Allows tests to test CopyTo(proto, true).
+  friend class ::google::protobuf::descriptor_unittest::DescriptorTest;
+
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(DescriptorProto* proto) const;
+
   // Internal version of DebugString; controls the level of indenting for
   // correct depth. Takes |options| to control debug-string options, and
   // |include_opening_clause| to indicate whether the "message ... " part of the
@@ -484,6 +503,7 @@
 
   const string& name() const;        // Name of this field within the message.
   const string& full_name() const;   // Fully-qualified name of the field.
+  const string& json_name() const;   // JSON name of this field.
   const FileDescriptor* file() const;// File in which this field was defined.
   bool is_extension() const;         // Is this an extension field?
   int number() const;                // Declared tag number.
@@ -624,6 +644,9 @@
  private:
   typedef FieldOptions OptionsType;
 
+  // Fill the json_name field of FieldDescriptorProto.
+  void CopyJsonNameTo(FieldDescriptorProto* proto) const;
+
   // See Descriptor::DebugString().
   enum PrintLabelFlag { PRINT_LABEL, OMIT_LABEL };
   void DebugString(int depth, PrintLabelFlag print_label_flag,
@@ -645,6 +668,12 @@
   const string* full_name_;
   const string* lowercase_name_;
   const string* camelcase_name_;
+  // Whether the user has specified the json_name field option in the .proto
+  // file.
+  bool has_json_name_;
+  // If has_json_name_ is true, it's the value specified by the user.
+  // Otherwise, it has the same value as lowercase_name_.
+  const string* json_name_;
   const FileDescriptor* file_;
   int number_;
   Type type_;
@@ -1202,6 +1231,9 @@
   // Write the source code information of this FileDescriptor into the given
   // FileDescriptorProto.  See CopyTo() above.
   void CopySourceCodeInfoTo(FileDescriptorProto* proto) const;
+  // Fill the json_name field of FieldDescriptorProto for all fields. Can only
+  // be called after CopyTo().
+  void CopyJsonNameTo(FileDescriptorProto* proto) const;
 
   // See Descriptor::DebugString().
   string DebugString() const;
@@ -1559,7 +1591,7 @@
   // This class contains a lot of hash maps with complicated types that
   // we'd like to keep out of the header.
   class Tables;
-  scoped_ptr<Tables> tables_;
+  google::protobuf::scoped_ptr<Tables> tables_;
 
   bool enforce_dependencies_;
   bool allow_unknown_;
@@ -1613,11 +1645,12 @@
                                const Descriptor::ReservedRange*)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
 
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, json_name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
@@ -1657,7 +1690,7 @@
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
                                const EnumValueDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
@@ -1672,14 +1705,14 @@
 PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
                                const MethodDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
 
@@ -1693,7 +1726,7 @@
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
 
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index fe23c0a..ff0cfcf 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/descriptor.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/descriptor.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -92,6 +93,12 @@
 const ::google::protobuf::Descriptor* SourceCodeInfo_Location_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   SourceCodeInfo_Location_reflection_ = NULL;
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GeneratedCodeInfo_reflection_ = NULL;
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GeneratedCodeInfo_Annotation_reflection_ = NULL;
 
 }  // namespace
 
@@ -200,7 +207,7 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_),
       -1);
   FieldDescriptorProto_descriptor_ = file->message_type(3);
-  static const int FieldDescriptorProto_offsets_[9] = {
+  static const int FieldDescriptorProto_offsets_[10] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, label_),
@@ -209,6 +216,7 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, extendee_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, default_value_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, oneof_index_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, json_name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, options_),
   };
   FieldDescriptorProto_reflection_ =
@@ -519,6 +527,39 @@
       sizeof(SourceCodeInfo_Location),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_),
       -1);
+  GeneratedCodeInfo_descriptor_ = file->message_type(18);
+  static const int GeneratedCodeInfo_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, annotation_),
+  };
+  GeneratedCodeInfo_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GeneratedCodeInfo_descriptor_,
+      GeneratedCodeInfo::default_instance_,
+      GeneratedCodeInfo_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(GeneratedCodeInfo),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, _internal_metadata_),
+      -1);
+  GeneratedCodeInfo_Annotation_descriptor_ = GeneratedCodeInfo_descriptor_->nested_type(0);
+  static const int GeneratedCodeInfo_Annotation_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, path_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, source_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, begin_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, end_),
+  };
+  GeneratedCodeInfo_Annotation_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GeneratedCodeInfo_Annotation_descriptor_,
+      GeneratedCodeInfo_Annotation::default_instance_,
+      GeneratedCodeInfo_Annotation_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(GeneratedCodeInfo_Annotation),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _internal_metadata_),
+      -1);
 }
 
 namespace {
@@ -575,6 +616,10 @@
       SourceCodeInfo_descriptor_, &SourceCodeInfo::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       SourceCodeInfo_Location_descriptor_, &SourceCodeInfo_Location::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GeneratedCodeInfo_descriptor_, &GeneratedCodeInfo::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GeneratedCodeInfo_Annotation_descriptor_, &GeneratedCodeInfo_Annotation::default_instance());
 }
 
 }  // namespace
@@ -624,6 +669,10 @@
   delete SourceCodeInfo_reflection_;
   delete SourceCodeInfo_Location::default_instance_;
   delete SourceCodeInfo_Location_reflection_;
+  delete GeneratedCodeInfo::default_instance_;
+  delete GeneratedCodeInfo_reflection_;
+  delete GeneratedCodeInfo_Annotation::default_instance_;
+  delete GeneratedCodeInfo_Annotation_reflection_;
 }
 
 void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() {
@@ -663,101 +712,106 @@
     "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
     "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005"
     "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang"
-    "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024FieldD"
+    "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\274\005\n\024FieldD"
     "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003"
     " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi"
     "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*"
     ".google.protobuf.FieldDescriptorProto.Ty"
     "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022"
     "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t "
-    "\001(\005\022.\n\007options\030\010 \001(\0132\035.google.protobuf.F"
-    "ieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n"
-    "\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UI"
-    "NT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006"
-    "\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYP"
-    "E_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSA"
-    "GE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n"
-    "\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_"
-    "SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT"
-    "64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LAB"
-    "EL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n\024One"
-    "ofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023Enum"
-    "DescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002"
-    " \003(\0132).google.protobuf.EnumValueDescript"
-    "orProto\022-\n\007options\030\003 \001(\0132\034.google.protob"
-    "uf.EnumOptions\"l\n\030EnumValueDescriptorPro"
-    "to\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007opti"
-    "ons\030\003 \001(\0132!.google.protobuf.EnumValueOpt"
-    "ions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004name\030"
-    "\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.protobuf."
-    "MethodDescriptorProto\0220\n\007options\030\003 \001(\0132\037"
-    ".google.protobuf.ServiceOptions\"\301\001\n\025Meth"
-    "odDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput"
-    "_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007opti"
-    "ons\030\004 \001(\0132\036.google.protobuf.MethodOption"
-    "s\022\037\n\020client_streaming\030\005 \001(\010:\005false\022\037\n\020se"
-    "rver_streaming\030\006 \001(\010:\005false\"\252\005\n\013FileOpti"
-    "ons\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_"
-    "classname\030\010 \001(\t\022\"\n\023java_multiple_files\030\n"
-    " \001(\010:\005false\022,\n\035java_generate_equals_and_"
-    "hash\030\024 \001(\010:\005false\022%\n\026java_string_check_u"
-    "tf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001(\0162)"
-    ".google.protobuf.FileOptions.OptimizeMod"
-    "e:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_gener"
-    "ic_services\030\020 \001(\010:\005false\022$\n\025java_generic"
-    "_services\030\021 \001(\010:\005false\022\"\n\023py_generic_ser"
-    "vices\030\022 \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005"
-    "false\022\037\n\020cc_enable_arenas\030\037 \001(\010:\005false\022\031"
-    "\n\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_name"
-    "space\030% \001(\t\022\'\n\037javanano_use_deprecated_p"
-    "ackage\030& \001(\010\022C\n\024uninterpreted_option\030\347\007 "
-    "\003(\0132$.google.protobuf.UninterpretedOptio"
-    "n\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZ"
-    "E\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016Mes"
-    "sageOptions\022&\n\027message_set_wire_format\030\001"
-    " \001(\010:\005false\022.\n\037no_standard_descriptor_ac"
-    "cessor\030\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:"
-    "\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpret"
-    "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint"
-    "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptio"
-    "ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel"
-    "dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?"
-    "\n\006jstype\030\006 \001(\0162$.google.protobuf.FieldOp"
-    "tions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005f"
-    "alse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030"
-    "\n \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 "
-    "\003(\0132$.google.protobuf.UninterpretedOptio"
-    "n\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRI"
-    "NG_PIECE\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJ"
-    "S_STRING\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n"
-    "\013EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndep"
-    "recated\030\003 \001(\010:\005false\022C\n\024uninterpreted_op"
-    "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
-    "tedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions"
-    "\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uninterpr"
-    "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni"
-    "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOp"
-    "tions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024unin"
-    "terpreted_option\030\347\007 \003(\0132$.google.protobu"
-    "f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMeth"
-    "odOptions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024"
-    "uninterpreted_option\030\347\007 \003(\0132$.google.pro"
-    "tobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n"
-    "\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goo"
-    "gle.protobuf.UninterpretedOption.NamePar"
-    "t\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_"
-    "int_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 "
-    "\001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_valu"
-    "e\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010Name"
-    "Part\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030"
-    "\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003"
-    "(\0132(.google.protobuf.SourceCodeInfo.Loca"
-    "tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s"
-    "pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022"
-    "\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de"
-    "tached_comments\030\006 \003(\tB;\n\023com.google.prot"
-    "obufB\020DescriptorProtosH\001Z\ndescriptor\242\002\003G"
-    "PB", 4962);
+    "\001(\005\022\021\n\tjson_name\030\n \001(\t\022.\n\007options\030\010 \001(\0132"
+    "\035.google.protobuf.FieldOptions\"\266\002\n\004Type\022"
+    "\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE"
+    "_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020"
+    "\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n"
+    "\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GR"
+    "OUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022"
+    "\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_"
+    "SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI"
+    "NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE"
+    "L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE"
+    "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004"
+    "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na"
+    "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu"
+    "f.EnumValueDescriptorProto\022-\n\007options\030\003 "
+    "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu"
+    "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n"
+    "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr"
+    "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr"
+    "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013"
+    "2&.google.protobuf.MethodDescriptorProto"
+    "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv"
+    "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004"
+    "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output"
+    "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr"
+    "otobuf.MethodOptions\022\037\n\020client_streaming"
+    "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:"
+    "\005false\"\256\005\n\013FileOptions\022\024\n\014java_package\030\001"
+    " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja"
+    "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g"
+    "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026"
+    "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o"
+    "ptimize_for\030\t \001(\0162).google.protobuf.File"
+    "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag"
+    "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa"
+    "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals"
+    "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n"
+    "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar"
+    "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$"
+    " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022+\n\037javana"
+    "no_use_deprecated_package\030& \001(\010B\002\030\001\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption\":\n\014OptimizeMode"
+    "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTI"
+    "ME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027me"
+    "ssage_set_wire_format\030\001 \001(\010:\005false\022.\n\037no"
+    "_standard_descriptor_accessor\030\002 \001(\010:\005fal"
+    "se\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_ent"
+    "ry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132"
+    "$.google.protobuf.UninterpretedOption*\t\010"
+    "\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\016"
+    "2#.google.protobuf.FieldOptions.CType:\006S"
+    "TRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$."
+    "google.protobuf.FieldOptions.JSType:\tJS_"
+    "NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecate"
+    "d\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption\"/\n\005CType\022\n\n\006STR"
+    "ING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JST"
+    "ype\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_"
+    "NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013a"
+    "llow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fa"
+    "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+    "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200"
+    "\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 "
+    "\001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003("
+    "\0132$.google.protobuf.UninterpretedOption*"
+    "\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecat"
+    "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030"
+    "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
+    "tion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepr"
+    "ecated\030! \001(\010:\005false\022C\n\024uninterpreted_opt"
+    "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret"
+    "edOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpt"
+    "ion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unin"
+    "terpretedOption.NamePart\022\030\n\020identifier_v"
+    "alue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032"
+    "\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_val"
+    "ue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggreg"
+    "ate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part"
+    "\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceC"
+    "odeInfo\022:\n\010location\030\001 \003(\0132(.google.proto"
+    "buf.SourceCodeInfo.Location\032\206\001\n\010Location"
+    "\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020"
+    "leading_comments\030\003 \001(\t\022\031\n\021trailing_comme"
+    "nts\030\004 \001(\t\022!\n\031leading_detached_comments\030\006"
+    " \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotation"
+    "\030\001 \003(\0132-.google.protobuf.GeneratedCodeIn"
+    "fo.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(\005BX\n\023com.google.protobufB\020D"
+    "escriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032Go"
+    "ogle.Protobuf.Reflection", 5184);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -782,6 +836,8 @@
   UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart();
   SourceCodeInfo::default_instance_ = new SourceCodeInfo();
   SourceCodeInfo_Location::default_instance_ = new SourceCodeInfo_Location();
+  GeneratedCodeInfo::default_instance_ = new GeneratedCodeInfo();
+  GeneratedCodeInfo_Annotation::default_instance_ = new GeneratedCodeInfo_Annotation();
   FileDescriptorSet::default_instance_->InitAsDefaultInstance();
   FileDescriptorProto::default_instance_->InitAsDefaultInstance();
   DescriptorProto::default_instance_->InitAsDefaultInstance();
@@ -804,6 +860,8 @@
   UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance();
   SourceCodeInfo::default_instance_->InitAsDefaultInstance();
   SourceCodeInfo_Location::default_instance_->InitAsDefaultInstance();
+  GeneratedCodeInfo::default_instance_->InitAsDefaultInstance();
+  GeneratedCodeInfo_Annotation::default_instance_->InitAsDefaultInstance();
   ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto);
 }
 
@@ -826,9 +884,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileDescriptorSet::kFileFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileDescriptorSet::FileDescriptorSet()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1093,7 +1151,7 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileDescriptorProto::kNameFieldNumber;
 const int FileDescriptorProto::kPackageFieldNumber;
 const int FileDescriptorProto::kDependencyFieldNumber;
@@ -1106,7 +1164,7 @@
 const int FileDescriptorProto::kOptionsFieldNumber;
 const int FileDescriptorProto::kSourceCodeInfoFieldNumber;
 const int FileDescriptorProto::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileDescriptorProto::FileDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2347,10 +2405,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DescriptorProto_ExtensionRange::kStartFieldNumber;
 const int DescriptorProto_ExtensionRange::kEndFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2630,10 +2688,10 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DescriptorProto_ReservedRange::kStartFieldNumber;
 const int DescriptorProto_ReservedRange::kEndFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DescriptorProto_ReservedRange::DescriptorProto_ReservedRange()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2913,7 +2971,7 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DescriptorProto::kNameFieldNumber;
 const int DescriptorProto::kFieldFieldNumber;
 const int DescriptorProto::kExtensionFieldNumber;
@@ -2924,7 +2982,7 @@
 const int DescriptorProto::kOptionsFieldNumber;
 const int DescriptorProto::kReservedRangeFieldNumber;
 const int DescriptorProto::kReservedNameFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DescriptorProto::DescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -4054,7 +4112,7 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
 const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
@@ -4076,7 +4134,7 @@
 const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
 const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
 const int FieldDescriptorProto::Type_ARRAYSIZE;
-#endif  // _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
   protobuf_AssignDescriptorsOnce();
   return FieldDescriptorProto_Label_descriptor_;
@@ -4092,15 +4150,15 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
 const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
 const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
 const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
 const int FieldDescriptorProto::Label_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldDescriptorProto::kNameFieldNumber;
 const int FieldDescriptorProto::kNumberFieldNumber;
 const int FieldDescriptorProto::kLabelFieldNumber;
@@ -4109,8 +4167,9 @@
 const int FieldDescriptorProto::kExtendeeFieldNumber;
 const int FieldDescriptorProto::kDefaultValueFieldNumber;
 const int FieldDescriptorProto::kOneofIndexFieldNumber;
+const int FieldDescriptorProto::kJsonNameFieldNumber;
 const int FieldDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldDescriptorProto::FieldDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -4141,6 +4200,7 @@
   extendee_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   oneof_index_ = 0;
+  json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
@@ -4155,6 +4215,7 @@
   type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   extendee_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
     delete options_;
   }
@@ -4204,8 +4265,13 @@
     }
     oneof_index_ = 0;
   }
-  if (has_options()) {
-    if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+  if (_has_bits_[8 / 32] & 768u) {
+    if (has_json_name()) {
+      json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_options()) {
+      if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
+    }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   if (_internal_metadata_.have_unknown_fields()) {
@@ -4369,6 +4435,23 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(82)) goto parse_json_name;
+        break;
+      }
+
+      // optional string json_name = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_json_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_json_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->json_name().data(), this->json_name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.FieldDescriptorProto.json_name");
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -4466,6 +4549,16 @@
     ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
   }
 
+  // optional string json_name = 10;
+  if (has_json_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      10, this->json_name(), output);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
@@ -4549,6 +4642,17 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target);
   }
 
+  // optional string json_name = 10;
+  if (has_json_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->json_name().data(), this->json_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.FieldDescriptorProto.json_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        10, this->json_name(), target);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
@@ -4616,13 +4720,22 @@
     }
 
   }
-  // optional .google.protobuf.FieldOptions options = 8;
-  if (has_options()) {
-    total_size += 1 +
-      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
-        *this->options_);
-  }
+  if (_has_bits_[8 / 32] & 768u) {
+    // optional string json_name = 10;
+    if (has_json_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->json_name());
+    }
 
+    // optional .google.protobuf.FieldOptions options = 8;
+    if (has_options()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->options_);
+    }
+
+  }
   if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -4679,6 +4792,10 @@
     }
   }
   if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_json_name()) {
+      set_has_json_name();
+      json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
+    }
     if (from.has_options()) {
       mutable_options()->::google::protobuf::FieldOptions::MergeFrom(from.options());
     }
@@ -4721,6 +4838,7 @@
   extendee_.Swap(&other->extendee_);
   default_value_.Swap(&other->default_value_);
   std::swap(oneof_index_, other->oneof_index_);
+  json_name_.Swap(&other->json_name_);
   std::swap(options_, other->options_);
   std::swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -5048,16 +5166,69 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
 }
 
-// optional .google.protobuf.FieldOptions options = 8;
-bool FieldDescriptorProto::has_options() const {
+// optional string json_name = 10;
+bool FieldDescriptorProto::has_json_name() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
-void FieldDescriptorProto::set_has_options() {
+void FieldDescriptorProto::set_has_json_name() {
   _has_bits_[0] |= 0x00000100u;
 }
-void FieldDescriptorProto::clear_has_options() {
+void FieldDescriptorProto::clear_has_json_name() {
   _has_bits_[0] &= ~0x00000100u;
 }
+void FieldDescriptorProto::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_json_name();
+}
+ const ::std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_json_name(const ::std::string& value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+ void FieldDescriptorProto::set_json_name(const char* value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
+}
+ void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
+}
+ ::std::string* FieldDescriptorProto::mutable_json_name() {
+  set_has_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* FieldDescriptorProto::release_json_name() {
+  clear_has_json_name();
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    set_has_json_name();
+  } else {
+    clear_has_json_name();
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+bool FieldDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void FieldDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void FieldDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000200u;
+}
 void FieldDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
   clear_has_options();
@@ -5095,9 +5266,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int OneofDescriptorProto::kNameFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 OneofDescriptorProto::OneofDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -5401,11 +5572,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumDescriptorProto::kNameFieldNumber;
 const int EnumDescriptorProto::kValueFieldNumber;
 const int EnumDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumDescriptorProto::EnumDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -5874,11 +6045,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumValueDescriptorProto::kNameFieldNumber;
 const int EnumValueDescriptorProto::kNumberFieldNumber;
 const int EnumValueDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumValueDescriptorProto::EnumValueDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -6337,11 +6508,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int ServiceDescriptorProto::kNameFieldNumber;
 const int ServiceDescriptorProto::kMethodFieldNumber;
 const int ServiceDescriptorProto::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 ServiceDescriptorProto::ServiceDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -6810,14 +6981,14 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MethodDescriptorProto::kNameFieldNumber;
 const int MethodDescriptorProto::kInputTypeFieldNumber;
 const int MethodDescriptorProto::kOutputTypeFieldNumber;
 const int MethodDescriptorProto::kOptionsFieldNumber;
 const int MethodDescriptorProto::kClientStreamingFieldNumber;
 const int MethodDescriptorProto::kServerStreamingFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MethodDescriptorProto::MethodDescriptorProto()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -7576,15 +7747,15 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FileOptions_OptimizeMode FileOptions::SPEED;
 const FileOptions_OptimizeMode FileOptions::CODE_SIZE;
 const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
 const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
 const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
 const int FileOptions::OptimizeMode_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FileOptions::kJavaPackageFieldNumber;
 const int FileOptions::kJavaOuterClassnameFieldNumber;
 const int FileOptions::kJavaMultipleFilesFieldNumber;
@@ -7601,7 +7772,7 @@
 const int FileOptions::kCsharpNamespaceFieldNumber;
 const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber;
 const int FileOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FileOptions::FileOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -7958,7 +8129,7 @@
         break;
       }
 
-      // optional bool javanano_use_deprecated_package = 38;
+      // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
       case 38: {
         if (tag == 304) {
          parse_javanano_use_deprecated_package:
@@ -8116,7 +8287,7 @@
       37, this->csharp_namespace(), output);
   }
 
-  // optional bool javanano_use_deprecated_package = 38;
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
   if (has_javanano_use_deprecated_package()) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output);
   }
@@ -8242,7 +8413,7 @@
         37, this->csharp_namespace(), target);
   }
 
-  // optional bool javanano_use_deprecated_package = 38;
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
   if (has_javanano_use_deprecated_package()) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target);
   }
@@ -8353,7 +8524,7 @@
           this->csharp_namespace());
     }
 
-    // optional bool javanano_use_deprecated_package = 38;
+    // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
     if (has_javanano_use_deprecated_package()) {
       total_size += 2 + 1;
     }
@@ -8994,7 +9165,7 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
 }
 
-// optional bool javanano_use_deprecated_package = 38;
+// optional bool javanano_use_deprecated_package = 38 [deprecated = true];
 bool FileOptions::has_javanano_use_deprecated_package() const {
   return (_has_bits_[0] & 0x00004000u) != 0;
 }
@@ -9052,13 +9223,13 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MessageOptions::kMessageSetWireFormatFieldNumber;
 const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber;
 const int MessageOptions::kDeprecatedFieldNumber;
 const int MessageOptions::kMapEntryFieldNumber;
 const int MessageOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MessageOptions::MessageOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -9610,14 +9781,14 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldOptions_CType FieldOptions::STRING;
 const FieldOptions_CType FieldOptions::CORD;
 const FieldOptions_CType FieldOptions::STRING_PIECE;
 const FieldOptions_CType FieldOptions::CType_MIN;
 const FieldOptions_CType FieldOptions::CType_MAX;
 const int FieldOptions::CType_ARRAYSIZE;
-#endif  // _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() {
   protobuf_AssignDescriptorsOnce();
   return FieldOptions_JSType_descriptor_;
@@ -9633,15 +9804,15 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const FieldOptions_JSType FieldOptions::JS_NORMAL;
 const FieldOptions_JSType FieldOptions::JS_STRING;
 const FieldOptions_JSType FieldOptions::JS_NUMBER;
 const FieldOptions_JSType FieldOptions::JSType_MIN;
 const FieldOptions_JSType FieldOptions::JSType_MAX;
 const int FieldOptions::JSType_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldOptions::kCtypeFieldNumber;
 const int FieldOptions::kPackedFieldNumber;
 const int FieldOptions::kJstypeFieldNumber;
@@ -9649,7 +9820,7 @@
 const int FieldOptions::kDeprecatedFieldNumber;
 const int FieldOptions::kWeakFieldNumber;
 const int FieldOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldOptions::FieldOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -10325,11 +10496,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumOptions::kAllowAliasFieldNumber;
 const int EnumOptions::kDeprecatedFieldNumber;
 const int EnumOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumOptions::EnumOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -10748,10 +10919,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumValueOptions::kDeprecatedFieldNumber;
 const int EnumValueOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumValueOptions::EnumValueOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11097,10 +11268,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int ServiceOptions::kDeprecatedFieldNumber;
 const int ServiceOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 ServiceOptions::ServiceOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11446,10 +11617,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int MethodOptions::kDeprecatedFieldNumber;
 const int MethodOptions::kUninterpretedOptionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 MethodOptions::MethodOptions()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -11795,10 +11966,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UninterpretedOption_NamePart::kNamePartFieldNumber;
 const int UninterpretedOption_NamePart::kIsExtensionFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UninterpretedOption_NamePart::UninterpretedOption_NamePart()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -12101,7 +12272,7 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UninterpretedOption::kNameFieldNumber;
 const int UninterpretedOption::kIdentifierValueFieldNumber;
 const int UninterpretedOption::kPositiveIntValueFieldNumber;
@@ -12109,7 +12280,7 @@
 const int UninterpretedOption::kDoubleValueFieldNumber;
 const int UninterpretedOption::kStringValueFieldNumber;
 const int UninterpretedOption::kAggregateValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UninterpretedOption::UninterpretedOption()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -12968,13 +13139,13 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int SourceCodeInfo_Location::kPathFieldNumber;
 const int SourceCodeInfo_Location::kSpanFieldNumber;
 const int SourceCodeInfo_Location::kLeadingCommentsFieldNumber;
 const int SourceCodeInfo_Location::kTrailingCommentsFieldNumber;
 const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceCodeInfo_Location::SourceCodeInfo_Location()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -13453,9 +13624,9 @@
 
 // -------------------------------------------------------------------
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int SourceCodeInfo::kLocationFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceCodeInfo::SourceCodeInfo()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -13941,6 +14112,812 @@
 
 #endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GeneratedCodeInfo_Annotation::kPathFieldNumber;
+const int GeneratedCodeInfo_Annotation::kSourceFileFieldNumber;
+const int GeneratedCodeInfo_Annotation::kBeginFieldNumber;
+const int GeneratedCodeInfo_Annotation::kEndFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+void GeneratedCodeInfo_Annotation::InitAsDefaultInstance() {
+}
+
+GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+void GeneratedCodeInfo_Annotation::SharedCtor() {
+  ::google::protobuf::internal::GetEmptyString();
+  _cached_size_ = 0;
+  source_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  begin_ = 0;
+  end_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation)
+  SharedDtor();
+}
+
+void GeneratedCodeInfo_Annotation::SharedDtor() {
+  source_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != default_instance_) {
+  }
+}
+
+void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GeneratedCodeInfo_Annotation::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GeneratedCodeInfo_Annotation_descriptor_;
+}
+
+const GeneratedCodeInfo_Annotation& GeneratedCodeInfo_Annotation::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::default_instance_ = NULL;
+
+GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::New(::google::protobuf::Arena* arena) const {
+  GeneratedCodeInfo_Annotation* n = new GeneratedCodeInfo_Annotation;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void GeneratedCodeInfo_Annotation::Clear() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<GeneratedCodeInfo_Annotation*>(16)->f)
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 14u) {
+    ZR_(begin_, end_);
+    if (has_source_file()) {
+      source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  path_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated int32 path = 1 [packed = true];
+      case 1: {
+        if (tag == 10) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_path())));
+        } else if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 10, input, this->mutable_path())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_source_file;
+        break;
+      }
+
+      // optional string source_file = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_source_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source_file().data(), this->source_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_begin;
+        break;
+      }
+
+      // optional int32 begin = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_begin:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &begin_)));
+          set_has_begin();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_end;
+        break;
+      }
+
+      // optional int32 end = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_end:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &end_)));
+          set_has_end();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo.Annotation)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo.Annotation)
+  return false;
+#undef DO_
+}
+
+void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  // repeated int32 path = 1 [packed = true];
+  if (this->path_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_path_cached_byte_size_);
+  }
+  for (int i = 0; i < this->path_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+      this->path(i), output);
+  }
+
+  // optional string source_file = 2;
+  if (has_source_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source_file().data(), this->source_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->source_file(), output);
+  }
+
+  // optional int32 begin = 3;
+  if (has_begin()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->begin(), output);
+  }
+
+  // optional int32 end = 4;
+  if (has_end()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->end(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation)
+}
+
+::google::protobuf::uint8* GeneratedCodeInfo_Annotation::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
+  // repeated int32 path = 1 [packed = true];
+  if (this->path_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      1,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _path_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->path_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32NoTagToArray(this->path(i), target);
+  }
+
+  // optional string source_file = 2;
+  if (has_source_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source_file().data(), this->source_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->source_file(), target);
+  }
+
+  // optional int32 begin = 3;
+  if (has_begin()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->begin(), target);
+  }
+
+  // optional int32 end = 4;
+  if (has_end()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->end(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
+  return target;
+}
+
+int GeneratedCodeInfo_Annotation::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[1 / 32] & 14u) {
+    // optional string source_file = 2;
+    if (has_source_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source_file());
+    }
+
+    // optional int32 begin = 3;
+    if (has_begin()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->begin());
+    }
+
+    // optional int32 end = 4;
+    if (has_end()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->end());
+    }
+
+  }
+  // repeated int32 path = 1 [packed = true];
+  {
+    int data_size = 0;
+    for (int i = 0; i < this->path_size(); i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->path(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _path_cached_byte_size_ = data_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GeneratedCodeInfo_Annotation::MergeFrom(const ::google::protobuf::Message& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo_Annotation* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo_Annotation>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  path_.MergeFrom(from.path_);
+  if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
+    if (from.has_source_file()) {
+      set_has_source_file();
+      source_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_file_);
+    }
+    if (from.has_begin()) {
+      set_begin(from.begin());
+    }
+    if (from.has_end()) {
+      set_end(from.end());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo_Annotation::IsInitialized() const {
+
+  return true;
+}
+
+void GeneratedCodeInfo_Annotation::Swap(GeneratedCodeInfo_Annotation* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* other) {
+  path_.UnsafeArenaSwap(&other->path_);
+  source_file_.Swap(&other->source_file_);
+  std::swap(begin_, other->begin_);
+  std::swap(end_, other->end_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GeneratedCodeInfo_Annotation_descriptor_;
+  metadata.reflection = GeneratedCodeInfo_Annotation_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GeneratedCodeInfo::kAnnotationFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GeneratedCodeInfo::GeneratedCodeInfo()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+void GeneratedCodeInfo::InitAsDefaultInstance() {
+}
+
+GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo)
+}
+
+void GeneratedCodeInfo::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+GeneratedCodeInfo::~GeneratedCodeInfo() {
+  // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo)
+  SharedDtor();
+}
+
+void GeneratedCodeInfo::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void GeneratedCodeInfo::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GeneratedCodeInfo::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GeneratedCodeInfo_descriptor_;
+}
+
+const GeneratedCodeInfo& GeneratedCodeInfo::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+GeneratedCodeInfo* GeneratedCodeInfo::default_instance_ = NULL;
+
+GeneratedCodeInfo* GeneratedCodeInfo::New(::google::protobuf::Arena* arena) const {
+  GeneratedCodeInfo* n = new GeneratedCodeInfo;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void GeneratedCodeInfo::Clear() {
+  annotation_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool GeneratedCodeInfo::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_annotation:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_annotation()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_annotation;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.GeneratedCodeInfo)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.GeneratedCodeInfo)
+  return false;
+#undef DO_
+}
+
+void GeneratedCodeInfo::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo)
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->annotation(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo)
+}
+
+::google::protobuf::uint8* GeneratedCodeInfo::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        1, this->annotation(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
+  return target;
+}
+
+int GeneratedCodeInfo::ByteSize() const {
+  int total_size = 0;
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  total_size += 1 * this->annotation_size();
+  for (int i = 0; i < this->annotation_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->annotation(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GeneratedCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GeneratedCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const GeneratedCodeInfo>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  annotation_.MergeFrom(from.annotation_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void GeneratedCodeInfo::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool GeneratedCodeInfo::IsInitialized() const {
+
+  return true;
+}
+
+void GeneratedCodeInfo::Swap(GeneratedCodeInfo* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void GeneratedCodeInfo::InternalSwap(GeneratedCodeInfo* other) {
+  annotation_.UnsafeArenaSwap(&other->annotation_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GeneratedCodeInfo::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GeneratedCodeInfo_descriptor_;
+  metadata.reflection = GeneratedCodeInfo_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+int GeneratedCodeInfo_Annotation::path_size() const {
+  return path_.size();
+}
+void GeneratedCodeInfo_Annotation::clear_path() {
+  path_.Clear();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_.Get(index);
+}
+ void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) {
+  path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+ void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) {
+  path_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return &path_;
+}
+
+// optional string source_file = 2;
+bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_source_file() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_source_file() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void GeneratedCodeInfo_Annotation::clear_source_file() {
+  source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source_file();
+}
+ const ::std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const char* value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+ ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  set_has_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  clear_has_source_file();
+  return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) {
+  if (source_file != NULL) {
+    set_has_source_file();
+  } else {
+    clear_has_source_file();
+  }
+  source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_begin() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_begin() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void GeneratedCodeInfo_Annotation::clear_begin() {
+  begin_ = 0;
+  clear_has_begin();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return begin_;
+}
+ void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) {
+  set_has_begin();
+  begin_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+bool GeneratedCodeInfo_Annotation::has_end() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void GeneratedCodeInfo_Annotation::set_has_end() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void GeneratedCodeInfo_Annotation::clear_has_end() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void GeneratedCodeInfo_Annotation::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+ ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return end_;
+}
+ void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+int GeneratedCodeInfo::annotation_size() const {
+  return annotation_.size();
+}
+void GeneratedCodeInfo::clear_annotation() {
+  annotation_.Clear();
+}
+const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Get(index);
+}
+::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Mutable(index);
+}
+::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &annotation_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
 // @@protoc_insertion_point(namespace_scope)
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 931ff02..3fe07bf 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -50,6 +50,8 @@
 class FileDescriptorProto;
 class FileDescriptorSet;
 class FileOptions;
+class GeneratedCodeInfo;
+class GeneratedCodeInfo_Annotation;
 class MessageOptions;
 class MethodDescriptorProto;
 class MethodOptions;
@@ -1133,6 +1135,18 @@
   ::google::protobuf::int32 oneof_index() const;
   void set_oneof_index(::google::protobuf::int32 value);
 
+  // optional string json_name = 10;
+  bool has_json_name() const;
+  void clear_json_name();
+  static const int kJsonNameFieldNumber = 10;
+  const ::std::string& json_name() const;
+  void set_json_name(const ::std::string& value);
+  void set_json_name(const char* value);
+  void set_json_name(const char* value, size_t size);
+  ::std::string* mutable_json_name();
+  ::std::string* release_json_name();
+  void set_allocated_json_name(::std::string* json_name);
+
   // optional .google.protobuf.FieldOptions options = 8;
   bool has_options() const;
   void clear_options();
@@ -1160,6 +1174,8 @@
   inline void clear_has_default_value();
   inline void set_has_oneof_index();
   inline void clear_has_oneof_index();
+  inline void set_has_json_name();
+  inline void clear_has_json_name();
   inline void set_has_options();
   inline void clear_has_options();
 
@@ -1174,6 +1190,7 @@
   int type_;
   ::google::protobuf::int32 oneof_index_;
   ::google::protobuf::internal::ArenaStringPtr default_value_;
+  ::google::protobuf::internal::ArenaStringPtr json_name_;
   ::google::protobuf::FieldOptions* options_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2000,12 +2017,12 @@
   ::std::string* release_csharp_namespace();
   void set_allocated_csharp_namespace(::std::string* csharp_namespace);
 
-  // optional bool javanano_use_deprecated_package = 38;
-  bool has_javanano_use_deprecated_package() const;
-  void clear_javanano_use_deprecated_package();
+  // optional bool javanano_use_deprecated_package = 38 [deprecated = true];
+  bool has_javanano_use_deprecated_package() const PROTOBUF_DEPRECATED;
+  void clear_javanano_use_deprecated_package() PROTOBUF_DEPRECATED;
   static const int kJavananoUseDeprecatedPackageFieldNumber = 38;
-  bool javanano_use_deprecated_package() const;
-  void set_javanano_use_deprecated_package(bool value);
+  bool javanano_use_deprecated_package() const PROTOBUF_DEPRECATED;
+  void set_javanano_use_deprecated_package(bool value) PROTOBUF_DEPRECATED;
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   int uninterpreted_option_size() const;
@@ -3375,6 +3392,228 @@
   void InitAsDefaultInstance();
   static SourceCodeInfo* default_instance_;
 };
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message {
+ public:
+  GeneratedCodeInfo_Annotation();
+  virtual ~GeneratedCodeInfo_Annotation();
+
+  GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from);
+
+  inline GeneratedCodeInfo_Annotation& operator=(const GeneratedCodeInfo_Annotation& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GeneratedCodeInfo_Annotation& default_instance();
+
+  void Swap(GeneratedCodeInfo_Annotation* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GeneratedCodeInfo_Annotation* New() const { return New(NULL); }
+
+  GeneratedCodeInfo_Annotation* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GeneratedCodeInfo_Annotation& from);
+  void MergeFrom(const GeneratedCodeInfo_Annotation& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GeneratedCodeInfo_Annotation* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated int32 path = 1 [packed = true];
+  int path_size() const;
+  void clear_path();
+  static const int kPathFieldNumber = 1;
+  ::google::protobuf::int32 path(int index) const;
+  void set_path(int index, ::google::protobuf::int32 value);
+  void add_path(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      path() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_path();
+
+  // optional string source_file = 2;
+  bool has_source_file() const;
+  void clear_source_file();
+  static const int kSourceFileFieldNumber = 2;
+  const ::std::string& source_file() const;
+  void set_source_file(const ::std::string& value);
+  void set_source_file(const char* value);
+  void set_source_file(const char* value, size_t size);
+  ::std::string* mutable_source_file();
+  ::std::string* release_source_file();
+  void set_allocated_source_file(::std::string* source_file);
+
+  // optional int32 begin = 3;
+  bool has_begin() const;
+  void clear_begin();
+  static const int kBeginFieldNumber = 3;
+  ::google::protobuf::int32 begin() const;
+  void set_begin(::google::protobuf::int32 value);
+
+  // optional int32 end = 4;
+  bool has_end() const;
+  void clear_end();
+  static const int kEndFieldNumber = 4;
+  ::google::protobuf::int32 end() const;
+  void set_end(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
+ private:
+  inline void set_has_source_file();
+  inline void clear_has_source_file();
+  inline void set_has_begin();
+  inline void clear_has_begin();
+  inline void set_has_end();
+  inline void clear_has_end();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_;
+  mutable int _path_cached_byte_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_file_;
+  ::google::protobuf::int32 begin_;
+  ::google::protobuf::int32 end_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static GeneratedCodeInfo_Annotation* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message {
+ public:
+  GeneratedCodeInfo();
+  virtual ~GeneratedCodeInfo();
+
+  GeneratedCodeInfo(const GeneratedCodeInfo& from);
+
+  inline GeneratedCodeInfo& operator=(const GeneratedCodeInfo& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GeneratedCodeInfo& default_instance();
+
+  void Swap(GeneratedCodeInfo* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GeneratedCodeInfo* New() const { return New(NULL); }
+
+  GeneratedCodeInfo* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GeneratedCodeInfo& from);
+  void MergeFrom(const GeneratedCodeInfo& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GeneratedCodeInfo* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef GeneratedCodeInfo_Annotation Annotation;
+
+  // accessors -------------------------------------------------------
+
+  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+  int annotation_size() const;
+  void clear_annotation();
+  static const int kAnnotationFieldNumber = 1;
+  const ::google::protobuf::GeneratedCodeInfo_Annotation& annotation(int index) const;
+  ::google::protobuf::GeneratedCodeInfo_Annotation* mutable_annotation(int index);
+  ::google::protobuf::GeneratedCodeInfo_Annotation* add_annotation();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+      mutable_annotation();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+      annotation() const;
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation > annotation_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static GeneratedCodeInfo* default_instance_;
+};
 // ===================================================================
 
 
@@ -4678,16 +4917,69 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.oneof_index)
 }
 
-// optional .google.protobuf.FieldOptions options = 8;
-inline bool FieldDescriptorProto::has_options() const {
+// optional string json_name = 10;
+inline bool FieldDescriptorProto::has_json_name() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
-inline void FieldDescriptorProto::set_has_options() {
+inline void FieldDescriptorProto::set_has_json_name() {
   _has_bits_[0] |= 0x00000100u;
 }
-inline void FieldDescriptorProto::clear_has_options() {
+inline void FieldDescriptorProto::clear_has_json_name() {
   _has_bits_[0] &= ~0x00000100u;
 }
+inline void FieldDescriptorProto::clear_json_name() {
+  json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_json_name();
+}
+inline const ::std::string& FieldDescriptorProto::json_name() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_json_name(const ::std::string& value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline void FieldDescriptorProto::set_json_name(const char* value) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline void FieldDescriptorProto::set_json_name(const char* value, size_t size) {
+  set_has_json_name();
+  json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldDescriptorProto.json_name)
+}
+inline ::std::string* FieldDescriptorProto::mutable_json_name() {
+  set_has_json_name();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.json_name)
+  return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* FieldDescriptorProto::release_json_name() {
+  clear_has_json_name();
+  return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FieldDescriptorProto::set_allocated_json_name(::std::string* json_name) {
+  if (json_name != NULL) {
+    set_has_json_name();
+  } else {
+    clear_has_json_name();
+  }
+  json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.FieldDescriptorProto.json_name)
+}
+
+// optional .google.protobuf.FieldOptions options = 8;
+inline bool FieldDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void FieldDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void FieldDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000200u;
+}
 inline void FieldDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
   clear_has_options();
@@ -5902,7 +6194,7 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace)
 }
 
-// optional bool javanano_use_deprecated_package = 38;
+// optional bool javanano_use_deprecated_package = 38 [deprecated = true];
 inline bool FileOptions::has_javanano_use_deprecated_package() const {
   return (_has_bits_[0] & 0x00004000u) != 0;
 }
@@ -7126,6 +7418,175 @@
   return location_;
 }
 
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo_Annotation
+
+// repeated int32 path = 1 [packed = true];
+inline int GeneratedCodeInfo_Annotation::path_size() const {
+  return path_.size();
+}
+inline void GeneratedCodeInfo_Annotation::clear_path() {
+  path_.Clear();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::path(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_.Get(index);
+}
+inline void GeneratedCodeInfo_Annotation::set_path(int index, ::google::protobuf::int32 value) {
+  path_.Set(index, value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline void GeneratedCodeInfo_Annotation::add_path(::google::protobuf::int32 value) {
+  path_.Add(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.Annotation.path)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+GeneratedCodeInfo_Annotation::path() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return path_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+GeneratedCodeInfo_Annotation::mutable_path() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.Annotation.path)
+  return &path_;
+}
+
+// optional string source_file = 2;
+inline bool GeneratedCodeInfo_Annotation::has_source_file() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_source_file() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_source_file() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_source_file() {
+  source_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source_file();
+}
+inline const ::std::string& GeneratedCodeInfo_Annotation::source_file() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const ::std::string& value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline void GeneratedCodeInfo_Annotation::set_source_file(const char* value, size_t size) {
+  set_has_source_file();
+  source_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+inline ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() {
+  set_has_source_file();
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+  return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* GeneratedCodeInfo_Annotation::release_source_file() {
+  clear_has_source_file();
+  return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GeneratedCodeInfo_Annotation::set_allocated_source_file(::std::string* source_file) {
+  if (source_file != NULL) {
+    set_has_source_file();
+  } else {
+    clear_has_source_file();
+  }
+  source_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source_file);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.GeneratedCodeInfo.Annotation.source_file)
+}
+
+// optional int32 begin = 3;
+inline bool GeneratedCodeInfo_Annotation::has_begin() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_begin() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_begin() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_begin() {
+  begin_ = 0;
+  clear_has_begin();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::begin() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+  return begin_;
+}
+inline void GeneratedCodeInfo_Annotation::set_begin(::google::protobuf::int32 value) {
+  set_has_begin();
+  begin_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.begin)
+}
+
+// optional int32 end = 4;
+inline bool GeneratedCodeInfo_Annotation::has_end() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void GeneratedCodeInfo_Annotation::set_has_end() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_has_end() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void GeneratedCodeInfo_Annotation::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+inline ::google::protobuf::int32 GeneratedCodeInfo_Annotation::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.end)
+  return end_;
+}
+inline void GeneratedCodeInfo_Annotation::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
+}
+
+// -------------------------------------------------------------------
+
+// GeneratedCodeInfo
+
+// repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
+inline int GeneratedCodeInfo::annotation_size() const {
+  return annotation_.size();
+}
+inline void GeneratedCodeInfo::clear_annotation() {
+  annotation_.Clear();
+}
+inline const ::google::protobuf::GeneratedCodeInfo_Annotation& GeneratedCodeInfo::annotation(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Get(index);
+}
+inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::mutable_annotation(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Mutable(index);
+}
+inline ::google::protobuf::GeneratedCodeInfo_Annotation* GeneratedCodeInfo::add_annotation() {
+  // @@protoc_insertion_point(field_add:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >*
+GeneratedCodeInfo::mutable_annotation() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return &annotation_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::GeneratedCodeInfo_Annotation >&
+GeneratedCodeInfo::annotation() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.GeneratedCodeInfo.annotation)
+  return annotation_;
+}
+
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
 // -------------------------------------------------------------------
 
@@ -7169,6 +7630,10 @@
 
 // -------------------------------------------------------------------
 
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 8f90a95..3e664d5 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -43,8 +43,7 @@
 option go_package = "descriptor";
 option java_package = "com.google.protobuf";
 option java_outer_classname = "DescriptorProtos";
-// Re-enable this once the tools have picked up the csharp_namespace option.
-// option csharp_namespace = "Google.ProtocolBuffers.DescriptorProtos";
+option csharp_namespace = "Google.Protobuf.Reflection";
 option objc_class_prefix = "GPB";
 
 // descriptor.proto must be optimized for speed because reflection-based
@@ -191,6 +190,12 @@
   // list.  This field is a member of that oneof.
   optional int32 oneof_index = 9;
 
+  // JSON name of this field. The value is set by protocol compiler. If the
+  // user has set a "json_name" option on this field, that option's value
+  // will be used. Otherwise, it's deduced from the field's name by converting
+  // it to camelCase.
+  optional string json_name = 10;
+
   optional FieldOptions options = 8;
 }
 
@@ -374,7 +379,7 @@
 
   // Whether the nano proto compiler should generate in the deprecated non-nano
   // suffixed package.
-  optional bool javanano_use_deprecated_package = 38;
+  optional bool javanano_use_deprecated_package = 38 [deprecated = true];
 
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
@@ -772,3 +777,29 @@
     repeated string leading_detached_comments = 6;
   }
 }
+
+// Describes the relationship between generated code and its original source
+// file. A GeneratedCodeInfo message is associated with only one generated
+// source file, but may contain references to different source .proto files.
+message GeneratedCodeInfo {
+  // An Annotation connects some span of text in generated code to an element
+  // of its generating .proto file.
+  repeated Annotation annotation = 1;
+  message Annotation {
+    // Identifies the element in the original source .proto file. This field
+    // is formatted the same as SourceCodeInfo.Location.path.
+    repeated int32 path = 1 [packed=true];
+
+    // Identifies the filesystem path to the original source .proto.
+    optional string source_file = 2;
+
+    // Identifies the starting offset in bytes in the generated code
+    // that relates to the identified object.
+    optional int32 begin = 3;
+
+    // Identifies the ending offset in bytes in the generated code that
+    // relates to the identified offset. The end offset should be one past
+    // the last relevant byte (so the length of the text = end - begin).
+    optional int32 end = 4;
+  }
+}
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index a87fa04..1fc3816 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -35,6 +35,10 @@
 // This file makes extensive use of RFC 3092.  :)
 
 #include <algorithm>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/descriptor_database.h>
 #include <google/protobuf/descriptor.h>
@@ -177,7 +181,7 @@
     EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
   }
 
-  scoped_ptr<DescriptorDatabaseTestCase> test_case_;
+  google::protobuf::scoped_ptr<DescriptorDatabaseTestCase> test_case_;
   DescriptorDatabase* database_;
 };
 
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index e9b027d..be8e0b7 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -34,6 +34,10 @@
 //
 // This file makes extensive use of RFC 3092.  :)
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/compiler/importer.h>
@@ -174,6 +178,61 @@
   AddEnumValue(AddEnum(file, name), name + "_DUMMY", 1);
 }
 
+class MockErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  MockErrorCollector() {}
+  ~MockErrorCollector() {}
+
+  string text_;
+  string warning_text_;
+
+  // implements ErrorCollector ---------------------------------------
+  void AddError(const string& filename,
+                const string& element_name, const Message* descriptor,
+                ErrorLocation location, const string& message) {
+    const char* location_name = NULL;
+    switch (location) {
+      case NAME         : location_name = "NAME"         ; break;
+      case NUMBER       : location_name = "NUMBER"       ; break;
+      case TYPE         : location_name = "TYPE"         ; break;
+      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
+      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
+      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
+      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
+      case OTHER        : location_name = "OTHER"        ; break;
+    }
+
+    strings::SubstituteAndAppend(
+      &text_, "$0: $1: $2: $3\n",
+      filename, element_name, location_name, message);
+  }
+
+  // implements ErrorCollector ---------------------------------------
+  void AddWarning(const string& filename, const string& element_name,
+                  const Message* descriptor, ErrorLocation location,
+                  const string& message) {
+    const char* location_name = NULL;
+    switch (location) {
+      case NAME         : location_name = "NAME"         ; break;
+      case NUMBER       : location_name = "NUMBER"       ; break;
+      case TYPE         : location_name = "TYPE"         ; break;
+      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
+      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
+      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
+      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
+      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
+      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
+      case OTHER        : location_name = "OTHER"        ; break;
+    }
+
+    strings::SubstituteAndAppend(
+      &warning_text_, "$0: $1: $2: $3\n",
+      filename, element_name, location_name, message);
+  }
+};
+
 // ===================================================================
 
 // Test simple files.
@@ -461,6 +520,16 @@
     //     map<int32, int32> map_int32_int32 = 1;
     //   }
     //
+    //   // in "json.proto"
+    //   message TestMessage4 {
+    //     optional int32 field_name1 = 1;
+    //     optional int32 fieldName2 = 2;
+    //     optional int32 FieldName3 = 3;
+    //     optional int32 _field_name4 = 4;
+    //     optional int32 FIELD_NAME5 = 5;
+    //     optional int32 field_name6 = 6 [json_name = "@type"];
+    //   }
+    //
     // We cheat and use TestForeign as the type for qux rather than create
     // an actual nested type.
     //
@@ -526,6 +595,30 @@
              FieldDescriptorProto::TYPE_MESSAGE)
         ->set_type_name("MapInt32Int32Entry");
 
+    FileDescriptorProto json_file;
+    json_file.set_name("json.proto");
+    json_file.set_syntax("proto3");
+    DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
+    AddField(message4, "field_name1", 1,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "fieldName2", 2,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FieldName3", 3,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "_field_name4", 4,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "FIELD_NAME5", 5,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32);
+    AddField(message4, "field_name6", 6,
+             FieldDescriptorProto::LABEL_OPTIONAL,
+             FieldDescriptorProto::TYPE_INT32)
+        ->set_json_name("@type");
+
     // Build the descriptors and get the pointers.
     foo_file_ = pool_.BuildFile(foo_file);
     ASSERT_TRUE(foo_file_ != NULL);
@@ -536,6 +629,9 @@
     map_file_ = pool_.BuildFile(map_file);
     ASSERT_TRUE(map_file_ != NULL);
 
+    json_file_ = pool_.BuildFile(json_file);
+    ASSERT_TRUE(json_file_ != NULL);
+
     ASSERT_EQ(1, foo_file_->enum_type_count());
     enum_ = foo_file_->enum_type(0);
 
@@ -562,6 +658,14 @@
 
     ASSERT_EQ(1, message3_->field_count());
     map_  = message3_->field(0);
+
+    ASSERT_EQ(1, json_file_->message_type_count());
+    message4_ = json_file_->message_type(0);
+  }
+
+  void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
+    message->CopyTo(proto);
+    message->CopyJsonNameTo(proto);
   }
 
   DescriptorPool pool_;
@@ -569,10 +673,12 @@
   const FileDescriptor* foo_file_;
   const FileDescriptor* bar_file_;
   const FileDescriptor* map_file_;
+  const FileDescriptor* json_file_;
 
   const Descriptor* message_;
   const Descriptor* message2_;
   const Descriptor* message3_;
+  const Descriptor* message4_;
   const Descriptor* foreign_;
   const EnumDescriptor* enum_;
 
@@ -664,6 +770,35 @@
   EXPECT_EQ("corge.grault.TestMessage2.quux", quux2_->full_name());
 }
 
+TEST_F(DescriptorTest, FieldJsonName) {
+  EXPECT_EQ("fieldName1", message4_->field(0)->json_name());
+  EXPECT_EQ("fieldName2", message4_->field(1)->json_name());
+  EXPECT_EQ("fieldName3", message4_->field(2)->json_name());
+  EXPECT_EQ("fieldName4", message4_->field(3)->json_name());
+  EXPECT_EQ("fIELDNAME5", message4_->field(4)->json_name());
+  EXPECT_EQ("@type", message4_->field(5)->json_name());
+
+  DescriptorProto proto;
+  message4_->CopyTo(&proto);
+  ASSERT_EQ(6, proto.field_size());
+  EXPECT_FALSE(proto.field(0).has_json_name());
+  EXPECT_FALSE(proto.field(1).has_json_name());
+  EXPECT_FALSE(proto.field(2).has_json_name());
+  EXPECT_FALSE(proto.field(3).has_json_name());
+  EXPECT_FALSE(proto.field(4).has_json_name());
+  EXPECT_EQ("@type", proto.field(5).json_name());
+
+  proto.Clear();
+  CopyWithJsonName(message4_, &proto);
+  ASSERT_EQ(6, proto.field_size());
+  EXPECT_EQ("fieldName1", proto.field(0).json_name());
+  EXPECT_EQ("fieldName2", proto.field(1).json_name());
+  EXPECT_EQ("fieldName3", proto.field(2).json_name());
+  EXPECT_EQ("fieldName4", proto.field(3).json_name());
+  EXPECT_EQ("fIELDNAME5", proto.field(4).json_name());
+  EXPECT_EQ("@type", proto.field(5).json_name());
+}
+
 TEST_F(DescriptorTest, FieldFile) {
   EXPECT_EQ(foo_file_, foo_->file());
   EXPECT_EQ(foo_file_, bar_->file());
@@ -1900,7 +2035,7 @@
     return field != NULL ? field->enum_type() : NULL;
   }
 
-  scoped_ptr<DescriptorPool> pool_;
+  google::protobuf::scoped_ptr<DescriptorPool> pool_;
 };
 
 TEST_F(MiscTest, TypeNames) {
@@ -2330,7 +2465,7 @@
   const FieldDescriptor* qux_field_;
 
   SimpleDescriptorDatabase db_;        // used if in FALLBACK_DATABASE mode.
-  scoped_ptr<DescriptorPool> pool_;
+  google::protobuf::scoped_ptr<DescriptorPool> pool_;
 };
 
 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
@@ -3040,78 +3175,96 @@
       ->file()->CopyTo(&file_proto);
   ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
 
-
   pool.AddUnusedImportTrackFile("custom_options_import.proto");
   ASSERT_TRUE(TextFormat::ParseFromString(
     "name: \"custom_options_import.proto\" "
     "package: \"protobuf_unittest\" "
     "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
     &file_proto));
-  pool.BuildFile(file_proto);
+
+  MockErrorCollector error_collector;
+  EXPECT_TRUE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
+  EXPECT_EQ("", error_collector.warning_text_);
+}
+
+// Verifies that proto files can correctly be parsed, even if the
+// custom options defined in the file are incompatible with those
+// compiled in the binary. See http://b/19276250.
+TEST(CustomOptions, OptionsWithRequiredEnums) {
+  DescriptorPool pool;
+
+  FileDescriptorProto file_proto;
+  MessageOptions::descriptor()->file()->CopyTo(&file_proto);
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // Create a new file descriptor proto containing a subset of the
+  // messages defined in google/protobuf/unittest_custom_options.proto.
+  file_proto.Clear();
+  file_proto.set_name("unittest_custom_options.proto");
+  file_proto.set_package("protobuf_unittest");
+  file_proto.add_dependency("google/protobuf/descriptor.proto");
+
+  // Add the "required_enum_opt" extension.
+  FieldDescriptorProto* extension = file_proto.add_extension();
+  protobuf_unittest::OldOptionType::descriptor()->file()
+      ->FindExtensionByName("required_enum_opt")->CopyTo(extension);
+
+  // Add a test message that uses the "required_enum_opt" option.
+  DescriptorProto* test_message_type = file_proto.add_message_type();
+  protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor()
+      ->CopyTo(test_message_type);
+
+  // Instruct the extension to use NewOptionType instead of
+  // OldOptionType, and add the descriptor of NewOptionType.
+  extension->set_type_name(".protobuf_unittest.NewOptionType");
+  DescriptorProto* new_option_type = file_proto.add_message_type();
+  protobuf_unittest::NewOptionType::descriptor()
+      ->CopyTo(new_option_type);
+
+  // Replace the value of the "required_enum_opt" option used in the
+  // test message with an enum value that only exists in NewOptionType.
+  ASSERT_TRUE(TextFormat::ParseFromString(
+      "uninterpreted_option { "
+      "  name { "
+      "    name_part: 'required_enum_opt' "
+      "    is_extension: true "
+      "  } "
+      "  aggregate_value: 'value: NEW_VALUE' "
+      "}",
+      test_message_type->mutable_options()));
+
+  // Add the file descriptor to the pool.
+  ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
+
+  // Find the test message.
+  const Descriptor* test_message = pool.FindMessageTypeByName(
+      "protobuf_unittest.TestMessageWithRequiredEnumOption");
+  ASSERT_TRUE(test_message != NULL);
+
+  const MessageOptions& options = test_message->options();
+  // Extract the "required_enum_opt" option. Since the binary does not
+  // know that the extension was updated, this will still return an
+  // OldOptionType message.
+  ASSERT_TRUE(
+      options.HasExtension(protobuf_unittest::required_enum_opt));
+  const protobuf_unittest::OldOptionType& old_enum_opt =
+      options.GetExtension(protobuf_unittest::required_enum_opt);
+
+  // Confirm that the required enum field is missing.
+  EXPECT_FALSE(old_enum_opt.IsInitialized());
+  EXPECT_FALSE(old_enum_opt.has_value());
+
+  string buf;
+  // Verify that the required enum field does show up when the option
+  // is re-parsed as a NewOptionType message;
+  protobuf_unittest::NewOptionType new_enum_opt;
+  EXPECT_TRUE(old_enum_opt.AppendPartialToString(&buf));
+  EXPECT_TRUE(new_enum_opt.ParseFromString(buf));
+  EXPECT_EQ(protobuf_unittest::NewOptionType::NEW_VALUE, new_enum_opt.value());
 }
 
 // ===================================================================
 
-// The tests below trigger every unique call to AddError() in descriptor.cc,
-// in the order in which they appear in that file.  I'm using TextFormat here
-// to specify the input descriptors because building them using code would
-// be too bulky.
-
-class MockErrorCollector : public DescriptorPool::ErrorCollector {
- public:
-  MockErrorCollector() {}
-  ~MockErrorCollector() {}
-
-  string text_;
-  string warning_text_;
-
-  // implements ErrorCollector ---------------------------------------
-  void AddError(const string& filename,
-                const string& element_name, const Message* descriptor,
-                ErrorLocation location, const string& message) {
-    const char* location_name = NULL;
-    switch (location) {
-      case NAME         : location_name = "NAME"         ; break;
-      case NUMBER       : location_name = "NUMBER"       ; break;
-      case TYPE         : location_name = "TYPE"         ; break;
-      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
-      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
-      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
-      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
-      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
-      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
-      case OTHER        : location_name = "OTHER"        ; break;
-    }
-
-    strings::SubstituteAndAppend(
-      &text_, "$0: $1: $2: $3\n",
-      filename, element_name, location_name, message);
-  }
-
-  // implements ErrorCollector ---------------------------------------
-  void AddWarning(const string& filename, const string& element_name,
-                  const Message* descriptor, ErrorLocation location,
-                  const string& message) {
-    const char* location_name = NULL;
-    switch (location) {
-      case NAME         : location_name = "NAME"         ; break;
-      case NUMBER       : location_name = "NUMBER"       ; break;
-      case TYPE         : location_name = "TYPE"         ; break;
-      case EXTENDEE     : location_name = "EXTENDEE"     ; break;
-      case DEFAULT_VALUE: location_name = "DEFAULT_VALUE"; break;
-      case OPTION_NAME  : location_name = "OPTION_NAME"  ; break;
-      case OPTION_VALUE : location_name = "OPTION_VALUE" ; break;
-      case INPUT_TYPE   : location_name = "INPUT_TYPE"   ; break;
-      case OUTPUT_TYPE  : location_name = "OUTPUT_TYPE"  ; break;
-      case OTHER        : location_name = "OTHER"        ; break;
-    }
-
-    strings::SubstituteAndAppend(
-      &warning_text_, "$0: $1: $2: $3\n",
-      filename, element_name, location_name, message);
-  }
-};
-
 class ValidationErrorTest : public testing::Test {
  protected:
   // Parse file_text as a FileDescriptorProto in text format and add it
@@ -5043,7 +5196,6 @@
 }
 
 TEST_F(ValidationErrorTest, UnusedImportWarning) {
-
   pool_.AddUnusedImportTrackFile("bar.proto");
   BuildFile(
     "name: \"bar.proto\" "
@@ -5075,7 +5227,7 @@
   // }
   //
   pool_.AddUnusedImportTrackFile("forward.proto");
-  BuildFile(
+  BuildFileWithWarnings(
     "name: \"forward.proto\""
     "dependency: \"base.proto\""
     "dependency: \"bar.proto\""
@@ -5085,7 +5237,8 @@
     "message_type {"
     "  name: \"Forward\""
     "  field { name:\"base\" number:1 label:LABEL_OPTIONAL type_name:\"Base\" }"
-    "}");
+    "}",
+    "forward.proto: bar.proto: OTHER: Import bar.proto but not used.\n");
 }
 
 namespace {
@@ -5681,6 +5834,32 @@
       "defining options.\n");
 }
 
+// Test that field names that may conflict in JSON is not allowed by protoc.
+TEST_F(ValidationErrorTest, ValidateProto3JsonName) {
+  // The comparison is case-insensitive.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" "
+      "conflicts with field \"name\". This is not allowed in proto3.\n");
+  // Underscores are ignored.
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type {"
+      "  name: 'Foo'"
+      "  field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "}",
+      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" "
+      "conflicts with field \"ab\". This is not allowed in proto3.\n");
+}
+
 // ===================================================================
 // DescriptorDatabase
 
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 2e22ccb..b325944 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/duration.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/duration.pb.h"
+#include <google/protobuf/duration.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -111,10 +112,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Duration::kSecondsFieldNumber;
 const int Duration::kNanosFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Duration::Duration()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto
index 7f172aa..78bcc74 100644
--- a/src/google/protobuf/duration.proto
+++ b/src/google/protobuf/duration.proto
@@ -27,15 +27,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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "DurationProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "DurationProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
 // A Duration represents a signed, fixed-length span of time represented
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 2324d95..8d689ac 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -64,9 +64,13 @@
 
 #include <algorithm>
 #include <google/protobuf/stubs/hash.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
@@ -229,8 +233,8 @@
 
     // Warning:  The order in which the following pointers are defined is
     //   important (the prototype must be deleted *before* the offsets).
-    scoped_array<int> offsets;
-    scoped_ptr<const GeneratedMessageReflection> reflection;
+    google::protobuf::scoped_array<int> offsets;
+    google::protobuf::scoped_ptr<const GeneratedMessageReflection> reflection;
     // Don't use a scoped_ptr to hold the prototype: the destructor for
     // DynamicMessage needs to know whether it is the prototype, and does so by
     // looking back at this field. This would assume details about the
@@ -415,7 +419,7 @@
   }
 
   // We need to manually run the destructors for repeated fields and strings,
-  // just as we ran their constructors in the the DynamicMessage constructor.
+  // just as we ran their constructors in the DynamicMessage constructor.
   // We also need to manually delete oneof fields if it is set and is string
   // or message.
   // Additionally, if any singular embedded messages have been allocated, we
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index b9796c7..70e437d 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -40,6 +40,11 @@
 // reflection_ops_unittest, cover the rest of the functionality used by
 // DynamicMessage.
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
 #include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/dynamic_message.h>
@@ -144,7 +149,7 @@
   // Check that all fields have independent offsets by setting each
   // one to a unique value then checking that they all still have those
   // unique values (i.e. they don't stomp each other).
-  scoped_ptr<Message> message(prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(prototype_->New());
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
   reflection_tester.SetAllFieldsViaReflection(message.get());
@@ -153,7 +158,7 @@
 
 TEST_F(DynamicMessageTest, Extensions) {
   // Check that extensions work.
-  scoped_ptr<Message> message(extensions_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(extensions_prototype_->New());
   TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
 
   reflection_tester.SetAllFieldsViaReflection(message.get());
@@ -162,7 +167,7 @@
 
 TEST_F(DynamicMessageTest, PackedFields) {
   // Check that packed fields work properly.
-  scoped_ptr<Message> message(packed_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(packed_prototype_->New());
   TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
 
   reflection_tester.SetPackedFieldsViaReflection(message.get());
@@ -171,7 +176,7 @@
 
 TEST_F(DynamicMessageTest, Oneof) {
   // Check that oneof fields work properly.
-  scoped_ptr<Message> message(oneof_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(oneof_prototype_->New());
 
   // Check default values.
   const Descriptor* descriptor = message->GetDescriptor();
@@ -232,7 +237,7 @@
   // Since we share the implementation with generated messages, we don't need
   // to test very much here.  Just make sure it appears to be working.
 
-  scoped_ptr<Message> message(prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(prototype_->New());
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
   int initial_space_used = message->SpaceUsed();
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 50cbd9a..f2eec78 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/empty.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/empty.pb.h"
+#include <google/protobuf/empty.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -79,9 +80,9 @@
 
   ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
     "\n\033google/protobuf/empty.proto\022\017google.pr"
-    "otobuf\"\007\n\005EmptyBM\n\023com.google.protobufB\n"
-    "EmptyProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf."
-    "WellKnownTypesb\006proto3", 142);
+    "otobuf\"\007\n\005EmptyBP\n\023com.google.protobufB\n"
+    "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob"
+    "uf.WellKnownTypesb\006proto3", 145);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/empty.proto", &protobuf_RegisterTypes);
   Empty::default_instance_ = new Empty();
@@ -108,8 +109,8 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
-#endif  // !_MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Empty::Empty()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -117,6 +118,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.Empty)
 }
 
+Empty::Empty(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
+}
+
 void Empty::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -140,10 +149,20 @@
 }
 
 void Empty::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void Empty::ArenaDtor(void* object) {
+  Empty* _this = reinterpret_cast< Empty* >(object);
+  (void)_this;
+}
+void Empty::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void Empty::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -162,11 +181,7 @@
 Empty* Empty::default_instance_ = NULL;
 
 Empty* Empty::New(::google::protobuf::Arena* arena) const {
-  Empty* n = new Empty;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
 }
 
 void Empty::Clear() {
@@ -255,6 +270,18 @@
 
 void Empty::Swap(Empty* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Empty temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Empty::UnsafeArenaSwap(Empty* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void Empty::InternalSwap(Empty* other) {
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 20876be..868009f 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -53,9 +53,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const Empty& default_instance();
 
+  void UnsafeArenaSwap(Empty* other);
   void Swap(Empty* other);
 
   // implements Message ----------------------------------------------
@@ -82,6 +87,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(Empty* other);
+  protected:
+  explicit Empty(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -101,6 +111,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   mutable int _cached_size_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto();
diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto
index 9dddc6c..b96daf2 100644
--- a/src/google/protobuf/empty.proto
+++ b/src/google/protobuf/empty.proto
@@ -27,16 +27,18 @@
 // 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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_multiple_files = true;
-option java_outer_classname = "EmptyProto";
-option java_package = "com.google.protobuf";
-option java_generate_equals_and_hash = true;
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
 
 // 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
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 919bd83..9afb236 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -34,6 +34,7 @@
 
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/io/coded_stream.h>
@@ -594,20 +595,21 @@
     ClearExtension(number);
     return;
   }
+  ::google::protobuf::Arena* message_arena = message->GetArena();
   Extension* extension;
   if (MaybeNewExtension(number, descriptor, &extension)) {
     extension->type = type;
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
     extension->is_repeated = false;
     extension->is_lazy = false;
-    if (message->GetArena() == arena_) {
+    if (message_arena == arena_) {
       extension->message_value = message;
+    } else if (message_arena == NULL) {
+      extension->message_value = message;
+      arena_->Own(message);  // not NULL because not equal to message_arena
     } else {
       extension->message_value = message->New(arena_);
       extension->message_value->CheckTypeAndMergeFrom(*message);
-      if (message->GetArena() == NULL) {
-        delete message;
-      }
     }
   } else {
     GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
@@ -617,14 +619,14 @@
       if (arena_ == NULL) {
         delete extension->message_value;
       }
-      if (message->GetArena() == arena_) {
+      if (message_arena == arena_) {
         extension->message_value = message;
+      } else if (message_arena == NULL) {
+        extension->message_value = message;
+        arena_->Own(message);  // not NULL because not equal to message_arena
       } else {
         extension->message_value = message->New(arena_);
         extension->message_value->CheckTypeAndMergeFrom(*message);
-        if (message->GetArena() == NULL) {
-          delete message;
-        }
       }
     }
   }
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index 0968125..bca179b 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -724,8 +724,7 @@
   static const RepeatedFieldType* GetDefaultRepeatedField();
 };
 
-LIBPROTOBUF_EXPORT extern ProtobufOnceType
-repeated_primitive_generic_type_traits_once_init_;
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_primitive_generic_type_traits_once_init_;
 
 class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
  private:
@@ -766,7 +765,7 @@
 }                                                                          \
 template<> inline const RepeatedField<TYPE>*                               \
     RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() {         \
-  GoogleOnceInit(                                                          \
+  ::google::protobuf::GoogleOnceInit(                                                          \
       &repeated_primitive_generic_type_traits_once_init_,                  \
       &RepeatedPrimitiveGenericTypeTraits::InitializeDefaultRepeatedFields); \
   return RepeatedPrimitiveGenericTypeTraits::                              \
@@ -822,8 +821,7 @@
   }
 };
 
-LIBPROTOBUF_EXPORT extern ProtobufOnceType
-repeated_string_type_traits_once_init_;
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_string_type_traits_once_init_;
 
 class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
  public:
@@ -868,7 +866,7 @@
   }
 
   static const RepeatedFieldType* GetDefaultRepeatedField() {
-    GoogleOnceInit(&repeated_string_type_traits_once_init_,
+    ::google::protobuf::GoogleOnceInit(&repeated_string_type_traits_once_init_,
                    &InitializeDefaultRepeatedFields);
     return default_repeated_field_;
   }
@@ -1034,8 +1032,7 @@
   static const RepeatedFieldType* GetDefaultRepeatedField();
 };
 
-LIBPROTOBUF_EXPORT extern ProtobufOnceType
-repeated_message_generic_type_traits_once_init_;
+LIBPROTOBUF_EXPORT extern ProtobufOnceType repeated_message_generic_type_traits_once_init_;
 
 // This class exists only to hold a generic default empty repeated field for all
 // message-type repeated field extensions.
@@ -1052,7 +1049,7 @@
 template<typename Type> inline
     const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
     RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
-  GoogleOnceInit(
+  ::google::protobuf::GoogleOnceInit(
       &repeated_message_generic_type_traits_once_init_,
       &RepeatedMessageGenericTypeTraits::InitializeDefaultRepeatedFields);
   return reinterpret_cast<const RepeatedFieldType*>(
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index 1569120..f40fcbc 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -360,9 +360,8 @@
   unittest::ForeignMessage* foreign_message = new unittest::ForeignMessage();
   message->SetAllocatedExtension(unittest::optional_foreign_message_extension,
                                  foreign_message);
-  // foreign_message is copied underneath, as foreign_message is on heap
-  // and extension_set is on an arena.
-  EXPECT_NE(foreign_message,
+  // foreign_message is now owned by the arena.
+  EXPECT_EQ(foreign_message,
             message->MutableExtension(
                 unittest::optional_foreign_message_extension));
 
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index d8f4ee9..01a6ce5 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/field_mask.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/field_mask.pb.h"
+#include <google/protobuf/field_mask.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -110,9 +111,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FieldMask::kPathsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FieldMask::FieldMask()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
index 8b21c69..908c8a8 100644
--- a/src/google/protobuf/field_mask.proto
+++ b/src/google/protobuf/field_mask.proto
@@ -27,16 +27,17 @@
 // 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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "FieldMaskProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "FieldMaskProto";
+option java_multiple_files = true;
 option objc_class_prefix = "GPB";
+option java_generate_equals_and_hash = true;
 
 // `FieldMask` represents a set of symbolic field paths, for example:
 //
@@ -69,7 +70,7 @@
 //     z: 8
 //
 // The result will not contain specific values for fields x,y and z
-// (there value will be set to the default, and omitted in proto text
+// (their value will be set to the default, and omitted in proto text
 // output):
 //
 //
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index df04384..85ebdef 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -43,6 +43,11 @@
 // rather than generated accessors.
 
 #include <google/protobuf/generated_message_reflection.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
@@ -354,7 +359,7 @@
   ASSERT_EQ(2, message.repeated_foreign_message_size());
   const protobuf_unittest::ForeignMessage* expected =
       message.mutable_repeated_foreign_message(1);
-  scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+  google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
       &message, descriptor->FindFieldByName("repeated_foreign_message")));
   EXPECT_EQ(expected, released.get());
 }
@@ -377,9 +382,9 @@
       unittest::repeated_foreign_message_extension));
   const protobuf_unittest::ForeignMessage* expected = message.MutableExtension(
       unittest::repeated_foreign_message_extension, 1);
-  scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
+  google::protobuf::scoped_ptr<Message> released(message.GetReflection()->ReleaseLast(
       &message, descriptor->file()->FindExtensionByName(
-          "repeated_foreign_message_extension")));
+                    "repeated_foreign_message_extension")));
   EXPECT_EQ(expected, released.get());
 
 }
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index afaca2e..7b813f8 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -63,7 +63,6 @@
 int StringSpaceUsedExcludingSelf(const string& str) {
   const void* start = &str;
   const void* end = &str + 1;
-
   if (start <= str.data() && str.data() < end) {
     // The string's data is stored inside the string object itself.
     return 0;
@@ -73,6 +72,7 @@
 }
 
 
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 4bcd354..e3a34d0 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -629,6 +629,24 @@
   had_error_ = false;
 }
 
+CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
+                                     bool do_eager_refresh)
+  : output_(output),
+    buffer_(NULL),
+    buffer_size_(0),
+    total_bytes_(0),
+    had_error_(false),
+    aliasing_enabled_(false) {
+  if (do_eager_refresh) {
+    // Eagerly Refresh() so buffer space is immediately available.
+    Refresh();
+    // The Refresh() may have failed. If the client doesn't write any data,
+    // though, don't consider this an error. If the client does write data, then
+    // another Refresh() will be attempted and it will set the error once again.
+    had_error_ = false;
+  }
+}
+
 CodedOutputStream::~CodedOutputStream() {
   Trim();
 }
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 361c406..e377100 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -109,6 +109,7 @@
 #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 
+#include <assert.h>
 #include <string>
 #include <utility>
 #ifdef _MSC_VER
@@ -116,7 +117,7 @@
   #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
     #define PROTOBUF_LITTLE_ENDIAN 1
   #endif
-  #if _MSC_VER >= 1300
+  #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
     // If MSVC has "/RTCc" set, it will complain about truncating casts at
     // runtime.  This file contains some intentional truncating casts.
     #pragma runtime_checks("c", off)
@@ -665,6 +666,7 @@
  public:
   // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
   explicit CodedOutputStream(ZeroCopyOutputStream* output);
+  CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh);
 
   // Destroy the CodedOutputStream and position the underlying
   // ZeroCopyOutputStream immediately after the last byte written.
@@ -1035,7 +1037,7 @@
 inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
                                                            int* size) {
   *data = buffer_;
-  *size = buffer_end_ - buffer_;
+  *size = static_cast<int>(buffer_end_ - buffer_);
 }
 
 inline bool CodedInputStream::ExpectAtEnd() {
@@ -1231,7 +1233,7 @@
 }
 
 inline int CodedInputStream::BufferSize() const {
-  return buffer_end_ - buffer_;
+  return static_cast<int>(buffer_end_ - buffer_);
 }
 
 inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
@@ -1284,9 +1286,9 @@
 }  // namespace protobuf
 
 
-#if defined(_MSC_VER) && _MSC_VER >= 1300
+#if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
   #pragma runtime_checks("c", restore)
-#endif  // _MSC_VER
+#endif  // _MSC_VER && !defined(__INTEL_COMPILER)
 
 }  // namespace google
 #endif  // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index 630c908..d1782e3 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -34,6 +34,10 @@
 //
 // This file contains tests and benchmarks.
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <vector>
 
 #include <google/protobuf/io/coded_stream.h>
@@ -679,7 +683,7 @@
 }
 
 TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) {
-  scoped_array<uint8> buffer(new uint8[8]);
+  google::protobuf::scoped_array<uint8> buffer(new uint8[8]);
   CodedInputStream coded_input(buffer.get(), 8);
   string str;
   EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30));
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index 1be6c86..9c621b6 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -241,9 +241,7 @@
 
 GzipOutputStream::~GzipOutputStream() {
   Close();
-  if (input_buffer_ != NULL) {
-    operator delete(input_buffer_);
-  }
+  operator delete(input_buffer_);
 }
 
 // private
diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc
index 579de9a..a90bb9a 100644
--- a/src/google/protobuf/io/strtod.cc
+++ b/src/google/protobuf/io/strtod.cc
@@ -32,6 +32,7 @@
 
 #include <cstdio>
 #include <cstring>
+#include <limits>
 #include <string>
 
 #include <google/protobuf/stubs/logging.h>
@@ -109,6 +110,16 @@
   return result;
 }
 
+float SafeDoubleToFloat(double value) {
+  if (value > std::numeric_limits<float>::max()) {
+    return std::numeric_limits<float>::infinity();
+  } else if (value < -std::numeric_limits<float>::max()) {
+    return -std::numeric_limits<float>::infinity();
+  } else {
+    return static_cast<float>(value);
+  }
+}
+
 }  // namespace io
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/strtod.h b/src/google/protobuf/io/strtod.h
index c2efc8d..f56e41c 100644
--- a/src/google/protobuf/io/strtod.h
+++ b/src/google/protobuf/io/strtod.h
@@ -43,6 +43,11 @@
 // uses a dot as the decimal separator.
 double NoLocaleStrtod(const char* str, char** endptr);
 
+// Casts a double value to a float value. If the value is outside of the
+// representable range of float, it will be converted to positive or negative
+// infinity.
+float SafeDoubleToFloat(double value);
+
 }  // namespace io
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc
index 7ccd633..3d57707 100644
--- a/src/google/protobuf/io/tokenizer.cc
+++ b/src/google/protobuf/io/tokenizer.cc
@@ -375,7 +375,7 @@
           // Possibly followed by two more octal digits, but these will
           // just be consumed by the main loop anyway so we don't need
           // to do so explicitly here.
-        } else if (TryConsume('x') || TryConsume('X')) {
+        } else if (TryConsume('x')) {
           if (!TryConsumeOne<HexDigit>()) {
             AddError("Expected hex digits for escape sequence.");
           }
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index 6526056..20d50a2 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -875,6 +875,8 @@
   // String errors.
   { "'\\l' foo", true,
     "0:2: Invalid escape sequence in string literal.\n" },
+  { "'\\X' foo", true,
+    "0:2: Invalid escape sequence in string literal.\n" },
   { "'\\x' foo", true,
     "0:3: Expected hex digits for escape sequence.\n" },
   { "'foo", false,
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
index 686e63f..083beca 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -157,6 +157,7 @@
 }
 
 bool StringOutputStream::Next(void** data, int* size) {
+  GOOGLE_CHECK_NE(NULL, target_);
   int old_size = target_->size();
 
   // Grow the string.
@@ -188,14 +189,44 @@
 
 void StringOutputStream::BackUp(int count) {
   GOOGLE_CHECK_GE(count, 0);
+  GOOGLE_CHECK_NE(NULL, target_);
   GOOGLE_CHECK_LE(count, target_->size());
   target_->resize(target_->size() - count);
 }
 
 int64 StringOutputStream::ByteCount() const {
+  GOOGLE_CHECK_NE(NULL, target_);
   return target_->size();
 }
 
+void StringOutputStream::SetString(string* target) {
+  target_ = target;
+}
+
+// ===================================================================
+
+LazyStringOutputStream::LazyStringOutputStream(
+    ResultCallback<string*>* callback)
+    : StringOutputStream(NULL),
+      callback_(GOOGLE_CHECK_NOTNULL(callback)),
+      string_is_set_(false) {
+}
+
+LazyStringOutputStream::~LazyStringOutputStream() {
+}
+
+bool LazyStringOutputStream::Next(void** data, int* size) {
+  if (!string_is_set_) {
+    SetString(callback_->Run());
+    string_is_set_ = true;
+  }
+  return StringOutputStream::Next(data, size);
+}
+
+int64 LazyStringOutputStream::ByteCount() const {
+  return string_is_set_ ? StringOutputStream::ByteCount() : 0;
+}
+
 // ===================================================================
 
 CopyingInputStream::~CopyingInputStream() {}
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
index 9cdf037..1c397de 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -44,6 +44,10 @@
 #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
 #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
 
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <string>
 #include <iosfwd>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -144,6 +148,9 @@
   void BackUp(int count);
   int64 ByteCount() const;
 
+ protected:
+  void SetString(string* target);
+
  private:
   static const int kMinimumSize = 16;
 
@@ -152,6 +159,27 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
 };
 
+// LazyStringOutputStream is a StringOutputStream with lazy acquisition of
+// the output string from a callback. The string is owned externally, and not
+// deleted in the stream destructor.
+class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream {
+ public:
+  // Callback should be permanent (non-self-deleting). Ownership is transferred
+  // to the LazyStringOutputStream.
+  explicit LazyStringOutputStream(ResultCallback<string*>* callback);
+  ~LazyStringOutputStream();
+
+  // implements ZeroCopyOutputStream, overriding StringOutputStream -----------
+  bool Next(void** data, int* size);
+  int64 ByteCount() const;
+
+ private:
+  const scoped_ptr<ResultCallback<string*> > callback_;
+  bool string_is_set_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream);
+};
+
 // Note:  There is no StringInputStream.  Instead, just create an
 // ArrayInputStream as follows:
 //   ArrayInputStream input(str.data(), str.size());
@@ -235,7 +263,7 @@
 
   // Data is read into this buffer.  It may be NULL if no buffer is currently
   // in use.  Otherwise, it points to an array of size buffer_size_.
-  scoped_array<uint8> buffer_;
+  google::protobuf::scoped_array<uint8> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
@@ -324,7 +352,7 @@
 
   // Data is written from this buffer.  It may be NULL if no buffer is
   // currently in use.  Otherwise, it points to an array of size buffer_size_.
-  scoped_array<uint8> buffer_;
+  google::protobuf::scoped_array<uint8> buffer_;
   const int buffer_size_;
 
   // Number of valid bytes currently in the buffer (i.e. the size last
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc
index 3850e76..8c7358c 100644
--- a/src/google/protobuf/io/zero_copy_stream_unittest.cc
+++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -57,6 +57,10 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 #include <sstream>
 
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -197,7 +201,7 @@
 }
 
 void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
-  scoped_array<char> buffer(new char[str.size() + 1]);
+  google::protobuf::scoped_array<char> buffer(new char[str.size() + 1]);
   buffer[str.size()] = '\0';
   EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
   EXPECT_STREQ(str.c_str(), buffer.get());
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 8b61573..dfc6242 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -155,7 +155,7 @@
                "MapKey::GetUInt32Value");
     return val_.uint32_value_;
   }
-  int32 GetBoolValue() const {
+  bool GetBoolValue() const {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL,
                "MapKey::GetBoolValue");
     return val_.bool_value_;
@@ -188,8 +188,9 @@
       case FieldDescriptor::CPPTYPE_ENUM:
       case FieldDescriptor::CPPTYPE_MESSAGE:
         GOOGLE_LOG(FATAL) << "Can't get here.";
-        return false;
     }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return false;
   }
 
   void CopyFrom(const MapKey& other) {
@@ -273,7 +274,7 @@
                "MapValueRef::SetInt32Value");
     *reinterpret_cast<int32*>(data_) = value;
   }
-  void SetUInt32Value(uint64 value) {
+  void SetUInt32Value(uint32 value) {
     TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32,
                "MapValueRef::SetUInt32Value");
     *reinterpret_cast<uint32*>(data_) = value;
@@ -495,7 +496,7 @@
     insert(other.begin(), other.end());
   }
   template <class InputIt>
-  explicit Map(const InputIt& first, const InputIt& last)
+  Map(const InputIt& first, const InputIt& last)
       : arena_(NULL),
         allocator_(arena_),
         elements_(0, hasher(), key_equal(), allocator_),
@@ -582,21 +583,22 @@
 
    private:
     typedef void DestructorSkippable_;
-    Arena* arena_;
+    Arena* const arena_;
 
     template <typename X>
     friend class MapAllocator;
   };
 
- public:
   typedef MapAllocator<std::pair<const Key, MapPair<Key, T>*> > Allocator;
+  typedef hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator>
+      InnerMap;
 
+ public:
   // Iterators
   class const_iterator
       : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t,
                              const value_type*, const value_type&> {
-    typedef typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
-                              Allocator>::const_iterator InnerIt;
+    typedef typename InnerMap::const_iterator InnerIt;
 
    public:
     const_iterator() {}
@@ -623,8 +625,7 @@
   };
 
   class iterator : public std::iterator<std::forward_iterator_tag, value_type> {
-    typedef typename hash_map<Key, value_type*, hasher, equal_to<Key>,
-                              Allocator>::iterator InnerIt;
+    typedef typename InnerMap::iterator InnerIt;
 
    public:
     iterator() {}
@@ -740,8 +741,7 @@
 
   // Erase
   size_type erase(const key_type& key) {
-    typename hash_map<Key, value_type*, hash<Key>, equal_to<Key>,
-                      Allocator>::iterator it = elements_.find(key);
+    typename InnerMap::iterator it = elements_.find(key);
     if (it == elements_.end()) {
       return 0;
     } else {
@@ -811,7 +811,7 @@
 
   Arena* arena_;
   Allocator allocator_;
-  hash_map<Key, value_type*, hash<Key>, equal_to<Key>, Allocator> elements_;
+  InnerMap elements_;
   int default_enum_value_;
 
   friend class ::google::protobuf::Arena;
@@ -850,8 +850,9 @@
       case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
       case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
         GOOGLE_LOG(FATAL) << "Can't get here.";
-        return 0;
     }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return 0;
   }
   bool
   operator()(const google::protobuf::MapKey& map_key1,
@@ -873,8 +874,9 @@
       case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
       case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
         GOOGLE_LOG(FATAL) << "Can't get here.";
-        return true;
     }
+    GOOGLE_LOG(FATAL) << "Can't get here.";
+    return true;
   }
 };
 GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index 16c4a08..f116697 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -155,7 +155,8 @@
   this_iter->key_.SetType(that_iter.key_.type());
   // MapValueRef::type() fails when containing data is null. However, if
   // this_iter points to MapEnd, data can be null.
-  this_iter->value_.SetType((FieldDescriptor::CppType)that_iter.value_.type_);
+  this_iter->value_.SetType(
+      static_cast<FieldDescriptor::CppType>(that_iter.value_.type_));
   SetMapIteratorValue(this_iter);
 }
 
diff --git a/src/google/protobuf/map_lite_test_util.h b/src/google/protobuf/map_lite_test_util.h
index 77b5336..66dedde 100644
--- a/src/google/protobuf/map_lite_test_util.h
+++ b/src/google/protobuf/map_lite_test_util.h
@@ -47,7 +47,7 @@
   // Set every field in the message to a default value.
   static void SetMapFieldsInitialized(protobuf_unittest::TestMapLite* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // Modify all the map fields of the message (which should already have been
   // initialized with SetMapFields()).
   static void ModifyMapFields(protobuf_unittest::TestMapLite* message);
 
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
index 6f9d616..916cc54 100644
--- a/src/google/protobuf/map_proto2_unittest.proto
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -31,6 +31,8 @@
 syntax = "proto2";
 
 
+import "google/protobuf/unittest_import.proto";
+
 // We don't put this in a package within proto2 because we need to make sure
 // that the generated code doesn't depend on being in the proto2 namespace.
 // In map_test_util.h we do "using namespace unittest = protobuf_unittest".
@@ -58,3 +60,7 @@
   map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
   map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
 }
+
+message TestImportEnumMap {
+  map<int32, protobuf_unittest_import.ImportEnumForMap> import_enum_amp = 1;
+}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 16a24c2..451b02e 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -2154,7 +2154,7 @@
   // Check that all fields have independent offsets by setting each
   // one to a unique value then checking that they all still have those
   // unique values (i.e. they don't stomp each other).
-  scoped_ptr<Message> message(map_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
   MapReflectionTester reflection_tester(map_descriptor_);
 
   reflection_tester.SetMapFieldsViaReflection(message.get());
@@ -2163,7 +2163,7 @@
 
 TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) {
   // Check that map fields work properly.
-  scoped_ptr<Message> message(map_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
 
   // Check set functions.
   MapReflectionTester reflection_tester(map_descriptor_);
@@ -2177,7 +2177,7 @@
   // Since we share the implementation with generated messages, we don't need
   // to test very much here.  Just make sure it appears to be working.
 
-  scoped_ptr<Message> message(map_prototype_->New());
+  google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
   MapReflectionTester reflection_tester(map_descriptor_);
 
   int initial_space_used = message->SpaceUsed();
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
index 107a639..deaf0f4 100644
--- a/src/google/protobuf/map_test_util.h
+++ b/src/google/protobuf/map_test_util.h
@@ -49,7 +49,7 @@
   // Set every field in the message to a default value.
   static void SetMapFieldsInitialized(unittest::TestMap* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // Modify all the map fields of the message (which should already have been
   // initialized with SetMapFields()).
   static void ModifyMapFields(unittest::TestMap* message);
 
diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h
index 7e8757e..b3ba4e0 100644
--- a/src/google/protobuf/map_test_util_impl.h
+++ b/src/google/protobuf/map_test_util_impl.h
@@ -64,7 +64,7 @@
   template <typename MapMessage>
   static void SetMapFieldsInitialized(MapMessage* message);
 
-  // Modify all the map fields of the messsage (which should already have been
+  // Modify all the map fields of the message (which should already have been
   // initialized with SetMapFields()).
   template <typename EnumType, EnumType enum_value, typename MapMessage>
   static void ModifyMapFields(MapMessage* message);
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 2f6416d..032748b 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -55,7 +55,6 @@
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/singleton.h>
 #include <google/protobuf/stubs/stl_util.h>
-#include <google/protobuf/stubs/port.h>
 
 namespace google {
 namespace protobuf {
@@ -495,11 +494,19 @@
   return prototype->New(arena);
 }
 template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
 google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
     Message* value) {
   return value->GetArena();
 }
 template<>
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+GOOGLE_ATTRIBUTE_NOINLINE
+#endif
 void* GenericTypeHandler<Message>::GetMaybeArenaPointer(
     Message* value) {
   return value->GetMaybeArenaPointer();
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 348e7c7..a4d9277 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -739,9 +739,9 @@
   // specifyed by 'field' passing ownership to the message.
   // TODO(tmarek): Make virtual after all subclasses have been
   // updated.
-  virtual void AddAllocatedMessage(Message* message,
-                                   const FieldDescriptor* field,
-                                   Message* new_entry) const {}
+  virtual void AddAllocatedMessage(Message* /* message */,
+                                   const FieldDescriptor* /*field */,
+                                   Message* /* new_entry */) const {}
 
 
   // Get a RepeatedFieldRef object that can be used to read the underlying
@@ -947,31 +947,31 @@
   // TODO(jieluo) - make the map APIs pure virtual after updating
   // all the subclasses.
   // Returns true if key is in map. Returns false if key is not in map field.
-  virtual bool ContainsMapKey(const Message& message,
-                              const FieldDescriptor* field,
-                              const MapKey& key) const {
+  virtual bool ContainsMapKey(const Message& /* message*/,
+                              const FieldDescriptor* /* field */,
+                              const MapKey& /* key */) const {
     return false;
   }
 
   // If key is in map field: Saves the value pointer to val and returns
   // false. If key in not in map field: Insert the key into map, saves
   // value pointer to val and retuns true.
-  virtual bool InsertOrLookupMapValue(Message* message,
-                                      const FieldDescriptor* field,
-                                      const MapKey& key,
-                                      MapValueRef* val) const {
+  virtual bool InsertOrLookupMapValue(Message* /* message */,
+                                      const FieldDescriptor* /* field */,
+                                      const MapKey& /* key */,
+                                      MapValueRef* /* val */) const {
     return false;
   }
 
   // Delete and returns true if key is in the map field. Returns false
   // otherwise.
-  virtual bool DeleteMapValue(Message* message,
-                              const FieldDescriptor* field,
-                              const MapKey& key) const {
+  virtual bool DeleteMapValue(Message* /* mesage */,
+                              const FieldDescriptor* /* field */,
+                              const MapKey& /* key */) const {
     return false;
   }
 
-  // Returns a MaIterator referring to the first element in the map field.
+  // Returns a MapIterator referring to the first element in the map field.
   // If the map field is empty, this function returns the same as
   // reflection::MapEnd. Mutation to the field may invalidate the iterator.
   virtual MapIterator MapBegin(
@@ -987,15 +987,15 @@
 
   // Get the number of <key, value> pair of a map field. The result may be
   // different from FieldSize which can have duplicate keys.
-  virtual int MapSize(const Message& message,
-                      const FieldDescriptor* field) const {
+  virtual int MapSize(const Message& /* message */,
+                      const FieldDescriptor* /* field */) const {
     return 0;
   }
 
   // Help method for MapIterator.
   friend class MapIterator;
   virtual internal::MapFieldBase* MapData(
-      Message* message, const FieldDescriptor* field) const {
+      Message* /* message */, const FieldDescriptor* /* field */) const {
     return NULL;
   }
 
diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h
index fdee150..219645d 100644
--- a/src/google/protobuf/metadata.h
+++ b/src/google/protobuf/metadata.h
@@ -56,7 +56,7 @@
 // The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to
 // indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container
 // pointer.
-class LIBPROTOBUF_EXPORT InternalMetadataWithArena {
+class InternalMetadataWithArena {
  public:
   InternalMetadataWithArena() : ptr_(NULL) {}
   explicit InternalMetadataWithArena(Arena* arena)
diff --git a/src/google/protobuf/proto_cast.h b/src/google/protobuf/proto_cast.h
deleted file mode 100644
index dc0e9ac..0000000
--- a/src/google/protobuf/proto_cast.h
+++ /dev/null
@@ -1,59 +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.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-#define GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
-
-#include <string>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-
-// proto_cast<> is used to simulate over-the-wire conversion of one
-// proto message into another.  This is primarily useful for unit tests
-// which validate the version-compatibility semantics of protobufs.
-// Usage is similar to C++-style typecasts:
-//
-// OldMessage old_message = /*...*/;
-// NewMessage new_message = proto_cast<NewMessage>(old_message);
-namespace google {
-template<typename NewProto,
-         typename OldProto>
-NewProto proto_cast(const OldProto& old_proto) {
-  string wire_format;
-  GOOGLE_CHECK(old_proto.SerializeToString(&wire_format));
-
-  NewProto new_proto;
-  GOOGLE_CHECK(new_proto.ParseFromString(wire_format));
-  return new_proto;
-}
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_PROTO_CAST_H__
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index b10e7a9..5447fa4 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -208,10 +208,19 @@
   // sizeof(*this)
   int SpaceUsedExcludingSelf() const;
 
-  // Remove the element referenced by position.
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
   iterator erase(const_iterator position);
 
-  // Remove the elements in the range [first, last).
+  // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
   iterator erase(const_iterator first, const_iterator last);
 
   // Get the Arena on which this RepeatedField stores its elements.
@@ -565,7 +574,7 @@
 
 template <typename GenericType>
 GenericType* GenericTypeHandler<GenericType>::NewFromPrototype(
-    const GenericType* prototype, ::google::protobuf::Arena* arena) {
+    const GenericType* /* prototype */, ::google::protobuf::Arena* arena) {
   return New(arena);
 }
 template <typename GenericType>
@@ -618,7 +627,7 @@
 // Message specialization bodies defined in message.cc. This split is necessary
 // to allow proto2-lite (which includes this header) to be independent of
 // Message.
-DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message);
+DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Message)
 
 
 #undef DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES
@@ -649,7 +658,7 @@
 //   StringTypeHandler is exported.  So, we factor out StringTypeHandlerBase,
 //   export that, then make StringTypeHandler be a subclass which is NOT
 //   exported.
-// TODO(kenton):  Now that StringSpaceUsedExcludingSelf() is in the lite

+// TODO(kenton):  Now that StringSpaceUsedExcludingSelf() is in the lite
 //   library, this can be cleaned up.
 class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
  public:
@@ -665,7 +674,7 @@
   static inline ::google::protobuf::Arena* GetArena(string*) {
     return NULL;
   }
-  static inline void* GetMaybeArenaPointer(string* value) {
+  static inline void* GetMaybeArenaPointer(string* /* value */) {
     return NULL;
   }
   static inline void Delete(string* value, Arena* arena) {
@@ -683,7 +692,7 @@
 class StringTypeHandler : public StringTypeHandlerBase {
  public:
   static int SpaceUsed(const string& value)  {
-    return sizeof(value) + StringSpaceUsedExcludingSelf(value);
+    return static_cast<int>(sizeof(value)) + StringSpaceUsedExcludingSelf(value);
   }
 };
 
@@ -885,10 +894,19 @@
   // so will trigger a GOOGLE_DCHECK-failure.
   Element* ReleaseCleared();
 
-  // Remove the element referenced by position.
+  // Removes the element referenced by position.
+  //
+  // Returns an iterator to the element immediately following the removed
+  // element.
+  //
+  // Invalidates all iterators at or after the removed element, including end().
   iterator erase(const_iterator position);
 
   // Removes the elements in the range [first, last).
+  //
+  // Returns an iterator to the element immediately following the removed range.
+  //
+  // Invalidates all iterators at or after the removed range, including end().
   iterator erase(const_iterator first, const_iterator last);
 
   // Gets the arena on which this RepeatedPtrField stores its elements.
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index c839763..f2eb7ae 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/source_context.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/source_context.pb.h"
+#include <google/protobuf/source_context.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -110,9 +111,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int SourceContext::kFileNameFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 SourceContext::SourceContext()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
index e9a27d6..d76252c 100644
--- a/src/google/protobuf/source_context.proto
+++ b/src/google/protobuf/source_context.proto
@@ -27,15 +27,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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_multiple_files = true;
-option java_outer_classname = "SourceContextProto";
-option java_package = "com.google.protobuf";
-option java_generate_equals_and_hash = true;
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "SourceContextProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
 // `SourceContext` represents information about the source of a
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index d5f8912..e020597 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/struct.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/struct.pb.h"
+#include <google/protobuf/struct.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -212,9 +213,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Struct::kFieldsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Struct::Struct()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -480,14 +481,14 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Value::kNullValueFieldNumber;
 const int Value::kNumberValueFieldNumber;
 const int Value::kStringValueFieldNumber;
 const int Value::kBoolValueFieldNumber;
 const int Value::kStructValueFieldNumber;
 const int Value::kListValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Value::Value()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1218,9 +1219,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int ListValue::kValuesFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 ListValue::ListValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
index b3e9e69..8562e2c 100644
--- a/src/google/protobuf/struct.proto
+++ b/src/google/protobuf/struct.proto
@@ -27,15 +27,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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "StructProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "StructProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
 
diff --git a/src/google/protobuf/stubs/atomicops.h b/src/google/protobuf/stubs/atomicops.h
index d5cead6..9b3d1e6 100644
--- a/src/google/protobuf/stubs/atomicops.h
+++ b/src/google/protobuf/stubs/atomicops.h
@@ -76,7 +76,7 @@
 #ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
 // We need to be able to go between Atomic64 and AtomicWord implicitly.  This
 // means Atomic64 and AtomicWord should be the same type on 64-bit.
-#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) || defined(GOOGLE_PROTOBUF_ARCH_SPARC)
+#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL)
 // NaCl's intptr_t is not actually 64-bits on 64-bit!
 // http://code.google.com/p/nativeclient/issues/detail?id=1162
 // sparcv9's pointer type is 32bits
@@ -192,7 +192,7 @@
 
 // AIX
 #elif defined(GOOGLE_PROTOBUF_OS_AIX)
-#include <google/protobuf/stubs/atomicops_internals_aix.h>
+#include <google/protobuf/stubs/atomicops_internals_power.h>
 
 // Apple.
 #elif defined(GOOGLE_PROTOBUF_OS_APPLE)
@@ -210,6 +210,8 @@
 #include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64)
 #include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_POWER)
+#include <google/protobuf/stubs/atomicops_internals_power.h>
 #elif defined(__native_client__)
 #include <google/protobuf/stubs/atomicops_internals_pnacl.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_PPC)
diff --git a/src/google/protobuf/stubs/atomicops_internals_aix.h b/src/google/protobuf/stubs/atomicops_internals_power.h
similarity index 100%
rename from src/google/protobuf/stubs/atomicops_internals_aix.h
rename to src/google/protobuf/stubs/atomicops_internals_power.h
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index c4f9ede..87271c5 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -78,6 +78,18 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure);
 };
 
+template<typename R>
+class ResultCallback {
+ public:
+  ResultCallback() {}
+  virtual ~ResultCallback() {}
+
+  virtual R Run() = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback);
+};
+
 template<typename R, typename A1>
 class LIBPROTOBUF_EXPORT ResultCallback1 {
  public:
@@ -240,6 +252,50 @@
   Arg2 arg2_;
 };
 
+template<typename R>
+class FunctionResultCallback_0_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)();
+
+  FunctionResultCallback_0_0(FunctionType function, bool self_deleting)
+      : function_(function), self_deleting_(self_deleting) {}
+  ~FunctionResultCallback_0_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_();
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+};
+
+template<typename R, typename P1>
+class FunctionResultCallback_1_0 : public ResultCallback<R> {
+ public:
+  typedef R (*FunctionType)(P1);
+
+  FunctionResultCallback_1_0(FunctionType function, bool self_deleting,
+                             P1 p1)
+      : function_(function), self_deleting_(self_deleting), p1_(p1) {}
+  ~FunctionResultCallback_1_0() {}
+
+  R Run() {
+    bool needs_delete = self_deleting_;  // read in case callback deletes
+    R result = function_(p1_);
+    if (needs_delete) delete this;
+    return result;
+  }
+
+ private:
+  FunctionType function_;
+  bool self_deleting_;
+  P1 p1_;
+};
+
 template<typename R, typename Arg1>
 class FunctionResultCallback_0_1 : public ResultCallback1<R, Arg1> {
  public:
@@ -325,8 +381,6 @@
   typename remove_reference<P5>::type p5_;
 };
 
-}  // namespace internal
-
 // See Closure.
 inline Closure* NewCallback(void (*function)()) {
   return new internal::FunctionClosure0(function, true);
@@ -410,6 +464,33 @@
     object, method, false, arg1, arg2);
 }
 
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, true);
+}
+
+// See ResultCallback
+template<typename R>
+inline ResultCallback<R>* NewPermanentCallback(R (*function)()) {
+  return new internal::FunctionResultCallback_0_0<R>(function, false);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewCallback(R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, true, p1);
+}
+
+// See ResultCallback
+template<typename R, typename P1>
+inline ResultCallback<R>* NewPermanentCallback(
+    R (*function)(P1), P1 p1) {
+  return new internal::FunctionResultCallback_1_0<R, P1>(
+      function, false, p1);
+}
+
 // See ResultCallback1
 template<typename R, typename A1>
 inline ResultCallback1<R, A1>* NewCallback(R (*function)(A1)) {
@@ -452,6 +533,8 @@
                                                     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.h b/src/google/protobuf/stubs/common.h
index 88e7084..9c05cac 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -146,7 +146,7 @@
 LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
 
 inline bool IsStructurallyValidUTF8(const std::string& str) {
-  return IsStructurallyValidUTF8(str.data(), str.length());
+  return IsStructurallyValidUTF8(str.data(), static_cast<int>(str.length()));
 }
 
 // Returns initial number of bytes of structually valid UTF-8.
diff --git a/src/google/protobuf/stubs/common_unittest.cc b/src/google/protobuf/stubs/common_unittest.cc
index f9e2cfd..25bae9b 100644
--- a/src/google/protobuf/stubs/common_unittest.cc
+++ b/src/google/protobuf/stubs/common_unittest.cc
@@ -41,6 +41,8 @@
 
 namespace google {
 namespace protobuf {
+using internal::NewCallback;
+using internal::NewPermanentCallback;
 namespace {
 
 // TODO(kenton):  More tests.
diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h
index c6f210f..5833432 100755
--- a/src/google/protobuf/stubs/hash.h
+++ b/src/google/protobuf/stubs/hash.h
@@ -41,10 +41,15 @@
 #define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
 #define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
 
-// Use C++11 unordered_{map|set} if available. Otherwise, libc++ always support
-// unordered_{map|set}
-#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X) || \
-    defined(_LIBCPP_VERSION)
+// Android
+#if defined(__ANDROID__)
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
+
+// Use C++11 unordered_{map|set} if available.
+#elif ((_LIBCPP_STD_VER >= 11) || \
+      (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
+      (__GLIBCXX__ > 20090421)))
 # define GOOGLE_PROTOBUF_HAS_CXX11_HASH
 
 // For XCode >= 4.6:  the compiler is clang with libc++.
diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc
index 9f4fb82..d80c64f 100644
--- a/src/google/protobuf/stubs/int128.cc
+++ b/src/google/protobuf/stubs/int128.cc
@@ -188,7 +188,8 @@
     if ((flags & std::ios::adjustfield) == std::ios::left) {
       rep.append(width - rep.size(), o.fill());
     } else {
-      rep.insert(0, width - rep.size(), o.fill());
+      rep.insert(static_cast<std::string::size_type>(0),
+                 width - rep.size(), o.fill());
     }
   }
 
diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc
index cb5a20d..37def58 100644
--- a/src/google/protobuf/stubs/once_unittest.cc
+++ b/src/google/protobuf/stubs/once_unittest.cc
@@ -43,6 +43,7 @@
 
 namespace google {
 namespace protobuf {
+using internal::NewCallback;
 namespace {
 
 class OnceInitTest : public testing::Test {
@@ -127,10 +128,11 @@
   };
 
   TestThread* RunInitOnceInNewThread() {
-    return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
+    return new TestThread(internal::NewCallback(this, &OnceInitTest::InitOnce));
   }
   TestThread* RunInitRecursiveOnceInNewThread() {
-    return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce));
+    return new TestThread(
+        internal::NewCallback(this, &OnceInitTest::InitRecursiveOnce));
   }
 
   enum State {
diff --git a/src/google/protobuf/stubs/platform_macros.h b/src/google/protobuf/stubs/platform_macros.h
index 9edf34b..4ba4b34 100644
--- a/src/google/protobuf/stubs/platform_macros.h
+++ b/src/google/protobuf/stubs/platform_macros.h
@@ -65,12 +65,12 @@
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #elif defined(sparc)
 #define GOOGLE_PROTOBUF_ARCH_SPARC 1
-#ifdef SOLARIS_64BIT_ENABLED
+#if defined(__sparc_v9__) || defined(__sparcv9) || defined(__arch64__)
 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1
 #else
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #endif
-#elif defined(_POWER)
+#elif defined(_POWER) || defined(__powerpc64__) || defined(__PPC64__)
 #define GOOGLE_PROTOBUF_ARCH_POWER 1
 #define GOOGLE_PROTOBUF_ARCH_64_BIT 1
 #elif defined(__PPC__)
@@ -100,6 +100,8 @@
 #if TARGET_OS_IPHONE
 #define GOOGLE_PROTOBUF_OS_IPHONE
 #endif
+#elif defined(__EMSCRIPTEN__)
+#define GOOGLE_PROTOBUF_OS_EMSCRIPTEN
 #elif defined(__native_client__)
 #define GOOGLE_PROTOBUF_OS_NACL
 #elif defined(sun)
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index b35a3af..1036dff 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -53,7 +53,7 @@
   #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
     #define PROTOBUF_LITTLE_ENDIAN 1
   #endif
-  #if defined(_MSC_VER) && _MSC_VER >= 1300
+  #if _MSC_VER >= 1300 && !defined(__INTEL_COMPILER)
     // If MSVC has "/RTCc" set, it will complain about truncating casts at
     // runtime.  This file contains some intentional truncating casts.
     #pragma runtime_checks("c", off)
diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h
index a9d2b37..ad84870 100644
--- a/src/google/protobuf/stubs/statusor.h
+++ b/src/google/protobuf/stubs/statusor.h
@@ -224,14 +224,14 @@
 template<typename T>
 template<typename U>
 inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
-    : status_(other.status_), value_(other.value_) {
+    : status_(other.status_), value_(other.status_.ok() ? other.value_ : NULL) {
 }
 
 template<typename T>
 template<typename U>
 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
   status_ = other.status_;
-  value_ = other.value_;
+  if (status_.ok()) value_ = other.value_;
   return *this;
 }
 
diff --git a/src/google/protobuf/stubs/stringpiece.h b/src/google/protobuf/stubs/stringpiece.h
index 353a60d..ec3ffd5 100644
--- a/src/google/protobuf/stubs/stringpiece.h
+++ b/src/google/protobuf/stubs/stringpiece.h
@@ -149,6 +149,7 @@
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
 
 namespace google {
 namespace protobuf {
@@ -437,4 +438,16 @@
 }  // namespace protobuf
 }  // namespace google
 
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START
+template<> struct hash<StringPiece> {
+  size_t operator()(const StringPiece& s) const {
+    size_t result = 0;
+    for (const char *str = s.data(), *end = str + s.size(); str < end; str++) {  
+      result = 5 * result + *str;
+    }
+    return result;
+  }
+};
+GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END
+
 #endif  // STRINGS_STRINGPIECE_H_
diff --git a/src/google/protobuf/stubs/stringpiece_unittest.cc b/src/google/protobuf/stubs/stringpiece_unittest.cc
index 9b5dae1..a52d81f 100644
--- a/src/google/protobuf/stubs/stringpiece_unittest.cc
+++ b/src/google/protobuf/stubs/stringpiece_unittest.cc
@@ -36,6 +36,7 @@
 #include <vector>
 
 #include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/stubs/hash.h>
 #include <gtest/gtest.h>
 
 namespace google {
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index 8442f2c..7ba92e8 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -524,27 +524,81 @@
   return used;
 }
 
-int CEscapeString(const char* src, int src_len, char* dest, int dest_len) {
-  return CEscapeInternal(src, src_len, dest, dest_len, false, false);
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+static inline size_t CEscapedLength(StringPiece src) {
+  static char c_escaped_len[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+  };
+
+  size_t escaped_len = 0;
+  for (int i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    escaped_len += c_escaped_len[c];
+  }
+  return escaped_len;
 }
 
 // ----------------------------------------------------------------------
-// CEscape()
-// CHexEscape()
-//    Copies 'src' to result, escaping dangerous characters using
-//    C-style escape sequences. This is very useful for preparing query
-//    flags. 'src' and 'dest' should not overlap. The 'Hex' version
-//    hexadecimal rather than octal sequences.
-//
-//    Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
+// Escapes 'src' using C-style escape sequences, and appends the escaped string
+// to 'dest'. This version is faster than calling CEscapeInternal as it computes
+// the required space using a lookup table, and also does not do any special
+// handling for Hex or UTF-8 characters.
 // ----------------------------------------------------------------------
+void CEscapeAndAppend(StringPiece src, string* dest) {
+  size_t escaped_len = CEscapedLength(src);
+  if (escaped_len == src.size()) {
+    dest->append(src.data(), src.size());
+    return;
+  }
+
+  size_t cur_dest_len = dest->size();
+  dest->resize(cur_dest_len + escaped_len);
+  char* append_ptr = &(*dest)[cur_dest_len];
+
+  for (int i = 0; i < src.size(); ++i) {
+    unsigned char c = static_cast<unsigned char>(src[i]);
+    switch (c) {
+      case '\n': *append_ptr++ = '\\'; *append_ptr++ = 'n'; break;
+      case '\r': *append_ptr++ = '\\'; *append_ptr++ = 'r'; break;
+      case '\t': *append_ptr++ = '\\'; *append_ptr++ = 't'; break;
+      case '\"': *append_ptr++ = '\\'; *append_ptr++ = '\"'; break;
+      case '\'': *append_ptr++ = '\\'; *append_ptr++ = '\''; break;
+      case '\\': *append_ptr++ = '\\'; *append_ptr++ = '\\'; break;
+      default:
+        if (!isprint(c)) {
+          *append_ptr++ = '\\';
+          *append_ptr++ = '0' + c / 64;
+          *append_ptr++ = '0' + (c % 64) / 8;
+          *append_ptr++ = '0' + c % 8;
+        } else {
+          *append_ptr++ = c;
+        }
+        break;
+    }
+  }
+}
+
 string CEscape(const string& src) {
-  const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
-  scoped_array<char> dest(new char[dest_length]);
-  const int len = CEscapeInternal(src.data(), src.size(),
-                                  dest.get(), dest_length, false, false);
-  GOOGLE_DCHECK_GE(len, 0);
-  return string(dest.get(), len);
+  string dest;
+  CEscapeAndAppend(src, &dest);
+  return dest;
 }
 
 namespace strings {
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index b22066b..27d4757 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -314,27 +314,21 @@
 LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
 
 // ----------------------------------------------------------------------
-// CEscapeString()
-//    Copies 'src' to 'dest', escaping dangerous characters using
-//    C-style escape sequences. This is very useful for preparing query
-//    flags. 'src' and 'dest' should not overlap.
-//    Returns the number of bytes written to 'dest' (not including the \0)
-//    or -1 if there was insufficient space.
-//
-//    Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
-// ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len,
-                                     char* dest, int dest_len);
-
-// ----------------------------------------------------------------------
 // CEscape()
-//    More convenient form of CEscapeString: returns result as a "string".
-//    This version is slower than CEscapeString() because it does more
-//    allocation.  However, it is much more convenient to use in
-//    non-speed-critical code like logging messages etc.
+//    Escapes 'src' using C-style escape sequences and returns the resulting
+//    string.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !isprint().
 // ----------------------------------------------------------------------
 LIBPROTOBUF_EXPORT string CEscape(const string& src);
 
+// ----------------------------------------------------------------------
+// CEscapeAndAppend()
+//    Escapes 'src' using C-style escape sequences, and appends the escaped
+//    string to 'dest'.
+// ----------------------------------------------------------------------
+LIBPROTOBUF_EXPORT void CEscapeAndAppend(StringPiece src, string* dest);
+
 namespace strings {
 // Like CEscape() but does not escape bytes with the upper bit set.
 LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src);
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index d449c00..1c13a1a 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -65,7 +65,7 @@
   static void SetOneof2(unittest::TestOneof2* message);
 
   // Use the repeated versions of the set_*() accessors to modify all the
-  // repeated fields of the messsage (which should already have been
+  // repeated fields of the message (which should already have been
   // initialized with Set*Fields()).  Set*Fields() itself only tests
   // the add_*() accessors.
   static void ModifyRepeatedFields(unittest::TestAllTypes* message);
diff --git a/src/google/protobuf/test_util_lite.h b/src/google/protobuf/test_util_lite.h
index f250c93..47a2269 100644
--- a/src/google/protobuf/test_util_lite.h
+++ b/src/google/protobuf/test_util_lite.h
@@ -52,7 +52,7 @@
   static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message);
 
   // Use the repeated versions of the set_*() accessors to modify all the
-  // repeated fields of the messsage (which should already have been
+  // repeated fields of the message (which should already have been
   // initialized with Set*Fields()).  Set*Fields() itself only tests
   // the add_*() accessors.
   static void ModifyRepeatedFields(unittest::TestAllTypesLite* message);
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 4d8c1f9..b0a5ce6 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -46,6 +46,7 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -377,19 +378,19 @@
     if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field,
                                          &any_value_field) &&
         TryConsume("[")) {
-      string full_type_name;
-      DO(ConsumeAnyTypeUrl(&full_type_name));
+      string full_type_name, prefix;
+      DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
       DO(Consume("]"));
+      TryConsume(":");  // ':' is optional between message labels and values.
       string serialized_value;
       DO(ConsumeAnyValue(full_type_name,
                          message->GetDescriptor()->file()->pool(),
                          &serialized_value));
       reflection->SetString(
           message, any_type_url_field,
-          string(internal::kTypeGoogleApisComPrefix) + full_type_name);
+          string(prefix + full_type_name));
       reflection->SetString(message, any_value_field, serialized_value);
       return true;
-      // Fall through.
     }
     if (TryConsume("[")) {
       // Extension.
@@ -656,7 +657,7 @@
       case FieldDescriptor::CPPTYPE_FLOAT: {
         double value;
         DO(ConsumeDouble(&value));
-        SET_FIELD(Float, static_cast<float>(value));
+        SET_FIELD(Float, io::SafeDoubleToFloat(value));
         break;
       }
 
@@ -981,7 +982,8 @@
   }
 
   // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
-  bool ConsumeAnyTypeUrl(string* full_type_name) {
+  // or "type.googleprod.com/full.type.Name"
+  bool ConsumeAnyTypeUrl(string* full_type_name, string* prefix) {
     // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
     // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
     string url1, url2, url3;
@@ -993,10 +995,12 @@
     DO(Consume("/"));
     DO(ConsumeFullTypeName(full_type_name));
 
-    const string prefix = url1 + "." + url2 + "." + url3 + "/";
-    if (prefix != internal::kTypeGoogleApisComPrefix) {
+    *prefix = url1 + "." + url2 + "." + url3 + "/";
+    if (*prefix != internal::kTypeGoogleApisComPrefix &&
+        *prefix != internal::kTypeGoogleProdComPrefix) {
       ReportError("TextFormat::Parser for Any supports only "
-                  "type.googleapi.com, but found \"" + prefix + "\"");
+                  "type.googleapis.com and type.googleprod.com, "
+                  "but found \"" + *prefix + "\"");
       return false;
     }
     return true;
@@ -1354,7 +1358,10 @@
   return SimpleDtoa(val);
 }
 string TextFormat::FieldValuePrinter::PrintString(const string& val) const {
-  return StrCat("\"", CEscape(val), "\"");
+  string printed("\"");
+  CEscapeAndAppend(val, &printed);
+  printed.push_back('\"');
+  return printed;
 }
 string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const {
   return PrintString(val);
@@ -1420,7 +1427,8 @@
     use_short_repeated_primitives_(false),
     hide_unknown_fields_(false),
     print_message_fields_in_index_order_(false),
-    expand_any_(false) {
+    expand_any_(false),
+    truncate_string_field_longer_than_(0LL) {
   SetUseUtf8StringEscaping(false);
 }
 
@@ -1772,11 +1780,21 @@
           ? reflection->GetRepeatedStringReference(
               message, field, index, &scratch)
           : reflection->GetStringReference(message, field, &scratch);
+      int64 size = value.size();
+      if (truncate_string_field_longer_than_ > 0) {
+        size = std::min(truncate_string_field_longer_than_,
+                        static_cast<int64>(value.size()));
+      }
+      string truncated_value(value.substr(0, size) + "...<truncated>...");
+      const string* value_to_print = &value;
+      if (size < value.size()) {
+        value_to_print = &truncated_value;
+      }
       if (field->type() == FieldDescriptor::TYPE_STRING) {
-        generator.Print(printer->PrintString(value));
+        generator.Print(printer->PrintString(*value_to_print));
       } else {
         GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
-        generator.Print(printer->PrintBytes(value));
+        generator.Print(printer->PrintBytes(*value_to_print));
       }
       break;
     }
@@ -1923,14 +1941,10 @@
         } else {
           // This field is not parseable as a Message.
           // So it is probably just a plain string.
-          generator.Print(": \"");
-          generator.Print(CEscape(value));
-          generator.Print("\"");
-          if (single_line_mode_) {
-            generator.Print(" ");
-          } else {
-            generator.Print("\n");
-          }
+          string printed(": \"");
+          CEscapeAndAppend(value, &printed);
+          printed.append(single_line_mode_ ? "\" " : "\"\n");
+          generator.Print(printed);
         }
         break;
       }
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 6717aec..ef3d4a8 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -219,6 +219,18 @@
       expand_any_ = expand;
     }
 
+    // If non-zero, we truncate all string fields that are  longer than this
+    // threshold.  This is useful when the proto message has very long strings,
+    // e.g., dump of encoded image file.
+    //
+    // NOTE(hfgong):  Setting a non-zero value breaks round-trip safe
+    // property of TextFormat::Printer.  That is, from the printed message, we
+    // cannot fully recover the original string field any more.
+    void SetTruncateStringFieldLongerThan(
+        const int64 truncate_string_field_longer_than) {
+      truncate_string_field_longer_than_ = truncate_string_field_longer_than;
+    }
+
     // Register a custom field-specific FieldValuePrinter for fields
     // with a particular FieldDescriptor.
     // Returns "true" if the registration succeeded, or "false", if there is
@@ -286,6 +298,8 @@
 
     bool expand_any_;
 
+    int64 truncate_string_field_longer_than_;
+
     google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
     typedef map<const FieldDescriptor*,
                 const FieldValuePrinter*> CustomPrinterMap;
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 1aafd8e..8d61be1 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -37,6 +37,10 @@
 #include <math.h>
 #include <stdlib.h>
 #include <limits>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
@@ -931,7 +935,7 @@
  protected:
   void ExpectFailure(const string& input, const string& message, int line,
                      int col) {
-    scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
+    google::protobuf::scoped_ptr<unittest::TestAllTypes> proto(new unittest::TestAllTypes);
     ExpectFailure(input, message, line, col, proto.get());
   }
 
@@ -992,7 +996,7 @@
 };
 
 TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
-  scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
   const Descriptor* d = message->GetDescriptor();
 
   string stringData =
@@ -1057,7 +1061,7 @@
 }
 
 TEST_F(TextFormatParserTest, ParseFieldValueFromString) {
-  scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
+  google::protobuf::scoped_ptr<unittest::TestAllTypes> message(new unittest::TestAllTypes);
   const Descriptor* d = message->GetDescriptor();
 
 #define EXPECT_FIELD(name, value, valuestring) \
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 2ee0ec2..c1c4402 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/timestamp.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/timestamp.pb.h"
+#include <google/protobuf/timestamp.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -82,9 +83,9 @@
   ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
     "\n\037google/protobuf/timestamp.proto\022\017googl"
     "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
-    "\022\r\n\005nanos\030\002 \001(\005BQ\n\023com.google.protobufB\016"
-    "TimestampProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Proto"
-    "buf.WellKnownTypesb\006proto3", 186);
+    "\022\r\n\005nanos\030\002 \001(\005BT\n\023com.google.protobufB\016"
+    "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr"
+    "otobuf.WellKnownTypesb\006proto3", 189);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/timestamp.proto", &protobuf_RegisterTypes);
   Timestamp::default_instance_ = new Timestamp();
@@ -111,10 +112,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Timestamp::kSecondsFieldNumber;
 const int Timestamp::kNanosFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Timestamp::Timestamp()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -122,6 +123,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.Timestamp)
 }
 
+Timestamp::Timestamp(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
+}
+
 void Timestamp::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -147,10 +156,20 @@
 }
 
 void Timestamp::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void Timestamp::ArenaDtor(void* object) {
+  Timestamp* _this = reinterpret_cast< Timestamp* >(object);
+  (void)_this;
+}
+void Timestamp::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void Timestamp::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -169,11 +188,7 @@
 Timestamp* Timestamp::default_instance_ = NULL;
 
 Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const {
-  Timestamp* n = new Timestamp;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<Timestamp>(arena);
 }
 
 void Timestamp::Clear() {
@@ -349,6 +364,18 @@
 
 void Timestamp::Swap(Timestamp* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Timestamp temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Timestamp::UnsafeArenaSwap(Timestamp* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void Timestamp::InternalSwap(Timestamp* other) {
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 85fc124..7bf6259 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -53,9 +53,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const Timestamp& default_instance();
 
+  void UnsafeArenaSwap(Timestamp* other);
   void Swap(Timestamp* other);
 
   // implements Message ----------------------------------------------
@@ -82,6 +87,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(Timestamp* other);
+  protected:
+  explicit Timestamp(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -113,6 +123,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::int64 seconds_;
   ::google::protobuf::int32 nanos_;
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
index 06b60e6..b51fc3f 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -27,15 +27,17 @@
 // 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.
+
 syntax = "proto3";
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "TimestampProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
 // A Timestamp represents a point in time independent of any time zone
@@ -92,6 +94,7 @@
 //     nanos = int((now - seconds) * 10**9)
 //     timestamp = Timestamp(seconds=seconds, nanos=nanos)
 //
+//
 message Timestamp {
 
   // Represents seconds of UTC time since Unix epoch
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 8f99356..7b47b3b 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/type.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/type.pb.h"
+#include <google/protobuf/type.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -70,7 +71,7 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _internal_metadata_),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _is_default_instance_));
   Field_descriptor_ = file->message_type(1);
-  static const int Field_offsets_[9] = {
+  static const int Field_offsets_[10] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, kind_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, cardinality_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, number_),
@@ -80,6 +81,7 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, packed_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, options_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, json_name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, default_value_),
   };
   Field_reflection_ =
     ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -203,37 +205,37 @@
     "\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc"
     "e_context\030\005 \001(\0132\036.google.protobuf.Source"
     "Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu"
-    "f.Syntax\"\276\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
+    "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
     "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001"
     "(\0162\".google.protobuf.Field.Cardinality\022\016"
     "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url"
     "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 "
     "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O"
-    "ption\022\021\n\tjson_name\030\n \001(\t\"\310\002\n\004Kind\022\020\n\014TYP"
-    "E_UNKNOWN\020\000\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLO"
-    "AT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n"
-    "\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_"
-    "FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020"
-    "\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nT"
-    "YPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENU"
-    "M\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020"
-    "\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013C"
-    "ardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022\030\n\024C"
-    "ARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY_REQ"
-    "UIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\316\001\n\004En"
-    "um\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132\032.go"
-    "ogle.protobuf.EnumValue\022(\n\007options\030\003 \003(\013"
-    "2\027.google.protobuf.Option\0226\n\016source_cont"
-    "ext\030\004 \001(\0132\036.google.protobuf.SourceContex"
-    "t\022\'\n\006syntax\030\005 \001(\0162\027.google.protobuf.Synt"
-    "ax\"S\n\tEnumValue\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030"
-    "\002 \001(\005\022(\n\007options\030\003 \003(\0132\027.google.protobuf"
-    ".Option\";\n\006Option\022\014\n\004name\030\001 \001(\t\022#\n\005value"
-    "\030\002 \001(\0132\024.google.protobuf.Any*.\n\006Syntax\022\021"
-    "\n\rSYNTAX_PROTO2\020\000\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023"
-    "com.google.protobufB\tTypeProtoP\001\240\001\001\242\002\003GP"
-    "B\252\002\036Google.Protobuf.WellKnownTypesb\006prot"
-    "o3", 1522);
+    "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu"
+    "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY"
+    "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6"
+    "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014"
+    "TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE"
+    "_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n"
+    "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY"
+    "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE"
+    "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020"
+    "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR"
+    "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION"
+    "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN"
+    "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022"
+    "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu"
+    "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu"
+    "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl"
+    "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016"
+    "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014"
+    "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030"
+    "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option"
+    "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p"
+    "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000"
+    "\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023com.google.protob"
+    "ufB\tTypeProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protob"
+    "uf.WellKnownTypesb\006proto3", 1545);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/type.proto", &protobuf_RegisterTypes);
   Type::default_instance_ = new Type();
@@ -282,14 +284,14 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Type::kNameFieldNumber;
 const int Type::kFieldsFieldNumber;
 const int Type::kOneofsFieldNumber;
 const int Type::kOptionsFieldNumber;
 const int Type::kSourceContextFieldNumber;
 const int Type::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Type::Type()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -967,7 +969,7 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const Field_Kind Field::TYPE_UNKNOWN;
 const Field_Kind Field::TYPE_DOUBLE;
 const Field_Kind Field::TYPE_FLOAT;
@@ -990,7 +992,7 @@
 const Field_Kind Field::Kind_MIN;
 const Field_Kind Field::Kind_MAX;
 const int Field::Kind_ARRAYSIZE;
-#endif  // _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor() {
   protobuf_AssignDescriptorsOnce();
   return Field_Cardinality_descriptor_;
@@ -1007,7 +1009,7 @@
   }
 }
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const Field_Cardinality Field::CARDINALITY_UNKNOWN;
 const Field_Cardinality Field::CARDINALITY_OPTIONAL;
 const Field_Cardinality Field::CARDINALITY_REQUIRED;
@@ -1015,8 +1017,8 @@
 const Field_Cardinality Field::Cardinality_MIN;
 const Field_Cardinality Field::Cardinality_MAX;
 const int Field::Cardinality_ARRAYSIZE;
-#endif  // _MSC_VER
-#ifndef _MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Field::kKindFieldNumber;
 const int Field::kCardinalityFieldNumber;
 const int Field::kNumberFieldNumber;
@@ -1026,7 +1028,8 @@
 const int Field::kPackedFieldNumber;
 const int Field::kOptionsFieldNumber;
 const int Field::kJsonNameFieldNumber;
-#endif  // !_MSC_VER
+const int Field::kDefaultValueFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Field::Field()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1058,6 +1061,7 @@
   oneof_index_ = 0;
   packed_ = false;
   json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 
 Field::~Field() {
@@ -1069,6 +1073,7 @@
   name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
   }
 }
@@ -1113,6 +1118,7 @@
   type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   packed_ = false;
   json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 
 #undef ZR_HELPER_
 #undef ZR_
@@ -1270,6 +1276,23 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(90)) goto parse_default_value;
+        break;
+      }
+
+      // optional string default_value = 11;
+      case 11: {
+        if (tag == 90) {
+         parse_default_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_default_value()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->default_value().data(), this->default_value().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "google.protobuf.Field.default_value"));
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1361,6 +1384,16 @@
       10, this->json_name(), output);
   }
 
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->default_value().data(), this->default_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      11, this->default_value(), output);
+  }
+
   // @@protoc_insertion_point(serialize_end:google.protobuf.Field)
 }
 
@@ -1434,6 +1467,17 @@
         10, this->json_name(), target);
   }
 
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->default_value().data(), this->default_value().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "google.protobuf.Field.default_value");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        11, this->default_value(), target);
+  }
+
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
   return target;
 }
@@ -1493,6 +1537,13 @@
         this->json_name());
   }
 
+  // optional string default_value = 11;
+  if (this->default_value().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->default_value());
+  }
+
   // repeated .google.protobuf.Option options = 9;
   total_size += 1 * this->options_size();
   for (int i = 0; i < this->options_size(); i++) {
@@ -1549,6 +1600,10 @@
 
     json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_);
   }
+  if (from.default_value().size() > 0) {
+
+    default_value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.default_value_);
+  }
 }
 
 void Field::CopyFrom(const ::google::protobuf::Message& from) {
@@ -1582,6 +1637,7 @@
   std::swap(packed_, other->packed_);
   options_.UnsafeArenaSwap(&other->options_);
   json_name_.Swap(&other->json_name_);
+  default_value_.Swap(&other->default_value_);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   std::swap(_cached_size_, other->_cached_size_);
 }
@@ -1826,17 +1882,60 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
 }
 
+// optional string default_value = 11;
+void Field::clear_default_value() {
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_default_value(const ::std::string& value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+ void Field::set_default_value(const char* value, size_t size) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+ ::std::string* Field::mutable_default_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* Field::release_default_value() {
+  
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void Field::set_allocated_default_value(::std::string* default_value) {
+  if (default_value != NULL) {
+    
+  } else {
+    
+  }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
 #endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Enum::kNameFieldNumber;
 const int Enum::kEnumvalueFieldNumber;
 const int Enum::kOptionsFieldNumber;
 const int Enum::kSourceContextFieldNumber;
 const int Enum::kSyntaxFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Enum::Enum()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2379,11 +2478,11 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumValue::kNameFieldNumber;
 const int EnumValue::kNumberFieldNumber;
 const int EnumValue::kOptionsFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 EnumValue::EnumValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2775,10 +2874,10 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Option::kNameFieldNumber;
 const int Option::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Option::Option()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index deda921..76fe8a6 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -28,8 +28,8 @@
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/unknown_field_set.h>
-#include "google/protobuf/any.pb.h"
-#include "google/protobuf/source_context.pb.h"
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/source_context.pb.h>
 // @@protoc_insertion_point(includes)
 
 namespace google {
@@ -471,6 +471,17 @@
   ::std::string* release_json_name();
   void set_allocated_json_name(::std::string* json_name);
 
+  // optional string default_value = 11;
+  void clear_default_value();
+  static const int kDefaultValueFieldNumber = 11;
+  const ::std::string& default_value() const;
+  void set_default_value(const ::std::string& value);
+  void set_default_value(const char* value);
+  void set_default_value(const char* value, size_t size);
+  ::std::string* mutable_default_value();
+  ::std::string* release_default_value();
+  void set_allocated_default_value(::std::string* default_value);
+
   // @@protoc_insertion_point(class_scope:google.protobuf.Field)
  private:
 
@@ -484,6 +495,7 @@
   ::google::protobuf::internal::ArenaStringPtr type_url_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_;
   ::google::protobuf::internal::ArenaStringPtr json_name_;
+  ::google::protobuf::internal::ArenaStringPtr default_value_;
   bool packed_;
   mutable int _cached_size_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto();
@@ -1264,6 +1276,49 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name)
 }
 
+// optional string default_value = 11;
+inline void Field::clear_default_value() {
+  default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline const ::std::string& Field::default_value() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Field.default_value)
+  return default_value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_default_value(const ::std::string& value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:google.protobuf.Field.default_value)
+}
+inline void Field::set_default_value(const char* value, size_t size) {
+  
+  default_value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.default_value)
+}
+inline ::std::string* Field::mutable_default_value() {
+  
+  // @@protoc_insertion_point(field_mutable:google.protobuf.Field.default_value)
+  return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Field::release_default_value() {
+  
+  return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Field::set_allocated_default_value(::std::string* default_value) {
+  if (default_value != NULL) {
+    
+  } else {
+    
+  }
+  default_value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), default_value);
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.default_value)
+}
+
 // -------------------------------------------------------------------
 
 // Enum
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
index 4df9576..1c9cf53 100644
--- a/src/google/protobuf/type.proto
+++ b/src/google/protobuf/type.proto
@@ -27,6 +27,7 @@
 // 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.
+
 syntax = "proto3";
 
 package google.protobuf;
@@ -34,22 +35,22 @@
 import "google/protobuf/any.proto";
 import "google/protobuf/source_context.proto";
 
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 option java_package = "com.google.protobuf";
 option java_outer_classname = "TypeProto";
 option java_multiple_files = true;
 option java_generate_equals_and_hash = true;
-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
 option objc_class_prefix = "GPB";
 
-// A light-weight descriptor for a proto message type.
+// A protocol buffer message type.
 message Type {
   // The fully qualified message name.
   string name = 1;
   // The list of fields.
   repeated Field fields = 2;
-  // The list of oneof definitions.
-  repeated string oneofs = 3;  // The list of oneofs declared in this Type
-  // The proto options.
+  // The list of types appearing in `oneof` definitions in this type.
+  repeated string oneofs = 3;
+  // The protocol buffer options.
   repeated Option options = 4;
   // The source context.
   SourceContext source_context = 5;
@@ -57,9 +58,9 @@
   Syntax syntax = 6;
 }
 
-// Field represents a single field of a message type.
+// A single field of a message type.
 message Field {
-  // Kind represents a basic field type.
+  // Basic field types.
   enum Kind {
     // Field type unknown.
     TYPE_UNKNOWN        = 0;
@@ -81,7 +82,7 @@
     TYPE_BOOL           = 8;
     // Field type string.
     TYPE_STRING         = 9;
-    // Field type group (deprecated proto2 type)
+    // Field type group. Proto2 syntax only, and deprecated.
     TYPE_GROUP          = 10;
     // Field type message.
     TYPE_MESSAGE        = 11;
@@ -101,38 +102,40 @@
     TYPE_SINT64         = 18;
   };
 
-  // Cardinality represents whether a field is optional, required, or
-  // repeated.
+  // Whether a field is optional, required, or repeated.
   enum Cardinality {
-    // The field cardinality is unknown. Typically an error condition.
+    // For fields with unknown cardinality.
     CARDINALITY_UNKNOWN = 0;
     // For optional fields.
     CARDINALITY_OPTIONAL = 1;
-    // For required fields. Not used for proto3.
+    // For required fields. Proto2 syntax only.
     CARDINALITY_REQUIRED = 2;
     // For repeated fields.
     CARDINALITY_REPEATED = 3;
   };
 
-  // The field kind.
+  // The field type.
   Kind kind = 1;
-  // The field cardinality, i.e. optional/required/repeated.
+  // The field cardinality.
   Cardinality cardinality = 2;
-  // The proto field number.
+  // The field number.
   int32 number = 3;
   // The field name.
   string name = 4;
-  // The type URL (without the scheme) when the type is MESSAGE or ENUM,
-  // such as `type.googleapis.com/google.protobuf.Empty`.
+  // The field type URL, without the scheme, for message or enumeration
+  // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
   string type_url = 6;
-  // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
+  // 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.
   int32 oneof_index = 7;
   // Whether to use alternative packed wire representation.
   bool packed = 8;
-  // The proto options.
+  // The protocol buffer options.
   repeated Option options = 9;
-  // The JSON name for this field.
+  // The field JSON name.
   string json_name = 10;
+  // The string value of the default value of this field. Proto2 syntax only.
+  string default_value = 11;
 }
 
 // Enum type definition.
@@ -141,7 +144,7 @@
   string name = 1;
   // Enum value definitions.
   repeated EnumValue enumvalue = 2;
-  // Proto options for the enum type.
+  // Protocol buffer options.
   repeated Option options = 3;
   // The source context.
   SourceContext source_context = 4;
@@ -155,22 +158,23 @@
   string name = 1;
   // Enum value number.
   int32 number = 2;
-  // Proto options for the enum value.
+  // Protocol buffer options.
   repeated Option options = 3;
 }
 
-// Proto option attached to messages/fields/enums etc.
+// A protocol buffer option, which can be attached to a message, field,
+// enumeration, etc.
 message Option {
-  // Proto option name.
+  // The option's name. For example, `"java_package"`.
   string name = 1;
-  // Proto option value.
+  // The option's value. For example, `"com.google.protobuf"`.
   Any value = 2;
 }
 
-// Syntax specifies the syntax in which a service element was defined.
+// The syntax in which a protocol buffer element is defined.
 enum Syntax {
-  // Syntax "proto2"
+  // Syntax `proto2`.
   SYNTAX_PROTO2 = 0;
-  // Syntax "proto3"
+  // Syntax `proto3`.
   SYNTAX_PROTO3 = 1;
 }
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index d4d6e86..4cc0e36 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -392,3 +392,30 @@
     optional int32 nested_extension = 7912573 [(field_opt2) = 1005];
   }
 }
+
+// Custom message option that has a required enum field.
+// WARNING: this is strongly discouraged!
+message OldOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+  }
+  required TestEnum value = 1;
+}
+
+// Updated version of the custom option above.
+message NewOptionType {
+  enum TestEnum {
+    OLD_VALUE = 0;
+    NEW_VALUE = 1;
+  }
+  required TestEnum value = 1;
+}
+
+extend google.protobuf.MessageOptions {
+  optional OldOptionType required_enum_opt = 106161807;
+}
+
+// Test message using the "required_enum_opt" option defined above.
+message TestMessageWithRequiredEnumOption {
+  option (required_enum_opt) = { value: OLD_VALUE };
+}
diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto
index 7e16522..8d03e38 100644
--- a/src/google/protobuf/unittest_import.proto
+++ b/src/google/protobuf/unittest_import.proto
@@ -64,3 +64,10 @@
   IMPORT_BAZ = 9;
 }
 
+
+// To use an enum in a map, it must has the first value as 0.
+enum ImportEnumForMap {
+  UNKNOWN = 0;
+  FOO = 1;
+  BAR = 2;
+}
diff --git a/src/google/protobuf/unittest_well_known_types.proto b/src/google/protobuf/unittest_well_known_types.proto
index 2cb7775..c907524 100644
--- a/src/google/protobuf/unittest_well_known_types.proto
+++ b/src/google/protobuf/unittest_well_known_types.proto
@@ -39,6 +39,8 @@
   google.protobuf.BoolValue bool_field = 16;
   google.protobuf.StringValue string_field = 17;
   google.protobuf.BytesValue bytes_field = 18;
+  // Part of struct, but useful to be able to test separately
+  google.protobuf.Value value_field = 19;
 }
 
 // A repeated field for each well-known type.
diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h
deleted file mode 100644
index 7c68ad6..0000000
--- a/src/google/protobuf/unknown_enum_impl.h
+++ /dev/null
@@ -1,154 +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.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-#define GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
-
-#include <stdlib.h>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/bridge/compatibility_mode_support.h>
-
-namespace google {
-namespace protobuf {
-
-// google/protobuf/message.h
-class Message;
-
-namespace util {
-
-// NOTE: You should not call these functions directly.  Instead use either
-// HAS_UNKNOWN_ENUM() or GET_UNKNOWN_ENUM(), defined in the public header.
-// The macro-versions operate in a type-safe manner and behave appropriately
-// for the proto version of the message, whereas these versions assume a
-// specific proto version and allow the caller to pass in any arbitrary integer
-// value as a field number.
-//
-// Returns whether the message has unrecognized the enum value for a given
-// field. It also stores the value into the unknown_value parameter if the
-// function returns true and the pointer is not NULL.
-//
-// In proto2, invalid enum values will be treated as unknown fields. This
-// function checks that case.
-bool HasUnknownEnum(const Message& message, int32 field_number,
-                    int32* unknown_value = NULL);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number,
-                             vector<int32>* unknown_values = NULL);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-bool HasUnknownEnumProto1(const Message& message, int32 field_number,
-                          int32* unknown_value);
-// Same as above, but returns all unknown enums.
-bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number,
-                                   vector<int32>* unknown_values);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool HasUnknownEnum_Template(const T& message, int32 field_number,
-                             int32* unknown_value = NULL) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    return HasUnknownEnum(message, field_number, unknown_value);
-  } else {
-    return HasUnknownEnumProto1(message, field_number, unknown_value);
-  }
-}
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-bool GetRepeatedEnumUnknowns_Template(
-    const T& message, int32 field_number,
-    vector<int32>* unknown_values = NULL) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    return GetRepeatedEnumUnknowns(message, field_number, unknown_values);
-  } else {
-    return GetRepeatedEnumUnknownsProto1(message, field_number,
-                                         unknown_values);
-  }
-}
-
-// NOTE: You should not call these functions directly.  Instead use
-// CLEAR_UNKNOWN_ENUM(), defined in the public header.  The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Clears the unknown entries of the given field of the message.
-void ClearUnknownEnum(Message* message, int32 field_number);
-// In proto1, clears the field if the value is out of range.
-// TODO(karner): Delete this or make it proto2-only once the migration
-// to proto2 is complete.
-void ClearUnknownEnumProto1(Message* message, int32 field_number);
-template <typename T>
-void ClearUnknownEnum_Template(T* message, int32 field_number) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    ClearUnknownEnum(message, field_number);
-  } else {
-    ClearUnknownEnumProto1(message, field_number);
-  }
-}
-
-// NOTE: You should not call these functions directly.  Instead use
-// SET_UNKNOWN_ENUM(), defined in the public header.  The macro-versions
-// operate in a type-safe manner and behave appropriately for the proto
-// version of the message, whereas these versions assume a specific proto
-// version and allow the caller to pass in any arbitrary integer value as a
-// field number.
-//
-// Sets the given value in the unknown fields of the message.
-void SetUnknownEnum(Message* message, int32 field_number, int32 unknown_value);
-// In proto1, invalue enum values are stored in the same way as valid enum
-// values.
-// TODO(karner): Delete this once the migration to proto2 is complete.
-void SetUnknownEnumProto1(Message* message, int32 field_number,
-                          int32 unknown_value);
-// Invokes the appropriate version based on whether the message is proto1
-// or proto2.
-template <typename T>
-void SetUnknownEnum_Template(T* message, int32 field_number,
-                             int32 unknown_value) {
-  if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value ||
-      !internal::is_base_of<ProtocolMessage, T>::value) {
-    SetUnknownEnum(message, field_number, unknown_value);
-  } else {
-    SetUnknownEnumProto1(message, field_number, unknown_value);
-  }
-}
-
-}  // namespace util
-}  // namespace protobuf
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_UNKNOWN_ENUM_IMPL_H__
diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto
deleted file mode 100644
index 3c549cc..0000000
--- a/src/google/protobuf/unknown_enum_test.proto
+++ /dev/null
@@ -1,62 +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.
-
-// Definitions of protos for testing cross-version compatibility.  The
-// UpRevision message acts as if it were a newer version of the DownRevision
-// message.  That is, UpRevision shares all the same fields as DownRevision,
-// but UpRevision can add fields and add enum values.
-syntax = "proto2";
-
-package google.protobuf.util;
-
-option csharp_namespace = "Google.ProtocolBuffers.TestProtos";
-
-message DownRevision {
-  enum Enum {
-    DEFAULT_VALUE = 2;
-    NONDEFAULT_VALUE = 3;
-  }
-
-  optional Enum value = 1 [default = DEFAULT_VALUE];
-  repeated Enum values = 2;
-}
-
-message UpRevision {
-  enum Enum {
-    DEFAULT_VALUE = 2;
-    NONDEFAULT_VALUE = 3;
-    NEW_VALUE = 4;
-    NEW_VALUE_2 = 5;
-    NEW_VALUE_3 = 6;
-  }
-
-  optional Enum value = 1 [default = DEFAULT_VALUE];
-  repeated Enum values = 2;
-}
diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h
index ee67626..8b83c69 100644
--- a/src/google/protobuf/util/field_comparator.h
+++ b/src/google/protobuf/util/field_comparator.h
@@ -93,7 +93,7 @@
 
 // Basic implementation of FieldComparator.  Supports four modes of floating
 // point value comparison: exact, approximate using MathUtil::AlmostEqual
-// method, and arbitrarilly precise using MathUtil::WithinFracionOrMargin.
+// method, and arbitrarilly precise using MathUtil::WithinFractionOrMargin.
 class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator {
  public:
   enum FloatComparison {
diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc
index 845839a..23f7d51 100644
--- a/src/google/protobuf/util/field_comparator_test.cc
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -35,6 +35,12 @@
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/mathutil.h>
+// This gtest header is put after mathutil.h intentionally. We have to do
+// this because mathutil.h includes mathlimits.h which requires cmath not
+// being included to compile on some versions of gcc:
+//   https://github.com/google/protobuf/blob/818c5eee08840355d70d2f3bdf1a2f17986a5e70/src/google/protobuf/stubs/mathlimits.h#L48
+// and the opensource version gtest.h header includes cmath transitively
+// somehow.
 #include <gtest/gtest.h>
 
 namespace google {
diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc
index 82034bd..c59f43a 100644
--- a/src/google/protobuf/util/field_mask_util.cc
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -43,7 +43,7 @@
   return Join(mask.paths(), ",");
 }
 
-void FieldMaskUtil::FromString(const string& str, FieldMask* out) {
+void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
   out->Clear();
   vector<string> paths = Split(str, ",");
   for (int i = 0; i < paths.size(); ++i) {
@@ -53,7 +53,7 @@
 }
 
 bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
-                                        const string& path) {
+                                        StringPiece path) {
   vector<string> parts = Split(path, ".");
   for (int i = 0; i < parts.size(); ++i) {
     const string& field_name = parts[i];
@@ -103,7 +103,7 @@
   // Add a field path into the tree. In a FieldMask, each field path matches
   // the specified field and also all its sub-fields. If the field path to
   // add is a sub-path of an existing field path in the tree (i.e., a leaf
-  // node), it means the tree already matchesthe the given path so nothing will
+  // node), it means the tree already matches the given path so nothing will
   // be added to the tree. If the path matches an existing non-leaf node in the
   // tree, that non-leaf node will be turned into a leaf node with all its
   // children removed because the path matches all the node's children.
@@ -386,15 +386,15 @@
   intersection.MergeToFieldMask(out);
 }
 
-bool FieldMaskUtil::IsPathInFieldMask(const string& path,
-                                      const FieldMask& mask) {
+bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
   for (int i = 0; i < mask.paths_size(); ++i) {
     const string& mask_path = mask.paths(i);
     if (path == mask_path) {
       return true;
     } else if (mask_path.length() < path.length()) {
       // Also check whether mask.paths(i) is a prefix of path.
-      if (path.compare(0, mask_path.length() + 1, mask_path + ".") == 0) {
+      if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
+          0) {
         return true;
       }
     }
diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h
index c99c34f..92f6989 100644
--- a/src/google/protobuf/util/field_mask_util.h
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -35,6 +35,7 @@
 
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/field_mask.pb.h>
+#include <google/protobuf/stubs/stringpiece.h>
 
 namespace google {
 namespace protobuf {
@@ -47,11 +48,11 @@
   // Converts FieldMask to/from string, formatted according to proto3 JSON
   // spec for FieldMask (e.g., "foo,bar,baz.quz").
   static string ToString(const FieldMask& mask);
-  static void FromString(const string& str, FieldMask* out);
+  static void FromString(StringPiece str, FieldMask* out);
 
   // Checks whether the given path is valid for type T.
   template <typename T>
-  static bool IsValidPath(const string& path) {
+  static bool IsValidPath(StringPiece path) {
     return InternalIsValidPath(T::descriptor(), path);
   }
 
@@ -67,7 +68,7 @@
   // Adds a path to FieldMask after checking whether the given path is valid.
   // This method check-fails if the path is not a valid path for type T.
   template <typename T>
-  static void AddPathToFieldMask(const string& path, FieldMask* mask) {
+  static void AddPathToFieldMask(StringPiece path, FieldMask* mask) {
     GOOGLE_CHECK(IsValidPath<T>(path));
     mask->add_paths(path);
   }
@@ -96,7 +97,7 @@
 
   // Returns true if path is covered by the given FieldMask. Note that path
   // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc.
-  static bool IsPathInFieldMask(const string& path, const FieldMask& mask);
+  static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
 
   class MergeOptions;
   // Merges fields specified in a FieldMask into another message.
@@ -105,7 +106,7 @@
 
  private:
   static bool InternalIsValidPath(const Descriptor* descriptor,
-                                  const string& path);
+                                  StringPiece path);
 
   static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor,
                                                FieldMask* out);
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index ea36079..b557429 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -35,8 +35,8 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/mathutil.h>
 #include <google/protobuf/stubs/mathlimits.h>
+#include <google/protobuf/stubs/mathutil.h>
 
 namespace google {
 namespace protobuf {
@@ -57,13 +57,8 @@
   return Status(util::error::INVALID_ARGUMENT, value_str);
 }
 
-// For general conversion between
-//     int32, int64, uint32, uint64, double and float
-// except conversion between double and float.
 template <typename To, typename From>
-StatusOr<To> NumberConvertAndCheck(From before) {
-  if (::google::protobuf::internal::is_same<From, To>::value) return before;
-  To after = static_cast<To>(before);
+StatusOr<To> ValidateNumberConversion(To after, From before) {
   if (after == before &&
       MathUtil::Sign<From>(before) == MathUtil::Sign<To>(after)) {
     return after;
@@ -76,6 +71,27 @@
   }
 }
 
+// For general conversion between
+//     int32, int64, uint32, uint64, double and float
+// except conversion between double and float.
+template <typename To, typename From>
+StatusOr<To> NumberConvertAndCheck(From before) {
+  if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
+// For conversion to integer types (int32, int64, uint32, uint64) from floating
+// point types (double, float) only.
+template <typename To, typename From>
+StatusOr<To> FloatingPointToIntConvertAndCheck(From before) {
+  if (::google::protobuf::internal::is_same<From, To>::value) return before;
+
+  To after = static_cast<To>(before);
+  return ValidateNumberConversion(after, before);
+}
+
 // For conversion between double and float only.
 template <typename To, typename From>
 StatusOr<To> FloatingPointConvertAndCheck(From before) {
@@ -96,30 +112,50 @@
 }  // namespace
 
 StatusOr<int32> DataPiece::ToInt32() const {
-  if (type_ == TYPE_STRING) {
-    return StringToNumber<int32>(safe_strto32);
-  }
+  if (type_ == TYPE_STRING) return StringToNumber<int32>(safe_strto32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int32, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int32, float>(float_);
+
   return GenericConvert<int32>();
 }
 
 StatusOr<uint32> DataPiece::ToUint32() const {
-  if (type_ == TYPE_STRING) {
-    return StringToNumber<uint32>(safe_strtou32);
-  }
+  if (type_ == TYPE_STRING) return StringToNumber<uint32>(safe_strtou32);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint32, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint32, float>(float_);
+
   return GenericConvert<uint32>();
 }
 
 StatusOr<int64> DataPiece::ToInt64() const {
-  if (type_ == TYPE_STRING) {
-    return StringToNumber<int64>(safe_strto64);
-  }
+  if (type_ == TYPE_STRING) return StringToNumber<int64>(safe_strto64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<int64, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<int64, float>(float_);
+
   return GenericConvert<int64>();
 }
 
 StatusOr<uint64> DataPiece::ToUint64() const {
-  if (type_ == TYPE_STRING) {
-    return StringToNumber<uint64>(safe_strtou64);
-  }
+  if (type_ == TYPE_STRING) return StringToNumber<uint64>(safe_strtou64);
+
+  if (type_ == TYPE_DOUBLE)
+    return FloatingPointToIntConvertAndCheck<uint64, double>(double_);
+
+  if (type_ == TYPE_FLOAT)
+    return FloatingPointToIntConvertAndCheck<uint64, float>(float_);
+
   return GenericConvert<uint64>();
 }
 
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index 2ab3fa8..f22bfe7 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -98,7 +98,8 @@
 
   static DataPiece NullData() { return DataPiece(TYPE_NULL, 0); }
 
-  virtual ~DataPiece() {}
+  virtual ~DataPiece() {
+  }
 
   // Accessors
   Type type() const { return type_; }
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc
index 97b248f..a63e560 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc
@@ -33,6 +33,7 @@
 #include <google/protobuf/stubs/hash.h>
 
 #include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {
@@ -42,13 +43,25 @@
 using util::StatusOr;
 namespace converter {
 
+namespace {
+// Helper function to convert string value to given data type by calling the
+// passed converter function on the DataPiece created from "value" argument.
+// If value is empty or if conversion fails, the default_value is returned.
+template <typename T>
+T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const,
+            T default_value) {
+  if (value.empty()) return default_value;
+  StatusOr<T> result = (DataPiece(value).*converter_fn)();
+  return result.ok() ? result.ValueOrDie() : default_value;
+}
+}  // namespace
+
 DefaultValueObjectWriter::DefaultValueObjectWriter(
     TypeResolver* type_resolver, const google::protobuf::Type& type,
     ObjectWriter* ow)
     : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
       own_typeinfo_(true),
       type_(type),
-      disable_normalize_(false),
       current_(NULL),
       root_(NULL),
       ow_(ow) {}
@@ -165,12 +178,6 @@
   return this;
 }
 
-DefaultValueObjectWriter*
-DefaultValueObjectWriter::DisableCaseNormalizationForNextKey() {
-  disable_normalize_ = true;
-  return this;
-}
-
 DefaultValueObjectWriter::Node::Node(const string& name,
                                      const google::protobuf::Type* type,
                                      NodeKind kind, const DataPiece& data,
@@ -178,7 +185,6 @@
     : name_(name),
       type_(type),
       kind_(kind),
-      disable_normalize_(false),
       is_any_(false),
       data_(data),
       is_placeholder_(is_placeholder) {}
@@ -198,10 +204,6 @@
 }
 
 void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
-  if (disable_normalize_) {
-    ow->DisableCaseNormalizationForNextKey();
-  }
-
   if (kind_ == PRIMITIVE) {
     ObjectWriter::RenderDataPieceTo(data_, name_, ow);
     return;
@@ -324,6 +326,7 @@
         }
       }
     }
+
     if (!is_map &&
         field.cardinality() ==
             google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
@@ -336,11 +339,11 @@
 
     // If the child field is of primitive type, sets its data to the default
     // value of its type.
-    google::protobuf::scoped_ptr<Node> child(
-        new Node(field.json_name(), field_type, kind,
-                 kind == PRIMITIVE ? CreateDefaultDataPieceForField(field)
-                                   : DataPiece::NullData(),
-                 true));
+    google::protobuf::scoped_ptr<Node> child(new Node(
+        field.json_name(), field_type, kind,
+        kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo)
+                          : DataPiece::NullData(),
+        true));
     new_children.push_back(child.release());
   }
   // Adds all leftover nodes in children_ to the beginning of new_child.
@@ -363,41 +366,68 @@
   }
 }
 
+DataPiece DefaultValueObjectWriter::FindEnumDefault(
+    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
+  if (!field.default_value().empty()) return DataPiece(field.default_value());
+
+  const google::protobuf::Enum* enum_type =
+      typeinfo->GetEnumByTypeUrl(field.type_url());
+  if (!enum_type) {
+    GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
+                 << "'";
+    return DataPiece::NullData();
+  }
+  // We treat the first value as the default if none is specified.
+  return enum_type->enumvalue_size() > 0
+             ? DataPiece(enum_type->enumvalue(0).name())
+             : DataPiece::NullData();
+}
+
 DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
-    const google::protobuf::Field& field) {
+    const google::protobuf::Field& field, const TypeInfo* typeinfo) {
   switch (field.kind()) {
     case google::protobuf::Field_Kind_TYPE_DOUBLE: {
-      return DataPiece(static_cast<double>(0));
+      return DataPiece(ConvertTo<double>(
+          field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
     }
     case google::protobuf::Field_Kind_TYPE_FLOAT: {
-      return DataPiece(static_cast<float>(0));
+      return DataPiece(ConvertTo<float>(
+          field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
     }
     case google::protobuf::Field_Kind_TYPE_INT64:
     case google::protobuf::Field_Kind_TYPE_SINT64:
     case google::protobuf::Field_Kind_TYPE_SFIXED64: {
-      return DataPiece(static_cast<int64>(0));
+      return DataPiece(ConvertTo<int64>(
+          field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
     }
     case google::protobuf::Field_Kind_TYPE_UINT64:
     case google::protobuf::Field_Kind_TYPE_FIXED64: {
-      return DataPiece(static_cast<uint64>(0));
+      return DataPiece(ConvertTo<uint64>(
+          field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
     }
     case google::protobuf::Field_Kind_TYPE_INT32:
     case google::protobuf::Field_Kind_TYPE_SINT32:
     case google::protobuf::Field_Kind_TYPE_SFIXED32: {
-      return DataPiece(static_cast<int32>(0));
+      return DataPiece(ConvertTo<int32>(
+          field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
     }
     case google::protobuf::Field_Kind_TYPE_BOOL: {
-      return DataPiece(false);
+      return DataPiece(
+          ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
     }
     case google::protobuf::Field_Kind_TYPE_STRING: {
-      return DataPiece(string());
+      return DataPiece(field.default_value());
     }
     case google::protobuf::Field_Kind_TYPE_BYTES: {
-      return DataPiece("", false);
+      return DataPiece(field.default_value(), false);
     }
     case google::protobuf::Field_Kind_TYPE_UINT32:
     case google::protobuf::Field_Kind_TYPE_FIXED32: {
-      return DataPiece(static_cast<uint32>(0));
+      return DataPiece(ConvertTo<uint32>(
+          field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      return FindEnumDefault(field, typeinfo);
     }
     default: { return DataPiece::NullData(); }
   }
@@ -408,7 +438,6 @@
   if (current_ == NULL) {
     root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(),
                          false));
-    root_->set_disable_normalize(GetAndResetDisableNormalize());
     root_->PopulateChildren(typeinfo_);
     current_ = root_.get();
     return this;
@@ -428,7 +457,6 @@
   }
 
   child->set_is_placeholder(false);
-  child->set_disable_normalize(GetAndResetDisableNormalize());
   if (child->kind() == OBJECT && child->number_of_children() == 0) {
     child->PopulateChildren(typeinfo_);
   }
@@ -454,21 +482,18 @@
   if (current_ == NULL) {
     root_.reset(
         new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false));
-    root_->set_disable_normalize(GetAndResetDisableNormalize());
     current_ = root_.get();
     return this;
   }
   MaybePopulateChildrenOfAny(current_);
   Node* child = current_->FindChild(name);
   if (child == NULL || child->kind() != LIST) {
-    GOOGLE_LOG(WARNING) << "Cannot find field '" << name << "'.";
     google::protobuf::scoped_ptr<Node> node(
         new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false));
     child = node.get();
     current_->AddChild(node.release());
   }
   child->set_is_placeholder(false);
-  child->set_disable_normalize(GetAndResetDisableNormalize());
 
   stack_.push(current_);
   current_ = child;
@@ -526,7 +551,6 @@
   } else {
     child->set_data(data);
   }
-  child->set_disable_normalize(GetAndResetDisableNormalize());
 }
 
 }  // namespace converter
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
index d454760..695b9dd 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.h
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -98,8 +98,6 @@
 
   virtual DefaultValueObjectWriter* RenderNull(StringPiece name);
 
-  virtual DefaultValueObjectWriter* DisableCaseNormalizationForNextKey();
-
  private:
   enum NodeKind {
     PRIMITIVE = 0,
@@ -110,7 +108,7 @@
 
   // "Node" represents a node in the tree that holds the input of
   // DefaultValueObjectWriter.
-  class Node {
+  class LIBPROTOBUF_EXPORT Node {
    public:
     Node(const string& name, const google::protobuf::Type* type, NodeKind kind,
          const DataPiece& data, bool is_placeholder);
@@ -149,10 +147,6 @@
 
     void set_data(const DataPiece& data) { data_ = data; }
 
-    void set_disable_normalize(bool disable_normalize) {
-      disable_normalize_ = disable_normalize;
-    }
-
     bool is_any() { return is_any_; }
 
     void set_is_any(bool is_any) { is_any_ = is_any; }
@@ -176,8 +170,6 @@
     const google::protobuf::Type* type_;
     // The kind of this node.
     NodeKind kind_;
-    // Whether to disable case normalization of the name.
-    bool disable_normalize_;
     // Whether this is a node for "Any".
     bool is_any_;
     // The data of this node when it is a leaf node.
@@ -201,16 +193,17 @@
 
   // Creates a DataPiece containing the default value of the type of the field.
   static DataPiece CreateDefaultDataPieceForField(
-      const google::protobuf::Field& field);
-
-  // Returns disable_normalize_ and reset it to false.
-  bool GetAndResetDisableNormalize() {
-    return disable_normalize_ ? (disable_normalize_ = false, true) : false;
-  }
+      const google::protobuf::Field& field, const TypeInfo* typeinfo);
 
   // Adds or replaces the data_ of a primitive child node.
   void RenderDataPiece(StringPiece name, const DataPiece& data);
 
+  // Returns the default enum value as a DataPiece, or the first enum value if
+  // there is no default. For proto3, where we cannot specify an explicit
+  // default, a zero value will always be returned.
+  static DataPiece FindEnumDefault(const google::protobuf::Field& field,
+                                   const TypeInfo* typeinfo);
+
   // Type information for all the types used in the descriptor. Used to find
   // google::protobuf::Type of nested messages/enums.
   const TypeInfo* typeinfo_;
@@ -221,8 +214,6 @@
   // Holds copies of strings passed to RenderString.
   vector<string*> string_values_;
 
-  // Whether to disable case normalization of the next node.
-  bool disable_normalize_;
   // The current Node. Owned by its parents.
   Node* current_;
   // The root Node.
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 237d072..8254c0f 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -43,21 +43,19 @@
 
 using google::protobuf::testing::DefaultValueTest;
 
-// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are
-// in the marshalling_test.cc and translator_integration_test.cc.
-class DefaultValueObjectWriterTest
+// Base class for setting up required state for running default values tests on
+// different descriptors.
+class BaseDefaultValueObjectWriterTest
     : public ::testing::TestWithParam<testing::TypeInfoSource> {
  protected:
-  DefaultValueObjectWriterTest()
+  explicit BaseDefaultValueObjectWriterTest(const Descriptor* descriptor)
       : helper_(GetParam()), mock_(), expects_(&mock_) {
-    helper_.ResetTypeInfo(DefaultValueTest::descriptor());
+    helper_.ResetTypeInfo(descriptor);
     testing_.reset(helper_.NewDefaultValueWriter(
-        string(kTypeServiceBaseUrl) + "/" +
-            DefaultValueTest::descriptor()->full_name(),
-        &mock_));
+        string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(), &mock_));
   }
 
-  virtual ~DefaultValueObjectWriterTest() {}
+  virtual ~BaseDefaultValueObjectWriterTest() {}
 
   TypeInfoTestHelper helper_;
   MockObjectWriter mock_;
@@ -65,6 +63,15 @@
   google::protobuf::scoped_ptr<DefaultValueObjectWriter> testing_;
 };
 
+// Tests to cover some basic DefaultValueObjectWriter use cases. More tests are
+// in the marshalling_test.cc and translator_integration_test.cc.
+class DefaultValueObjectWriterTest : public BaseDefaultValueObjectWriterTest {
+ protected:
+  DefaultValueObjectWriterTest()
+      : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {}
+  virtual ~DefaultValueObjectWriterTest() {}
+};
+
 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                         DefaultValueObjectWriterTest,
                         ::testing::Values(
@@ -74,6 +81,8 @@
   // Set expectation
   expects_.StartObject("")
       ->RenderDouble("doubleValue", 0.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
       ->RenderFloat("floatValue", 0.0)
       ->RenderInt64("int64Value", 0)
       ->RenderUint64("uint64Value", 0)
@@ -82,6 +91,7 @@
       ->RenderBool("boolValue", false)
       ->RenderString("stringValue", "")
       ->RenderBytes("bytesValue", "")
+      ->RenderString("enumValue", "ENUM_FIRST")
       ->EndObject();
 
   // Actual testing
@@ -92,6 +102,8 @@
   // Set expectation
   expects_.StartObject("")
       ->RenderDouble("doubleValue", 1.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
       ->RenderFloat("floatValue", 0.0)
       ->RenderInt64("int64Value", 0)
       ->RenderUint64("uint64Value", 0)
@@ -99,6 +111,7 @@
       ->RenderUint32("uint32Value", 0)
       ->RenderBool("boolValue", false)
       ->RenderString("stringValue", "")
+      ->RenderString("enumValue", "ENUM_FIRST")
       ->EndObject();
 
   // Actual testing
@@ -109,6 +122,8 @@
   // Set expectation
   expects_.StartObject("")
       ->RenderDouble("doubleValue", 1.0)
+      ->StartList("repeatedDouble")
+      ->EndList()
       ->RenderFloat("floatValue", 0.0)
       ->RenderInt64("int64Value", 0)
       ->RenderUint64("uint64Value", 0)
@@ -120,6 +135,7 @@
       ->StartObject("unknownObject")
       ->RenderString("unknown", "def")
       ->EndObject()
+      ->RenderString("enumValue", "ENUM_FIRST")
       ->EndObject();
 
   // Actual testing
@@ -132,6 +148,7 @@
       ->EndObject();
 }
 
+
 }  // namespace testing
 }  // namespace converter
 }  // namespace util
diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h
index 2699684..3f06393 100644
--- a/src/google/protobuf/util/internal/error_listener.h
+++ b/src/google/protobuf/util/internal/error_listener.h
@@ -31,11 +31,13 @@
 #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
 
+#include <algorithm>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #include <string>
+#include <vector>
 
 #include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc
index 36dc8ef..24bd554 100644
--- a/src/google/protobuf/util/internal/json_escaping.cc
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -186,7 +186,7 @@
                    uint32 *cp, int* num_left, int *num_read) {
   if (*num_left == 0) {
     // Last read was complete. Start reading a new unicode code point.
-    *cp = str[index++];
+    *cp = static_cast<uint8>(str[index++]);
     *num_read = 1;
     // The length of the code point is determined from reading the first byte.
     //
@@ -235,7 +235,7 @@
     *num_read = 0;
   }
   while (*num_left > 0 && index < str.size()) {
-    uint32 ch = str[index++];
+    uint32 ch = static_cast<uint8>(str[index++]);
     --(*num_left);
     ++(*num_read);
     *cp = (*cp << 6) | (ch & 0x3f);
diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc
index f81e330..94d2ab7 100644
--- a/src/google/protobuf/util/internal/json_objectwriter.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -37,8 +37,8 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/util/internal/json_escaping.h>
-#include <google/protobuf/stubs/mathlimits.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
 
 namespace google {
 namespace protobuf {
@@ -116,7 +116,7 @@
 
 JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
                                                  double value) {
-  if (google::protobuf::MathLimits<double>::IsFinite(value)) {
+  if (MathLimits<double>::IsFinite(value)) {
     return RenderSimple(name, SimpleDtoa(value));
   }
 
@@ -126,7 +126,7 @@
 
 JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name,
                                                 float value) {
-  if (google::protobuf::MathLimits<float>::IsFinite(value)) {
+  if (MathLimits<float>::IsFinite(value)) {
     return RenderSimple(name, SimpleFtoa(value));
   }
 
diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc
index dcd6060..9d82016 100644
--- a/src/google/protobuf/util/internal/json_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc
@@ -47,8 +47,7 @@
   JsonObjectWriterTest()
       : str_stream_(new StringOutputStream(&output_)),
         out_stream_(new CodedOutputStream(str_stream_)),
-        ow_(NULL) {
-  }
+        ow_(NULL) {}
 
   virtual ~JsonObjectWriterTest() {
     delete ow_;
@@ -64,36 +63,34 @@
 
 TEST_F(JsonObjectWriterTest, EmptyRootObject) {
   ow_ = new JsonObjectWriter("", out_stream_);
-  ow_->StartObject("")
-     ->EndObject();
+  ow_->StartObject("")->EndObject();
   EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, EmptyObject) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartObject("")
-       ->RenderString("test", "value")
-       ->StartObject("empty")
-       ->EndObject()
-     ->EndObject();
+      ->RenderString("test", "value")
+      ->StartObject("empty")
+      ->EndObject()
+      ->EndObject();
   EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}",
             output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, EmptyRootList) {
   ow_ = new JsonObjectWriter("", out_stream_);
-  ow_->StartList("")
-     ->EndList();
+  ow_->StartList("")->EndList();
   EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, EmptyList) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartObject("")
-       ->RenderString("test", "value")
-       ->StartList("empty")
-       ->EndList()
-     ->EndObject();
+      ->RenderString("test", "value")
+      ->StartList("empty")
+      ->EndList()
+      ->EndObject();
   EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}",
             output_.substr(0, out_stream_->ByteCount()));
 }
@@ -101,10 +98,10 @@
 TEST_F(JsonObjectWriterTest, ObjectInObject) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartObject("")
-       ->StartObject("nested")
-         ->RenderString("field", "value")
-       ->EndObject()
-     ->EndObject();
+      ->StartObject("nested")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndObject();
   EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}",
             output_.substr(0, out_stream_->ByteCount()));
 }
@@ -112,10 +109,10 @@
 TEST_F(JsonObjectWriterTest, ListInObject) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartObject("")
-       ->StartList("nested")
-         ->RenderString("", "value")
-       ->EndList()
-     ->EndObject();
+      ->StartList("nested")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndObject();
   EXPECT_EQ("{\"nested\":[\"value\"]}",
             output_.substr(0, out_stream_->ByteCount()));
 }
@@ -123,10 +120,10 @@
 TEST_F(JsonObjectWriterTest, ObjectInList) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartList("")
-       ->StartObject("")
-         ->RenderString("field", "value")
-       ->EndObject()
-     ->EndList();
+      ->StartObject("")
+      ->RenderString("field", "value")
+      ->EndObject()
+      ->EndList();
   EXPECT_EQ("[{\"field\":\"value\"}]",
             output_.substr(0, out_stream_->ByteCount()));
 }
@@ -134,10 +131,10 @@
 TEST_F(JsonObjectWriterTest, ListInList) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartList("")
-       ->StartList("")
-         ->RenderString("", "value")
-       ->EndList()
-     ->EndList();
+      ->StartList("")
+      ->RenderString("", "value")
+      ->EndList()
+      ->EndList();
   EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount()));
 }
 
@@ -156,14 +153,18 @@
       ->EndObject();
   EXPECT_EQ(
       "{\"bool\":true,"
-      "\"double\":" + ValueAsString<double>(1.7976931348623157e+308) + ","
-      "\"float\":" + ValueAsString<float>(3.4028235e+38) + ","
-      "\"int\":-2147483648,"
-      "\"long\":\"-9223372036854775808\","
-      "\"bytes\":\"YWJyYWNhZGFicmE=\","
-      "\"string\":\"string\","
-      "\"emptybytes\":\"\","
-      "\"emptystring\":\"\"}",
+      "\"double\":" +
+          ValueAsString<double>(std::numeric_limits<double>::max()) +
+          ","
+          "\"float\":" +
+          ValueAsString<float>(std::numeric_limits<float>::max()) +
+          ","
+          "\"int\":-2147483648,"
+          "\"long\":\"-9223372036854775808\","
+          "\"bytes\":\"YWJyYWNhZGFicmE=\","
+          "\"string\":\"string\","
+          "\"emptybytes\":\"\","
+          "\"emptystring\":\"\"}",
       output_.substr(0, out_stream_->ByteCount()));
 }
 
@@ -181,81 +182,83 @@
 TEST_F(JsonObjectWriterTest, PrettyPrintList) {
   ow_ = new JsonObjectWriter(" ", out_stream_);
   ow_->StartObject("")
-       ->StartList("items")
-         ->RenderString("", "item1")
-         ->RenderString("", "item2")
-         ->RenderString("", "item3")
-       ->EndList()
-       ->StartList("empty")
-       ->EndList()
-     ->EndObject();
-  EXPECT_EQ("{\n"
-            " \"items\": [\n"
-            "  \"item1\",\n"
-            "  \"item2\",\n"
-            "  \"item3\"\n"
-            " ],\n"
-            " \"empty\": []\n"
-            "}\n",
-            output_.substr(0, out_stream_->ByteCount()));
+      ->StartList("items")
+      ->RenderString("", "item1")
+      ->RenderString("", "item2")
+      ->RenderString("", "item3")
+      ->EndList()
+      ->StartList("empty")
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"items\": [\n"
+      "  \"item1\",\n"
+      "  \"item2\",\n"
+      "  \"item3\"\n"
+      " ],\n"
+      " \"empty\": []\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, PrettyPrintObject) {
   ow_ = new JsonObjectWriter(" ", out_stream_);
   ow_->StartObject("")
-       ->StartObject("items")
-         ->RenderString("key1", "item1")
-         ->RenderString("key2", "item2")
-         ->RenderString("key3", "item3")
-       ->EndObject()
-       ->StartObject("empty")
-       ->EndObject()
-     ->EndObject();
-  EXPECT_EQ("{\n"
-            " \"items\": {\n"
-            "  \"key1\": \"item1\",\n"
-            "  \"key2\": \"item2\",\n"
-            "  \"key3\": \"item3\"\n"
-            " },\n"
-            " \"empty\": {}\n"
-            "}\n",
-            output_.substr(0, out_stream_->ByteCount()));
+      ->StartObject("items")
+      ->RenderString("key1", "item1")
+      ->RenderString("key2", "item2")
+      ->RenderString("key3", "item3")
+      ->EndObject()
+      ->StartObject("empty")
+      ->EndObject()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"items\": {\n"
+      "  \"key1\": \"item1\",\n"
+      "  \"key2\": \"item2\",\n"
+      "  \"key3\": \"item3\"\n"
+      " },\n"
+      " \"empty\": {}\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) {
   ow_ = new JsonObjectWriter(" ", out_stream_);
   ow_->StartObject("")
-       ->StartList("list")
-         ->StartObject("")
-         ->EndObject()
-       ->EndList()
-     ->EndObject();
-  EXPECT_EQ("{\n"
-            " \"list\": [\n"
-            "  {}\n"
-            " ]\n"
-            "}\n",
-            output_.substr(0, out_stream_->ByteCount()));
+      ->StartList("list")
+      ->StartObject("")
+      ->EndObject()
+      ->EndList()
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      " \"list\": [\n"
+      "  {}\n"
+      " ]\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) {
   ow_ = new JsonObjectWriter("  ", out_stream_);
   ow_->StartObject("")
-       ->RenderBool("bool", true)
-       ->RenderInt32("int", 42)
-     ->EndObject();
-  EXPECT_EQ("{\n"
-            "  \"bool\": true,\n"
-            "  \"int\": 42\n"
-            "}\n",
-            output_.substr(0, out_stream_->ByteCount()));
+      ->RenderBool("bool", true)
+      ->RenderInt32("int", 42)
+      ->EndObject();
+  EXPECT_EQ(
+      "{\n"
+      "  \"bool\": true,\n"
+      "  \"int\": 42\n"
+      "}\n",
+      output_.substr(0, out_stream_->ByteCount()));
 }
 
 TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
   ow_ = new JsonObjectWriter("", out_stream_);
-  ow_->StartObject("")
-       ->RenderString("string", "'<>&amp;\\\"\r\n")
-     ->EndObject();
+  ow_->StartObject("")->RenderString("string", "'<>&amp;\\\"\r\n")->EndObject();
   EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&amp;\\\\\\\"\\r\\n\"}",
             output_.substr(0, out_stream_->ByteCount()));
 }
@@ -263,13 +266,13 @@
 TEST_F(JsonObjectWriterTest, Stringification) {
   ow_ = new JsonObjectWriter("", out_stream_);
   ow_->StartObject("")
-       ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
-       ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
-       ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
-       ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
-       ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
-       ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
-     ->EndObject();
+      ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
+      ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
+      ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
+      ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
+      ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
+      ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
+      ->EndObject();
   EXPECT_EQ(
       "{\"double_nan\":\"NaN\","
       "\"float_nan\":\"NaN\","
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index a7ef7fe..df91675 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -157,10 +157,10 @@
     char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' ');
     p_ = json_ = StringPiece(coerced, leftover_.size());
   } else {
+    p_ = json_ = leftover_;
     if (!internal::IsStructurallyValidUTF8(leftover_)) {
       return ReportFailure("Encountered non UTF-8 code points.");
     }
-    p_ = json_ = leftover_;
   }
 
   // Parse the remainder in finishing mode, which reports errors for things like
diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc
index c833ed1..3414826 100644
--- a/src/google/protobuf/util/internal/json_stream_parser_test.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -348,6 +348,7 @@
   for (int i = 0; i <= json.length(); ++i) {
     DoErrorTest(json, i, "Encountered non UTF-8 code points.");
   }
+  DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points.");
 }
 
 #ifndef _MSC_VER
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
index 20bd362..e695f45 100644
--- a/src/google/protobuf/util/internal/object_writer.h
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -101,11 +101,6 @@
   // Renders a Null value.
   virtual ObjectWriter* RenderNull(StringPiece name) = 0;
 
-  // Disables case normalization. Any RenderTYPE call after calling this
-  // function will output the name field as-is. No normalization is attempted on
-  // it. This setting is reset immediately after the next RenderTYPE is called.
-  virtual ObjectWriter* DisableCaseNormalizationForNextKey() { return this; }
-
   // Renders a DataPiece object to a ObjectWriter.
   static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
                                 ObjectWriter* ow);
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
new file mode 100644
index 0000000..47e0009
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -0,0 +1,744 @@
+// 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.
+
+#include <google/protobuf/util/internal/proto_writer.h>
+
+#include <functional>
+#include <stack>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/stubs/time.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/statusor.h>
+
+
+namespace google {
+namespace protobuf {
+namespace util {
+namespace converter {
+
+using google::protobuf::internal::WireFormatLite;
+using google::protobuf::io::CodedOutputStream;
+using util::error::INVALID_ARGUMENT;
+using util::Status;
+using util::StatusOr;
+
+
+ProtoWriter::ProtoWriter(TypeResolver* type_resolver,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
+      own_typeinfo_(true),
+      done_(false),
+      element_(NULL),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::ProtoWriter(const TypeInfo* typeinfo,
+                         const google::protobuf::Type& type,
+                         strings::ByteSink* output, ErrorListener* listener)
+    : master_type_(type),
+      typeinfo_(typeinfo),
+      own_typeinfo_(false),
+      done_(false),
+      element_(NULL),
+      size_insert_(),
+      output_(output),
+      buffer_(),
+      adapter_(&buffer_),
+      stream_(new CodedOutputStream(&adapter_)),
+      listener_(listener),
+      invalid_depth_(0),
+      tracker_(new ObjectLocationTracker()) {}
+
+ProtoWriter::~ProtoWriter() {
+  if (own_typeinfo_) {
+    delete typeinfo_;
+  }
+  if (element_ == NULL) return;
+  // Cleanup explicitly in order to avoid destructor stack overflow when input
+  // is deeply nested.
+  // Cast to BaseElement to avoid doing additional checks (like missing fields)
+  // during pop().
+  google::protobuf::scoped_ptr<BaseElement> element(
+      static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+  while (element != NULL) {
+    element.reset(element->pop<BaseElement>());
+  }
+}
+
+namespace {
+
+// Writes an INT32 field, including tag to the stream.
+inline Status WriteInt32(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// writes an SFIXED32 field, including tag, to the stream.
+inline Status WriteSFixed32(int field_number, const DataPiece& data,
+                            CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// Writes an SINT32 field, including tag, to the stream.
+inline Status WriteSInt32(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<int32> i32 = data.ToInt32();
+  if (i32.ok()) {
+    WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
+  }
+  return i32.status();
+}
+
+// Writes a FIXED32 field, including tag, to the stream.
+inline Status WriteFixed32(int field_number, const DataPiece& data,
+                           CodedOutputStream* stream) {
+  StatusOr<uint32> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
+  }
+  return u32.status();
+}
+
+// Writes a UINT32 field, including tag, to the stream.
+inline Status WriteUInt32(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<uint32> u32 = data.ToUint32();
+  if (u32.ok()) {
+    WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
+  }
+  return u32.status();
+}
+
+// Writes an INT64 field, including tag, to the stream.
+inline Status WriteInt64(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SFIXED64 field, including tag, to the stream.
+inline Status WriteSFixed64(int field_number, const DataPiece& data,
+                            CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes an SINT64 field, including tag, to the stream.
+inline Status WriteSInt64(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<int64> i64 = data.ToInt64();
+  if (i64.ok()) {
+    WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
+  }
+  return i64.status();
+}
+
+// Writes a FIXED64 field, including tag, to the stream.
+inline Status WriteFixed64(int field_number, const DataPiece& data,
+                           CodedOutputStream* stream) {
+  StatusOr<uint64> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a UINT64 field, including tag, to the stream.
+inline Status WriteUInt64(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<uint64> u64 = data.ToUint64();
+  if (u64.ok()) {
+    WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
+  }
+  return u64.status();
+}
+
+// Writes a DOUBLE field, including tag, to the stream.
+inline Status WriteDouble(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<double> d = data.ToDouble();
+  if (d.ok()) {
+    WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
+  }
+  return d.status();
+}
+
+// Writes a FLOAT field, including tag, to the stream.
+inline Status WriteFloat(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<float> f = data.ToFloat();
+  if (f.ok()) {
+    WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
+  }
+  return f.status();
+}
+
+// Writes a BOOL field, including tag, to the stream.
+inline Status WriteBool(int field_number, const DataPiece& data,
+                        CodedOutputStream* stream) {
+  StatusOr<bool> b = data.ToBool();
+  if (b.ok()) {
+    WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
+  }
+  return b.status();
+}
+
+// Writes a BYTES field, including tag, to the stream.
+inline Status WriteBytes(int field_number, const DataPiece& data,
+                         CodedOutputStream* stream) {
+  StatusOr<string> c = data.ToBytes();
+  if (c.ok()) {
+    WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
+  }
+  return c.status();
+}
+
+// Writes a STRING field, including tag, to the stream.
+inline Status WriteString(int field_number, const DataPiece& data,
+                          CodedOutputStream* stream) {
+  StatusOr<string> s = data.ToString();
+  if (s.ok()) {
+    WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
+  }
+  return s.status();
+}
+
+// Writes an ENUM field, including tag, to the stream.
+inline Status WriteEnum(int field_number, const DataPiece& data,
+                        const google::protobuf::Enum* enum_type,
+                        CodedOutputStream* stream) {
+  StatusOr<int> e = data.ToEnum(enum_type);
+  if (e.ok()) {
+    WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
+  }
+  return e.status();
+}
+
+// Given a google::protobuf::Type, returns the set of all required fields.
+std::set<const google::protobuf::Field*> GetRequiredFields(
+    const google::protobuf::Type& type) {
+  std::set<const google::protobuf::Field*> required;
+  for (int i = 0; i < type.fields_size(); i++) {
+    const google::protobuf::Field& field = type.fields(i);
+    if (field.cardinality() ==
+        google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+      required.insert(&field);
+    }
+  }
+  return required;
+}
+
+}  // namespace
+
+ProtoWriter::ProtoElement::ProtoElement(const TypeInfo* typeinfo,
+                                        const google::protobuf::Type& type,
+                                        ProtoWriter* enclosing)
+    : BaseElement(NULL),
+      ow_(enclosing),
+      parent_field_(NULL),
+      typeinfo_(typeinfo),
+      type_(type),
+      required_fields_(GetRequiredFields(type)),
+      size_index_(-1),
+      array_index_(-1) {}
+
+ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
+                                        const google::protobuf::Field* field,
+                                        const google::protobuf::Type& type,
+                                        bool is_list)
+    : BaseElement(parent),
+      ow_(this->parent()->ow_),
+      parent_field_(field),
+      typeinfo_(this->parent()->typeinfo_),
+      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) {
+  if (!is_list) {
+    if (ow_->IsRepeated(*field)) {
+      // Update array_index_ if it is an explicit list.
+      if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
+    } else {
+      this->parent()->RegisterField(field);
+    }
+
+    if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+      required_fields_ = GetRequiredFields(type_);
+      int start_pos = ow_->stream_->ByteCount();
+      // length of serialized message is the final buffer position minus
+      // starting buffer position, plus length adjustments for size fields
+      // of any nested messages. We start with -start_pos here, so we only
+      // need to add the final buffer position to it at the end.
+      SizeInfo info = {start_pos, -start_pos};
+      ow_->size_insert_.push_back(info);
+    }
+  }
+}
+
+ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
+  // Calls the registered error listener for any required field(s) not yet
+  // seen.
+  for (set<const google::protobuf::Field*>::iterator it =
+           required_fields_.begin();
+       it != required_fields_.end(); ++it) {
+    ow_->MissingField((*it)->name());
+  }
+  // Computes the total number of proto bytes used by a message, also adjusts
+  // the size of all parent messages by the length of this size field.
+  // If size_index_ < 0, this is not a message, so no size field is added.
+  if (size_index_ >= 0) {
+    // Add the final buffer position to compute the total length of this
+    // serialized message. The stored value (before this addition) already
+    // contains the total length of the size fields of all nested messages
+    // minus the initial buffer position.
+    ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
+    // Calculate the length required to serialize the size field of the
+    // message, and propagate this additional size information upward to
+    // all enclosing messages.
+    int size = ow_->size_insert_[size_index_].size;
+    int length = CodedOutputStream::VarintSize32(size);
+    for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
+      // Only nested messages have size field, lists do not have size field.
+      if (e->size_index_ >= 0) {
+        ow_->size_insert_[e->size_index_].size += length;
+      }
+    }
+  }
+  return BaseElement::pop<ProtoElement>();
+}
+
+void ProtoWriter::ProtoElement::RegisterField(
+    const google::protobuf::Field* field) {
+  if (!required_fields_.empty() &&
+      field->cardinality() ==
+          google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
+    required_fields_.erase(field);
+  }
+}
+
+string ProtoWriter::ProtoElement::ToString() const {
+  if (parent() == NULL) return "";
+  string loc = parent()->ToString();
+  if (!ow_->IsRepeated(*parent_field_) ||
+      parent()->parent_field_ != parent_field_) {
+    string name = parent_field_->name();
+    int i = 0;
+    while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
+    if (i > 0 && i == name.size()) {  // safe field name
+      if (loc.empty()) {
+        loc = name;
+      } else {
+        StrAppend(&loc, ".", name);
+      }
+    } else {
+      StrAppend(&loc, "[\"", CEscape(name), "\"]");
+    }
+  }
+  if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
+    StrAppend(&loc, "[", array_index_ - 1, "]");
+  }
+  return loc.empty() ? "." : loc;
+}
+
+bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
+  return ContainsKey(oneof_indices_, index);
+}
+
+void ProtoWriter::ProtoElement::TakeOneofIndex(int32 index) {
+  InsertIfNotPresent(&oneof_indices_, index);
+}
+
+void ProtoWriter::InvalidName(StringPiece unknown_name, StringPiece message) {
+  listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
+}
+
+void ProtoWriter::InvalidValue(StringPiece type_name, StringPiece value) {
+  listener_->InvalidValue(location(), type_name, value);
+}
+
+void ProtoWriter::MissingField(StringPiece missing_name) {
+  listener_->MissingField(location(), missing_name);
+}
+
+ProtoWriter* ProtoWriter::StartObject(StringPiece name) {
+  // Starting the root message. Create the root ProtoElement and return.
+  if (element_ == NULL) {
+    if (!name.empty()) {
+      InvalidName(name, "Root element should not be named.");
+    }
+    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+    return this;
+  }
+
+  const google::protobuf::Field* field = NULL;
+  field = BeginNamed(name, false);
+  if (field == NULL) return this;
+
+  // Check to see if this field is a oneof and that no oneof in that group has
+  // already been set.
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    ++invalid_depth_;
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+    WriteTag(*field);
+  element_.reset(new ProtoElement(element_.release(), field, *type, false));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::EndObject() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+    return this;
+  }
+
+  if (element_ != NULL) {
+    element_.reset(element_->pop());
+  }
+
+
+  // If ending the root element,
+  // then serialize the full message with calculated sizes.
+  if (element_ == NULL) {
+    WriteRootMessage();
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::StartList(StringPiece name) {
+  const google::protobuf::Field* field = BeginNamed(name, true);
+  if (field == NULL) return this;
+
+  if (!ValidOneof(*field, name)) {
+    ++invalid_depth_;
+    return this;
+  }
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    ++invalid_depth_;
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+  element_.reset(new ProtoElement(element_.release(), field, *type, true));
+  return this;
+}
+
+ProtoWriter* ProtoWriter::EndList() {
+  if (invalid_depth_ > 0) {
+    --invalid_depth_;
+  } else if (element_ != NULL) {
+    element_.reset(element_->pop());
+  }
+  return this;
+}
+
+ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name,
+                                          const DataPiece& data) {
+  Status status;
+  if (invalid_depth_ > 0) return this;
+
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) return this;
+
+  if (!ValidOneof(*field, name)) return this;
+
+  const google::protobuf::Type* type = LookupType(field);
+  if (type == NULL) {
+    InvalidName(name,
+                StrCat("Missing descriptor for field: ", field->type_url()));
+    return this;
+  }
+
+  // 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));
+
+  if (field->kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
+      field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+    InvalidValue(field->type_url().empty()
+                     ? google::protobuf::Field_Kind_Name(field->kind())
+                     : field->type_url(),
+                 data.ValueAsStringOrDefault(""));
+    element_.reset(element()->pop());
+    return this;
+  }
+
+  switch (field->kind()) {
+    case google::protobuf::Field_Kind_TYPE_INT32: {
+      status = WriteInt32(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
+      status = WriteSFixed32(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT32: {
+      status = WriteSInt32(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED32: {
+      status = WriteFixed32(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT32: {
+      status = WriteUInt32(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_INT64: {
+      status = WriteInt64(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
+      status = WriteSFixed64(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_SINT64: {
+      status = WriteSInt64(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FIXED64: {
+      status = WriteFixed64(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_UINT64: {
+      status = WriteUInt64(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
+      status = WriteDouble(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_FLOAT: {
+      status = WriteFloat(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BOOL: {
+      status = WriteBool(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_BYTES: {
+      status = WriteBytes(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_STRING: {
+      status = WriteString(field->number(), data, stream_.get());
+      break;
+    }
+    case google::protobuf::Field_Kind_TYPE_ENUM: {
+      status = WriteEnum(field->number(), data,
+                         typeinfo_->GetEnumByTypeUrl(field->type_url()),
+                         stream_.get());
+      break;
+    }
+    default:  // TYPE_GROUP or TYPE_MESSAGE
+      status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
+  }
+
+  if (!status.ok()) {
+    InvalidValue(google::protobuf::Field_Kind_Name(field->kind()),
+                 status.error_message());
+  }
+
+  element_.reset(element()->pop());
+  return this;
+}
+
+bool ProtoWriter::ValidOneof(const google::protobuf::Field& field,
+                             StringPiece unnormalized_name) {
+  if (element_ == NULL) return true;
+
+  if (field.oneof_index() > 0) {
+    if (element_->IsOneofIndexTaken(field.oneof_index())) {
+      InvalidValue(
+          "oneof",
+          StrCat("oneof field '",
+                 element_->type().oneofs(field.oneof_index() - 1),
+                 "' is already set. Cannot set '", unnormalized_name, "'"));
+      return false;
+    }
+    element_->TakeOneofIndex(field.oneof_index());
+  }
+  return true;
+}
+
+bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) {
+  return field.cardinality() ==
+         google::protobuf::Field_Cardinality_CARDINALITY_REPEATED;
+}
+
+const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name,
+                                                       bool is_list) {
+  if (invalid_depth_ > 0) {
+    ++invalid_depth_;
+    return NULL;
+  }
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) {
+    ++invalid_depth_;
+    // InvalidName() already called in Lookup().
+    return NULL;
+  }
+  if (is_list && !IsRepeated(*field)) {
+    ++invalid_depth_;
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return NULL;
+  }
+  return field;
+}
+
+const google::protobuf::Field* ProtoWriter::Lookup(
+    StringPiece unnormalized_name) {
+  ProtoElement* e = element();
+  if (e == NULL) {
+    InvalidName(unnormalized_name, "Root element must be a message.");
+    return NULL;
+  }
+  if (unnormalized_name.empty()) {
+    // Objects in repeated field inherit the same field descriptor.
+    if (e->parent_field() == NULL) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+    } else if (!IsRepeated(*e->parent_field())) {
+      InvalidName(unnormalized_name, "Proto fields must have a name.");
+      return NULL;
+    }
+    return e->parent_field();
+  }
+  const google::protobuf::Field* field =
+      typeinfo_->FindField(&e->type(), unnormalized_name);
+  if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
+  return field;
+}
+
+const google::protobuf::Type* ProtoWriter::LookupType(
+    const google::protobuf::Field* field) {
+  return ((field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE ||
+           field->kind() == google::protobuf::Field_Kind_TYPE_GROUP)
+              ? typeinfo_->GetTypeByTypeUrl(field->type_url())
+              : &element_->type());
+}
+
+void ProtoWriter::WriteRootMessage() {
+  GOOGLE_DCHECK(!done_);
+  int curr_pos = 0;
+  // Calls the destructor of CodedOutputStream to remove any uninitialized
+  // memory from the Cord before we read it.
+  stream_.reset(NULL);
+  const void* data;
+  int length;
+  google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
+  while (input_stream.Next(&data, &length)) {
+    if (length == 0) continue;
+    int num_bytes = length;
+    // Write up to where we need to insert the size field.
+    // The number of bytes we may write is the smaller of:
+    //   - the current fragment size
+    //   - the distance to the next position where a size field needs to be
+    //     inserted.
+    if (!size_insert_.empty() &&
+        size_insert_.front().pos - curr_pos < num_bytes) {
+      num_bytes = size_insert_.front().pos - curr_pos;
+    }
+    output_->Append(static_cast<const char*>(data), num_bytes);
+    if (num_bytes < length) {
+      input_stream.BackUp(length - num_bytes);
+    }
+    curr_pos += num_bytes;
+    // Insert the size field.
+    //   size_insert_.front():      the next <index, size> pair to be written.
+    //   size_insert_.front().pos:  position of the size field.
+    //   size_insert_.front().size: the size (integer) to be inserted.
+    if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
+      // Varint32 occupies at most 10 bytes.
+      uint8 insert_buffer[10];
+      uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
+          size_insert_.front().size, insert_buffer);
+      output_->Append(reinterpret_cast<const char*>(insert_buffer),
+                      insert_buffer_pos - insert_buffer);
+      size_insert_.pop_front();
+    }
+  }
+  output_->Flush();
+  stream_.reset(new CodedOutputStream(&adapter_));
+  done_ = true;
+}
+
+void ProtoWriter::WriteTag(const google::protobuf::Field& field) {
+  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
+      static_cast<WireFormatLite::FieldType>(field.kind()));
+  stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+}
+
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
new file mode 100644
index 0000000..e631e56
--- /dev/null
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -0,0 +1,315 @@
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+
+#include <deque>
+#include <google/protobuf/stubs/hash.h>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/internal/datapiece.h>
+#include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
+#include <google/protobuf/util/type_resolver.h>
+#include <google/protobuf/stubs/bytestream.h>
+
+namespace google {
+namespace protobuf {
+namespace io {
+class CodedOutputStream;
+}  // namespace io
+}  // namespace protobuf
+
+
+namespace protobuf {
+class Type;
+class Field;
+}  // namespace protobuf
+
+
+namespace protobuf {
+namespace util {
+namespace converter {
+
+class ObjectLocationTracker;
+
+// An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class does not support special types like Struct or Map. However, since
+// this class supports raw protobuf, it can be used to provide support for
+// special types by inheriting from it or by wrapping it.
+//
+// It also supports streaming.
+class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
+ public:
+// Constructor. Does not take ownership of any parameter passed in.
+  ProtoWriter(TypeResolver* type_resolver, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+  virtual ~ProtoWriter();
+
+  // ObjectWriter methods.
+  virtual ProtoWriter* StartObject(StringPiece name);
+  virtual ProtoWriter* EndObject();
+  virtual ProtoWriter* StartList(StringPiece name);
+  virtual ProtoWriter* EndList();
+  virtual ProtoWriter* RenderBool(StringPiece name, bool value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderInt32(StringPiece name, int32 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderUint32(StringPiece name, uint32 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderInt64(StringPiece name, int64 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderUint64(StringPiece name, uint64 value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderDouble(StringPiece name, double value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderFloat(StringPiece name, float value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) {
+    return RenderDataPiece(name, DataPiece(value));
+  }
+  virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) {
+    return RenderDataPiece(name, DataPiece(value, false));
+  }
+  virtual ProtoWriter* RenderNull(StringPiece name) {
+    return RenderDataPiece(name, DataPiece::NullData());
+  }
+
+  // Renders a DataPiece 'value' into a field whose wire type is determined
+  // from the given field 'name'.
+  virtual ProtoWriter* RenderDataPiece(StringPiece name,
+                                       const DataPiece& value);
+
+  // Returns the location tracker to use for tracking locations for errors.
+  const LocationTrackerInterface& location() {
+    return element_ != NULL ? *element_ : *tracker_;
+  }
+
+  // When true, we finished writing to output a complete message.
+  bool done() const { return done_; }
+
+  // Returns the proto stream object.
+  google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); }
+
+  // Getters and mutators of invalid_depth_.
+  void IncrementInvalidDepth() { ++invalid_depth_; }
+  void DecrementInvalidDepth() { --invalid_depth_; }
+  int invalid_depth() { return invalid_depth_; }
+
+  ErrorListener* listener() { return listener_; }
+
+  const TypeInfo* typeinfo() { return typeinfo_; }
+
+ protected:
+  class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+   public:
+    // Constructor for the root element. No parent nor field.
+    ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+                 ProtoWriter* enclosing);
+
+    // Constructor for a field of an element.
+    ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
+                 const google::protobuf::Type& type, bool is_list);
+
+    virtual ~ProtoElement() {}
+
+    // Called just before the destructor for clean up:
+    //   - reports any missing required fields
+    //   - computes the space needed by the size field, and augment the
+    //     length of all parent messages by this additional space.
+    //   - releases and returns the parent pointer.
+    ProtoElement* pop();
+
+    // Accessors
+    // parent_field() may be NULL if we are at root.
+    const google::protobuf::Field* parent_field() const {
+      return parent_field_;
+    }
+    const google::protobuf::Type& type() const { return type_; }
+
+    // Registers field for accounting required fields.
+    void RegisterField(const google::protobuf::Field* field);
+
+    // To report location on error messages.
+    virtual string ToString() const;
+
+    virtual ProtoElement* parent() const {
+      return static_cast<ProtoElement*>(BaseElement::parent());
+    }
+
+    // Returns true if the index is already taken by a preceeding oneof input.
+    bool IsOneofIndexTaken(int32 index);
+
+    // Marks the oneof 'index' as taken. Future inputs to this oneof will
+    // generate an error.
+    void TakeOneofIndex(int32 index);
+
+   private:
+    // Used for access to variables of the enclosing instance of
+    // ProtoWriter.
+    ProtoWriter* ow_;
+
+    // Describes the element as a field in the parent message.
+    // parent_field_ is NULL if and only if this element is the root element.
+    const google::protobuf::Field* parent_field_;
+
+    // TypeInfo to lookup types.
+    const TypeInfo* typeinfo_;
+
+    // Additional variables if this element is a message:
+    // (Root element is always a message).
+    // type_             : the type of this element.
+    // required_fields_  : set of required fields.
+    // size_index_       : index into ProtoWriter::size_insert_
+    //                     for later insertion of serialized message length.
+    const google::protobuf::Type& type_;
+    std::set<const google::protobuf::Field*> required_fields_;
+    const int size_index_;
+
+    // Tracks position in repeated fields, needed for LocationTrackerInterface.
+    int array_index_;
+
+    // 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_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
+  };
+
+  // Container for inserting 'size' information at the 'pos' position.
+  struct SizeInfo {
+    const int pos;
+    int size;
+  };
+
+  ProtoWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type,
+              strings::ByteSink* output, ErrorListener* listener);
+
+  virtual ProtoElement* element() { return element_.get(); }
+
+  // Helper methods for calling ErrorListener. See error_listener.h.
+  void InvalidName(StringPiece unknown_name, StringPiece message);
+  void InvalidValue(StringPiece type_name, StringPiece value);
+  void MissingField(StringPiece missing_name);
+
+  // Common code for BeginObject() and BeginList() that does invalid_depth_
+  // bookkeeping associated with name lookup.
+  const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
+
+  // Lookup the field in the current element. Looks in the base descriptor
+  // and in any extension. This will report an error if the field cannot be
+  // found or if multiple matching extensions are found.
+  const google::protobuf::Field* Lookup(StringPiece name);
+
+  // Lookup the field type in the type descriptor. Returns NULL if the type
+  // is not known.
+  const google::protobuf::Type* LookupType(
+      const google::protobuf::Field* field);
+
+  // Write serialized output to the final output ByteSink, inserting all
+  // the size information for nested messages that are missing from the
+  // intermediate Cord buffer.
+  void WriteRootMessage();
+
+  // Helper method to write proto tags based on the given field.
+  void WriteTag(const google::protobuf::Field& field);
+
+
+  // Returns true if the field for type_ can be set as a oneof. If field is not
+  // a oneof type, this function does nothing and returns true.
+  // If another field for this oneof is already set, this function returns
+  // false. It also calls the appropriate error callback.
+  // unnormalized_name is used for error string.
+  bool ValidOneof(const google::protobuf::Field& field,
+                  StringPiece unnormalized_name);
+
+  // Returns true if the field is repeated.
+  bool IsRepeated(const google::protobuf::Field& field);
+
+ private:
+  // Variables for describing the structure of the input tree:
+  // master_type_: descriptor for the whole protobuf message.
+  // typeinfo_ : the TypeInfo object to lookup types.
+  const google::protobuf::Type& master_type_;
+  const TypeInfo* typeinfo_;
+  // Whether we own the typeinfo_ object.
+  bool own_typeinfo_;
+
+  // Indicates whether we finished writing root message completely.
+  bool done_;
+
+  // Variable for internal state processing:
+  // element_    : the current element.
+  // size_insert_: sizes of nested messages.
+  //               pos  - position to insert the size field.
+  //               size - size value to be inserted.
+  google::protobuf::scoped_ptr<ProtoElement> element_;
+  std::deque<SizeInfo> size_insert_;
+
+  // Variables for output generation:
+  // output_  : pointer to an external ByteSink for final user-visible output.
+  // buffer_  : buffer holding partial message before being ready for output_.
+  // adapter_ : internal adapter between CodedOutputStream and buffer_.
+  // stream_  : wrapper for writing tags and other encodings in wire format.
+  strings::ByteSink* output_;
+  string buffer_;
+  google::protobuf::io::StringOutputStream adapter_;
+  google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
+
+  // Variables for error tracking and reporting:
+  // listener_     : a place to report any errors found.
+  // invalid_depth_: number of enclosing invalid nested messages.
+  // tracker_      : the root location tracker interface.
+  ErrorListener* listener_;
+  int invalid_depth_;
+  google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+
+  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoWriter);
+};
+
+}  // namespace converter
+}  // namespace util
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 996e1f8..034d616 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -47,7 +47,6 @@
 #include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
-#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/stubs/status_macros.h>
 
 
@@ -140,10 +139,11 @@
                                              const uint32 end_tag,
                                              bool include_start_and_end,
                                              ObjectWriter* ow) const {
-  const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
-  if (type_renderer != NULL) {
-    return (*type_renderer)(this, type, name, ow);
-  }
+
+    const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
+    if (type_renderer != NULL) {
+      return (*type_renderer)(this, type, name, ow);
+    }
 
   const google::protobuf::Field* field = NULL;
   string field_name;
@@ -171,7 +171,9 @@
 
     if (field->cardinality() ==
         google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
-      if (IsMap(*field)) {
+      bool check_maps = true;
+
+      if (check_maps && IsMap(*field)) {
         ow->StartObject(field_name);
         ASSIGN_OR_RETURN(tag, RenderMap(field, field_name, tag, ow));
         ow->EndObject();
@@ -218,48 +220,32 @@
   const google::protobuf::Type* field_type =
       typeinfo_->GetTypeByTypeUrl(field->type_url());
   uint32 tag_to_return = 0;
-  if (IsPackable(*field) &&
-      list_tag ==
-          WireFormatLite::MakeTag(field->number(),
-                                  WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
-    RETURN_IF_ERROR(RenderPackedMapEntry(field_type, ow));
-    tag_to_return = stream_->ReadTag();
-  } else {
-    do {
-      RETURN_IF_ERROR(RenderMapEntry(field_type, ow));
-    } while ((tag_to_return = stream_->ReadTag()) == list_tag);
-  }
-  return tag_to_return;
-}
-
-Status ProtoStreamObjectSource::RenderMapEntry(
-    const google::protobuf::Type* type, ObjectWriter* ow) const {
-  uint32 buffer32;
-  stream_->ReadVarint32(&buffer32);  // message length
-  int old_limit = stream_->PushLimit(buffer32);
-  string map_key;
-  for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
-    const google::protobuf::Field* field = FindAndVerifyField(*type, tag);
-    if (field == NULL) {
-      WireFormat::SkipField(stream_, tag, NULL);
-      continue;
-    }
-    // Map field numbers are key = 1 and value = 2
-    if (field->number() == 1) {
-      map_key = ReadFieldValueAsString(*field);
-    } else if (field->number() == 2) {
-      if (map_key.empty()) {
-        return Status(util::error::INTERNAL, "Map key must be non-empty");
+  do {
+    // Render map entry message type.
+    uint32 buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    string map_key;
+    for (uint32 tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
+      const google::protobuf::Field* field =
+          FindAndVerifyField(*field_type, tag);
+      if (field == NULL) {
+        WireFormat::SkipField(stream_, tag, NULL);
+        continue;
       }
-      // Disable case normalization for map keys as they are just data. We
-      // retain them intact.
-      ow->DisableCaseNormalizationForNextKey();
-      RETURN_IF_ERROR(RenderField(field, map_key, ow));
+      // Map field numbers are key = 1 and value = 2
+      if (field->number() == 1) {
+        map_key = ReadFieldValueAsString(*field);
+      } else if (field->number() == 2) {
+        if (map_key.empty()) {
+          return Status(util::error::INTERNAL, "Map key must be non-empty");
+        }
+        RETURN_IF_ERROR(RenderField(field, map_key, ow));
+      }
     }
-  }
-  stream_->PopLimit(old_limit);
-
-  return Status::OK;
+    stream_->PopLimit(old_limit);
+  } while ((tag_to_return = stream_->ReadTag()) == list_tag);
+  return tag_to_return;
 }
 
 Status ProtoStreamObjectSource::RenderPacked(
@@ -274,18 +260,6 @@
   return Status::OK;
 }
 
-Status ProtoStreamObjectSource::RenderPackedMapEntry(
-    const google::protobuf::Type* type, ObjectWriter* ow) const {
-  uint32 length;
-  stream_->ReadVarint32(&length);
-  int old_limit = stream_->PushLimit(length);
-  while (stream_->BytesUntilLimit() > 0) {
-    RETURN_IF_ERROR(RenderMapEntry(type, ow));
-  }
-  stream_->PopLimit(old_limit);
-  return Status::OK;
-}
-
 Status ProtoStreamObjectSource::RenderTimestamp(
     const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
     StringPiece field_name, ObjectWriter* ow) {
@@ -332,10 +306,9 @@
   if (seconds < 0) {
     if (nanos > 0) {
       return Status(util::error::INTERNAL,
-                    StrCat(
-                        "Duration nanos is non-negative, but seconds is "
-                        "negative for field: ",
-                        field_name));
+                    StrCat("Duration nanos is non-negative, but seconds is "
+                           "negative for field: ",
+                           field_name));
     }
     sign = "-";
     seconds = -seconds;
@@ -602,10 +575,10 @@
   // nested_type cannot be null at this time.
   const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
 
-  // We know the type so we can render it. Recursively parse the nested stream
-  // using a nested ProtoStreamObjectSource using our nested type information.
   google::protobuf::io::ArrayInputStream zero_copy_stream(value.data(), value.size());
   google::protobuf::io::CodedInputStream in_stream(&zero_copy_stream);
+  // We know the type so we can render it. Recursively parse the nested stream
+  // using a nested ProtoStreamObjectSource using our nested type information.
   ProtoStreamObjectSource nested_os(&in_stream, os->typeinfo_, *nested_type);
 
   // We manually call start and end object here so we can inject the @type.
@@ -648,6 +621,7 @@
   return Status::OK;
 }
 
+
 hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
     ProtoStreamObjectSource::renderers_ = NULL;
 GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
@@ -670,13 +644,15 @@
       &ProtoStreamObjectSource::RenderInt32;
   (*renderers_)["google.protobuf.UInt32Value"] =
       &ProtoStreamObjectSource::RenderUInt32;
-  (*renderers_)["google.protobuf.BoolValue"] = &ProtoStreamObjectSource::RenderBool;
+  (*renderers_)["google.protobuf.BoolValue"] =
+      &ProtoStreamObjectSource::RenderBool;
   (*renderers_)["google.protobuf.StringValue"] =
       &ProtoStreamObjectSource::RenderString;
   (*renderers_)["google.protobuf.BytesValue"] =
       &ProtoStreamObjectSource::RenderBytes;
   (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
-  (*renderers_)["google.protobuf.Struct"] = &ProtoStreamObjectSource::RenderStruct;
+  (*renderers_)["google.protobuf.Struct"] =
+      &ProtoStreamObjectSource::RenderStruct;
   (*renderers_)["google.protobuf.Value"] =
       &ProtoStreamObjectSource::RenderStructValue;
   (*renderers_)["google.protobuf.ListValue"] =
@@ -701,87 +677,118 @@
 Status ProtoStreamObjectSource::RenderField(
     const google::protobuf::Field* field, StringPiece field_name,
     ObjectWriter* ow) const {
+  // Short-circuit message types as it tends to call WriteMessage recursively
+  // and ends up using a lot of stack space. Keep the stack usage of this
+  // message small in order to preserve stack space and not crash.
+  if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
+    uint32 buffer32;
+    stream_->ReadVarint32(&buffer32);  // message length
+    int old_limit = stream_->PushLimit(buffer32);
+    // Get the nested message type for this field.
+    const google::protobuf::Type* type =
+        typeinfo_->GetTypeByTypeUrl(field->type_url());
+    if (type == NULL) {
+      return Status(util::error::INTERNAL,
+                    StrCat("Invalid configuration. Could not find the type: ",
+                           field->type_url()));
+    }
+
+    // Short-circuit any special type rendering to save call-stack space.
+    const TypeRenderer* type_renderer = FindTypeRenderer(type->name());
+
+    bool use_type_renderer = type_renderer != NULL;
+
+    if (use_type_renderer) {
+      RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow));
+    } else {
+      RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
+    }
+    if (!stream_->ConsumedEntireMessage()) {
+      return Status(util::error::INVALID_ARGUMENT,
+                    "Nested protocol message not parsed in its entirety.");
+    }
+    stream_->PopLimit(old_limit);
+  } else {
+    // Render all other non-message types.
+    return RenderNonMessageField(field, field_name, ow);
+  }
+  return Status::OK;
+}
+
+Status ProtoStreamObjectSource::RenderNonMessageField(
+    const google::protobuf::Field* field, StringPiece field_name,
+    ObjectWriter* ow) const {
+  // Temporary buffers of different types.
+  uint32 buffer32;
+  uint64 buffer64;
+  string strbuffer;
   switch (field->kind()) {
     case google::protobuf::Field_Kind_TYPE_BOOL: {
-      uint64 buffer64;
       stream_->ReadVarint64(&buffer64);
       ow->RenderBool(field_name, buffer64 != 0);
       break;
     }
     case google::protobuf::Field_Kind_TYPE_INT32: {
-      uint32 buffer32;
       stream_->ReadVarint32(&buffer32);
       ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_INT64: {
-      uint64 buffer64;
       stream_->ReadVarint64(&buffer64);
       ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_UINT32: {
-      uint32 buffer32;
       stream_->ReadVarint32(&buffer32);
       ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_UINT64: {
-      uint64 buffer64;
       stream_->ReadVarint64(&buffer64);
       ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_SINT32: {
-      uint32 buffer32;
       stream_->ReadVarint32(&buffer32);
       ow->RenderInt32(field_name, WireFormatLite::ZigZagDecode32(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_SINT64: {
-      uint64 buffer64;
       stream_->ReadVarint64(&buffer64);
       ow->RenderInt64(field_name, WireFormatLite::ZigZagDecode64(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_SFIXED32: {
-      uint32 buffer32;
       stream_->ReadLittleEndian32(&buffer32);
       ow->RenderInt32(field_name, bit_cast<int32>(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_SFIXED64: {
-      uint64 buffer64;
       stream_->ReadLittleEndian64(&buffer64);
       ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_FIXED32: {
-      uint32 buffer32;
       stream_->ReadLittleEndian32(&buffer32);
       ow->RenderUint32(field_name, bit_cast<uint32>(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_FIXED64: {
-      uint64 buffer64;
       stream_->ReadLittleEndian64(&buffer64);
       ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_FLOAT: {
-      uint32 buffer32;
       stream_->ReadLittleEndian32(&buffer32);
       ow->RenderFloat(field_name, bit_cast<float>(buffer32));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_DOUBLE: {
-      uint64 buffer64;
       stream_->ReadLittleEndian64(&buffer64);
       ow->RenderDouble(field_name, bit_cast<double>(buffer64));
       break;
     }
     case google::protobuf::Field_Kind_TYPE_ENUM: {
-      uint32 buffer32;
       stream_->ReadVarint32(&buffer32);
 
       // If the field represents an explicit NULL value, render null.
@@ -803,44 +810,20 @@
           ow->RenderString(field_name, enum_value->name());
         }
       } else {
-        GOOGLE_LOG(INFO) << "Unkown enum skipped: " << field->type_url();
+        GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url();
       }
       break;
     }
     case google::protobuf::Field_Kind_TYPE_STRING: {
-      uint32 buffer32;
-      string str;
       stream_->ReadVarint32(&buffer32);  // string size.
-      stream_->ReadString(&str, buffer32);
-      ow->RenderString(field_name, str);
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderString(field_name, strbuffer);
       break;
     }
     case google::protobuf::Field_Kind_TYPE_BYTES: {
-      uint32 buffer32;
       stream_->ReadVarint32(&buffer32);  // bytes size.
-      string value;
-      stream_->ReadString(&value, buffer32);
-      ow->RenderBytes(field_name, value);
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_MESSAGE: {
-      uint32 buffer32;
-      stream_->ReadVarint32(&buffer32);  // message length
-      int old_limit = stream_->PushLimit(buffer32);
-      // Get the nested message type for this field.
-      const google::protobuf::Type* type =
-          typeinfo_->GetTypeByTypeUrl(field->type_url());
-      if (type == NULL) {
-        return Status(util::error::INTERNAL,
-                      StrCat("Invalid configuration. Could not find the type: ",
-                             field->type_url()));
-      }
-      RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
-      if (!stream_->ConsumedEntireMessage()) {
-        return Status(util::error::INVALID_ARGUMENT,
-                      "Nested protocol message not parsed in its entirety.");
-      }
-      stream_->PopLimit(old_limit);
+      stream_->ReadString(&strbuffer, buffer32);
+      ow->RenderBytes(field_name, strbuffer);
       break;
     }
     default:
@@ -988,7 +971,7 @@
   uint32 nanos = 0;
   uint32 tag = 0;
   int64 signed_seconds = 0;
-  int64 signed_nanos = 0;
+  int32 signed_nanos = 0;
 
   for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
     const google::protobuf::Field* field = FindAndVerifyField(type, tag);
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index f52383a..78defa1 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -122,20 +122,12 @@
                                      StringPiece name, uint32 list_tag,
                                      ObjectWriter* ow) const;
 
-  // Renders an entry in a map, advancing stream pointers appropriately.
-  util::Status RenderMapEntry(const google::protobuf::Type* type,
-                                ObjectWriter* ow) const;
-
   // Renders a packed repeating field. A packed field is stored as:
   // {tag length item1 item2 item3} instead of the less efficient
   // {tag item1 tag item2 tag item3}.
   util::Status RenderPacked(const google::protobuf::Field* field,
                               ObjectWriter* ow) const;
 
-  // Equivalent of RenderPacked, but for map entries.
-  util::Status RenderPackedMapEntry(const google::protobuf::Type* type,
-                                      ObjectWriter* ow) const;
-
   // Renders a google.protobuf.Timestamp value to ObjectWriter
   static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
                                         const google::protobuf::Type& type,
@@ -188,8 +180,7 @@
 
   // Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
   static util::Status RenderStructListValue(
-      const ProtoStreamObjectSource* os,
-      const google::protobuf::Type& type,
+      const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
       StringPiece name, ObjectWriter* ow);
 
   // Render the "Any" type.
@@ -211,6 +202,13 @@
   util::Status RenderField(const google::protobuf::Field* field,
                              StringPiece field_name, ObjectWriter* ow) const;
 
+  // Same as above but renders all non-message field types. Callers don't call
+  // this function directly. They just use RenderField.
+  util::Status RenderNonMessageField(const google::protobuf::Field* field,
+                                       StringPiece field_name,
+                                       ObjectWriter* ow) const;
+
+
   // Reads field value according to Field spec in 'field' and returns the read
   // value as string. This only works for primitive datatypes (no message
   // types).
@@ -238,6 +236,7 @@
   // google::protobuf::Type of the message source.
   const google::protobuf::Type& type_;
 
+
   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
 };
 
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
index f6e5ee7..561f676 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -327,9 +327,16 @@
   DoTest(primitive, Primitive::descriptor());
 }
 
+TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
+  Author author;
+  author.set_id(12345);
+
+  ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
+  DoTest(author, Author::descriptor());
+}
+
 TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
   Author* author = new Author();
-  author->set_id(101L);
   author->set_name("Tolstoy");
   Book book;
   book.set_title("My Book");
@@ -338,7 +345,6 @@
   ow_.StartObject("")
       ->RenderString("title", "My Book")
       ->StartObject("author")
-      ->RenderUint64("id", bit_cast<uint64>(101LL))
       ->RenderString("name", "Tolstoy")
       ->EndObject()
       ->EndObject();
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index a935ac3..786bf0b 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -33,13 +33,13 @@
 #include <functional>
 #include <stack>
 
+#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/stubs/time.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/util/internal/field_mask_utility.h>
 #include <google/protobuf/util/internal/object_location_tracker.h>
 #include <google/protobuf/util/internal/constants.h>
 #include <google/protobuf/util/internal/utility.h>
-#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/statusor.h>
@@ -51,7 +51,6 @@
 namespace converter {
 
 using google::protobuf::internal::WireFormatLite;
-using google::protobuf::io::CodedOutputStream;
 using util::error::INVALID_ARGUMENT;
 using util::Status;
 using util::StatusOr;
@@ -60,230 +59,31 @@
 ProtoStreamObjectWriter::ProtoStreamObjectWriter(
     TypeResolver* type_resolver, const google::protobuf::Type& type,
     strings::ByteSink* output, ErrorListener* listener)
-    : master_type_(type),
-      typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
-      own_typeinfo_(true),
-      done_(false),
-      element_(NULL),
-      size_insert_(),
-      output_(output),
-      buffer_(),
-      adapter_(&buffer_),
-      stream_(new CodedOutputStream(&adapter_)),
-      listener_(listener),
-      invalid_depth_(0),
-      tracker_(new ObjectLocationTracker()) {}
+    : ProtoWriter(type_resolver, type, output, listener),
+      master_type_(type),
+      current_(NULL) {}
 
 ProtoStreamObjectWriter::ProtoStreamObjectWriter(
     const TypeInfo* typeinfo, const google::protobuf::Type& type,
     strings::ByteSink* output, ErrorListener* listener)
-    : master_type_(type),
-      typeinfo_(typeinfo),
-      own_typeinfo_(false),
-      done_(false),
-      element_(NULL),
-      size_insert_(),
-      output_(output),
-      buffer_(),
-      adapter_(&buffer_),
-      stream_(new CodedOutputStream(&adapter_)),
-      listener_(listener),
-      invalid_depth_(0),
-      tracker_(new ObjectLocationTracker()) {}
+    : ProtoWriter(typeinfo, type, output, listener),
+      master_type_(type),
+      current_(NULL) {}
 
 ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
-  if (own_typeinfo_) {
-    delete typeinfo_;
-  }
-  if (element_ == NULL) return;
+  if (current_ == NULL) return;
   // Cleanup explicitly in order to avoid destructor stack overflow when input
   // is deeply nested.
   // Cast to BaseElement to avoid doing additional checks (like missing fields)
   // during pop().
   google::protobuf::scoped_ptr<BaseElement> element(
-      static_cast<BaseElement*>(element_.get())->pop<BaseElement>());
+      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
   while (element != NULL) {
     element.reset(element->pop<BaseElement>());
   }
 }
 
 namespace {
-
-// Writes an INT32 field, including tag to the stream.
-inline Status WriteInt32(int field_number, const DataPiece& data,
-                         CodedOutputStream* stream) {
-  StatusOr<int32> i32 = data.ToInt32();
-  if (i32.ok()) {
-    WireFormatLite::WriteInt32(field_number, i32.ValueOrDie(), stream);
-  }
-  return i32.status();
-}
-
-// writes an SFIXED32 field, including tag, to the stream.
-inline Status WriteSFixed32(int field_number, const DataPiece& data,
-                            CodedOutputStream* stream) {
-  StatusOr<int32> i32 = data.ToInt32();
-  if (i32.ok()) {
-    WireFormatLite::WriteSFixed32(field_number, i32.ValueOrDie(), stream);
-  }
-  return i32.status();
-}
-
-// Writes an SINT32 field, including tag, to the stream.
-inline Status WriteSInt32(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<int32> i32 = data.ToInt32();
-  if (i32.ok()) {
-    WireFormatLite::WriteSInt32(field_number, i32.ValueOrDie(), stream);
-  }
-  return i32.status();
-}
-
-// Writes a FIXED32 field, including tag, to the stream.
-inline Status WriteFixed32(int field_number, const DataPiece& data,
-                           CodedOutputStream* stream) {
-  StatusOr<uint32> u32 = data.ToUint32();
-  if (u32.ok()) {
-    WireFormatLite::WriteFixed32(field_number, u32.ValueOrDie(), stream);
-  }
-  return u32.status();
-}
-
-// Writes a UINT32 field, including tag, to the stream.
-inline Status WriteUInt32(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<uint32> u32 = data.ToUint32();
-  if (u32.ok()) {
-    WireFormatLite::WriteUInt32(field_number, u32.ValueOrDie(), stream);
-  }
-  return u32.status();
-}
-
-// Writes an INT64 field, including tag, to the stream.
-inline Status WriteInt64(int field_number, const DataPiece& data,
-                         CodedOutputStream* stream) {
-  StatusOr<int64> i64 = data.ToInt64();
-  if (i64.ok()) {
-    WireFormatLite::WriteInt64(field_number, i64.ValueOrDie(), stream);
-  }
-  return i64.status();
-}
-
-// Writes an SFIXED64 field, including tag, to the stream.
-inline Status WriteSFixed64(int field_number, const DataPiece& data,
-                            CodedOutputStream* stream) {
-  StatusOr<int64> i64 = data.ToInt64();
-  if (i64.ok()) {
-    WireFormatLite::WriteSFixed64(field_number, i64.ValueOrDie(), stream);
-  }
-  return i64.status();
-}
-
-// Writes an SINT64 field, including tag, to the stream.
-inline Status WriteSInt64(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<int64> i64 = data.ToInt64();
-  if (i64.ok()) {
-    WireFormatLite::WriteSInt64(field_number, i64.ValueOrDie(), stream);
-  }
-  return i64.status();
-}
-
-// Writes a FIXED64 field, including tag, to the stream.
-inline Status WriteFixed64(int field_number, const DataPiece& data,
-                           CodedOutputStream* stream) {
-  StatusOr<uint64> u64 = data.ToUint64();
-  if (u64.ok()) {
-    WireFormatLite::WriteFixed64(field_number, u64.ValueOrDie(), stream);
-  }
-  return u64.status();
-}
-
-// Writes a UINT64 field, including tag, to the stream.
-inline Status WriteUInt64(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<uint64> u64 = data.ToUint64();
-  if (u64.ok()) {
-    WireFormatLite::WriteUInt64(field_number, u64.ValueOrDie(), stream);
-  }
-  return u64.status();
-}
-
-// Writes a DOUBLE field, including tag, to the stream.
-inline Status WriteDouble(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<double> d = data.ToDouble();
-  if (d.ok()) {
-    WireFormatLite::WriteDouble(field_number, d.ValueOrDie(), stream);
-  }
-  return d.status();
-}
-
-// Writes a FLOAT field, including tag, to the stream.
-inline Status WriteFloat(int field_number, const DataPiece& data,
-                         CodedOutputStream* stream) {
-  StatusOr<float> f = data.ToFloat();
-  if (f.ok()) {
-    WireFormatLite::WriteFloat(field_number, f.ValueOrDie(), stream);
-  }
-  return f.status();
-}
-
-// Writes a BOOL field, including tag, to the stream.
-inline Status WriteBool(int field_number, const DataPiece& data,
-                        CodedOutputStream* stream) {
-  StatusOr<bool> b = data.ToBool();
-  if (b.ok()) {
-    WireFormatLite::WriteBool(field_number, b.ValueOrDie(), stream);
-  }
-  return b.status();
-}
-
-// Writes a BYTES field, including tag, to the stream.
-inline Status WriteBytes(int field_number, const DataPiece& data,
-                         CodedOutputStream* stream) {
-  StatusOr<string> c = data.ToBytes();
-  if (c.ok()) {
-    WireFormatLite::WriteBytes(field_number, c.ValueOrDie(), stream);
-  }
-  return c.status();
-}
-
-// Writes a STRING field, including tag, to the stream.
-inline Status WriteString(int field_number, const DataPiece& data,
-                          CodedOutputStream* stream) {
-  StatusOr<string> s = data.ToString();
-  if (s.ok()) {
-    WireFormatLite::WriteString(field_number, s.ValueOrDie(), stream);
-  }
-  return s.status();
-}
-
-// Writes an ENUM field, including tag, to the stream.
-inline Status WriteEnum(int field_number, const DataPiece& data,
-                        const google::protobuf::Enum* enum_type,
-                        CodedOutputStream* stream) {
-  StatusOr<int> e = data.ToEnum(enum_type);
-  if (e.ok()) {
-    WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
-  }
-  return e.status();
-}
-
-// Given a google::protobuf::Type, returns the set of all required fields.
-std::set<const google::protobuf::Field*> GetRequiredFields(
-    const google::protobuf::Type& type) {
-  std::set<const google::protobuf::Field*> required;
-  for (int i = 0; i < type.fields_size(); i++) {
-    const google::protobuf::Field& field = type.fields(i);
-    if (field.cardinality() ==
-        google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
-      required.insert(&field);
-    }
-  }
-  return required;
-}
-
 // Utility method to split a string representation of Timestamp or Duration and
 // return the parts.
 void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
@@ -298,6 +98,78 @@
   }
 }
 
+Status GetNanosFromStringPiece(StringPiece s_nanos,
+                               const char* parse_failure_message,
+                               const char* exceeded_limit_message,
+                               int32* nanos) {
+  *nanos = 0;
+
+  // Count the number of leading 0s and consume them.
+  int num_leading_zeros = 0;
+  while (s_nanos.Consume("0")) {
+    num_leading_zeros++;
+  }
+  int32 i_nanos = 0;
+  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
+  // "0." + s_nanos.ToString() seconds. An int32 is used for the
+  // conversion to 'nanos', rather than a double, so that there is no
+  // loss of precision.
+  if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
+    return Status(INVALID_ARGUMENT, parse_failure_message);
+  }
+  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
+    return Status(INVALID_ARGUMENT, exceeded_limit_message);
+  }
+  // s_nanos should only have digits. No whitespace.
+  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
+    return Status(INVALID_ARGUMENT, parse_failure_message);
+  }
+
+  if (i_nanos > 0) {
+    // 'scale' is the number of digits to the right of the decimal
+    // point in "0." + s_nanos.ToString()
+    int32 scale = num_leading_zeros + s_nanos.size();
+    // 'conversion' converts i_nanos into nanoseconds.
+    // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
+    // For efficiency, we precompute the conversion factor.
+    int32 conversion = 0;
+    switch (scale) {
+      case 1:
+        conversion = 100000000;
+        break;
+      case 2:
+        conversion = 10000000;
+        break;
+      case 3:
+        conversion = 1000000;
+        break;
+      case 4:
+        conversion = 100000;
+        break;
+      case 5:
+        conversion = 10000;
+        break;
+      case 6:
+        conversion = 1000;
+        break;
+      case 7:
+        conversion = 100;
+        break;
+      case 8:
+        conversion = 10;
+        break;
+      case 9:
+        conversion = 1;
+        break;
+      default:
+        return Status(INVALID_ARGUMENT, exceeded_limit_message);
+    }
+    *nanos = i_nanos * conversion;
+  }
+
+  return Status::OK;
+}
+
 }  // namespace
 
 ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
@@ -397,8 +269,8 @@
     const TypeRenderer* type_renderer =
         FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name()));
     if (type_renderer) {
-      // TODO(rikka): Don't just ignore the util::Status object!
-      (*type_renderer)(ow_.get(), value);
+      Status status = (*type_renderer)(ow_.get(), value);
+      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
     } else {
       ow_->RenderDataPiece(name, value);
     }
@@ -421,7 +293,7 @@
   }
   // Resolve the type url, and report an error if we failed to resolve it.
   StatusOr<const google::protobuf::Type*> resolved_type =
-      parent_->typeinfo_->ResolveTypeUrl(type_url_);
+      parent_->typeinfo()->ResolveTypeUrl(type_url_);
   if (!resolved_type.ok()) {
     parent_->InvalidValue("Any", resolved_type.status().error_message());
     invalid_ = true;
@@ -440,8 +312,8 @@
 
   // Create our object writer and initialize it with the first StartObject
   // call.
-  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo_, *type, &output_,
-                                        parent_->listener_));
+  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
+                                        parent_->listener()));
   ow_->StartObject("");
 }
 
@@ -453,588 +325,431 @@
   }
   // Render the type_url and value fields directly to the stream.
   // type_url has tag 1 and value has tag 2.
-  WireFormatLite::WriteString(1, type_url_, parent_->stream_.get());
+  WireFormatLite::WriteString(1, type_url_, parent_->stream());
   if (!data_.empty()) {
-    WireFormatLite::WriteBytes(2, data_, parent_->stream_.get());
+    WireFormatLite::WriteBytes(2, data_, parent_->stream());
   }
 }
 
-ProtoStreamObjectWriter::ProtoElement::ProtoElement(
-    const TypeInfo* typeinfo, const google::protobuf::Type& type,
-    ProtoStreamObjectWriter* enclosing)
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
     : BaseElement(NULL),
       ow_(enclosing),
       any_(),
-      field_(NULL),
-      typeinfo_(typeinfo),
-      type_(type),
-      required_fields_(GetRequiredFields(type)),
-      is_repeated_type_(false),
-      size_index_(-1),
-      array_index_(-1),
-      element_type_(GetElementType(type_)) {
-  if (element_type_ == ANY) {
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type_ == ANY) {
     any_.reset(new AnyWriter(ow_));
   }
 }
 
-ProtoStreamObjectWriter::ProtoElement::ProtoElement(
-    ProtoStreamObjectWriter::ProtoElement* parent,
-    const google::protobuf::Field* field, const google::protobuf::Type& type,
-    ElementType element_type)
+ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
+                                    ItemType item_type, bool is_placeholder,
+                                    bool is_list)
     : BaseElement(parent),
       ow_(this->parent()->ow_),
       any_(),
-      field_(field),
-      typeinfo_(this->parent()->typeinfo_),
-      type_(type),
-      is_repeated_type_(element_type == ProtoElement::LIST ||
-                        element_type == ProtoElement::STRUCT_LIST ||
-                        element_type == ProtoElement::MAP ||
-                        element_type == ProtoElement::STRUCT_MAP),
-      size_index_(!is_repeated_type_ &&
-                          field->kind() ==
-                              google::protobuf::Field_Kind_TYPE_MESSAGE
-                      ? ow_->size_insert_.size()
-                      : -1),
-      array_index_(is_repeated_type_ ? 0 : -1),
-      element_type_(element_type) {
-  if (!is_repeated_type_) {
-    if (field->cardinality() ==
-        google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
-      // Update array_index_ if it is an explicit list.
-      if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
-    } else {
-      this->parent()->RegisterField(field);
-    }
-    if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
-      required_fields_ = GetRequiredFields(type_);
-      int start_pos = ow_->stream_->ByteCount();
-      // length of serialized message is the final buffer position minus
-      // starting buffer position, plus length adjustments for size fields
-      // of any nested messages. We start with -start_pos here, so we only
-      // need to add the final buffer position to it at the end.
-      SizeInfo info = {start_pos, -start_pos};
-      ow_->size_insert_.push_back(info);
-    }
-  }
-  if (element_type == ANY) {
+      item_type_(item_type),
+      is_placeholder_(is_placeholder),
+      is_list_(is_list) {
+  if (item_type == ANY) {
     any_.reset(new AnyWriter(ow_));
   }
 }
 
-ProtoStreamObjectWriter::ProtoElement*
-ProtoStreamObjectWriter::ProtoElement::pop() {
-  // Calls the registered error listener for any required field(s) not yet
-  // seen.
-  for (set<const google::protobuf::Field*>::iterator it =
-           required_fields_.begin();
-       it != required_fields_.end(); ++it) {
-    ow_->MissingField((*it)->name());
-  }
-  // Computes the total number of proto bytes used by a message, also adjusts
-  // the size of all parent messages by the length of this size field.
-  // If size_index_ < 0, this is not a message, so no size field is added.
-  if (size_index_ >= 0) {
-    // Add the final buffer position to compute the total length of this
-    // serialized message. The stored value (before this addition) already
-    // contains the total length of the size fields of all nested messages
-    // minus the initial buffer position.
-    ow_->size_insert_[size_index_].size += ow_->stream_->ByteCount();
-    // Calculate the length required to serialize the size field of the
-    // message, and propagate this additional size information upward to
-    // all enclosing messages.
-    int size = ow_->size_insert_[size_index_].size;
-    int length = CodedOutputStream::VarintSize32(size);
-    for (ProtoElement* e = parent(); e != NULL; e = e->parent()) {
-      // Only nested messages have size field, lists do not have size field.
-      if (e->size_index_ >= 0) {
-        ow_->size_insert_[e->size_index_].size += length;
-      }
-    }
-  }
-  return BaseElement::pop<ProtoElement>();
-}
-
-void ProtoStreamObjectWriter::ProtoElement::RegisterField(
-    const google::protobuf::Field* field) {
-  if (!required_fields_.empty() &&
-      field->cardinality() ==
-          google::protobuf::Field_Cardinality_CARDINALITY_REQUIRED) {
-    required_fields_.erase(field);
-  }
-}
-
-string ProtoStreamObjectWriter::ProtoElement::ToString() const {
-  if (parent() == NULL) return "";
-  string loc = parent()->ToString();
-  if (field_->cardinality() !=
-          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED ||
-      parent()->field_ != field_) {
-    string name = field_->name();
-    int i = 0;
-    while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
-    if (i > 0 && i == name.size()) {  // safe field name
-      if (loc.empty()) {
-        loc = name;
-      } else {
-        StrAppend(&loc, ".", name);
-      }
-    } else {
-      StrAppend(&loc, "[\"", CEscape(name), "\"]");
-    }
-  }
-  if (field_->cardinality() ==
-          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
-      array_index_ > 0) {
-    StrAppend(&loc, "[", array_index_ - 1, "]");
-  }
-  return loc.empty() ? "." : loc;
-}
-
-bool ProtoStreamObjectWriter::ProtoElement::OneofIndexTaken(int32 index) {
-  return ContainsKey(oneof_indices_, index);
-}
-
-void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) {
-  InsertIfNotPresent(&oneof_indices_, index);
-}
-
-inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name,
-                                                 StringPiece message) {
-  listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
-}
-
-inline void ProtoStreamObjectWriter::InvalidValue(StringPiece type_name,
-                                                  StringPiece value) {
-  listener_->InvalidValue(location(), type_name, value);
-}
-
-inline void ProtoStreamObjectWriter::MissingField(StringPiece missing_name) {
-  listener_->MissingField(location(), missing_name);
+bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
+    StringPiece map_key) {
+  return InsertIfNotPresent(&map_keys_, map_key.ToString());
 }
 
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
     StringPiece name) {
-  // Starting the root message. Create the root ProtoElement and return.
-  if (element_ == NULL) {
-    if (!name.empty()) {
-      InvalidName(name, "Root element should not be named.");
-    }
-    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Starting the root message. Create the root Item and return.
+  // ANY message type does not need special handling, just set the ItemType
+  // to ANY.
+  if (current_ == NULL) {
+    ProtoWriter::StartObject(name);
+    current_.reset(new Item(
+        this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
+        false, false));
 
     // If master type is a special type that needs extra values to be written to
     // stream, we write those values.
     if (master_type_.name() == kStructType) {
-      StartStruct(NULL);
-    } else if (master_type_.name() == kStructValueType) {
-      // We got a StartObject call with google.protobuf.Value field. This means
-      // we are starting an object within google.protobuf.Value type. The only
+      // Struct has a map<string, Value> field called "fields".
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      // "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructValueType) {
+      // We got a StartObject call with google.protobuf.Value field. The only
       // object within that type is a struct type. So start a struct.
-      const google::protobuf::Field* field = StartStructValueInStruct(NULL);
-      StartStruct(field);
+      //
+      // The struct field in Value type is named "struct_value"
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      // Also start the map field "fields" within the struct.
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
+      InvalidValue(kStructListValueType,
+                   "Cannot start root message with ListValue.");
+    }
+
+    return this;
+  }
+
+  // Send all ANY events to AnyWriter.
+  if (current_->IsAny()) {
+    current_->any()->StartObject(name);
+    return this;
+  }
+
+  // If we are within a map, we render name as keys and send StartObject to the
+  // value field.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
+      return this;
+    }
+
+    // Map is a repeated field of message type with a "key" and a "value" field.
+    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
+    // message MapFieldEntry {
+    //   key_type key = 1;
+    //   value_type value = 2;
+    // }
+    //
+    // repeated MapFieldEntry map_field = N;
+    //
+    // That means, we render the following element within a list (hence no
+    // name):
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key", DataPiece(name));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid so far after starting map fields.
+    if (invalid_depth() > 0) return this;
+
+    // If top of stack is g.p.Struct type, start the struct the map field within
+    // it.
+    if (element() != NULL && IsStruct(*element()->parent_field())) {
+      // Render "fields": [
+      Push("fields", Item::MAP, true, true);
+      return this;
+    }
+
+    // If top of stack is g.p.Value type, start the Struct within it.
+    if (element() != NULL && IsStructValue(*element()->parent_field())) {
+      // Render
+      // "struct_value": {
+      //   "fields": [
+      Push("struct_value", Item::MESSAGE, true, false);
+      Push("fields", Item::MAP, true, true);
     }
     return this;
   }
 
-  const google::protobuf::Field* field = NULL;
-  if (element_ != NULL && element_->IsAny()) {
-    element_->any()->StartObject(name);
-    return this;
-  } else if (element_ != NULL &&
-             (element_->IsMap() || element_->IsStructMap())) {
-    field = StartMapEntry(name);
-    if (element_->IsStructMapEntry()) {
-      // If the top element is a map entry, this means we are starting another
-      // struct within a struct.
-      field = StartStructValueInStruct(field);
-    }
-  } else if (element_ != NULL && element_->IsStructList()) {
-    // If the top element is a list, then we are starting a list field within a
-    // struct.
-    field = Lookup(name);
-    field = StartStructValueInStruct(field);
-  } else {
-    field = BeginNamed(name, false);
-  }
-  if (field == NULL) {
-    return this;
-  }
+  const google::protobuf::Field* field = BeginNamed(name, false);
+  if (field == NULL) return this;
 
-  const google::protobuf::Type* type = LookupType(field);
-  if (type == NULL) {
-    ++invalid_depth_;
-    InvalidName(name,
-                StrCat("Missing descriptor for field: ", field->type_url()));
-    return this;
-  }
-
-  // Check to see if this field is a oneof and that no oneof in that group has
-  // already been set.
-  if (!ValidOneof(*field, name)) {
-    ++invalid_depth_;
-    return this;
-  }
-
-  if (field->type_url() == GetFullTypeWithUrl(kStructType)) {
+  if (IsStruct(*field)) {
     // Start a struct object.
-    StartStruct(field);
-  } else if (field->type_url() == GetFullTypeWithUrl(kStructValueType)) {
-    // We got a StartObject call with google.protobuf.Value field. This means we
-    // are starting an object within google.protobuf.Value type. The only object
-    // within that type is a struct type. So start a struct.
-    field = StartStructValueInStruct(field);
-    StartStruct(field);
-  } else if (field->type_url() == GetFullTypeWithUrl(kAnyType)) {
-    // Begin an Any. We can't do the real work till we get the @type field.
-    WriteTag(*field);
-    element_.reset(
-        new ProtoElement(element_.release(), field, *type, ProtoElement::ANY));
-  } else if (IsMap(*field)) {
-    // Begin a map.
-    // A map is triggered by a StartObject() call if the current field has a map
-    // type. Map values are written to proto in a manner detailed in comments
-    // above StartMapEntry() function.
-    element_.reset(
-        new ProtoElement(element_.release(), field, *type, ProtoElement::MAP));
-  } else {
-    WriteTag(*field);
-    element_.reset(new ProtoElement(element_.release(), field, *type,
-                                    ProtoElement::MESSAGE));
+    // Render
+    // "<name>": {
+    //   "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
   }
+
+  if (IsStructValue(*field)) {
+    // We got a StartObject call with google.protobuf.Value field.  The only
+    // object within that type is a struct type. So start a struct.
+    // Render
+    // "<name>": {
+    //   "struct_value": {
+    //     "fields": {
+    Push(name, Item::MESSAGE, false, false);
+    Push("struct_value", Item::MESSAGE, true, false);
+    Push("fields", Item::MAP, true, true);
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    // Begin a map. A map is triggered by a StartObject() call if the current
+    // field has a map type.
+    // A map type is always repeated, hence set is_list to true.
+    // Render
+    // "<name>": [
+    Push(name, Item::MAP, false, true);
+    return this;
+  }
+
+  // A regular message type. Pass it directly to ProtoWriter.
+  // Render
+  // "<name>": {
+  Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
   return this;
 }
 
-// Proto3 maps are represented on the wire as a message with
-// "key" and a "value".
-//
-// For example, the syntax:
-// map<key_type, value_type> map_field = N;
-//
-// is represented as:
-// message MapFieldEntry {
-//   option map_entry = true;   // marks the map construct in the descriptor
-//
-//   key_type key = 1;
-//   value_type value = 2;
-// }
-// repeated MapFieldEntry map_field = N;
-//
-// See go/proto3-maps for more information.
-const google::protobuf::Field* ProtoStreamObjectWriter::StartMapEntry(
-    StringPiece name) {
-  // top of stack is already a map field
-  const google::protobuf::Field* field = element_->field();
-  const google::protobuf::Type& type = element_->type();
-  // If we come from a regular map, use MAP_ENTRY or if we come from a struct,
-  // use STRUCT_MAP_ENTRY. These values are used later in StartObject/StartList
-  // or RenderDataPiece for making appropriate decisions.
-  ProtoElement::ElementType element_type = element_->IsStructMap()
-                                               ? ProtoElement::STRUCT_MAP_ENTRY
-                                               : ProtoElement::MAP_ENTRY;
-  WriteTag(*field);
-  element_.reset(
-      new ProtoElement(element_.release(), field, type, element_type));
-  RenderDataPiece("key", DataPiece(name));
-  return BeginNamed("value", false);
-}
-
-// Starts a google.protobuf.Struct.
-// 'field' represents a field in a message of type google.protobuf.Struct.  A
-// struct contains a map with name 'fields'. This function starts this map as
-// well.
-// When 'field' is NULL, it means that the top level message is of struct
-// type.
-void ProtoStreamObjectWriter::StartStruct(
-    const google::protobuf::Field* field) {
-  const google::protobuf::Type* type = NULL;
-  if (field) {
-    type = LookupType(field);
-    WriteTag(*field);
-    element_.reset(new ProtoElement(element_.release(), field, *type,
-                                    ProtoElement::STRUCT));
-  }
-  const google::protobuf::Field* struct_field = BeginNamed("fields", false);
-
-  if (!struct_field) {
-    // It is a programmatic error if this happens. Log an error.
-    GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'fields' within "
-               << (field ? field->type_url() : "google.protobuf.Struct");
-    return;
-  }
-
-  type = LookupType(struct_field);
-  element_.reset(new ProtoElement(element_.release(), struct_field, *type,
-                                  ProtoElement::STRUCT_MAP));
-}
-
-// Starts a "struct_value" within struct.proto's google.protobuf.Value type.
-// 'field' should be of the type google.protobuf.Value.
-// Returns the field identifying "struct_value" within the given field.
-//
-// If field is NULL, then we are starting struct_value at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field*
-ProtoStreamObjectWriter::StartStructValueInStruct(
-    const google::protobuf::Field* field) {
-  if (field) {
-    const google::protobuf::Type* type = LookupType(field);
-    WriteTag(*field);
-    element_.reset(new ProtoElement(element_.release(), field, *type,
-                                    ProtoElement::STRUCT_VALUE));
-  }
-  return BeginNamed("struct_value", false);
-}
-
-// Starts a "list_value" within struct.proto's google.protobuf.Value type.
-// 'field' should be of the type google.protobuf.Value.
-// Returns the field identifying "list_value" within the given field.
-//
-// If field is NULL, then we are starting list_value at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field* ProtoStreamObjectWriter::StartListValueInStruct(
-    const google::protobuf::Field* field) {
-  if (field) {
-    const google::protobuf::Type* type = LookupType(field);
-    WriteTag(*field);
-    element_.reset(new ProtoElement(element_.release(), field, *type,
-                                    ProtoElement::STRUCT_VALUE));
-  }
-  const google::protobuf::Field* list_value = BeginNamed("list_value", false);
-
-  if (!list_value) {
-    // It is a programmatic error if this happens. Log an error.
-    GOOGLE_LOG(ERROR) << "Invalid internal state. Cannot find 'list_value' within "
-               << (field ? field->type_url() : "google.protobuf.Value");
-    return field;
-  }
-
-  return StartRepeatedValuesInListValue(list_value);
-}
-
-// Starts the repeated "values" field in struct.proto's
-// google.protobuf.ListValue type. 'field' should be of type
-// google.protobuf.ListValue.
-//
-// If field is NULL, then we are starting ListValue at the top-level, in
-// this case skip writing any tag information for the passed field.
-const google::protobuf::Field*
-ProtoStreamObjectWriter::StartRepeatedValuesInListValue(
-    const google::protobuf::Field* field) {
-  if (field) {
-    const google::protobuf::Type* type = LookupType(field);
-    WriteTag(*field);
-    element_.reset(new ProtoElement(element_.release(), field, *type,
-                                    ProtoElement::STRUCT_LIST_VALUE));
-  }
-  return BeginNamed("values", true);
-}
-
-void ProtoStreamObjectWriter::SkipElements() {
-  if (element_ == NULL) return;
-
-  ProtoElement::ElementType element_type = element_->element_type();
-  while (element_type == ProtoElement::STRUCT ||
-         element_type == ProtoElement::STRUCT_LIST_VALUE ||
-         element_type == ProtoElement::STRUCT_VALUE ||
-         element_type == ProtoElement::STRUCT_MAP_ENTRY ||
-         element_type == ProtoElement::MAP_ENTRY) {
-    element_.reset(element_->pop());
-    element_type =
-        element_ != NULL ? element_->element_type() : ProtoElement::MESSAGE;
-  }
-}
-
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
-  if (invalid_depth_ > 0) {
-    --invalid_depth_;
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
     return this;
   }
-  if (element_ != NULL && element_->IsAny()) {
-    if (element_->any()->EndObject()) {
-      return this;
-    }
-  }
-  if (element_ != NULL) {
-    element_.reset(element_->pop());
+
+  if (current_ == NULL) return this;
+
+  if (current_->IsAny()) {
+    if (current_->any()->EndObject()) return this;
   }
 
-  // Skip sentinel elements added to keep track of new proto3 types - map,
-  // struct.
-  SkipElements();
+  Pop();
 
-  // If ending the root element,
-  // then serialize the full message with calculated sizes.
-  if (element_ == NULL) {
-    WriteRootMessage();
-  }
   return this;
 }
 
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
-  const google::protobuf::Field* field = NULL;
+  if (invalid_depth() > 0) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
   // Since we cannot have a top-level repeated item in protobuf, the only way
-  // element_ can be null when here is when we start a top-level list
-  // google.protobuf.ListValue.
-  if (element_ == NULL) {
+  // this is valid is if we start a special type google.protobuf.ListValue or
+  // google.protobuf.Value.
+  if (current_ == NULL) {
     if (!name.empty()) {
       InvalidName(name, "Root element should not be named.");
+      IncrementInvalidDepth();
+      return this;
     }
-    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
 
     // If master type is a special type that needs extra values to be written to
     // stream, we write those values.
     if (master_type_.name() == kStructValueType) {
       // We got a StartList with google.protobuf.Value master type. This means
       // we have to start the "list_value" within google.protobuf.Value.
-      field = StartListValueInStruct(NULL);
-    } else if (master_type_.name() == kStructListValueType) {
+      //
+      // See
+      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
+      //
+      // Render
+      // "<name>": {
+      //   "list_value": {
+      //     "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("list_value", Item::MESSAGE, true, false);
+      Push("values", Item::MESSAGE, true, true);
+      return this;
+    }
+
+    if (master_type_.name() == kStructListValueType) {
       // We got a StartList with google.protobuf.ListValue master type. This
       // means we have to start the "values" within google.protobuf.ListValue.
-      field = StartRepeatedValuesInListValue(NULL);
-    }
-
-    // field is NULL when master_type_ is anything other than
-    // google.protobuf.Value or google.protobuf.ListValue.
-    if (field) {
-      const google::protobuf::Type* type = LookupType(field);
-      element_.reset(new ProtoElement(element_.release(), field, *type,
-                                      ProtoElement::STRUCT_LIST));
-    }
-    return this;
-  }
-
-  if (element_->IsAny()) {
-    element_->any()->StartList(name);
-    return this;
-  }
-  // The type of element we push to stack.
-  ProtoElement::ElementType element_type = ProtoElement::LIST;
-
-  // Check if we need to start a map. This can heppen when there is either a map
-  // or a struct type within a list.
-  if (element_->IsMap() || element_->IsStructMap()) {
-    field = StartMapEntry(name);
-    if (field == NULL) return this;
-
-    if (element_->IsStructMapEntry()) {
-      // If the top element is a map entry, this means we are starting a list
-      // within a struct or a map.
-      // An example sequence of calls would be
-      //    StartObject -> StartList
-      field = StartListValueInStruct(field);
-      if (field == NULL) return this;
-    }
-
-    element_type = ProtoElement::STRUCT_LIST;
-  } else if (element_->IsStructList()) {
-    // If the top element is a STRUCT_LIST, this means we are starting a list
-    // within the current list (inside a struct).
-    // An example call sequence would be
-    //    StartObject -> StartList -> StartList
-    // with StartObject starting a struct.
-
-    // Lookup the last list type in element stack as we are adding an element of
-    // the same type.
-    field = Lookup(name);
-    if (field == NULL) return this;
-
-    field = StartListValueInStruct(field);
-    if (field == NULL) return this;
-
-    element_type = ProtoElement::STRUCT_LIST;
-  } else {
-    // Lookup field corresponding to 'name'. If it is a google.protobuf.Value
-    // or google.protobuf.ListValue type, then StartList is a valid call, start
-    // this list.
-    // We cannot use Lookup() here as it will produce InvalidName() error if the
-    // field is not found. We do not want to error here as it would cause us to
-    // report errors twice, once here and again later in BeginNamed() call.
-    // Also we ignore if the field is not found here as it is caught later.
-    field = typeinfo_->FindField(&element_->type(), name);
-
-    // Only check for oneof collisions on the first StartList call. We identify
-    // the first call with !name.empty() check. Subsequent list element calls
-    // will not have the name filled.
-    if (!name.empty() && field && !ValidOneof(*field, name)) {
-      ++invalid_depth_;
+      //
+      // Render
+      // "<name>": {
+      //   "values": [  // Start this list.
+      ProtoWriter::StartObject(name);
+      current_.reset(new Item(this, Item::MESSAGE, false, false));
+      Push("values", Item::MESSAGE, true, true);
       return this;
     }
 
-    // It is an error to try to bind to map, which behind the scenes is a list.
-    if (field && IsMap(*field)) {
-      // Push field to stack for error location tracking & reporting.
-      element_.reset(new ProtoElement(element_.release(), field,
-                                      *LookupType(field),
-                                      ProtoElement::MESSAGE));
-      InvalidValue("Map", "Cannot bind a list to map.");
-      ++invalid_depth_;
-      element_->pop();
+    // Send the event to ProtoWriter so proper errors can be reported.
+    //
+    // Render a regular list:
+    // "<name>": [
+    ProtoWriter::StartList(name);
+    current_.reset(new Item(this, Item::MESSAGE, false, true));
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->StartList(name);
+    return this;
+  }
+
+  // If the top of stack is a map, we are starting a list value within a map.
+  // Since map does not allow repeated values, this can only happen when the map
+  // value is of a special type that renders a list in JSON.  These can be one
+  // of 3 cases:
+  // i. We are rendering a list value within google.protobuf.Struct
+  // ii. We are rendering a list value within google.protobuf.Value
+  // iii. We are rendering a list value with type google.protobuf.ListValue.
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) {
+      IncrementInvalidDepth();
       return this;
     }
 
-    if (field && field->type_url() == GetFullTypeWithUrl(kStructValueType)) {
-      // There are 2 cases possible:
-      //   a. g.p.Value is repeated
-      //   b. g.p.Value is not repeated
-      //
-      // For case (a), the StartList should bind to the repeated g.p.Value.
-      // For case (b), the StartList should bind to g.p.ListValue within the
-      // g.p.Value.
-      //
-      // This means, for case (a), we treat it just like any other repeated
-      // message, except we would apply an appropriate element_type so future
-      // Start or Render calls are routed appropriately.
-      if (field->cardinality() !=
-          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
-        field = StartListValueInStruct(field);
+    // Start the repeated map entry object.
+    // Render
+    // { "key": "<name>", "value": {
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key", DataPiece(name));
+    Push("value", Item::MESSAGE, true, false);
+
+    // Make sure we are valid after pushing all above items.
+    if (invalid_depth() > 0) return this;
+
+    // case i and ii above. Start "list_value" field within g.p.Value
+    if (element() != NULL && element()->parent_field() != NULL) {
+      // Render
+      // "list_value": {
+      //   "values": [  // Start this list
+      if (IsStructValue(*element()->parent_field())) {
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
       }
-      element_type = ProtoElement::STRUCT_LIST;
-    } else if (field &&
-               field->type_url() == GetFullTypeWithUrl(kStructListValueType)) {
-      // We got a StartList with google.protobuf.ListValue master type. This
-      // means we have to start the "values" within google.protobuf.ListValue.
-      field = StartRepeatedValuesInListValue(field);
-    } else {
-      // If no special types are to be bound, fall back to normal processing of
-      // StartList.
-      field = BeginNamed(name, true);
-    }
-    if (field == NULL) return this;
-  }
 
-  const google::protobuf::Type* type = LookupType(field);
-  if (type == NULL) {
-    ++invalid_depth_;
-    InvalidName(name,
-                StrCat("Missing descriptor for field: ", field->type_url()));
+      // Render
+      // "values": [
+      if (IsStructListValue(*element()->parent_field())) {
+        // case iii above. Bind directly to g.p.ListValue
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Report an error.
+    InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
+                               "') within a map."));
     return this;
   }
 
-  element_.reset(
-      new ProtoElement(element_.release(), field, *type, element_type));
+  // When name is empty and stack is not empty, we are rendering an item within
+  // a list.
+  if (name.empty()) {
+    if (element() != NULL && element()->parent_field() != NULL) {
+      if (IsStructValue(*element()->parent_field())) {
+        // Since it is g.p.Value, we bind directly to the list_value.
+        // Render
+        // {  // g.p.Value item within the list
+        //   "list_value": {
+        //     "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("list_value", Item::MESSAGE, true, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+
+      if (IsStructListValue(*element()->parent_field())) {
+        // Since it is g.p.ListValue, we bind to it directly.
+        // Render
+        // {  // g.p.ListValue item within the list
+        //   "values": [
+        Push("", Item::MESSAGE, false, false);
+        Push("values", Item::MESSAGE, true, true);
+        return this;
+      }
+    }
+
+    // Pass the event to underlying ProtoWriter.
+    Push(name, Item::MESSAGE, false, true);
+    return this;
+  }
+
+  // name is not empty
+  const google::protobuf::Field* field = Lookup(name);
+  if (field == NULL) {
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  if (IsStructValue(*field)) {
+    // If g.p.Value is repeated, start that list. Otherwise, start the
+    // "list_value" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "list_value" field.
+    // Render
+    // "<name>": {
+    //   "list_value": {
+    //     "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("list_value", Item::MESSAGE, true, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  if (IsStructListValue(*field)) {
+    // If g.p.ListValue is repeated, start that list. Otherwise, start the
+    // "values" within it.
+    if (IsRepeated(*field)) {
+      // Render it just like a regular repeated field.
+      // "<name>": [
+      Push(name, Item::MESSAGE, false, true);
+      return this;
+    }
+
+    // Start the "values" field within g.p.ListValue.
+    // Render
+    // "<name>": {
+    //   "values": [
+    Push(name, Item::MESSAGE, false, false);
+    Push("values", Item::MESSAGE, true, true);
+    return this;
+  }
+
+  // If we are here, the field should be repeated. Report an error otherwise.
+  if (!IsRepeated(*field)) {
+    IncrementInvalidDepth();
+    InvalidName(name, "Proto field is not repeating, cannot start list.");
+    return this;
+  }
+
+  if (IsMap(*field)) {
+    InvalidValue("Map",
+                 StrCat("Cannot bind a list to map for field '", name, "'."));
+    IncrementInvalidDepth();
+    return this;
+  }
+
+  // Pass the event to ProtoWriter.
+  // Render
+  // "<name>": [
+  Push(name, Item::MESSAGE, false, true);
   return this;
 }
 
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
-  if (invalid_depth_ > 0) {
-    --invalid_depth_;
-  } else if (element_ != NULL) {
-    if (element_->IsAny()) {
-      element_->any()->EndList();
-    } else {
-      element_.reset(element_->pop());
-      // Skip sentinel elements added to keep track of new proto3 types - map,
-      // struct.
-      SkipElements();
-    }
+  if (invalid_depth() > 0) {
+    DecrementInvalidDepth();
+    return this;
   }
 
-  // When element_ is NULL, we have reached the root message type. Write out
-  // the bytes.
-  if (element_ == NULL) {
-    WriteRootMessage();
+  if (current_ == NULL) return this;
+
+  if (current_->IsAny()) {
+    current_->any()->EndList();
+    return this;
   }
+
+  Pop();
   return this;
 }
 
@@ -1067,7 +782,7 @@
                     "null values are supported.");
     }
   }
-  ow->RenderDataPiece(struct_field_name, data);
+  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
   return Status::OK;
 }
 
@@ -1089,15 +804,15 @@
   }
 
 
-  ow->RenderDataPiece("seconds", DataPiece(seconds));
-  ow->RenderDataPiece("nanos", DataPiece(nanos));
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
   return Status::OK;
 }
 
 static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
                                                 StringPiece path) {
-  ow->RenderDataPiece("paths",
-                      DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase)));
+  ow->ProtoWriter::RenderDataPiece(
+      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase)));
   return Status::OK;
 }
 
@@ -1113,7 +828,7 @@
 // conversions as much as possible. Because ToSnakeCase sometimes returns the
 // wrong value.
   google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
-      NewPermanentCallback(&RenderOneFieldPath, ow));
+      google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
   return DecodeCompactFieldMaskPaths(data.str(), callback.get());
 }
 
@@ -1146,221 +861,131 @@
                   "Invalid duration format, failed to parse seconds");
   }
 
-  double d_nanos = 0;
-  if (!safe_strtod("0." + s_nanos.ToString(), &d_nanos)) {
-    return Status(INVALID_ARGUMENT,
-                  "Invalid duration format, failed to parse nanos seconds");
+  int32 nanos = 0;
+  Status nanos_status = GetNanosFromStringPiece(
+      s_nanos, "Invalid duration format, failed to parse nano seconds",
+      "Duration value exceeds limits", &nanos);
+  if (!nanos_status.ok()) {
+    return nanos_status;
   }
+  nanos = sign * nanos;
 
-  int32 nanos = sign * static_cast<int32>(d_nanos * kNanosPerSecond);
   int64 seconds = sign * unsigned_seconds;
-
   if (seconds > kMaxSeconds || seconds < kMinSeconds ||
       nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
     return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
   }
 
-  ow->RenderDataPiece("seconds", DataPiece(seconds));
-  ow->RenderDataPiece("nanos", DataPiece(nanos));
+  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
+  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
   return Status::OK;
 }
 
 Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
                                                   const DataPiece& data) {
-  ow->RenderDataPiece("value", data);
+  ow->ProtoWriter::RenderDataPiece("value", data);
   return Status::OK;
 }
 
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
     StringPiece name, const DataPiece& data) {
   Status status;
-  if (invalid_depth_ > 0) return this;
-  if (element_ != NULL && element_->IsAny()) {
-    element_->any()->RenderDataPiece(name, data);
+  if (invalid_depth() > 0) return this;
+
+  if (current_ == NULL) {
+    const TypeRenderer* type_renderer =
+        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
+    if (type_renderer == NULL) {
+      InvalidName(name, "Root element must be a message.");
+      return this;
+    }
+    // Render the special type.
+    // "<name>": {
+    //   ... Render special type ...
+    // }
+    ProtoWriter::StartObject(name);
+    status = (*type_renderer)(this, data);
+    if (!status.ok()) {
+      InvalidValue(master_type_.name(),
+                   StrCat("Field '", name, "', ", status.error_message()));
+    }
+    ProtoWriter::EndObject();
+    return this;
+  }
+
+  if (current_->IsAny()) {
+    current_->any()->RenderDataPiece(name, data);
     return this;
   }
 
   const google::protobuf::Field* field = NULL;
-  string type_url;
-  bool is_map_entry = false;
-  // We are at the root when element_ == NULL.
-  if (element_ == NULL) {
-    type_url = GetFullTypeWithUrl(master_type_.name());
-  } else {
-    if (element_->IsMap() || element_->IsStructMap()) {
-      is_map_entry = true;
-      field = StartMapEntry(name);
-    } else {
-      field = Lookup(name);
-    }
+  if (current_->IsMap()) {
+    if (!ValidMapKey(name)) return this;
+
+    // Render an item in repeated map list.
+    // { "key": "<name>", "value":
+    Push("", Item::MESSAGE, false, false);
+    ProtoWriter::RenderDataPiece("key", DataPiece(name));
+    field = Lookup("value");
     if (field == NULL) {
+      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
       return this;
     }
 
-    // Check to see if this field is a oneof and that no oneof in that group has
-    // already been set.
-    if (!ValidOneof(*field, name)) return this;
+    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
+    if (type_renderer != NULL) {
+      // Map's value type is a special type. Render it like a message:
+      // "value": {
+      //   ... Render special type ...
+      // }
+      Push("value", Item::MESSAGE, true, false);
+      status = (*type_renderer)(this, data);
+      if (!status.ok()) {
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.error_message()));
+      }
+      Pop();
+      return this;
+    }
 
-    type_url = field->type_url();
+    // If we are rendering explicit null values and the backend proto field is
+    // not of the google.protobuf.NullType type, we do nothing.
+    if (data.type() == DataPiece::TYPE_NULL &&
+        field->type_url() != kStructNullValueTypeUrl) {
+      return this;
+    }
+
+    // Render the map value as a primitive type.
+    ProtoWriter::RenderDataPiece("value", data);
+    Pop();
+    return this;
   }
 
-  // Check if there are any well known type renderers available for type_url.
-  const TypeRenderer* type_renderer = FindTypeRenderer(type_url);
+  field = Lookup(name);
+  if (field == NULL) return this;
+
+  // Check if the field is of special type. Render it accordingly if so.
+  const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
   if (type_renderer != NULL) {
-    // Push the current element to stack so lookups in type_renderer will
-    // find the fields. We do an EndObject soon after, which pops this. This is
-    // safe because all well-known types are messages.
-    if (element_ == NULL) {
-      element_.reset(new ProtoElement(typeinfo_, master_type_, this));
-    } else {
-      if (field) {
-        WriteTag(*field);
-        const google::protobuf::Type* type = LookupType(field);
-        element_.reset(new ProtoElement(element_.release(), field, *type,
-                                        ProtoElement::MESSAGE));
-      }
-    }
+    Push(name, Item::MESSAGE, false, false);
     status = (*type_renderer)(this, data);
     if (!status.ok()) {
-      InvalidValue(type_url,
+      InvalidValue(field->type_url(),
                    StrCat("Field '", name, "', ", status.error_message()));
     }
-    EndObject();
-    return this;
-  } else if (element_ == NULL) {  // no message type found at root
-    element_.reset(new ProtoElement(typeinfo_, master_type_, this));
-    InvalidName(name, "Root element must be a message.");
+    Pop();
     return this;
   }
 
-  if (field == NULL) {
-    return this;
-  }
-  const google::protobuf::Type* type = LookupType(field);
-  if (type == NULL) {
-    InvalidName(name,
-                StrCat("Missing descriptor for field: ", field->type_url()));
-    return this;
-  }
-
-  // Whether we should pop at the end. Set to true if the data field is a
-  // message type, which can happen in case of struct values.
-  bool should_pop = false;
-
-  RenderSimpleDataPiece(*field, *type, data);
-
-  if (should_pop && element_ != NULL) {
-    element_.reset(element_->pop());
-  }
-
-  if (is_map_entry) {
-    // Ending map is the same as ending an object.
-    EndObject();
-  }
-  return this;
-}
-
-void ProtoStreamObjectWriter::RenderSimpleDataPiece(
-    const google::protobuf::Field& field, const google::protobuf::Type& type,
-    const DataPiece& data) {
-  // If we are rendering explicit null values and the backend proto field is not
-  // of the google.protobuf.NullType type, we do nothing.
+  // If we are rendering explicit null values and the backend proto field is
+  // not of the google.protobuf.NullType type, we do nothing.
   if (data.type() == DataPiece::TYPE_NULL &&
-      field.type_url() != kStructNullValueTypeUrl) {
-    return;
+      field->type_url() != kStructNullValueTypeUrl) {
+    return this;
   }
 
-  // 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,
-                                  ProtoElement::MESSAGE));
-
-  // Make sure that field represents a simple data type.
-  if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN ||
-      field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
-    InvalidValue(field.type_url().empty()
-                     ? google::protobuf::Field_Kind_Name(field.kind())
-                     : field.type_url(),
-                 data.ValueAsStringOrDefault(""));
-    return;
-  }
-
-  Status status;
-  switch (field.kind()) {
-    case google::protobuf::Field_Kind_TYPE_INT32: {
-      status = WriteInt32(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_SFIXED32: {
-      status = WriteSFixed32(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_SINT32: {
-      status = WriteSInt32(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_FIXED32: {
-      status = WriteFixed32(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_UINT32: {
-      status = WriteUInt32(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_INT64: {
-      status = WriteInt64(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_SFIXED64: {
-      status = WriteSFixed64(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_SINT64: {
-      status = WriteSInt64(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_FIXED64: {
-      status = WriteFixed64(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_UINT64: {
-      status = WriteUInt64(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_DOUBLE: {
-      status = WriteDouble(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_FLOAT: {
-      status = WriteFloat(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_BOOL: {
-      status = WriteBool(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_BYTES: {
-      status = WriteBytes(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_STRING: {
-      status = WriteString(field.number(), data, stream_.get());
-      break;
-    }
-    case google::protobuf::Field_Kind_TYPE_ENUM: {
-      status = WriteEnum(field.number(), data,
-                         typeinfo_->GetEnumByTypeUrl(field.type_url()),
-                         stream_.get());
-      break;
-    }
-    default:  // TYPE_GROUP or TYPE_MESSAGE
-      status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
-  }
-  if (!status.ok()) {
-    InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
-                 status.error_message());
-  }
-  element_.reset(element_->pop());
+  ProtoWriter::RenderDataPiece(name, data);
+  return this;
 }
 
 // Map of functions that are responsible for rendering well known type
@@ -1429,167 +1054,43 @@
   return FindOrNull(*renderers_, type_url);
 }
 
-ProtoStreamObjectWriter::ProtoElement::ElementType
-ProtoStreamObjectWriter::GetElementType(const google::protobuf::Type& type) {
-  if (type.name() == kAnyType) {
-    return ProtoElement::ANY;
-  } else if (type.name() == kStructType) {
-    return ProtoElement::STRUCT;
-  } else if (type.name() == kStructValueType) {
-    return ProtoElement::STRUCT_VALUE;
-  } else if (type.name() == kStructListValueType) {
-    return ProtoElement::STRUCT_LIST_VALUE;
-  } else {
-    return ProtoElement::MESSAGE;
-  }
-}
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+  if (current_ == NULL) return true;
 
-bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field,
-                                         StringPiece unnormalized_name) {
-  if (element_ == NULL) return true;
-
-  if (field.oneof_index() > 0) {
-    if (element_->OneofIndexTaken(field.oneof_index())) {
-      InvalidValue(
-          "oneof",
-          StrCat("oneof field '",
-                 element_->type().oneofs(field.oneof_index() - 1),
-                 "' is already set. Cannot set '", unnormalized_name, "'"));
-      return false;
-    }
-    element_->TakeOneofIndex(field.oneof_index());
+  if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+    listener()->InvalidName(
+        location(), unnormalized_name,
+        StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
+    return false;
   }
+
   return true;
 }
 
-const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed(
-    StringPiece name, bool is_list) {
-  if (invalid_depth_ > 0) {
-    ++invalid_depth_;
-    return NULL;
-  }
-  const google::protobuf::Field* field = Lookup(name);
-  if (field == NULL) {
-    ++invalid_depth_;
-    // InvalidName() already called in Lookup().
-    return NULL;
-  }
-  if (is_list &&
-      field->cardinality() !=
-          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
-    ++invalid_depth_;
-    InvalidName(name, "Proto field is not repeating, cannot start list.");
-    return NULL;
-  }
-  return field;
+void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
+                                   bool is_placeholder, bool is_list) {
+  is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
+
+  // invalid_depth == 0 means it is a successful StartObject or StartList.
+  if (invalid_depth() == 0)
+    current_.reset(
+        new Item(current_.release(), item_type, is_placeholder, is_list));
 }
 
-const google::protobuf::Field* ProtoStreamObjectWriter::Lookup(
-    StringPiece unnormalized_name) {
-  ProtoElement* e = element();
-  if (e == NULL) {
-    InvalidName(unnormalized_name, "Root element must be a message.");
-    return NULL;
+void ProtoStreamObjectWriter::Pop() {
+  // Pop all placeholder items sending StartObject or StartList events to
+  // ProtoWriter according to is_list value.
+  while (current_ != NULL && current_->is_placeholder()) {
+    PopOneElement();
   }
-  if (unnormalized_name.empty()) {
-    // Objects in repeated field inherit the same field descriptor.
-    if (e->field() == NULL) {
-      InvalidName(unnormalized_name, "Proto fields must have a name.");
-    } else if (e->field()->cardinality() !=
-               google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
-      InvalidName(unnormalized_name, "Proto fields must have a name.");
-      return NULL;
-    }
-    return e->field();
+  if (current_ != NULL) {
+    PopOneElement();
   }
-  const google::protobuf::Field* field =
-      typeinfo_->FindField(&e->type(), unnormalized_name);
-  if (field == NULL) InvalidName(unnormalized_name, "Cannot find field.");
-  return field;
 }
 
-const google::protobuf::Type* ProtoStreamObjectWriter::LookupType(
-    const google::protobuf::Field* field) {
-  return (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
-              ? typeinfo_->GetTypeByTypeUrl(field->type_url())
-              : &element_->type());
-}
-
-// Looks up the oneof struct field based on the data type.
-StatusOr<const google::protobuf::Field*>
-ProtoStreamObjectWriter::LookupStructField(DataPiece::Type type) {
-  const google::protobuf::Field* field = NULL;
-  switch (type) {
-    // Our JSON parser parses numbers as either int64, uint64, or double.
-    case DataPiece::TYPE_INT64:
-    case DataPiece::TYPE_UINT64:
-    case DataPiece::TYPE_DOUBLE: {
-      field = Lookup("number_value");
-      break;
-    }
-    case DataPiece::TYPE_STRING: {
-      field = Lookup("string_value");
-      break;
-    }
-    case DataPiece::TYPE_BOOL: {
-      field = Lookup("bool_value");
-      break;
-    }
-    case DataPiece::TYPE_NULL: {
-      field = Lookup("null_value");
-      break;
-    }
-    default: { return Status(INVALID_ARGUMENT, "Invalid struct data type"); }
-  }
-  if (field == NULL) {
-    return Status(INVALID_ARGUMENT, "Could not lookup struct field");
-  }
-  return field;
-}
-
-void ProtoStreamObjectWriter::WriteRootMessage() {
-  GOOGLE_DCHECK(!done_);
-  int curr_pos = 0;
-  // Calls the destructor of CodedOutputStream to remove any uninitialized
-  // memory from the Cord before we read it.
-  stream_.reset(NULL);
-  const void* data;
-  int length;
-  google::protobuf::io::ArrayInputStream input_stream(buffer_.data(), buffer_.size());
-  while (input_stream.Next(&data, &length)) {
-    if (length == 0) continue;
-    int num_bytes = length;
-    // Write up to where we need to insert the size field.
-    // The number of bytes we may write is the smaller of:
-    //   - the current fragment size
-    //   - the distance to the next position where a size field needs to be
-    //     inserted.
-    if (!size_insert_.empty() &&
-        size_insert_.front().pos - curr_pos < num_bytes) {
-      num_bytes = size_insert_.front().pos - curr_pos;
-    }
-    output_->Append(static_cast<const char*>(data), num_bytes);
-    if (num_bytes < length) {
-      input_stream.BackUp(length - num_bytes);
-    }
-    curr_pos += num_bytes;
-    // Insert the size field.
-    //   size_insert_.front():      the next <index, size> pair to be written.
-    //   size_insert_.front().pos:  position of the size field.
-    //   size_insert_.front().size: the size (integer) to be inserted.
-    if (!size_insert_.empty() && curr_pos == size_insert_.front().pos) {
-      // Varint32 occupies at most 10 bytes.
-      uint8 insert_buffer[10];
-      uint8* insert_buffer_pos = CodedOutputStream::WriteVarint32ToArray(
-          size_insert_.front().size, insert_buffer);
-      output_->Append(reinterpret_cast<const char*>(insert_buffer),
-                      insert_buffer_pos - insert_buffer);
-      size_insert_.pop_front();
-    }
-  }
-  output_->Flush();
-  stream_.reset(new CodedOutputStream(&adapter_));
-  done_ = true;
+void ProtoStreamObjectWriter::PopOneElement() {
+  current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
+  current_.reset(current_->pop<Item>());
 }
 
 bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
@@ -1600,7 +1101,7 @@
     return false;
   }
   const google::protobuf::Type* field_type =
-      typeinfo_->GetTypeByTypeUrl(field.type_url());
+      typeinfo()->GetTypeByTypeUrl(field.type_url());
 
   // TODO(xiaofeng): Unify option names.
   return GetBoolOptionOrDefault(field_type->options(),
@@ -1608,10 +1109,22 @@
          GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
 }
 
-void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) {
-  WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
-      static_cast<WireFormatLite::FieldType>(field.kind()));
-  stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
+bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kAnyType;
+}
+
+bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructType;
+}
+
+bool ProtoStreamObjectWriter::IsStructValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
+}
+
+bool ProtoStreamObjectWriter::IsStructListValue(
+    const google::protobuf::Field& field) {
+  return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
 }
 
 }  // namespace converter
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index 8f49120..08ac6e3 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -42,6 +42,7 @@
 #include <google/protobuf/util/internal/type_info.h>
 #include <google/protobuf/util/internal/datapiece.h>
 #include <google/protobuf/util/internal/error_listener.h>
+#include <google/protobuf/util/internal/proto_writer.h>
 #include <google/protobuf/util/internal/structured_objectwriter.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/bytestream.h>
@@ -67,9 +68,11 @@
 class ObjectLocationTracker;
 
 // An ObjectWriter that can write protobuf bytes directly from writer events.
+// This class supports all special types like Struct and Map. It uses
+// the ProtoWriter class to write raw proto bytes.
 //
 // It also supports streaming.
-class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter {
+class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter {
  public:
 // Constructor. Does not take ownership of any parameter passed in.
   ProtoStreamObjectWriter(TypeResolver* type_resolver,
@@ -82,56 +85,13 @@
   virtual ProtoStreamObjectWriter* EndObject();
   virtual ProtoStreamObjectWriter* StartList(StringPiece name);
   virtual ProtoStreamObjectWriter* EndList();
-  virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, bool value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, int32 value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name,
-                                                uint32 value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, int64 value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name,
-                                                uint64 value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderDouble(StringPiece name,
-                                                double value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, float value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderString(StringPiece name,
-                                                StringPiece value) {
-    return RenderDataPiece(name, DataPiece(value));
-  }
-  virtual ProtoStreamObjectWriter* RenderBytes(StringPiece name,
-                                               StringPiece value) {
-    return RenderDataPiece(name, DataPiece(value, false));
-  }
-  virtual ProtoStreamObjectWriter* RenderNull(StringPiece name) {
-    return RenderDataPiece(name, DataPiece::NullData());
-  }
 
   // Renders a DataPiece 'value' into a field whose wire type is determined
   // from the given field 'name'.
-  ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
-                                           const DataPiece& value);
+  virtual ProtoStreamObjectWriter* RenderDataPiece(StringPiece name,
+                                                   const DataPiece& value);
 
-  // Returns the location tracker to use for tracking locations for errors.
-  const LocationTrackerInterface& location() {
-    return element_ != NULL ? *element_ : *tracker_;
-  }
-
-  // When true, we finished writing to output a complete message.
-  bool done() const { return done_; }
-
- private:
+ protected:
   // Function that renders a well known type with modified behavior.
   typedef util::Status (*TypeRenderer)(ProtoStreamObjectWriter*,
                                          const DataPiece&);
@@ -192,72 +152,46 @@
     bool has_injected_value_message_;
   };
 
-  class LIBPROTOBUF_EXPORT ProtoElement : public BaseElement, public LocationTrackerInterface {
+  // Represents an item in a stack of items used to keep state between
+  // ObjectWrier events.
+  class LIBPROTOBUF_EXPORT Item : public BaseElement {
    public:
-    // Indicates the type of element. Special types like LIST, MAP, MAP_ENTRY,
-    // STRUCT etc. are used to deduce other information based on their position
-    // on the stack of elements.
-    enum ElementType {
-      MESSAGE,       // Simple message
-      LIST,          // List/repeated element
-      MAP,           // Proto3 map type
-      MAP_ENTRY,     // Proto3 map message type, with 'key' and 'value' fields
-      ANY,           // Proto3 Any type
-      STRUCT,        // Proto3 struct type
-      STRUCT_VALUE,  // Struct's Value message type
-      STRUCT_LIST,   // List type indicator within a struct
-      STRUCT_LIST_VALUE,  // Struct Value's ListValue message type
-      STRUCT_MAP,         // Struct within a struct type
-      STRUCT_MAP_ENTRY    // Struct map's entry type with 'key' and 'value'
-                          // fields
+    // Indicates the type of item.
+    enum ItemType {
+      MESSAGE,  // Simple message
+      MAP,      // Proto3 map type
+      ANY,      // Proto3 Any type
     };
 
-    // Constructor for the root element. No parent nor field.
-    ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type,
-                 ProtoStreamObjectWriter* enclosing);
+    // Constructor for the root item.
+    Item(ProtoStreamObjectWriter* enclosing, ItemType item_type,
+         bool is_placeholder, bool is_list);
 
-    // Constructor for a field of an element.
-    ProtoElement(ProtoElement* parent, const google::protobuf::Field* field,
-                 const google::protobuf::Type& type, ElementType element_type);
+    // Constructor for a field of a message.
+    Item(Item* parent, ItemType item_type, bool is_placeholder, bool is_list);
 
-    virtual ~ProtoElement() {}
-
-    // Called just before the destructor for clean up:
-    //   - reports any missing required fields
-    //   - computes the space needed by the size field, and augment the
-    //     length of all parent messages by this additional space.
-    //   - releases and returns the parent pointer.
-    ProtoElement* pop();
-
-    // Accessors
-    const google::protobuf::Field* field() const { return field_; }
-    const google::protobuf::Type& type() const { return type_; }
+    virtual ~Item() {}
 
     // These functions return true if the element type is corresponding to the
     // type in function name.
-    bool IsMap() { return element_type_ == MAP; }
-    bool IsStructMap() { return element_type_ == STRUCT_MAP; }
-    bool IsStructMapEntry() { return element_type_ == STRUCT_MAP_ENTRY; }
-    bool IsStructList() { return element_type_ == STRUCT_LIST; }
-    bool IsAny() { return element_type_ == ANY; }
-
-    ElementType element_type() { return element_type_; }
-
-    void RegisterField(const google::protobuf::Field* field);
-    virtual string ToString() const;
+    bool IsMap() { return item_type_ == MAP; }
+    bool IsAny() { return item_type_ == ANY; }
 
     AnyWriter* any() const { return any_.get(); }
 
-    virtual ProtoElement* parent() const {
-      return static_cast<ProtoElement*>(BaseElement::parent());
+    virtual Item* parent() const {
+      return static_cast<Item*>(BaseElement::parent());
     }
 
-    // Returns true if the index is already taken by a preceeding oneof input.
-    bool OneofIndexTaken(int32 index);
+    // Inserts map key into hash set if and only if the key did NOT already
+    // exist in hash set.
+    // The hash set (map_keys_) is ONLY used to keep track of map keys.
+    // Return true if insert successfully; returns false if the map key was
+    // already present.
+    bool InsertMapKeyIfNotPresent(StringPiece map_key);
 
-    // Marks the oneof 'index' as taken. Future inputs to this oneof will
-    // generate an error.
-    void TakeOneofIndex(int32 index);
+    bool is_placeholder() const { return is_placeholder_; }
+    bool is_list() const { return is_list_; }
 
    private:
     // Used for access to variables of the enclosing instance of
@@ -267,121 +201,42 @@
     // A writer for Any objects, handles all Any-related nonsense.
     google::protobuf::scoped_ptr<AnyWriter> any_;
 
-    // Describes the element as a field in the parent message.
-    // field_ is NULL if and only if this element is the root element.
-    const google::protobuf::Field* field_;
-
-    // TypeInfo to lookup types.
-    const TypeInfo* typeinfo_;
-
-    // Additional variables if this element is a message:
-    // (Root element is always a message).
-    // descriptor_     : describes allowed fields in the message.
-    // required_fields_: set of required fields.
-    // is_repeated_type_ : true if the element is of type list or map.
-    // size_index_     : index into ProtoStreamObjectWriter::size_insert_
-    //                   for later insertion of serialized message length.
-    const google::protobuf::Type& type_;
-    std::set<const google::protobuf::Field*> required_fields_;
-    const bool is_repeated_type_;
-    const int size_index_;
-
-    // Tracks position in repeated fields, needed for LocationTrackerInterface.
-    int array_index_;
-
     // The type of this element, see enum for permissible types.
-    ElementType element_type_;
+    ItemType item_type_;
 
-    // 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_;
+    // Set of map keys already seen for the type_. Used to validate incoming
+    // messages so no map key appears more than once.
+    hash_set<string> map_keys_;
 
-    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
-  };
+    // Conveys whether this Item is a placeholder or not. Placeholder items are
+    // pushed to stack to account for special types.
+    bool is_placeholder_;
 
-  // Container for inserting 'size' information at the 'pos' position.
-  struct SizeInfo {
-    const int pos;
-    int size;
+    // Conveys whether this Item is a list or not. This is used to send
+    // StartList or EndList calls to underlying ObjectWriter.
+    bool is_list_;
+
+    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Item);
   };
 
   ProtoStreamObjectWriter(const TypeInfo* typeinfo,
                           const google::protobuf::Type& type,
                           strings::ByteSink* output, ErrorListener* listener);
 
-  ProtoElement* element() { return element_.get(); }
-
-  // Helper methods for calling ErrorListener. See error_listener.h.
-  void InvalidName(StringPiece unknown_name, StringPiece message);
-  void InvalidValue(StringPiece type_name, StringPiece value);
-  void MissingField(StringPiece missing_name);
-
-  // Common code for BeginObject() and BeginList() that does invalid_depth_
-  // bookkeeping associated with name lookup.
-  const google::protobuf::Field* BeginNamed(StringPiece name, bool is_list);
-
-  // Lookup the field in the current element. Looks in the base descriptor
-  // and in any extension. This will report an error if the field cannot be
-  // found or if multiple matching extensions are found.
-  const google::protobuf::Field* Lookup(StringPiece name);
-
-  // Lookup the field type in the type descriptor. Returns NULL if the type
-  // is not known.
-  const google::protobuf::Type* LookupType(
-      const google::protobuf::Field* field);
-
-  // Looks up the oneof struct Value field depending on the type.
-  // On failure to find, it returns an appropriate error.
-  util::StatusOr<const google::protobuf::Field*> LookupStructField(
-      DataPiece::Type type);
-
-  // Starts an entry in map. This will be called after placing map element at
-  // the top of the stack. Uses this information to write map entries.
-  const google::protobuf::Field* StartMapEntry(StringPiece name);
-
-  // Starts a google.protobuf.Struct.
-  // 'field' is of type google.protobuf.Struct.
-  // If field is NULL, it indicates that the top-level message is a struct
-  // type.
-  void StartStruct(const google::protobuf::Field* field);
-
-  // Starts another struct within a struct.
-  // 'field' is of type google.protobuf.Value (see struct.proto).
-  const google::protobuf::Field* StartStructValueInStruct(
-      const google::protobuf::Field* field);
-
-  // Starts a list within a struct.
-  // 'field' is of type google.protobuf.ListValue (see struct.proto).
-  const google::protobuf::Field* StartListValueInStruct(
-      const google::protobuf::Field* field);
-
-  // Starts the repeated "values" field in struct.proto's
-  // google.protobuf.ListValue type. 'field' should be of type
-  // google.protobuf.ListValue.
-  const google::protobuf::Field* StartRepeatedValuesInListValue(
-      const google::protobuf::Field* field);
-
-  // Pops sentinel elements off the stack.
-  void SkipElements();
-
-  // Write serialized output to the final output ByteSink, inserting all
-  // the size information for nested messages that are missing from the
-  // intermediate Cord buffer.
-  void WriteRootMessage();
-
   // Returns true if the field is a map.
   bool IsMap(const google::protobuf::Field& field);
 
   // Returns true if the field is an any.
   bool IsAny(const google::protobuf::Field& field);
 
-  // Helper method to write proto tags based on the given field.
-  void WriteTag(const google::protobuf::Field& field);
+  // Returns true if the field is google.protobuf.Struct.
+  bool IsStruct(const google::protobuf::Field& field);
 
-  // Helper function to render primitive data types in DataPiece.
-  void RenderSimpleDataPiece(const google::protobuf::Field& field,
-                             const google::protobuf::Type& type,
-                             const DataPiece& data);
+  // Returns true if the field is google.protobuf.Value.
+  bool IsStructValue(const google::protobuf::Field& field);
+
+  // Returns true if the field is google.protobuf.ListValue.
+  bool IsStructListValue(const google::protobuf::Field& field);
 
   // Renders google.protobuf.Value in struct.proto. It picks the right oneof
   // type based on value's type.
@@ -405,61 +260,46 @@
   static util::Status RenderWrapperType(ProtoStreamObjectWriter* ow,
                                           const DataPiece& value);
 
-  // Helper functions to create the map and find functions responsible for
-  // rendering well known types, keyed by type URL.
-  static hash_map<string, TypeRenderer>* renderers_;
   static void InitRendererMap();
   static void DeleteRendererMap();
   static TypeRenderer* FindTypeRenderer(const string& type_url);
 
-  // Returns the ProtoElement::ElementType for the given Type.
-  static ProtoElement::ElementType GetElementType(
-      const google::protobuf::Type& type);
+  // Returns true if the map key for type_ is not duplicated key.
+  // If map key is duplicated key, this function returns false.
+  // Note that caller should make sure that the current proto element (current_)
+  // is of element type MAP or STRUCT_MAP.
+  // It also calls the appropriate error callback and unnormalzied_name is used
+  // for error string.
+  bool ValidMapKey(StringPiece unnormalized_name);
 
-  // Returns true if the field for type_ can be set as a oneof. If field is not
-  // a oneof type, this function does nothing and returns true.
-  // If another field for this oneof is already set, this function returns
-  // false. It also calls the appropriate error callback.
-  // unnormalized_name is used for error string.
-  bool ValidOneof(const google::protobuf::Field& field,
-                  StringPiece unnormalized_name);
+  // Pushes an item on to the stack. Also calls either StartObject or StartList
+  // on the underlying ObjectWriter depending on whether is_list is false or
+  // not.
+  // is_placeholder conveys whether the item is a placeholder item or not.
+  // Placeholder items are pushed when adding auxillary types' StartObject or
+  // StartList calls.
+  void Push(StringPiece name, Item::ItemType item_type, bool is_placeholder,
+            bool is_list);
+
+  // Pops items from the stack. All placeholder items are popped until a
+  // non-placeholder item is found.
+  void Pop();
+
+  // Pops one element from the stack. Calls EndObject() or EndList() on the
+  // underlying ObjectWriter depending on the value of is_list_.
+  void PopOneElement();
+
+ private:
+  // Helper functions to create the map and find functions responsible for
+  // rendering well known types, keyed by type URL.
+  static hash_map<string, TypeRenderer>* renderers_;
 
   // Variables for describing the structure of the input tree:
   // master_type_: descriptor for the whole protobuf message.
-  // typeinfo_ : the TypeInfo object to lookup types.
   const google::protobuf::Type& master_type_;
-  const TypeInfo* typeinfo_;
-  // Whether we own the typeinfo_ object.
-  bool own_typeinfo_;
 
-  // Indicates whether we finished writing root message completely.
-  bool done_;
-
-  // Variable for internal state processing:
-  // element_    : the current element.
-  // size_insert_: sizes of nested messages.
-  //               pos  - position to insert the size field.
-  //               size - size value to be inserted.
-  google::protobuf::scoped_ptr<ProtoElement> element_;
-  std::deque<SizeInfo> size_insert_;
-
-  // Variables for output generation:
-  // output_  : pointer to an external ByteSink for final user-visible output.
-  // buffer_  : buffer holding partial message before being ready for output_.
-  // adapter_ : internal adapter between CodedOutputStream and Cord buffer_.
-  // stream_  : wrapper for writing tags and other encodings in wire format.
-  strings::ByteSink* output_;
-  string buffer_;
-  google::protobuf::io::StringOutputStream adapter_;
-  google::protobuf::scoped_ptr<google::protobuf::io::CodedOutputStream> stream_;
-
-  // Variables for error tracking and reporting:
-  // listener_     : a place to report any errors found.
-  // invalid_depth_: number of enclosing invalid nested messages.
-  // tracker_      : the root location tracker interface.
-  ErrorListener* listener_;
-  int invalid_depth_;
-  google::protobuf::scoped_ptr<LocationTrackerInterface> tracker_;
+  // The current element, variable for internal state processing.
+  google::protobuf::scoped_ptr<Item> current_;
 
   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter);
 };
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 96e5ccf..5f9ffb9 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -45,6 +45,7 @@
 #include <google/protobuf/util/internal/testdata/field_mask.pb.h>
 #include <google/protobuf/util/internal/type_info_test_helper.h>
 #include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/stubs/bytestream.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/util/internal/testdata/anys.pb.h>
@@ -139,7 +140,9 @@
     google::protobuf::scoped_ptr<Message> message(expected.New());
     message->ParsePartialFromIstream(&istream);
 
-    EXPECT_EQ(expected.DebugString(), message->DebugString());
+    if (!MessageDifferencer::Equivalent(expected, *message)) {
+      EXPECT_EQ(expected.DebugString(), message->DebugString());
+    }
   }
 
   void CheckOutput(const Message& expected) { CheckOutput(expected, -1); }
@@ -156,7 +159,12 @@
 
 MATCHER_P(HasObjectLocation, expected,
           "Verifies the expected object location") {
-  string actual = std::tr1::get<0>(arg).ToString();
+  string actual;
+#if __cplusplus >= 201103L
+  actual = std::get<0>(arg).ToString();
+#else
+  actual = std::tr1::get<0>(arg).ToString();
+#endif
   if (actual.compare(expected) == 0) return true;
   *result_listener << "actual location is: " << actual;
   return false;
@@ -233,6 +241,21 @@
   CheckOutput(book);
 }
 
+TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) {
+  Book book;
+  Author* robert = book.mutable_author();
+  robert->set_id(12345);
+  robert->set_name("robert");
+
+  ow_->StartObject("")
+      ->StartObject("author")
+      ->RenderUint64("@id", 12345)
+      ->RenderString("name", "robert")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(book);
+}
+
 TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) {
   Primitive full;
   full.set_fix32(101);
@@ -788,10 +811,6 @@
               InvalidName(_, StringPiece("oops"),
                           StringPiece("Root element should not be named.")))
       .With(Args<0>(HasObjectLocation("")));
-  EXPECT_CALL(listener_,
-              InvalidName(_, StringPiece(""),
-                          StringPiece("Proto fields must have a name.")))
-      .With(Args<0>(HasObjectLocation("")));
   ow_->StartList("oops")->RenderString("", "item")->EndList();
   CheckOutput(empty, 0);
 }
@@ -851,15 +870,31 @@
   }
 };
 
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterTimestampDurationTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) {
+  TimestampDuration timestamp;
+  google::protobuf::Timestamp* ts = timestamp.mutable_ts();
+  ts->set_seconds(1448249855);
+  ts->set_nanos(33155000);
+
+  ow_->StartObject("")
+      ->RenderString("ts", "2015-11-23T03:37:35.033155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) {
   TimestampDuration timestamp;
 
   EXPECT_CALL(
       listener_,
-      InvalidValue(
-          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
-          StringPiece("Field 'ts', Illegal timestamp format; timestamps "
-                      "must end with 'Z'")));
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: ")));
 
   ow_->StartObject("")->RenderString("ts", "")->EndObject();
   CheckOutput(timestamp);
@@ -870,10 +905,9 @@
 
   EXPECT_CALL(
       listener_,
-      InvalidValue(
-          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
-          StringPiece(
-              "Field 'ts', Invalid time format: Failed to parse input")));
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: Z")));
 
   ow_->StartObject("")->RenderString("ts", "Z")->EndObject();
   CheckOutput(timestamp);
@@ -884,10 +918,10 @@
 
   EXPECT_CALL(
       listener_,
-      InvalidValue(
-          _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
-          StringPiece("Field 'ts', Invalid time format, failed to parse nano "
-                      "seconds")));
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "1970-01-01T00:00:00.ABZ")));
 
   ow_->StartObject("")
       ->RenderString("ts", "1970-01-01T00:00:00.ABZ")
@@ -902,7 +936,8 @@
       listener_,
       InvalidValue(_,
                    StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
-                   StringPiece("Field 'ts', Timestamp value exceeds limits")));
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "-8032-10-18T00:00:00.000Z")));
 
   ow_->StartObject("")
       ->RenderString("ts", "-8032-10-18T00:00:00.000Z")
@@ -910,9 +945,66 @@
   CheckOutput(timestamp);
 }
 
-// TODO(skarvaje): Write a test for nanos that exceed limit. Currently, it is
-// not possible to construct a test case where nanos exceed limit because of
-// floating point arithmetic.
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033155   Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155   Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033155 1234Z")));
+
+  ow_->StartObject("")
+      // Whitespace in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) {
+  TimestampDuration timestamp;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+                   StringPiece("Field 'ts', Invalid time format: "
+                               "2015-11-23T03:37:35.033abc155Z")));
+
+  ow_->StartObject("")
+      // Non-numeric characters in the Timestamp nanos is not allowed.
+      ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z")
+      ->EndObject();
+  CheckOutput(timestamp);
+}
+
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) {
+  TimestampDuration duration;
+  google::protobuf::Duration* dur = duration.mutable_dur();
+  dur->set_seconds(1448216930);
+  dur->set_nanos(132262000);
+
+  ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject();
+  CheckOutput(duration);
+}
 
 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) {
   TimestampDuration duration;
@@ -950,7 +1042,7 @@
       InvalidValue(
           _, StringPiece("type.googleapis.com/google.protobuf.Duration"),
           StringPiece("Field 'dur', Invalid duration format, failed to "
-                      "parse nanos seconds")));
+                      "parse nano seconds")));
 
   ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject();
   CheckOutput(duration);
@@ -969,6 +1061,19 @@
   CheckOutput(duration);
 }
 
+TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) {
+  TimestampDuration duration;
+
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(_,
+                   StringPiece("type.googleapis.com/google.protobuf.Duration"),
+                   StringPiece("Field 'dur', Duration value exceeds limits")));
+
+  ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject();
+  CheckOutput(duration);
+}
+
 TEST_P(ProtoStreamObjectWriterTimestampDurationTest,
        MismatchedTimestampTypeInput) {
   TimestampDuration timestamp;
@@ -1008,6 +1113,11 @@
   }
 };
 
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterStructTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
 // TODO(skarvaje): Write tests for failure cases.
 TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) {
   StructType struct_type;
@@ -1046,18 +1156,69 @@
   CheckOutput(struct_type);
 }
 
+TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("gBike"),
+                  StringPiece("Repeated map key: 'gBike' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("gBike", "v1")
+      ->RenderString("gBike", "v2")
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->RenderString("k1", "v1")
+      ->StartList("k1")
+      ->RenderString("", "v2")
+      ->EndList()
+      ->EndObject()
+      ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->StartObject("object")
+      ->StartObject("k1")
+      ->RenderString("sub_k1", "v1")
+      ->EndObject()
+      ->StartObject("k1")
+      ->RenderString("sub_k2", "v2")
+      ->EndObject()
+      ->EndObject()
+      ->EndObject();
+}
+
 class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest {
  protected:
   ProtoStreamObjectWriterMapTest()
       : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {}
 };
 
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterMapTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
 TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
   MapIn mm;
-  EXPECT_CALL(listener_,
-              InvalidValue(_, StringPiece("Map"),
-                           StringPiece("Cannot bind a list to map.")))
-      .With(Args<0>(HasObjectLocation("map_input")));
+  EXPECT_CALL(
+      listener_,
+      InvalidValue(
+          _, StringPiece("Map"),
+          StringPiece("Cannot bind a list to map for field 'map_input'.")));
   ow_->StartObject("")
       ->StartList("map_input")
       ->RenderString("a", "b")
@@ -1066,17 +1227,37 @@
   CheckOutput(mm);
 }
 
+TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) {
+  EXPECT_CALL(
+      listener_,
+      InvalidName(_, StringPiece("k1"),
+                  StringPiece("Repeated map key: 'k1' is already set.")));
+  ow_->StartObject("")
+      ->RenderString("other", "test")
+      ->StartObject("map_input")
+      ->RenderString("k1", "v1")
+      ->RenderString("k1", "v2")
+      ->EndObject()
+      ->EndObject();
+}
+
 class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
  protected:
   ProtoStreamObjectWriterAnyTest() {
     vector<const Descriptor*> descriptors;
     descriptors.push_back(AnyOut::descriptor());
     descriptors.push_back(google::protobuf::DoubleValue::descriptor());
+    descriptors.push_back(google::protobuf::Timestamp::descriptor());
     descriptors.push_back(google::protobuf::Any::descriptor());
     ResetTypeInfo(descriptors);
   }
 };
 
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterAnyTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
 TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) {
   AnyOut any;
   google::protobuf::Any* any_type = any.mutable_any();
@@ -1119,8 +1300,6 @@
       ->EndObject()
       ->EndObject()
       ->EndObject();
-
-  CheckOutput(out, 115);
 }
 
 TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
@@ -1155,8 +1334,6 @@
       ->EndObject()
       ->EndObject()
       ->EndObject();
-
-  CheckOutput(out, 159);
 }
 
 TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
@@ -1263,6 +1440,23 @@
   CheckOutput(any);
 }
 
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) {
+  EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+                                      StringPiece("Invalid time format: ")));
+
+  AnyOut any;
+  google::protobuf::Any* any_type = any.mutable_any();
+  any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp");
+
+  ow_->StartObject("")
+      ->StartObject("any")
+      ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
+      ->RenderString("value", "")
+      ->EndObject()
+      ->EndObject();
+  CheckOutput(any);
+}
+
 class ProtoStreamObjectWriterFieldMaskTest
     : public BaseProtoStreamObjectWriterTest {
  protected:
@@ -1274,6 +1468,11 @@
   }
 };
 
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+                        ProtoStreamObjectWriterFieldMaskTest,
+                        ::testing::Values(
+                            testing::USE_TYPE_RESOLVER));
+
 TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) {
   FieldMaskTest expected;
   expected.set_id("1");
@@ -1486,13 +1685,17 @@
 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) {
   FieldMaskTest expected;
   expected.mutable_single_mask()->add_paths(
-      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War孙天涌,./?><\\\\\"]");
+      // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character 孙.
+      // We cannot embed non-ASCII characters in the code directly because
+      // some windows compilers will try to interpret them using the system's
+      // current encoding and end up with invalid UTF-8 byte sequence.
+      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]");
   expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]");
 
   ow_->StartObject("");
   ow_->RenderString(
       "single_mask",
-      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War孙天涌,./?><\\\\\"],"
+      "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"],"
       "path.to.map[\"key2\"]");
   ow_->EndObject();
 
@@ -1683,6 +1886,7 @@
   ow_->RenderString("strData", "blah");
   ow_->RenderInt32("intData", 123);
   ow_->EndObject();
+  ow_->EndObject();
 }
 
 }  // namespace converter
diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter.h b/src/google/protobuf/util/internal/snake2camel_objectwriter.h
deleted file mode 100644
index 9b4ab8a..0000000
--- a/src/google/protobuf/util/internal/snake2camel_objectwriter.h
+++ /dev/null
@@ -1,165 +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.
-
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
-
-#include <string>
-
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/stringpiece.h>
-#include <google/protobuf/util/internal/object_writer.h>
-#include <google/protobuf/util/internal/utility.h>
-
-namespace google {
-namespace protobuf {
-namespace util {
-namespace converter {
-
-// Snake2CamelObjectWriter is an ObjectWriter than translates each field name
-// from snake_case to camelCase. Typical usage is:
-//     ProtoStreamObjectSource psos(...);
-//     JsonObjectWriter jow(...);
-//     Snake2CamelObjectWriter snake_to_camel(&jow);
-//     psos.writeTo(&snake_to_camel);
-class Snake2CamelObjectWriter : public ObjectWriter {
- public:
-  explicit Snake2CamelObjectWriter(ObjectWriter* ow)
-      : ow_(ow), normalize_case_(true) {}
-  virtual ~Snake2CamelObjectWriter() {}
-
-  // ObjectWriter methods.
-  virtual Snake2CamelObjectWriter* StartObject(StringPiece name) {
-    ow_->StartObject(name);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* EndObject() {
-    ow_->EndObject();
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* StartList(StringPiece name) {
-    ow_->StartList(name);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* EndList() {
-    ow_->EndList();
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderBool(StringPiece name, bool value) {
-    ow_->RenderBool(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderInt32(StringPiece name, int32 value) {
-    ow_->RenderInt32(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderUint32(StringPiece name,
-                                                uint32 value) {
-    ow_->RenderUint32(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderInt64(StringPiece name, int64 value) {
-    ow_->RenderInt64(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderUint64(StringPiece name,
-                                                uint64 value) {
-    ow_->RenderUint64(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderDouble(StringPiece name,
-                                                double value) {
-    ow_->RenderDouble(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderFloat(StringPiece name, float value) {
-    ow_->RenderFloat(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderString(StringPiece name,
-                                                StringPiece value) {
-    ow_->RenderString(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderBytes(StringPiece name,
-                                               StringPiece value) {
-    ow_->RenderBytes(name, value);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* RenderNull(StringPiece name) {
-    ow_->RenderNull(name);
-    return this;
-  }
-
-  virtual Snake2CamelObjectWriter* DisableCaseNormalizationForNextKey() {
-    normalize_case_ = false;
-    return this;
-  }
-
- private:
-  ObjectWriter* ow_;
-  bool normalize_case_;
-
-  bool ShouldNormalizeCase(StringPiece name) {
-    if (normalize_case_) {
-      return !IsCamel(name);
-    } else {
-      normalize_case_ = true;
-      return false;
-    }
-  }
-
-  bool IsCamel(StringPiece name) {
-    return name.empty() || (ascii_islower(name[0]) && !name.contains("_"));
-  }
-
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Snake2CamelObjectWriter);
-};
-
-}  // namespace converter
-}  // namespace util
-}  // namespace protobuf
-
-}  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_SNAKE2CAMEL_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto
index 6e2f109..82b8176 100644
--- a/src/google/protobuf/util/internal/testdata/books.proto
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -66,7 +66,7 @@
 
 // An author of a book
 message Author {
-  optional uint64 id = 1;
+  optional uint64 id = 1 [json_name = "@id"];
   optional string name = 2;
   repeated string pseudonym = 3;
   optional bool alive = 4;
diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto
index ebbdf6a..cccc741 100644
--- a/src/google/protobuf/util/internal/testdata/default_value.proto
+++ b/src/google/protobuf/util/internal/testdata/default_value.proto
@@ -75,9 +75,10 @@
   IntToStringMap int_to_string = 403;
   MixedMap mixed1 = 404;
   MixedMap2 mixed2 = 405;
-  MessageMap map_of_objects = 406;
-  MixedMap mixed_empty = 407;
-  MessageMap message_map_empty = 408;
+  MixedMap2 empty_mixed2 = 406;
+  MessageMap map_of_objects = 407;
+  MixedMap mixed_empty = 408;
+  MessageMap message_map_empty = 409;
   DoubleValueMessage double_value = 501;
   DoubleValueMessage double_value_default = 502;
 }
diff --git a/src/google/protobuf/util/internal/testdata/default_value_test.proto b/src/google/protobuf/util/internal/testdata/default_value_test.proto
index 21b85e6..9328834 100644
--- a/src/google/protobuf/util/internal/testdata/default_value_test.proto
+++ b/src/google/protobuf/util/internal/testdata/default_value_test.proto
@@ -43,4 +43,11 @@
   bool bool_value = 13;
   string string_value = 15;
   bytes bytes_value = 17 [ctype = CORD];
+
+  enum EnumDefault {
+    ENUM_FIRST = 0;
+    ENUM_SECOND = 1;
+    ENUM_THIRD = 2;
+  }
+  EnumDefault enum_value = 18;
 }
diff --git a/src/google/protobuf/util/internal/testdata/maps.proto b/src/google/protobuf/util/internal/testdata/maps.proto
index 7fb42a2..6475ecd 100644
--- a/src/google/protobuf/util/internal/testdata/maps.proto
+++ b/src/google/protobuf/util/internal/testdata/maps.proto
@@ -44,6 +44,35 @@
   map<string, MapM> map1 = 1;
   map<string, MapOut> map2 = 2;
   map<int32, string> map3 = 3;
+  map<bool, string> map4 = 5;
+  string bar = 4;
+}
+
+// A message with exactly the same wire representation as MapOut, but using
+// repeated message fields instead of map fields. We use this message to test
+// the wire-format compatibility of the JSON transcoder (e.g., whether it
+// handles missing keys correctly).
+message MapOutWireFormat {
+  message Map1Entry {
+    string key = 1;
+    MapM value = 2;
+  }
+  repeated Map1Entry map1 = 1;
+  message Map2Entry {
+    string key = 1;
+    MapOut value = 2;
+  }
+  repeated Map2Entry map2 = 2;
+  message Map3Entry {
+    int32 key = 1;
+    string value = 2;
+  }
+  repeated Map3Entry map3 = 3;
+  message Map4Entry {
+    bool key = 1;
+    string value = 2;
+  }
+  repeated Map4Entry map4 = 5;
   string bar = 4;
 }
 
diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc
index a45a76e..00a8ee7 100644
--- a/src/google/protobuf/util/internal/type_info.cc
+++ b/src/google/protobuf/util/internal/type_info.cc
@@ -136,8 +136,7 @@
     for (int i = 0; i < type->fields_size(); ++i) {
       const google::protobuf::Field& field = type->fields(i);
       StringPiece name = field.name();
-      StringPiece camel_case_name =
-          *string_storage_.insert(ToCamelCase(name)).first;
+      StringPiece camel_case_name = field.json_name();
       const StringPiece* existing = InsertOrReturnExisting(
           &camel_case_name_table_, camel_case_name, name);
       if (existing && *existing != name) {
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 5d7dcc8..1ddf248 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -49,7 +49,8 @@
 namespace {
 const StringPiece SkipWhiteSpace(StringPiece str) {
   StringPiece::size_type i;
-  for (i = 0; i < str.size() && isspace(str[i]); ++i) {}
+  for (i = 0; i < str.size() && isspace(str[i]); ++i) {
+  }
   GOOGLE_DCHECK(i == str.size() || !isspace(str[i]));
   return StringPiece(str, i);
 }
@@ -160,6 +161,19 @@
   return NULL;
 }
 
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name) {
+  if (type != NULL) {
+    for (int i = 0; i < type->fields_size(); ++i) {
+      const google::protobuf::Field& field = type->fields(i);
+      if (field.json_name() == json_name) {
+        return &field;
+      }
+    }
+  }
+  return NULL;
+}
+
 const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
     const google::protobuf::Enum* enum_type, StringPiece enum_name) {
   if (enum_type != NULL) {
@@ -298,29 +312,41 @@
                                  "google.protobuf.MessageOptions.map_entry", false));
 }
 
+bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
+  return GetBoolOptionOrDefault(
+      type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false);
+}
+
 string DoubleAsString(double value) {
-  if (google::protobuf::MathLimits<double>::IsPosInf(value)) return "Infinity";
-  if (google::protobuf::MathLimits<double>::IsNegInf(value)) return "-Infinity";
-  if (google::protobuf::MathLimits<double>::IsNaN(value)) return "NaN";
+  if (MathLimits<double>::IsPosInf(value)) return "Infinity";
+  if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
+  if (MathLimits<double>::IsNaN(value)) return "NaN";
 
   return SimpleDtoa(value);
 }
 
 string FloatAsString(float value) {
-  if (google::protobuf::MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
+  if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
   return DoubleAsString(value);
 }
 
-bool SafeStrToFloat(StringPiece str, float *value) {
+bool SafeStrToFloat(StringPiece str, float* value) {
   double double_value;
   if (!safe_strtod(str, &double_value)) {
     return false;
   }
-  *value = static_cast<float>(double_value);
 
-  if (google::protobuf::MathLimits<float>::IsInf(*value)) {
+  if (MathLimits<double>::IsInf(double_value) ||
+      MathLimits<double>::IsNaN(double_value))
+    return false;
+
+  // Fail if the value is not representable in float.
+  if (double_value > std::numeric_limits<float>::max() ||
+      double_value < -std::numeric_limits<float>::max()) {
     return false;
   }
+
+  *value = static_cast<float>(double_value);
   return true;
 }
 
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 87f7602..33df8ed 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -127,6 +127,11 @@
 const google::protobuf::Field* FindFieldInTypeOrNull(
     const google::protobuf::Type* type, StringPiece field_name);
 
+// Similar to FindFieldInTypeOrNull, but this looks up fields with given
+// json_name.
+const google::protobuf::Field* FindJsonFieldInTypeOrNull(
+    const google::protobuf::Type* type, StringPiece json_name);
+
 // Finds and returns the EnumValue identified by enum_name in the passed tech
 // Enum object. Returns NULL if none found.
 const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
@@ -138,9 +143,6 @@
     const google::protobuf::Enum* enum_type, int32 value);
 
 // Converts input to camel-case and returns it.
-// Tests are in wrappers/translator/snake2camel_objectwriter_test.cc
-// TODO(skarvaje): Isolate tests for this function and put them in
-// utility_test.cc
 LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input);
 
 // Converts input to snake_case and returns it.
@@ -157,6 +159,9 @@
 LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field,
            const google::protobuf::Type& type);
 
+// Returns true if the given type has special MessageSet wire format.
+bool IsMessageSetWireFormat(const google::protobuf::Type& type);
+
 // Infinity/NaN-aware conversion to string.
 LIBPROTOBUF_EXPORT string DoubleAsString(double value);
 LIBPROTOBUF_EXPORT string FloatAsString(float value);
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
index 7a28286..a1e24c1 100644
--- a/src/google/protobuf/util/json_format_proto3.proto
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -100,6 +100,16 @@
   map<string, int32> string_map = 6;
 }
 
+message TestNestedMap {
+  map<bool, int32> bool_map = 1;
+  map<int32, int32> int32_map = 2;
+  map<int64, int32> int64_map = 3;
+  map<uint32, int32> uint32_map = 4;
+  map<uint64, int32> uint64_map = 5;
+  map<string, int32> string_map = 6;
+  map<string, TestNestedMap> map_map = 7;
+}
+
 message TestWrapper {
   google.protobuf.BoolValue bool_value = 1;
   google.protobuf.Int32Value int32_value = 2;
@@ -155,3 +165,12 @@
   google.protobuf.ListValue value = 1;
   repeated google.protobuf.ListValue repeated_value = 2;
 }
+
+message TestBoolValue {
+  bool bool_value = 1;
+  map<bool, int32> bool_map = 2;
+}
+
+message TestCustomJsonName {
+  int32 value = 1 [json_name = "@value"];
+}
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 6cd40fd..c3b8d50 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -34,7 +34,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/util/internal/default_value_objectwriter.h>
-#include <google/protobuf/util/internal/snake2camel_objectwriter.h>
 #include <google/protobuf/util/internal/error_listener.h>
 #include <google/protobuf/util/internal/json_objectwriter.h>
 #include <google/protobuf/util/internal/json_stream_parser.h>
@@ -83,13 +82,12 @@
   io::CodedOutputStream out_stream(json_output);
   converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "",
                                           &out_stream);
-  converter::Snake2CamelObjectWriter snake2camel_writer(&json_writer);
   if (options.always_print_primitive_fields) {
     converter::DefaultValueObjectWriter default_value_writer(
-        resolver, type, &snake2camel_writer);
+        resolver, type, &json_writer);
     return proto_source.WriteTo(&default_value_writer);
   } else {
-    return proto_source.WriteTo(&snake2camel_writer);
+    return proto_source.WriteTo(&json_writer);
   }
 }
 
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index f4dc356..da68495 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -163,7 +163,7 @@
 class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
  public:
   explicit SegmentedZeroCopyOutputStream(list<Segment> segments)
-      : segments_(segments), last_segment_(NULL, 0), byte_count_(0) {}
+      : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_count_(0) {}
 
   virtual bool Next(void** buffer, int* length) {
     if (segments_.empty()) {
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index d709da5..0f879dc 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -238,9 +238,25 @@
   GOOGLE_CHECK(key_comparator == NULL)
       << "Cannot treat this repeated field as both Map and Set for"
       << " comparison.  Field name is: " << field->full_name();
+  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+      << "Cannot treat the same field as both SET and LIST. Field name is: "
+      << field->full_name();
   set_fields_.insert(field);
 }
 
+void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
+  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
+                              << field->full_name();
+  const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
+  GOOGLE_CHECK(key_comparator == NULL)
+      << "Cannot treat this repeated field as both Map and Set for"
+      << " comparison.  Field name is: " << field->full_name();
+  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
+      << "Cannot treat the same field as both SET and LIST. Field name is: "
+      << field->full_name();
+  list_fields_.insert(field);
+}
+
 void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
                                     const FieldDescriptor* key) {
   GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
@@ -255,6 +271,9 @@
   GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
       << "Cannot treat this repeated field as both Map and Set for "
       << "comparison.";
+  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
+      << "Cannot treat this repeated field as both Map and List for "
+      << "comparison.";
   MapKeyComparator* key_comparator =
       new MultipleFieldsMapKeyComparator(this, key);
   owned_key_comparators_.push_back(key_comparator);
@@ -920,7 +939,8 @@
 bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
   if (!field->is_repeated()) return false;
   if (field->is_map()) return true;
-  if (repeated_field_comparison_ == AS_SET) return true;
+  if (repeated_field_comparison_ == AS_SET)
+    return list_fields_.find(field) == list_fields_.end();
   return (set_fields_.find(field) != set_fields_.end());
 }
 
@@ -946,6 +966,18 @@
   return false;
 }
 
+bool MessageDifferencer::IsUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const SpecificField& field, const vector<SpecificField>& parent_fields) {
+  for (int i = 0; i < ignore_criteria_.size(); ++i) {
+    if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field,
+                                                   parent_fields)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 const MessageDifferencer::MapKeyComparator* MessageDifferencer
     ::GetMapKeyComparator(const FieldDescriptor* field) {
   if (!field->is_repeated()) return NULL;
@@ -1127,15 +1159,6 @@
       continue;
     }
 
-    if (change_type == ADDITION || change_type == DELETION ||
-        change_type == MODIFICATION) {
-      if (reporter_ == NULL) {
-        // We found a difference and we have no reproter.
-        return false;
-      }
-      is_different = true;
-    }
-
     // Build the SpecificField.  This is slightly complicated.
     SpecificField specific_field;
     specific_field.unknown_field_number = focus_field->number();
@@ -1160,6 +1183,25 @@
       specific_field.new_index = index2 - current_repeated_start2;
     }
 
+    if (IsUnknownFieldIgnored(message1, message2, specific_field,
+                              *parent_field)) {
+      if (reporter_ != NULL) {
+        parent_field->push_back(specific_field);
+        reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
+        parent_field->pop_back();
+      }
+      return true;
+    }
+
+    if (change_type == ADDITION || change_type == DELETION ||
+        change_type == MODIFICATION) {
+      if (reporter_ == NULL) {
+        // We found a difference and we have no reproter.
+        return false;
+      }
+      is_different = true;
+    }
+
     parent_field->push_back(specific_field);
 
     switch (change_type) {
@@ -1341,9 +1383,11 @@
       // doesn't neccessarily 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 = NewPermanentCallback(
-          this, &MessageDifferencer::IsMatch, repeated_field, key_comparator,
-          &message1, &message2, parent_fields);
+      MaximumMatcher::NodeMatchCallback* callback =
+          google::protobuf::internal::NewPermanentCallback(
+              this, &MessageDifferencer::IsMatch,
+              repeated_field, key_comparator,
+              &message1, &message2, parent_fields);
       MaximumMatcher matcher(count1, count2, callback, match_list1,
                              match_list2);
       // If diff info is not needed, we should end the matching process as
@@ -1625,6 +1669,18 @@
   printer_->Print("\n");  // Print for newlines.
 }
 
+void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
+    const Message& message1, const Message& message2,
+    const vector<SpecificField>& field_path) {
+  printer_->Print("ignored: ");
+  PrintPath(field_path, true);
+  if (CheckPathChanged(field_path)) {
+    printer_->Print(" -> ");
+    PrintPath(field_path, false);
+  }
+  printer_->Print("\n");  // Print for newlines.
+}
+
 }  // namespace util
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index e002a0f..3ea74e6 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -278,6 +278,13 @@
         const Message& message2,
         const vector<SpecificField>& field_path) { }
 
+    // Report that an unkown field is ignored. (see comment above).
+    // Note this is a different function since the last SpecificField in field
+    // path has a null field.  This could break existing Reporter.
+    virtual void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const vector<SpecificField>& field_path) {}
+
    private:
     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter);
   };
@@ -317,6 +324,16 @@
         const Message& message2,
         const FieldDescriptor* field,
         const vector<SpecificField>& parent_fields) = 0;
+
+    // Returns true if the unknown field should be ignored.
+    // Note: This will be called for unknown fields as well in which case
+    //       field.field will be null.
+    virtual bool IsUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const SpecificField& field,
+        const vector<SpecificField>& parent_fields) {
+      return false;
+    }
   };
 
   // To add a Reporter, construct default here, then use ReportDifferencesTo or
@@ -380,9 +397,16 @@
   // + n^3) in which n^3 is the time complexity of the maximum matching
   // algorithm.
   //
-  // REQUIRES:  field->is_repeated()
+  // REQUIRES:  field->is_repeated() and field not registered with TreatAsList
   void TreatAsSet(const FieldDescriptor* field);
 
+  // The elements of the given repeated field will be treated as a list for
+  // diffing purposes, so different orderings of the same elements will NOT be
+  // considered equal.
+  //
+  // REQUIRED: field->is_repeated() and field not registered with TreatAsSet
+  void TreatAsList(const FieldDescriptor* field);
+
   // The elements of the given repeated field will be treated as a map for
   // diffing purposes, with |key| being the map key.  Thus, elements with the
   // same key will be compared even if they do not appear at the same index.
@@ -583,6 +607,10 @@
                                const Message& message2,
                                const vector<SpecificField>& field_path);
 
+    virtual void ReportUnknownFieldIgnored(
+        const Message& message1, const Message& message2,
+        const vector<SpecificField>& field_path);
+
    protected:
     // Prints the specified path of fields to the buffer.
     virtual void PrintPath(const vector<SpecificField>& field_path,
@@ -722,6 +750,12 @@
       const FieldDescriptor* field,
       const vector<SpecificField>& parent_fields);
 
+  // Returns true if this unknown field is to be ignored when this
+  // MessageDifferencer compares messages.
+  bool IsUnknownFieldIgnored(const Message& message1, const Message& message2,
+                             const SpecificField& field,
+                             const vector<SpecificField>& parent_fields);
+
   // Returns MapKeyComparator* when this field has been configured to
   // be treated as a map.  If not, returns NULL.
   const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field);
@@ -764,6 +798,7 @@
   RepeatedFieldComparison repeated_field_comparison_;
 
   FieldSet set_fields_;
+  FieldSet list_fields_;
   // Keeps track of MapKeyComparators that are created within
   // MessageDifferencer. These MapKeyComparators should be deleted
   // before MessageDifferencer is destroyed.
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 701b94a..a867c88 100755
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -1103,12 +1103,19 @@
   msg1.add_rw("change"); msg2.add_rw("change");
 
   // Compare
-  util::MessageDifferencer differencer;
-  differencer.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
-                         item->GetDescriptor()->FindFieldByName("a"));
-  differencer.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv"));
-  differencer.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra"));
-  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  util::MessageDifferencer differencer1;
+  differencer1.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+                          item->GetDescriptor()->FindFieldByName("a"));
+  differencer1.TreatAsSet(msg1.GetDescriptor()->FindFieldByName("rv"));
+  differencer1.TreatAsSet(item->GetDescriptor()->FindFieldByName("ra"));
+  EXPECT_TRUE(differencer1.Compare(msg1, msg2));
+
+  util::MessageDifferencer differencer2;
+  differencer2.TreatAsMap(msg1.GetDescriptor()->FindFieldByName("item"),
+                          item->GetDescriptor()->FindFieldByName("a"));
+  differencer2.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  differencer2.TreatAsList(msg1.GetDescriptor()->FindFieldByName("rw"));
+  EXPECT_TRUE(differencer2.Compare(msg1, msg2));
 }
 
 TEST(MessageDifferencerTest, RepeatedFieldMapTest_Partial) {
@@ -1168,6 +1175,11 @@
   differencer.TreatAsSet(GetFieldDescriptor(a, "rv"));
   EXPECT_TRUE(differencer.Compare(b, a));
   EXPECT_FALSE(differencer.Compare(c, a));
+
+  util::MessageDifferencer differencer1;
+  differencer1.set_repeated_field_comparison(util::MessageDifferencer::AS_SET);
+  EXPECT_TRUE(differencer1.Compare(b, a));
+  EXPECT_FALSE(differencer1.Compare(c, a));
 }
 
 TEST(MessageDifferencerTest, RepeatedFieldSetTest_PartialSimple) {
@@ -1442,11 +1454,10 @@
 
 class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria {
  public:
-  bool IsIgnored(
+  virtual bool IsIgnored(
       const Message& message1, const Message& message2,
       const FieldDescriptor* field,
-      const vector<util::MessageDifferencer::SpecificField>& parent_fields)
-      override {
+      const vector<util::MessageDifferencer::SpecificField>& parent_fields) {
     string name = "";
     for (int i = 0; i < parent_fields.size(); ++i) {
       name += parent_fields[i].field->name() + ".";
@@ -1488,8 +1499,10 @@
 class ValueProductMapKeyComparator
     : public util::MessageDifferencer::MapKeyComparator {
  public:
-  virtual bool IsMatch(const Message &message1,
-                       const Message &message2) const {
+  typedef util::MessageDifferencer::SpecificField SpecificField;
+  virtual bool IsMatch(
+      const Message &message1, const Message &message2,
+      const vector<SpecificField>& parent_fields) const {
     const Reflection* reflection1 = message1.GetReflection();
     const Reflection* reflection2 = message2.GetReflection();
     // FieldDescriptor for item.ra
@@ -2803,15 +2816,20 @@
                               const Message& msg1, const Message& msg2,
                               bool result) {
     string output;
-    io::StringOutputStream output_stream(&output);
-    MessageDifferencer::StreamReporter reporter(&output_stream);
-    reporter.set_report_modified_aggregates(true);
-    differencer->set_report_matches(true);
-    differencer->ReportDifferencesTo(&reporter);
-    if (result) {
-      EXPECT_TRUE(differencer->Compare(msg1, msg2));
-    } else {
-      EXPECT_FALSE(differencer->Compare(msg1, msg2));
+    {
+      // Before we return the "output" string, we must make sure the
+      // StreamReporter is destructored because its destructor will
+      // flush the stream.
+      io::StringOutputStream output_stream(&output);
+      MessageDifferencer::StreamReporter reporter(&output_stream);
+      reporter.set_report_modified_aggregates(true);
+      differencer->set_report_matches(true);
+      differencer->ReportDifferencesTo(&reporter);
+      if (result) {
+        EXPECT_TRUE(differencer->Compare(msg1, msg2));
+      } else {
+        EXPECT_FALSE(differencer->Compare(msg1, msg2));
+      }
     }
     return output;
   }
diff --git a/src/google/protobuf/util/time_util.h b/src/google/protobuf/util/time_util.h
index 58dbf8e..1bac089 100644
--- a/src/google/protobuf/util/time_util.h
+++ b/src/google/protobuf/util/time_util.h
@@ -41,7 +41,6 @@
 #endif
 
 #include <google/protobuf/duration.pb.h>
-#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/timestamp.pb.h>
 
 namespace google {
@@ -243,10 +242,8 @@
 // Overloaded operators for Timestamp
 //
 // Assignement operators.
-LIBPROTOBUF_EXPORT
-Timestamp& operator+=(Timestamp& t, const Duration& d);  // NOLINT
-LIBPROTOBUF_EXPORT
-Timestamp& operator-=(Timestamp& t, const Duration& d);  // NOLINT
+LIBPROTOBUF_EXPORT Timestamp& operator+=(Timestamp& t, const Duration& d);  // NOLINT
+LIBPROTOBUF_EXPORT Timestamp& operator-=(Timestamp& t, const Duration& d);  // NOLINT
 // Relational operators.
 inline bool operator<(const Timestamp& t1, const Timestamp& t2) {
   if (t1.seconds() == t2.seconds()) {
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index 908634e..9639390 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -34,6 +34,7 @@
 #include <google/protobuf/wrappers.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/status.h>
@@ -53,8 +54,7 @@
 using util::error::INVALID_ARGUMENT;
 using util::error::NOT_FOUND;
 
-bool SplitTypeUrl(const string& type_url,
-                  string* url_prefix,
+bool SplitTypeUrl(const string& type_url, string* url_prefix,
                   string* message_name) {
   size_t pos = type_url.find_last_of("/");
   if (pos == string::npos) {
@@ -65,60 +65,19 @@
   return true;
 }
 
-// This code is originally defined in
-// //google/protobuf/util/converter/utility.h. Copied here due to component
-// dependency.
-// TODO(xiaofeng): Remove this when converter code is in components.
-string ToCamelCase(const StringPiece input) {
-  bool capitalize_next = false;
-  bool was_cap = true;
-  bool is_cap = false;
-  bool first_word = true;
-  string result;
-  result.reserve(input.size());
-
-  for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
-    is_cap = ascii_isupper(input[i]);
-    if (input[i] == '_') {
-      capitalize_next = true;
-      if (!result.empty()) first_word = false;
-      continue;
-    } else if (first_word) {
-      // Consider when the current character B is capitalized,
-      // first word ends when:
-      // 1) following a lowercase:   "...aB..."
-      // 2) followed by a lowercase: "...ABc..."
-      if (!result.empty() && is_cap &&
-          (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
-        first_word = false;
-      } else {
-        result.push_back(ascii_tolower(input[i]));
-        continue;
-      }
-    } else if (capitalize_next) {
-      capitalize_next = false;
-      if (ascii_islower(input[i])) {
-        result.push_back(ascii_toupper(input[i]));
-        continue;
-      }
-    }
-    result.push_back(input[i]);
-  }
-  return result;
-}
-
 class DescriptorPoolTypeResolver : public TypeResolver {
  public:
   DescriptorPoolTypeResolver(const string& url_prefix,
                              const DescriptorPool* pool)
-      : url_prefix_(url_prefix), pool_(pool) {
-  }
+      : url_prefix_(url_prefix), pool_(pool) {}
 
   Status ResolveMessageType(const string& type_url, Type* type) {
     string url_prefix, message_name;
     if (!SplitTypeUrl(type_url, &url_prefix, &message_name) ||
         url_prefix != url_prefix_) {
-      return Status(INVALID_ARGUMENT, "Failed to parse type url: " + type_url);
+      return Status(INVALID_ARGUMENT,
+                    StrCat("Invalid type URL, type URLs must be of the form '",
+                           url_prefix_, "/<typename>', got: ", type_url));
     }
     if (url_prefix != url_prefix_) {
       return Status(INVALID_ARGUMENT,
@@ -126,7 +85,8 @@
     }
     const Descriptor* descriptor = pool_->FindMessageTypeByName(message_name);
     if (descriptor == NULL) {
-      return Status(NOT_FOUND, "Cannot found the type: " + message_name);
+      return Status(NOT_FOUND,
+                    "Invalid type URL, unknown type: " + message_name);
     }
     ConvertDescriptor(descriptor, type);
     return Status();
@@ -136,7 +96,9 @@
     string url_prefix, type_name;
     if (!SplitTypeUrl(type_url, &url_prefix, &type_name) ||
         url_prefix != url_prefix_) {
-      return Status(INVALID_ARGUMENT, "Failed to parse type url: " + type_url);
+      return Status(INVALID_ARGUMENT,
+                    StrCat("Invalid type URL, type URLs must be of the form '",
+                           url_prefix_, "/<typename>', got: ", type_url));
     }
     if (url_prefix != url_prefix_) {
       return Status(INVALID_ARGUMENT,
@@ -144,7 +106,7 @@
     }
     const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
     if (descriptor == NULL) {
-      return Status(NOT_FOUND, "Cannot found the type: " + type_name);
+      return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
     }
     ConvertEnumDescriptor(descriptor, enum_type);
     return Status();
@@ -197,7 +159,10 @@
     }
     field->set_number(descriptor->number());
     field->set_name(descriptor->name());
-    field->set_json_name(ToCamelCase(descriptor->name()));
+    field->set_json_name(descriptor->json_name());
+    if (descriptor->has_default_value()) {
+      field->set_default_value(DefaultValueAsString(descriptor));
+    }
     if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
       field->set_type_url(GetTypeUrl(descriptor->message_type()));
     } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
@@ -221,8 +186,7 @@
         descriptor->file()->name());
     for (int i = 0; i < descriptor->value_count(); ++i) {
       const EnumValueDescriptor* value_descriptor = descriptor->value(i);
-      EnumValue* value =
-          enum_type->mutable_enumvalue()->Add();
+      EnumValue* value = enum_type->mutable_enumvalue()->Add();
       value->set_name(value_descriptor->name());
       value->set_number(value_descriptor->number());
 
@@ -239,14 +203,54 @@
     return url_prefix_ + "/" + descriptor->full_name();
   }
 
+  string DefaultValueAsString(const FieldDescriptor* descriptor) {
+    switch (descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        return SimpleItoa(descriptor->default_value_int32());
+        break;
+      case FieldDescriptor::CPPTYPE_INT64:
+        return SimpleItoa(descriptor->default_value_int64());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return SimpleItoa(descriptor->default_value_uint32());
+        break;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return SimpleItoa(descriptor->default_value_uint64());
+        break;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        return SimpleFtoa(descriptor->default_value_float());
+        break;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        return SimpleDtoa(descriptor->default_value_double());
+        break;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return descriptor->default_value_bool() ? "true" : "false";
+        break;
+      case FieldDescriptor::CPPTYPE_STRING:
+        if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+          return CEscape(descriptor->default_value_string());
+        } else {
+          return descriptor->default_value_string();
+        }
+        break;
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return descriptor->default_value_enum()->name();
+        break;
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
+        break;
+    }
+    return "";
+  }
+
   string url_prefix_;
   const DescriptorPool* pool_;
 };
 
 }  // namespace
 
-TypeResolver* NewTypeResolverForDescriptorPool(
-    const string& url_prefix, const DescriptorPool* pool) {
+TypeResolver* NewTypeResolverForDescriptorPool(const string& url_prefix,
+                                               const DescriptorPool* pool) {
   return new DescriptorPoolTypeResolver(url_prefix, pool);
 }
 
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index 74b2d0d..8a0bf65 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -43,6 +43,7 @@
 #include <google/protobuf/map_unittest.pb.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/util/json_format_proto3.pb.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -332,6 +333,19 @@
   EnumHasValue(type, "NEG", -1);
 }
 
+TEST_F(DescriptorPoolTypeResolverTest, TestJsonName) {
+  Type type;
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+                           GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type)
+                  .ok());
+  EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name());
+
+  ASSERT_TRUE(resolver_->ResolveMessageType(
+                           GetTypeUrl<proto3::TestCustomJsonName>(), &type)
+                  .ok());
+  EXPECT_EQ("@value", FindField(type, "value")->json_name());
+}
+
 }  // namespace
 }  // namespace util
 }  // namespace protobuf
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index 847e350..7f1093c 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -49,8 +49,10 @@
 namespace protobuf {
 namespace internal {
 
-#ifndef _MSC_VER    // MSVC doesn't like definitions of inline constants, GCC
-                    // requires them.
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+// Old version of MSVC doesn't like definitions of inline constants, GCC
+// requires them.
 const int WireFormatLite::kMessageSetItemStartTag;
 const int WireFormatLite::kMessageSetItemEndTag;
 const int WireFormatLite::kMessageSetTypeIdTag;
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 991c3d0..79493ca 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -412,12 +412,12 @@
       CPPTYPE, WireFormatLite::DECLARED_TYPE>(input, values);                  \
 }
 
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
-READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
 
 #undef READ_REPEATED_PACKED_FIXED_SIZE_PRIMITIVE
 
@@ -835,12 +835,14 @@
 }
 
 inline int WireFormatLite::StringSize(const string& value) {
-  return io::CodedOutputStream::VarintSize32(value.size()) +
-         value.size();
+  return static_cast<int>(
+      io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+      value.size());
 }
 inline int WireFormatLite::BytesSize(const string& value) {
-  return io::CodedOutputStream::VarintSize32(value.size()) +
-         value.size();
+  return static_cast<int>(
+      io::CodedOutputStream::VarintSize32(static_cast<uint32>(value.size())) +
+      value.size());
 }
 
 
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index b2a7e97..212dd21 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -2,11 +2,12 @@
 // source: google/protobuf/wrappers.proto
 
 #define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "google/protobuf/wrappers.pb.h"
+#include <google/protobuf/wrappers.pb.h>
 
 #include <algorithm>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/wire_format_lite_inl.h>
@@ -262,10 +263,10 @@
     "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013"
     "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022"
     "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001"
-    " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BP\n\023com"
-    ".google.protobufB\rWrappersProtoP\001\240\001\001\242\002\003G"
-    "PB\252\002\036Google.Protobuf.WellKnownTypesb\006pro"
-    "to3", 403);
+    " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BS\n\023com"
+    ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242"
+    "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006"
+    "proto3", 406);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/wrappers.proto", &protobuf_RegisterTypes);
   DoubleValue::default_instance_ = new DoubleValue();
@@ -308,9 +309,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int DoubleValue::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 DoubleValue::DoubleValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -318,6 +319,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.DoubleValue)
 }
 
+DoubleValue::DoubleValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
+}
+
 void DoubleValue::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -342,10 +351,20 @@
 }
 
 void DoubleValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void DoubleValue::ArenaDtor(void* object) {
+  DoubleValue* _this = reinterpret_cast< DoubleValue* >(object);
+  (void)_this;
+}
+void DoubleValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void DoubleValue::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -364,11 +383,7 @@
 DoubleValue* DoubleValue::default_instance_ = NULL;
 
 DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const {
-  DoubleValue* n = new DoubleValue;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<DoubleValue>(arena);
 }
 
 void DoubleValue::Clear() {
@@ -495,6 +510,18 @@
 
 void DoubleValue::Swap(DoubleValue* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    DoubleValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void DoubleValue::UnsafeArenaSwap(DoubleValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void DoubleValue::InternalSwap(DoubleValue* other) {
@@ -532,9 +559,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int FloatValue::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 FloatValue::FloatValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -542,6 +569,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.FloatValue)
 }
 
+FloatValue::FloatValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
+}
+
 void FloatValue::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -566,10 +601,20 @@
 }
 
 void FloatValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void FloatValue::ArenaDtor(void* object) {
+  FloatValue* _this = reinterpret_cast< FloatValue* >(object);
+  (void)_this;
+}
+void FloatValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void FloatValue::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -588,11 +633,7 @@
 FloatValue* FloatValue::default_instance_ = NULL;
 
 FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const {
-  FloatValue* n = new FloatValue;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<FloatValue>(arena);
 }
 
 void FloatValue::Clear() {
@@ -719,6 +760,18 @@
 
 void FloatValue::Swap(FloatValue* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    FloatValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void FloatValue::UnsafeArenaSwap(FloatValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void FloatValue::InternalSwap(FloatValue* other) {
@@ -756,9 +809,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Int64Value::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Int64Value::Int64Value()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -766,6 +819,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.Int64Value)
 }
 
+Int64Value::Int64Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
+}
+
 void Int64Value::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -790,10 +851,20 @@
 }
 
 void Int64Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void Int64Value::ArenaDtor(void* object) {
+  Int64Value* _this = reinterpret_cast< Int64Value* >(object);
+  (void)_this;
+}
+void Int64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void Int64Value::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -812,11 +883,7 @@
 Int64Value* Int64Value::default_instance_ = NULL;
 
 Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const {
-  Int64Value* n = new Int64Value;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<Int64Value>(arena);
 }
 
 void Int64Value::Clear() {
@@ -945,6 +1012,18 @@
 
 void Int64Value::Swap(Int64Value* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Int64Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Int64Value::UnsafeArenaSwap(Int64Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void Int64Value::InternalSwap(Int64Value* other) {
@@ -982,9 +1061,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UInt64Value::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UInt64Value::UInt64Value()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -992,6 +1071,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.UInt64Value)
 }
 
+UInt64Value::UInt64Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
+}
+
 void UInt64Value::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -1016,10 +1103,20 @@
 }
 
 void UInt64Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void UInt64Value::ArenaDtor(void* object) {
+  UInt64Value* _this = reinterpret_cast< UInt64Value* >(object);
+  (void)_this;
+}
+void UInt64Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void UInt64Value::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -1038,11 +1135,7 @@
 UInt64Value* UInt64Value::default_instance_ = NULL;
 
 UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const {
-  UInt64Value* n = new UInt64Value;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<UInt64Value>(arena);
 }
 
 void UInt64Value::Clear() {
@@ -1171,6 +1264,18 @@
 
 void UInt64Value::Swap(UInt64Value* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    UInt64Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void UInt64Value::UnsafeArenaSwap(UInt64Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void UInt64Value::InternalSwap(UInt64Value* other) {
@@ -1208,9 +1313,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int Int32Value::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 Int32Value::Int32Value()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1218,6 +1323,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.Int32Value)
 }
 
+Int32Value::Int32Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
+}
+
 void Int32Value::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -1242,10 +1355,20 @@
 }
 
 void Int32Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void Int32Value::ArenaDtor(void* object) {
+  Int32Value* _this = reinterpret_cast< Int32Value* >(object);
+  (void)_this;
+}
+void Int32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void Int32Value::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -1264,11 +1387,7 @@
 Int32Value* Int32Value::default_instance_ = NULL;
 
 Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const {
-  Int32Value* n = new Int32Value;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<Int32Value>(arena);
 }
 
 void Int32Value::Clear() {
@@ -1397,6 +1516,18 @@
 
 void Int32Value::Swap(Int32Value* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    Int32Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void Int32Value::UnsafeArenaSwap(Int32Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void Int32Value::InternalSwap(Int32Value* other) {
@@ -1434,9 +1565,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int UInt32Value::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 UInt32Value::UInt32Value()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1444,6 +1575,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.UInt32Value)
 }
 
+UInt32Value::UInt32Value(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
+}
+
 void UInt32Value::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -1468,10 +1607,20 @@
 }
 
 void UInt32Value::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void UInt32Value::ArenaDtor(void* object) {
+  UInt32Value* _this = reinterpret_cast< UInt32Value* >(object);
+  (void)_this;
+}
+void UInt32Value::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void UInt32Value::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -1490,11 +1639,7 @@
 UInt32Value* UInt32Value::default_instance_ = NULL;
 
 UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const {
-  UInt32Value* n = new UInt32Value;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<UInt32Value>(arena);
 }
 
 void UInt32Value::Clear() {
@@ -1623,6 +1768,18 @@
 
 void UInt32Value::Swap(UInt32Value* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    UInt32Value temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void UInt32Value::UnsafeArenaSwap(UInt32Value* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void UInt32Value::InternalSwap(UInt32Value* other) {
@@ -1660,9 +1817,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int BoolValue::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 BoolValue::BoolValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1670,6 +1827,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.BoolValue)
 }
 
+BoolValue::BoolValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
+}
+
 void BoolValue::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -1694,10 +1859,20 @@
 }
 
 void BoolValue::SharedDtor() {
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
   if (this != default_instance_) {
   }
 }
 
+void BoolValue::ArenaDtor(void* object) {
+  BoolValue* _this = reinterpret_cast< BoolValue* >(object);
+  (void)_this;
+}
+void BoolValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void BoolValue::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -1716,11 +1891,7 @@
 BoolValue* BoolValue::default_instance_ = NULL;
 
 BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const {
-  BoolValue* n = new BoolValue;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<BoolValue>(arena);
 }
 
 void BoolValue::Clear() {
@@ -1847,6 +2018,18 @@
 
 void BoolValue::Swap(BoolValue* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    BoolValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void BoolValue::UnsafeArenaSwap(BoolValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void BoolValue::InternalSwap(BoolValue* other) {
@@ -1884,9 +2067,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int StringValue::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 StringValue::StringValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -1894,6 +2077,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.StringValue)
 }
 
+StringValue::StringValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
+}
+
 void StringValue::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -1919,11 +2110,21 @@
 }
 
 void StringValue::SharedDtor() {
-  value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
   if (this != default_instance_) {
   }
 }
 
+void StringValue::ArenaDtor(void* object) {
+  StringValue* _this = reinterpret_cast< StringValue* >(object);
+  (void)_this;
+}
+void StringValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void StringValue::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -1942,15 +2143,11 @@
 StringValue* StringValue::default_instance_ = NULL;
 
 StringValue* StringValue::New(::google::protobuf::Arena* arena) const {
-  StringValue* n = new StringValue;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<StringValue>(arena);
 }
 
 void StringValue::Clear() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 
 bool StringValue::MergePartialFromCodedStream(
@@ -2065,8 +2262,7 @@
 void StringValue::MergeFrom(const StringValue& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from.value().size() > 0) {
-
-    value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+    set_value(from.value());
   }
 }
 
@@ -2089,6 +2285,18 @@
 
 void StringValue::Swap(StringValue* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    StringValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void StringValue::UnsafeArenaSwap(StringValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void StringValue::InternalSwap(StringValue* other) {
@@ -2110,36 +2318,44 @@
 
 // optional string value = 1;
 void StringValue::clear_value() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
  const ::std::string& StringValue::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  void StringValue::set_value(const ::std::string& value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
 }
  void StringValue::set_value(const char* value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
 }
- void StringValue::set_value(const char* value, size_t size) {
+ void StringValue::set_value(const char* value,
+    size_t size) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
-      ::std::string(reinterpret_cast<const char*>(value), size));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
 }
  ::std::string* StringValue::mutable_value() {
   
   // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
-  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
  ::std::string* StringValue::release_value() {
   
-  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* StringValue::unsafe_arena_release_value() {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
 }
  void StringValue::set_allocated_value(::std::string* value) {
   if (value != NULL) {
@@ -2147,7 +2363,20 @@
   } else {
     
   }
-  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+ void StringValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
 }
 
@@ -2155,9 +2384,9 @@
 
 // ===================================================================
 
-#ifndef _MSC_VER
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int BytesValue::kValueFieldNumber;
-#endif  // !_MSC_VER
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 BytesValue::BytesValue()
   : ::google::protobuf::Message(), _internal_metadata_(NULL) {
@@ -2165,6 +2394,14 @@
   // @@protoc_insertion_point(constructor:google.protobuf.BytesValue)
 }
 
+BytesValue::BytesValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
+}
+
 void BytesValue::InitAsDefaultInstance() {
   _is_default_instance_ = true;
 }
@@ -2190,11 +2427,21 @@
 }
 
 void BytesValue::SharedDtor() {
-  value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (GetArenaNoVirtual() != NULL) {
+    return;
+  }
+
+  value_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
   if (this != default_instance_) {
   }
 }
 
+void BytesValue::ArenaDtor(void* object) {
+  BytesValue* _this = reinterpret_cast< BytesValue* >(object);
+  (void)_this;
+}
+void BytesValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
 void BytesValue::SetCachedSize(int size) const {
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = size;
@@ -2213,15 +2460,11 @@
 BytesValue* BytesValue::default_instance_ = NULL;
 
 BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const {
-  BytesValue* n = new BytesValue;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
+  return ::google::protobuf::Arena::CreateMessage<BytesValue>(arena);
 }
 
 void BytesValue::Clear() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 
 bool BytesValue::MergePartialFromCodedStream(
@@ -2324,8 +2567,7 @@
 void BytesValue::MergeFrom(const BytesValue& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
   if (from.value().size() > 0) {
-
-    value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
+    set_value(from.value());
   }
 }
 
@@ -2348,6 +2590,18 @@
 
 void BytesValue::Swap(BytesValue* other) {
   if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    BytesValue temp;
+    temp.MergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void BytesValue::UnsafeArenaSwap(BytesValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
   InternalSwap(other);
 }
 void BytesValue::InternalSwap(BytesValue* other) {
@@ -2369,36 +2623,44 @@
 
 // optional bytes value = 1;
 void BytesValue::clear_value() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
  const ::std::string& BytesValue::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  void BytesValue::set_value(const ::std::string& value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
 }
  void BytesValue::set_value(const char* value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
 }
- void BytesValue::set_value(const void* value, size_t size) {
+ void BytesValue::set_value(const void* value,
+    size_t size) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
-      ::std::string(reinterpret_cast<const char*>(value), size));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
 }
  ::std::string* BytesValue::mutable_value() {
   
   // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
-  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
  ::std::string* BytesValue::release_value() {
   
-  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+ ::std::string* BytesValue::unsafe_arena_release_value() {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
 }
  void BytesValue::set_allocated_value(::std::string* value) {
   if (value != NULL) {
@@ -2406,7 +2668,20 @@
   } else {
     
   }
-  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+ void BytesValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
 }
 
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 15bcc7a..7dca938 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -61,9 +61,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const DoubleValue& default_instance();
 
+  void UnsafeArenaSwap(DoubleValue* other);
   void Swap(DoubleValue* other);
 
   // implements Message ----------------------------------------------
@@ -90,6 +95,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(DoubleValue* other);
+  protected:
+  explicit DoubleValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -115,6 +125,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   double value_;
   mutable int _cached_size_;
@@ -139,9 +152,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const FloatValue& default_instance();
 
+  void UnsafeArenaSwap(FloatValue* other);
   void Swap(FloatValue* other);
 
   // implements Message ----------------------------------------------
@@ -168,6 +186,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(FloatValue* other);
+  protected:
+  explicit FloatValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -193,6 +216,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   float value_;
   mutable int _cached_size_;
@@ -217,9 +243,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const Int64Value& default_instance();
 
+  void UnsafeArenaSwap(Int64Value* other);
   void Swap(Int64Value* other);
 
   // implements Message ----------------------------------------------
@@ -246,6 +277,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(Int64Value* other);
+  protected:
+  explicit Int64Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -271,6 +307,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::int64 value_;
   mutable int _cached_size_;
@@ -295,9 +334,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const UInt64Value& default_instance();
 
+  void UnsafeArenaSwap(UInt64Value* other);
   void Swap(UInt64Value* other);
 
   // implements Message ----------------------------------------------
@@ -324,6 +368,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(UInt64Value* other);
+  protected:
+  explicit UInt64Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -349,6 +398,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::uint64 value_;
   mutable int _cached_size_;
@@ -373,9 +425,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const Int32Value& default_instance();
 
+  void UnsafeArenaSwap(Int32Value* other);
   void Swap(Int32Value* other);
 
   // implements Message ----------------------------------------------
@@ -402,6 +459,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(Int32Value* other);
+  protected:
+  explicit Int32Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -427,6 +489,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::int32 value_;
   mutable int _cached_size_;
@@ -451,9 +516,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const UInt32Value& default_instance();
 
+  void UnsafeArenaSwap(UInt32Value* other);
   void Swap(UInt32Value* other);
 
   // implements Message ----------------------------------------------
@@ -480,6 +550,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(UInt32Value* other);
+  protected:
+  explicit UInt32Value(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -505,6 +580,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::uint32 value_;
   mutable int _cached_size_;
@@ -529,9 +607,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const BoolValue& default_instance();
 
+  void UnsafeArenaSwap(BoolValue* other);
   void Swap(BoolValue* other);
 
   // implements Message ----------------------------------------------
@@ -558,6 +641,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(BoolValue* other);
+  protected:
+  explicit BoolValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -583,6 +671,9 @@
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   bool value_;
   mutable int _cached_size_;
@@ -607,9 +698,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const StringValue& default_instance();
 
+  void UnsafeArenaSwap(StringValue* other);
   void Swap(StringValue* other);
 
   // implements Message ----------------------------------------------
@@ -636,6 +732,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(StringValue* other);
+  protected:
+  explicit StringValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -661,11 +762,17 @@
   ::std::string* mutable_value();
   ::std::string* release_value();
   void set_allocated_value(::std::string* value);
+  ::std::string* unsafe_arena_release_value();
+  void unsafe_arena_set_allocated_value(
+      ::std::string* value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.StringValue)
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::internal::ArenaStringPtr value_;
   mutable int _cached_size_;
@@ -690,9 +797,14 @@
     return *this;
   }
 
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
   static const ::google::protobuf::Descriptor* descriptor();
   static const BytesValue& default_instance();
 
+  void UnsafeArenaSwap(BytesValue* other);
   void Swap(BytesValue* other);
 
   // implements Message ----------------------------------------------
@@ -719,6 +831,11 @@
   void SharedDtor();
   void SetCachedSize(int size) const;
   void InternalSwap(BytesValue* other);
+  protected:
+  explicit BytesValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return _internal_metadata_.arena();
@@ -744,11 +861,17 @@
   ::std::string* mutable_value();
   ::std::string* release_value();
   void set_allocated_value(::std::string* value);
+  ::std::string* unsafe_arena_release_value();
+  void unsafe_arena_set_allocated_value(
+      ::std::string* value);
 
   // @@protoc_insertion_point(class_scope:google.protobuf.BytesValue)
  private:
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
   bool _is_default_instance_;
   ::google::protobuf::internal::ArenaStringPtr value_;
   mutable int _cached_size_;
@@ -895,36 +1018,44 @@
 
 // optional string value = 1;
 inline void StringValue::clear_value() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 inline const ::std::string& StringValue::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.StringValue.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void StringValue::set_value(const ::std::string& value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set:google.protobuf.StringValue.value)
 }
 inline void StringValue::set_value(const char* value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_char:google.protobuf.StringValue.value)
 }
-inline void StringValue::set_value(const char* value, size_t size) {
+inline void StringValue::set_value(const char* value,
+    size_t size) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
-      ::std::string(reinterpret_cast<const char*>(value), size));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.StringValue.value)
 }
 inline ::std::string* StringValue::mutable_value() {
   
   // @@protoc_insertion_point(field_mutable:google.protobuf.StringValue.value)
-  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 inline ::std::string* StringValue::release_value() {
   
-  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* StringValue::unsafe_arena_release_value() {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
 }
 inline void StringValue::set_allocated_value(::std::string* value) {
   if (value != NULL) {
@@ -932,7 +1063,20 @@
   } else {
     
   }
-  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
+}
+inline void StringValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value)
 }
 
@@ -942,36 +1086,44 @@
 
 // optional bytes value = 1;
 inline void BytesValue::clear_value() {
-  value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 inline const ::std::string& BytesValue::value() const {
   // @@protoc_insertion_point(field_get:google.protobuf.BytesValue.value)
-  return value_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
 inline void BytesValue::set_value(const ::std::string& value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set:google.protobuf.BytesValue.value)
 }
 inline void BytesValue::set_value(const char* value) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_char:google.protobuf.BytesValue.value)
 }
-inline void BytesValue::set_value(const void* value, size_t size) {
+inline void BytesValue::set_value(const void* value,
+    size_t size) {
   
-  value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
-      ::std::string(reinterpret_cast<const char*>(value), size));
+  value_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_pointer:google.protobuf.BytesValue.value)
 }
 inline ::std::string* BytesValue::mutable_value() {
   
   // @@protoc_insertion_point(field_mutable:google.protobuf.BytesValue.value)
-  return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
 }
 inline ::std::string* BytesValue::release_value() {
   
-  return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* BytesValue::unsafe_arena_release_value() {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  
+  return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
 }
 inline void BytesValue::set_allocated_value(::std::string* value) {
   if (value != NULL) {
@@ -979,7 +1131,20 @@
   } else {
     
   }
-  value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  value_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
+}
+inline void BytesValue::unsafe_arena_set_allocated_value(
+    ::std::string* value) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (value != NULL) {
+    
+  } else {
+    
+  }
+  value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      value, GetArenaNoVirtual());
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value)
 }
 
diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto
index a1d6e44..040d8a2 100644
--- a/src/google/protobuf/wrappers.proto
+++ b/src/google/protobuf/wrappers.proto
@@ -37,11 +37,12 @@
 
 package google.protobuf;
 
-option java_generate_equals_and_hash = true;
-option java_multiple_files = true;
-option java_outer_classname = "WrappersProto";
-option java_package = "com.google.protobuf";
 option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option java_generate_equals_and_hash = true;
 option objc_class_prefix = "GPB";
 
 // Wrapper message for `double`.
diff --git a/travis.sh b/travis.sh
index b4a908d..ff5e99d 100755
--- a/travis.sh
+++ b/travis.sh
@@ -11,6 +11,15 @@
 # For when some other test needs the C++ main build, including protoc and
 # libprotobuf.
 internal_build_cpp() {
+  if [ $(uname -s) == "Linux" ]; then
+    # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more
+    # decent C++ 11 support in order to compile conformance tests.
+    sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+    sudo apt-get update -qq
+    sudo apt-get install -qq g++-4.8
+    export CXX="g++-4.8" CC="gcc-4.8"
+  fi
+
   ./autogen.sh
   ./configure
   make -j2
@@ -47,6 +56,24 @@
   cd conformance && make test_csharp && cd ..
 }
 
+build_golang() {
+  # Go build needs `protoc`.
+  internal_build_cpp
+  # Add protoc to the path so that the examples build finds it.
+  export PATH="`pwd`/src:$PATH"
+
+  # Install Go and the Go protobuf compiler plugin.
+  sudo apt-get update -qq
+  sudo apt-get install -qq golang
+  export GOPATH="$HOME/gocode"
+  mkdir -p "$GOPATH/src/github.com/google"
+  ln -s "`pwd`" "$GOPATH/src/github.com/google/protobuf"
+  export PATH="$GOPATH/bin:$PATH"
+  go get github.com/golang/protobuf/protoc-gen-go
+
+  cd examples && make gotest && cd ..
+}
+
 use_java() {
   version=$1
   case "$version" in
@@ -75,7 +102,17 @@
 build_java() {
   # Java build needs `protoc`.
   internal_build_cpp
-  cd java && mvn test && cd ..
+  cd java && mvn test && mvn install
+  cd util && mvn test
+  cd ../..
+}
+
+build_java_with_conformance_tests() {
+  # Java build needs `protoc`.
+  internal_build_cpp
+  cd java && mvn test && mvn install
+  cd util && mvn test && mvn assembly:single
+  cd ../..
   cd conformance && make test_java && cd ..
 }
 
@@ -91,7 +128,7 @@
 }
 build_java_jdk7() {
   use_java jdk7
-  build_java
+  build_java_with_conformance_tests
 }
 build_java_oracle7() {
   use_java oracle7
@@ -112,7 +149,12 @@
 }
 
 internal_install_python_deps() {
-  sudo pip install tox
+  # Install tox (OS X doesn't have pip).
+  if [ $(uname -s) == "Darwin" ]; then
+    sudo easy_install tox
+  else
+    sudo pip install tox
+  fi
   # Only install Python2.6/3.x on Linux.
   if [ $(uname -s) == "Linux" ]; then
     sudo apt-get install -y python-software-properties # for apt-add-repository
@@ -124,6 +166,66 @@
   fi
 }
 
+internal_objectivec_common () {
+  # Make sure xctool is up to date. Adapted from
+  #  http://docs.travis-ci.com/user/osx-ci-environment/
+  # We don't use a before_install because we test multiple OSes.
+  brew update
+  # xctool 0.2.8 seems to have a bug where it randomly kills tests saying
+  # they failed. Disabling the updates, but letting it report about being
+  # updates as a hint that this needs to eventually get re-enabled.
+  #   https://github.com/facebook/xctool/issues/619
+  #   https://github.com/google/protobuf/issues/1232
+  brew outdated xctool || true
+  #brew outdated xctool || brew upgrade xctool
+  # Reused the build script that takes care of configuring and ensuring things
+  # are up to date. Xcode and conformance tests will be directly invoked.
+  objectivec/DevTools/full_mac_build.sh \
+      --core-only --skip-xcode --skip-objc-conformance
+}
+
+internal_xctool_debug_and_release() {
+  # Always use -reporter plain to avoid escape codes in output (makes travis
+  # logs easier to read).
+  xctool -reporter plain -configuration Debug "$@"
+  xctool -reporter plain -configuration Release "$@"
+}
+
+build_objectivec_ios() {
+  internal_objectivec_common
+  # https://github.com/facebook/xctool/issues/509 - unlike xcodebuild, xctool
+  # doesn't support >1 destination, so we have to build first and then run the
+  # tests one destination at a time.
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+    -scheme ProtocolBuffers \
+    -sdk iphonesimulator \
+    build-tests
+  IOS_DESTINATIONS=(
+    "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPhone 6,OS=9.2" # 64bit
+    "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
+    "platform=iOS Simulator,name=iPad Air,OS=9.2" # 64bit
+  )
+  for i in "${IOS_DESTINATIONS[@]}" ; do
+    internal_xctool_debug_and_release \
+      -project objectivec/ProtocolBuffers_iOS.xcodeproj \
+      -scheme ProtocolBuffers \
+      -sdk iphonesimulator \
+      -destination "${i}" \
+      run-tests
+  done
+}
+
+build_objectivec_osx() {
+  internal_objectivec_common
+  internal_xctool_debug_and_release \
+    -project objectivec/ProtocolBuffers_OSX.xcodeproj \
+    -scheme ProtocolBuffers \
+    -destination "platform=OS X,arch=x86_64" \
+    test
+  cd conformance && make test_objc && cd ..
+}
 
 build_python() {
   internal_build_cpp
@@ -147,7 +249,8 @@
   cd python
   # Only test Python 2.6/3.x on Linux
   if [ $(uname -s) == "Linux" ]; then
-    envlist=py\{26,27,33,34\}-cpp
+    # py26 is currently disabled due to json_format
+    envlist=py\{27,33,34\}-cpp
   else
     envlist=py27-cpp
   fi
@@ -176,6 +279,11 @@
   cd ruby && bash travis-test.sh jruby && cd ..
 }
 
+build_javascript() {
+  internal_build_cpp
+  cd js && npm install && npm test && cd ..
+}
+
 # -------- main --------
 
 if [ "$#" -ne 1 ]; then
@@ -188,6 +296,8 @@
             javanano_jdk6 |
             javanano_jdk7 |
             javanano_oracle7 |
+            objectivec_ios |
+            objectivec_osx |
             python |
             python_cpp |
             ruby_19 |
diff --git a/util/python/BUILD b/util/python/BUILD
new file mode 100644
index 0000000..358c381
--- /dev/null
+++ b/util/python/BUILD
@@ -0,0 +1,8 @@
+# This is a placeholder for python headers. Projects needing to use
+# fast cpp protos in protobuf's python interface should build with
+# --define=use_fast_cpp_protos=true, and in addition, provide
+# //util/python:python_headers dependency that in turn provides Python.h.
+cc_library(
+    name = "python_headers",
+    visibility = ["//visibility:public"],
+)