Merge pull request #9479 from haberman/sync-stage-2

Integrate from Piper for C++, Java, and Python
diff --git a/BUILD b/BUILD
index 23dcd6f..8a84954 100644
--- a/BUILD
+++ b/BUILD
@@ -46,7 +46,6 @@
     ":msvc": MSVC_COPTS,
     "//conditions:default": [
         "-DHAVE_ZLIB",
-        "-Wmissing-field-initializers",
         "-Woverloaded-virtual",
         "-Wno-sign-compare",
     ],
@@ -161,7 +160,6 @@
         "src/google/protobuf/arenastring.cc",
         "src/google/protobuf/extension_set.cc",
         "src/google/protobuf/generated_enum_util.cc",
-        "src/google/protobuf/generated_message_table_driven_lite.cc",
         "src/google/protobuf/generated_message_tctable_lite.cc",
         "src/google/protobuf/generated_message_util.cc",
         "src/google/protobuf/implicit_weak_message.cc",
@@ -223,7 +221,6 @@
         "src/google/protobuf/field_mask.pb.cc",
         "src/google/protobuf/generated_message_bases.cc",
         "src/google/protobuf/generated_message_reflection.cc",
-        "src/google/protobuf/generated_message_table_driven.cc",
         "src/google/protobuf/generated_message_tctable_full.cc",
         "src/google/protobuf/io/gzip_stream.cc",
         "src/google/protobuf/io/printer.cc",
@@ -499,6 +496,8 @@
         "src/google/protobuf/compiler/plugin.cc",
         "src/google/protobuf/compiler/plugin.pb.cc",
         "src/google/protobuf/compiler/python/python_generator.cc",
+        "src/google/protobuf/compiler/python/python_helpers.cc",
+        "src/google/protobuf/compiler/python/python_pyi_generator.cc",
         "src/google/protobuf/compiler/ruby/ruby_generator.cc",
         "src/google/protobuf/compiler/subprocess.cc",
         "src/google/protobuf/compiler/zip_writer.cc",
diff --git a/CHANGES.txt b/CHANGES.txt
index ea9e6af..6a1e8b9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -9,6 +9,78 @@
   * Unknown enums for proto2 protos now properly implement proto2's behavior of
     putting such values in unknown fields.
 
+  Java
+  * Don't support map fields in DynamicMessage.Builder.{getFieldBuilder,getRepeatedFieldBuilder}
+  * Fix parseFrom to only throw InvalidProtocolBufferException
+  * InvalidProtocolBufferException now allows arbitrary wrapped Exception types.
+  * Fix bug in `FieldSet.Builder.mergeFrom`
+  * Flush CodedOutputStream also flushes underlying OutputStream
+  * When oneof case is the same and the field type is Message, merge the
+    subfield. (previously it was replaced.)’
+  * add @CheckReturnValue to some protobuf types
+  * Report original exceptions when parsing JSON
+  * Add more info to @deprecated javadoc for set/get/has methods
+  * Fix initialization bug in doc comment line numbers
+
+  Kotlin
+  * Add orNull extensions for optional message fields in Kotlin.
+
+  Python
+  * Fix type annotations of some Duration and Timestamp methods.
+  * Repeated field containers are now generic in field types and could be used
+    in type annotations.
+  * Protobuf python generated codes are simplified. Descriptors and message
+    classes' definitions are now dynamic created in internal/builder.py.
+    Insertion Points for messages classes are discarded.
+  * protoc is now able to generate python stub (.pyi) by --gen_pyi
+  * has_presence is added for FieldDescriptor in python
+  * Loosen indexing type requirements to allow valid __index__() implementations
+    rather than only PyLongObjects.
+  * Fix the deepcopy bug caused by not copying message_listener.
+  * Added python JSON parse recursion limit (default 100)
+  * path info is added for python JSON parse errors
+  * Pure python repeated scalar fields will not able to pickle. Convert to list
+    first.
+  * Timestamp.ToDatetime() now accepts an optional tzinfo parameter. If
+    specified, the function returns a timezone-aware datetime in the given time
+    zone. If omitted or None, the function returns a timezone-naive UTC datetime
+    (as previously).
+  * Adds client_streaming and server_streaming fields to MethodDescriptor.
+
+  Compiler
+  * Migrate IsDefault(const std::string*) and UnsafeSetDefault(const std::string*)
+  * Implement strong qualified tags for TaggedPtr
+  * Rework allocations to power-of-two byte sizes.
+  * Migrate IsDefault(const std::string*) and UnsafeSetDefault(const std::string*)
+  * Implement strong qualified tags for TaggedPtr
+  * Make TaggedPtr Set...() calls explicitly spell out the content type.
+  * Check for parsing error before verifying UTF8.
+  * Enforce a maximum message nesting limit of 32 in the descriptor builder to
+    guard against stack overflows
+  * Fixed bugs in operators for RepeatedPtrIterator
+  * Assert a maximum map alignment for allocated values
+  * Fix proto1 group extension protodb parsing error
+  * Do not log/report the same descriptor symbol multiple times if it contains
+    more than one invalid character.
+  * Add UnknownFieldSet::SerializeToString and SerializeToCodedStream.
+
+  Arenas
+  * Change Repeated*Field to reuse memory when using arenas.
+  * Implements pbarenaz for profiling proto arenas
+  * Introduce CreateString() and CreateArenaString() for cleaner semantics
+  * Fix unreferenced parameter for MSVC builds
+  * Add UnsafeSetAllocated to be used for one-of string fields.
+  * Make Arena::AllocateAligned() a public function.
+  * Determine if ArenaDtor related code generation is necessary in one place.
+  * Implement on demand register ArenaDtor for InlinedStringField
+
+  C++
+  * manually *struct Cord fields to work better with arenas.
+  * manually destruct map fields.
+  * Generate narrower code
+  * Fix https://github.com/protocolbuffers/protobuf/issues/9378 by removing
+    shadowed _cached_size_ field
+
 2022-01-28 version 3.19.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
 
   Python
diff --git a/Makefile.am b/Makefile.am
index 149e475..343b5f7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -308,6 +308,7 @@
   java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java          \
   java/core/src/main/java/com/google/protobuf/CodedOutputStream.java               \
   java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java         \
+  java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java             \
   java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java    \
   java/core/src/main/java/com/google/protobuf/Descriptors.java                     \
   java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java      \
@@ -331,6 +332,7 @@
   java/core/src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java     \
   java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java            \
   java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java              \
+  java/core/src/main/java/com/google/protobuf/InlineMe.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  \
@@ -442,9 +444,9 @@
   java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.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/InvalidProtocolBufferExceptionTest.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               \
@@ -506,6 +508,7 @@
   java/core/src/test/proto/com/google/protobuf/any_test.proto                      \
   java/core/src/test/proto/com/google/protobuf/cached_field_size_test.proto        \
   java/core/src/test/proto/com/google/protobuf/deprecated_file.proto               \
+  java/core/src/test/proto/com/google/protobuf/dynamic_message_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          \
@@ -596,10 +599,12 @@
   java/util/src/main/java/com/google/protobuf/util/Structs.java                    \
   java/util/src/main/java/com/google/protobuf/util/Timestamps.java                 \
   java/util/src/main/java/com/google/protobuf/util/Values.java                     \
+  java/util/src/test/java/com/google/protobuf/util/DurationsTest.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/StructsTest.java                \
+  java/util/src/test/java/com/google/protobuf/util/TimestampsTest.java             \
   java/util/src/test/java/com/google/protobuf/util/ValuesTest.java                 \
   java/util/src/test/proto/com/google/protobuf/util/json_test.proto
 
@@ -1019,6 +1024,7 @@
   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/builder.py                                 \
   python/google/protobuf/internal/containers.py                              \
   python/google/protobuf/internal/decoder.py                                 \
   python/google/protobuf/internal/descriptor_database_test.py                \
diff --git a/benchmarks/README.md b/benchmarks/README.md
index 7f9693c..13a8843 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -4,8 +4,8 @@
 This directory contains benchmarking schemas and data sets that you
 can use to test a variety of performance scenarios against your
 protobuf language runtime. If you are looking for performance
-numbers of officially support languages, see [here](
-https://github.com/protocolbuffers/protobuf/blob/master/docs/performance.md)
+numbers of officially supported languages, see [Protobuf Performance](
+https://github.com/protocolbuffers/protobuf/blob/master/docs/performance.md).
 
 ## Prerequisite
 
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index 605c5f9..2f53be0 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -41,6 +41,8 @@
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h" include\google\protobuf\compiler\python\python_generator.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_pyi_generator.h" include\google\protobuf\compiler\python\python_pyi_generator.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_helpers.h" include\google\protobuf\compiler\python\python_helpers.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.pb.h" include\google\protobuf\descriptor.pb.h
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
index a0bc994..5e98748 100644
--- a/cmake/libprotobuf-lite.cmake
+++ b/cmake/libprotobuf-lite.cmake
@@ -2,9 +2,9 @@
   ${protobuf_source_dir}/src/google/protobuf/any_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/arena.cc
   ${protobuf_source_dir}/src/google/protobuf/arenastring.cc
+  ${protobuf_source_dir}/src/google/protobuf/arenaz_sampler.cc
   ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_enum_util.cc
-  ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
   ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.cc
@@ -38,15 +38,13 @@
   ${protobuf_source_dir}/src/google/protobuf/arena.h
   ${protobuf_source_dir}/src/google/protobuf/arena_impl.h
   ${protobuf_source_dir}/src/google/protobuf/arenastring.h
+  ${protobuf_source_dir}/src/google/protobuf/arenaz_sampler.h
   ${protobuf_source_dir}/src/google/protobuf/explicitly_constructed.h
   ${protobuf_source_dir}/src/google/protobuf/extension_set.h
   ${protobuf_source_dir}/src/google/protobuf/extension_set_inl.h
   ${protobuf_source_dir}/src/google/protobuf/generated_enum_util.h
-  ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven.h
-  ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.h
   ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_decl.h
   ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_impl.h
-  ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_impl.inc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.h
   ${protobuf_source_dir}/src/google/protobuf/has_bits.h
   ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.h
diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake
index 51003b8..ef5a3cf 100644
--- a/cmake/libprotobuf.cmake
+++ b/cmake/libprotobuf.cmake
@@ -14,13 +14,13 @@
   ${protobuf_source_dir}/src/google/protobuf/field_mask.pb.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_bases.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_reflection.cc
-  ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_full.cc
   ${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/printer.cc
   ${protobuf_source_dir}/src/google/protobuf/io/tokenizer.cc
   ${protobuf_source_dir}/src/google/protobuf/map_field.cc
   ${protobuf_source_dir}/src/google/protobuf/message.cc
+  ${protobuf_source_dir}/src/google/protobuf/reflection_internal.h
   ${protobuf_source_dir}/src/google/protobuf/reflection_ops.cc
   ${protobuf_source_dir}/src/google/protobuf/service.cc
   ${protobuf_source_dir}/src/google/protobuf/source_context.pb.cc
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index 6f04331..ed20f31 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -36,6 +36,7 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field.h
   ${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
@@ -64,24 +65,38 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/js/js_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/js/well_known_types_embed.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_extension.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_file.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_map_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/php/php_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_helpers.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_pyi_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.h
 )
 
 set(libprotoc_headers
@@ -95,18 +110,16 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_names.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_options.h
-  ${protobuf_source_dir}/src/google/protobuf/compiler/importer.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_kotlin_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_names.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/js/js_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
-  ${protobuf_source_dir}/src/google/protobuf/compiler/parser.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/php/php_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.h
-  ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.h
+  ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_pyi_generator.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.h
 )
 
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 1556838..006c371 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -129,10 +129,10 @@
 
 set(common_test_files
   ${common_lite_test_files}
+  ${protobuf_source_dir}/src/google/protobuf/compiler/mock_code_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/map_test_util.inc
   ${protobuf_source_dir}/src/google/protobuf/reflection_tester.cc
   ${protobuf_source_dir}/src/google/protobuf/test_util.cc
-  ${protobuf_source_dir}/src/google/protobuf/test_util.inc
   ${protobuf_source_dir}/src/google/protobuf/testing/file.cc
   ${protobuf_source_dir}/src/google/protobuf/testing/googletest.cc
 )
@@ -141,7 +141,9 @@
   ${protobuf_source_dir}/src/google/protobuf/any_test.cc
   ${protobuf_source_dir}/src/google/protobuf/arena_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/arenastring_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/arenaz_sampler_test.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/annotation_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/compiler/annotation_test_util.h
   ${protobuf_source_dir}/src/google/protobuf/compiler/command_line_interface_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc
@@ -154,7 +156,6 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/importer_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_plugin_unittest.cc
-  ${protobuf_source_dir}/src/google/protobuf/compiler/mock_code_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/parser_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -165,6 +166,7 @@
   ${protobuf_source_dir}/src/google/protobuf/dynamic_message_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/extension_set_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_reflection_unittest.cc
+  ${protobuf_source_dir}/src/google/protobuf/generated_message_tctable_lite_test.cc
   ${protobuf_source_dir}/src/google/protobuf/inlined_string_field_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream_unittest.cc
   ${protobuf_source_dir}/src/google/protobuf/io/io_win32_unittest.cc
diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java
index 100bec4..f724548 100644
--- a/conformance/ConformanceJava.java
+++ b/conformance/ConformanceJava.java
@@ -361,7 +361,7 @@
 
       case TEXT_FORMAT:
         return Conformance.ConformanceResponse.newBuilder()
-            .setTextPayload(TextFormat.printToString(testMessage))
+            .setTextPayload(TextFormat.printer().printToString(testMessage))
             .build();
 
       default:
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
index 1572ac0..19222c7 100644
--- a/conformance/conformance_test_runner.cc
+++ b/conformance/conformance_test_runner.cc
@@ -162,7 +162,7 @@
     // 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;
+    int status = 0;
     waitpid(child_pid_, &status, WEXITED);
 
     string error_msg;
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
index d2db53d..94f089c 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs
@@ -25,7 +25,7 @@
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "Cipnb29nbGUvcHJvdG9idWYvdGVzdF9tZXNzYWdlc19wcm90bzIucHJvdG8S",
-            "HXByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yIqQ+ChJUZXN0QWxsVHlw",
+            "HXByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yIsQ+ChJUZXN0QWxsVHlw",
             "ZXNQcm90bzISFgoOb3B0aW9uYWxfaW50MzIYASABKAUSFgoOb3B0aW9uYWxf",
             "aW50NjQYAiABKAMSFwoPb3B0aW9uYWxfdWludDMyGAMgASgNEhcKD29wdGlv",
             "bmFsX3VpbnQ2NBgEIAEoBBIXCg9vcHRpb25hbF9zaW50MzIYBSABKBESFwoP",
@@ -148,79 +148,81 @@
             "NTY3ODkxMjM0NTY3ODkSHQoNZGVmYXVsdF9mbG9hdBj7ASABKAI6BTllKzA5",
             "Eh4KDmRlZmF1bHRfZG91YmxlGPwBIAEoAToFN2UrMjISGwoMZGVmYXVsdF9i",
             "b29sGP0BIAEoCDoEdHJ1ZRIgCg5kZWZhdWx0X3N0cmluZxj+ASABKAk6B1Jv",
-            "c2VidWQSEwoKZmllbGRuYW1lMRiRAyABKAUSFAoLZmllbGRfbmFtZTIYkgMg",
-            "ASgFEhUKDF9maWVsZF9uYW1lMxiTAyABKAUSFgoNZmllbGRfX25hbWU0XxiU",
-            "AyABKAUSFAoLZmllbGQwbmFtZTUYlQMgASgFEhYKDWZpZWxkXzBfbmFtZTYY",
-            "lgMgASgFEhMKCmZpZWxkTmFtZTcYlwMgASgFEhMKCkZpZWxkTmFtZTgYmAMg",
-            "ASgFEhQKC2ZpZWxkX05hbWU5GJkDIAEoBRIVCgxGaWVsZF9OYW1lMTAYmgMg",
-            "ASgFEhUKDEZJRUxEX05BTUUxMRibAyABKAUSFQoMRklFTERfbmFtZTEyGJwD",
-            "IAEoBRIXCg5fX2ZpZWxkX25hbWUxMxidAyABKAUSFwoOX19GaWVsZF9uYW1l",
-            "MTQYngMgASgFEhYKDWZpZWxkX19uYW1lMTUYnwMgASgFEhYKDWZpZWxkX19O",
-            "YW1lMTYYoAMgASgFEhcKDmZpZWxkX25hbWUxN19fGKEDIAEoBRIXCg5GaWVs",
-            "ZF9uYW1lMThfXxiiAyABKAUaYgoNTmVzdGVkTWVzc2FnZRIJCgFhGAEgASgF",
-            "EkYKC2NvcmVjdXJzaXZlGAIgASgLMjEucHJvdG9idWZfdGVzdF9tZXNzYWdl",
-            "cy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8yGjQKEk1hcEludDMySW50MzJF",
-            "bnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcElu",
-            "dDY0SW50NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgB",
-            "GjYKFE1hcFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1",
-            "ZRgCIAEoDToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEg",
-            "ASgEEg0KBXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRy",
-            "eRILCgNrZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2",
-            "NFNpbnQ2NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEa",
-            "OAoWTWFwRml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFs",
-            "dWUYAiABKAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5",
-            "GAEgASgGEg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhl",
-            "ZDMyRW50cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhN",
-            "YXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVl",
-            "GAIgASgQOgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgF",
-            "Eg0KBXZhbHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsK",
-            "A2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xF",
-            "bnRyeRILCgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGjYKFE1hcFN0",
-            "cmluZ1N0cmluZ0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToC",
-            "OAEaNQoTTWFwU3RyaW5nQnl0ZXNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFs",
-            "dWUYAiABKAw6AjgBGn4KG01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRIL",
-            "CgNrZXkYASABKAkSTgoFdmFsdWUYAiABKAsyPy5wcm90b2J1Zl90ZXN0X21l",
-            "c3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIuTmVzdGVkTWVzc2Fn",
-            "ZToCOAEacwocTWFwU3RyaW5nRm9yZWlnbk1lc3NhZ2VFbnRyeRILCgNrZXkY",
-            "ASABKAkSQgoFdmFsdWUYAiABKAsyMy5wcm90b2J1Zl90ZXN0X21lc3NhZ2Vz",
-            "LnByb3RvMi5Gb3JlaWduTWVzc2FnZVByb3RvMjoCOAEaeAoYTWFwU3RyaW5n",
-            "TmVzdGVkRW51bUVudHJ5EgsKA2tleRgBIAEoCRJLCgV2YWx1ZRgCIAEoDjI8",
+            "c2VidWQSHgoNZGVmYXVsdF9ieXRlcxj/ASABKAw6Bmpvc2h1YRITCgpmaWVs",
+            "ZG5hbWUxGJEDIAEoBRIUCgtmaWVsZF9uYW1lMhiSAyABKAUSFQoMX2ZpZWxk",
+            "X25hbWUzGJMDIAEoBRIWCg1maWVsZF9fbmFtZTRfGJQDIAEoBRIUCgtmaWVs",
+            "ZDBuYW1lNRiVAyABKAUSFgoNZmllbGRfMF9uYW1lNhiWAyABKAUSEwoKZmll",
+            "bGROYW1lNxiXAyABKAUSEwoKRmllbGROYW1lOBiYAyABKAUSFAoLZmllbGRf",
+            "TmFtZTkYmQMgASgFEhUKDEZpZWxkX05hbWUxMBiaAyABKAUSFQoMRklFTERf",
+            "TkFNRTExGJsDIAEoBRIVCgxGSUVMRF9uYW1lMTIYnAMgASgFEhcKDl9fZmll",
+            "bGRfbmFtZTEzGJ0DIAEoBRIXCg5fX0ZpZWxkX25hbWUxNBieAyABKAUSFgoN",
+            "ZmllbGRfX25hbWUxNRifAyABKAUSFgoNZmllbGRfX05hbWUxNhigAyABKAUS",
+            "FwoOZmllbGRfbmFtZTE3X18YoQMgASgFEhcKDkZpZWxkX25hbWUxOF9fGKID",
+            "IAEoBRpiCg1OZXN0ZWRNZXNzYWdlEgkKAWEYASABKAUSRgoLY29yZWN1cnNp",
+            "dmUYAiABKAsyMS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0",
+            "QWxsVHlwZXNQcm90bzIaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tleRgB",
+            "IAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVudHJ5",
+            "EgsKA2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWludDMy",
+            "VWludDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4ARo2",
+            "ChRNYXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFsdWUY",
+            "AiABKAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgBIAEo",
+            "ERINCgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50cnkS",
+            "CwoDa2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhlZDMy",
+            "Rml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoCOAEa",
+            "OAoWTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoFdmFs",
+            "dWUYAiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRILCgNr",
+            "ZXkYASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0U2Zp",
+            "eGVkNjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgBGjQK",
+            "Ek1hcEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiAB",
+            "KAI6AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgFEg0K",
+            "BXZhbHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tleRgB",
+            "IAEoCBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5nRW50",
+            "cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo1ChNNYXBTdHJp",
+            "bmdCeXRlc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoDDoCOAEa",
+            "fgobTWFwU3RyaW5nTmVzdGVkTWVzc2FnZUVudHJ5EgsKA2tleRgBIAEoCRJO",
+            "CgV2YWx1ZRgCIAEoCzI/LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8y",
+            "LlRlc3RBbGxUeXBlc1Byb3RvMi5OZXN0ZWRNZXNzYWdlOgI4ARpzChxNYXBT",
+            "dHJpbmdGb3JlaWduTWVzc2FnZUVudHJ5EgsKA2tleRgBIAEoCRJCCgV2YWx1",
+            "ZRgCIAEoCzIzLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLkZvcmVp",
+            "Z25NZXNzYWdlUHJvdG8yOgI4ARp4ChhNYXBTdHJpbmdOZXN0ZWRFbnVtRW50",
+            "cnkSCwoDa2V5GAEgASgJEksKBXZhbHVlGAIgASgOMjwucHJvdG9idWZfdGVz",
+            "dF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8yLk5lc3RlZEVu",
+            "dW06AjgBGm0KGU1hcFN0cmluZ0ZvcmVpZ25FbnVtRW50cnkSCwoDa2V5GAEg",
+            "ASgJEj8KBXZhbHVlGAIgASgOMjAucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5w",
+            "cm90bzIuRm9yZWlnbkVudW1Qcm90bzI6AjgBGjMKBERhdGESFAoLZ3JvdXBf",
+            "aW50MzIYygEgASgFEhUKDGdyb3VwX3VpbnQzMhjLASABKA0aIQoRTWVzc2Fn",
+            "ZVNldENvcnJlY3QqCAgEEP////8HOgIIARrgAQobTWVzc2FnZVNldENvcnJl",
+            "Y3RFeHRlbnNpb24xEgsKA3N0chgZIAEoCTKzAQoVbWVzc2FnZV9zZXRfZXh0",
+            "ZW5zaW9uEkMucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFs",
+            "bFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0GPm7XiABKAsyTS5wcm90",
+            "b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIu",
+            "TWVzc2FnZVNldENvcnJlY3RFeHRlbnNpb24xGt8BChtNZXNzYWdlU2V0Q29y",
+            "cmVjdEV4dGVuc2lvbjISCQoBaRgJIAEoBTK0AQoVbWVzc2FnZV9zZXRfZXh0",
+            "ZW5zaW9uEkMucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFs",
+            "bFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0GJCz/AEgASgLMk0ucHJv",
+            "dG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8y",
+            "Lk1lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMiI5CgpOZXN0ZWRFbnVtEgcK",
+            "A0ZPTxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8BKgUI",
+            "eBDJAUINCgtvbmVvZl9maWVsZEoGCOgHEJBOIiEKFEZvcmVpZ25NZXNzYWdl",
+            "UHJvdG8yEgkKAWMYASABKAUiwQIKFVVua25vd25Ub1Rlc3RBbGxUeXBlcxIX",
+            "Cg5vcHRpb25hbF9pbnQzMhjpByABKAUSGAoPb3B0aW9uYWxfc3RyaW5nGOoH",
+            "IAEoCRJMCg5uZXN0ZWRfbWVzc2FnZRjrByABKAsyMy5wcm90b2J1Zl90ZXN0",
+            "X21lc3NhZ2VzLnByb3RvMi5Gb3JlaWduTWVzc2FnZVByb3RvMhJaCg1vcHRp",
+            "b25hbGdyb3VwGOwHIAEoCjJCLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJv",
+            "dG8yLlVua25vd25Ub1Rlc3RBbGxUeXBlcy5PcHRpb25hbEdyb3VwEhYKDW9w",
+            "dGlvbmFsX2Jvb2wY7gcgASgIEhcKDnJlcGVhdGVkX2ludDMyGPMHIAMoBRoa",
+            "Cg1PcHRpb25hbEdyb3VwEgkKAWEYASABKAUiFgoUTnVsbEh5cG90aGVzaXNQ",
+            "cm90bzIiLwoORW51bU9ubHlQcm90bzIiHQoEQm9vbBIKCgZrRmFsc2UQABIJ",
+            "CgVrVHJ1ZRABIh8KD09uZVN0cmluZ1Byb3RvMhIMCgRkYXRhGAEgASgJKkYK",
+            "EUZvcmVpZ25FbnVtUHJvdG8yEg8KC0ZPUkVJR05fRk9PEAASDwoLRk9SRUlH",
+            "Tl9CQVIQARIPCgtGT1JFSUdOX0JBWhACOkoKD2V4dGVuc2lvbl9pbnQzMhIx",
             "LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1By",
-            "b3RvMi5OZXN0ZWRFbnVtOgI4ARptChlNYXBTdHJpbmdGb3JlaWduRW51bUVu",
-            "dHJ5EgsKA2tleRgBIAEoCRI/CgV2YWx1ZRgCIAEoDjIwLnByb3RvYnVmX3Rl",
-            "c3RfbWVzc2FnZXMucHJvdG8yLkZvcmVpZ25FbnVtUHJvdG8yOgI4ARozCgRE",
-            "YXRhEhQKC2dyb3VwX2ludDMyGMoBIAEoBRIVCgxncm91cF91aW50MzIYywEg",
-            "ASgNGiEKEU1lc3NhZ2VTZXRDb3JyZWN0KggIBBD/////BzoCCAEa4AEKG01l",
-            "c3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMRILCgNzdHIYGSABKAkyswEKFW1l",
-            "c3NhZ2Vfc2V0X2V4dGVuc2lvbhJDLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu",
-            "cHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdBj5",
-            "u14gASgLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFs",
-            "bFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMRrfAQob",
-            "TWVzc2FnZVNldENvcnJlY3RFeHRlbnNpb24yEgkKAWkYCSABKAUytAEKFW1l",
-            "c3NhZ2Vfc2V0X2V4dGVuc2lvbhJDLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu",
-            "cHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdBiQ",
-            "s/wBIAEoCzJNLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RB",
-            "bGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdEV4dGVuc2lvbjIiOQoK",
-            "TmVzdGVkRW51bRIHCgNGT08QABIHCgNCQVIQARIHCgNCQVoQAhIQCgNORUcQ",
-            "////////////ASoFCHgQyQFCDQoLb25lb2ZfZmllbGRKBgjoBxCQTiIhChRG",
-            "b3JlaWduTWVzc2FnZVByb3RvMhIJCgFjGAEgASgFIsECChVVbmtub3duVG9U",
-            "ZXN0QWxsVHlwZXMSFwoOb3B0aW9uYWxfaW50MzIY6QcgASgFEhgKD29wdGlv",
-            "bmFsX3N0cmluZxjqByABKAkSTAoObmVzdGVkX21lc3NhZ2UY6wcgASgLMjMu",
-            "cHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuRm9yZWlnbk1lc3NhZ2VQ",
-            "cm90bzISWgoNb3B0aW9uYWxncm91cBjsByABKAoyQi5wcm90b2J1Zl90ZXN0",
-            "X21lc3NhZ2VzLnByb3RvMi5Vbmtub3duVG9UZXN0QWxsVHlwZXMuT3B0aW9u",
-            "YWxHcm91cBIWCg1vcHRpb25hbF9ib29sGO4HIAEoCBIXCg5yZXBlYXRlZF9p",
-            "bnQzMhjzByADKAUaGgoNT3B0aW9uYWxHcm91cBIJCgFhGAEgASgFIhYKFE51",
-            "bGxIeXBvdGhlc2lzUHJvdG8yIi8KDkVudW1Pbmx5UHJvdG8yIh0KBEJvb2wS",
-            "CgoGa0ZhbHNlEAASCQoFa1RydWUQASpGChFGb3JlaWduRW51bVByb3RvMhIP",
-            "CgtGT1JFSUdOX0ZPTxAAEg8KC0ZPUkVJR05fQkFSEAESDwoLRk9SRUlHTl9C",
-            "QVoQAjpKCg9leHRlbnNpb25faW50MzISMS5wcm90b2J1Zl90ZXN0X21lc3Nh",
-            "Z2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIYeCABKAVCLwooY29tLmdv",
-            "b2dsZS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMkgB+AEB"));
+            "b3RvMhh4IAEoBUIvCihjb20uZ29vZ2xlLnByb3RvYnVmX3Rlc3RfbWVzc2Fn",
+            "ZXMucHJvdG8ySAH4AQE="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto2.ForeignEnumProto2), }, new pb::Extension[] { TestMessagesProto2Extensions.ExtensionInt32 }, new pbr::GeneratedClrTypeInfo[] {
-            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.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", "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedNestedEnum", "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedNestedEnum", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "Data", "DefaultInt32", "DefaultInt64", "DefaultUint32", "DefaultUint64", "DefaultSint32", "DefaultSint64", "DefaultFixed32", "DefaultFixed64", "DefaultSfixed32", "DefaultSfixed64", "DefaultFloat", "DefaultDouble", "DefaultBool", "DefaultString", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.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", "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedNestedEnum", "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedNestedEnum", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "Data", "DefaultInt32", "DefaultInt64", "DefaultUint32", "DefaultUint64", "DefaultSint32", "DefaultSint64", "DefaultFixed32", "DefaultFixed64", "DefaultSfixed32", "DefaultSfixed64", "DefaultFloat", "DefaultDouble", "DefaultBool", "DefaultString", "DefaultBytes", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.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, null, new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data.Parser, new[]{ "GroupInt32", "GroupUint32" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrect), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrect.Parser, null, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Parser, new[]{ "Str" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Extensions.MessageSetExtension }, null),
@@ -228,7 +230,8 @@
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.ForeignMessageProto2), global::ProtobufTestMessages.Proto2.ForeignMessageProto2.Parser, new[]{ "C" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalString", "NestedMessage", "OptionalGroup", "OptionalBool", "RepeatedInt32" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup.Parser, new[]{ "A" }, null, null, null, null)}),
             new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.NullHypothesisProto2), global::ProtobufTestMessages.Proto2.NullHypothesisProto2.Parser, null, null, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2), global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Types.Bool) }, null, null)
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2), global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Types.Bool) }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.OneStringProto2), global::ProtobufTestMessages.Proto2.OneStringProto2.Parser, new[]{ "Data" }, null, null, null, null)
           }));
     }
     #endregion
@@ -404,6 +407,7 @@
       defaultDouble_ = other.defaultDouble_;
       defaultBool_ = other.defaultBool_;
       defaultString_ = other.defaultString_;
+      defaultBytes_ = other.defaultBytes_;
       fieldname1_ = other.fieldname1_;
       fieldName2_ = other.fieldName2_;
       FieldName3_ = other.FieldName3_;
@@ -2394,6 +2398,32 @@
       defaultString_ = null;
     }
 
+    /// <summary>Field number for the "default_bytes" field.</summary>
+    public const int DefaultBytesFieldNumber = 255;
+    private readonly static pb::ByteString DefaultBytesDefaultValue = pb::ByteString.FromBase64("am9zaHVh");
+
+    private pb::ByteString defaultBytes_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public pb::ByteString DefaultBytes {
+      get { return defaultBytes_ ?? DefaultBytesDefaultValue; }
+      set {
+        defaultBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+    /// <summary>Gets whether the "default_bytes" field is set</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool HasDefaultBytes {
+      get { return defaultBytes_ != null; }
+    }
+    /// <summary>Clears the value of the "default_bytes" field</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void ClearDefaultBytes() {
+      defaultBytes_ = null;
+    }
+
     /// <summary>Field number for the "fieldname1" field.</summary>
     public const int Fieldname1FieldNumber = 401;
     private readonly static int Fieldname1DefaultValue = 0;
@@ -3041,6 +3071,7 @@
       if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(DefaultDouble, other.DefaultDouble)) return false;
       if (DefaultBool != other.DefaultBool) return false;
       if (DefaultString != other.DefaultString) return false;
+      if (DefaultBytes != other.DefaultBytes) return false;
       if (Fieldname1 != other.Fieldname1) return false;
       if (FieldName2 != other.FieldName2) return false;
       if (FieldName3 != other.FieldName3) return false;
@@ -3184,6 +3215,7 @@
       if (HasDefaultDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(DefaultDouble);
       if (HasDefaultBool) hash ^= DefaultBool.GetHashCode();
       if (HasDefaultString) hash ^= DefaultString.GetHashCode();
+      if (HasDefaultBytes) hash ^= DefaultBytes.GetHashCode();
       if (HasFieldname1) hash ^= Fieldname1.GetHashCode();
       if (HasFieldName2) hash ^= FieldName2.GetHashCode();
       if (HasFieldName3) hash ^= FieldName3.GetHashCode();
@@ -3477,6 +3509,10 @@
         output.WriteRawTag(242, 15);
         output.WriteString(DefaultString);
       }
+      if (HasDefaultBytes) {
+        output.WriteRawTag(250, 15);
+        output.WriteBytes(DefaultBytes);
+      }
       if (HasFieldname1) {
         output.WriteRawTag(136, 25);
         output.WriteInt32(Fieldname1);
@@ -3815,6 +3851,10 @@
         output.WriteRawTag(242, 15);
         output.WriteString(DefaultString);
       }
+      if (HasDefaultBytes) {
+        output.WriteRawTag(250, 15);
+        output.WriteBytes(DefaultBytes);
+      }
       if (HasFieldname1) {
         output.WriteRawTag(136, 25);
         output.WriteInt32(Fieldname1);
@@ -4106,6 +4146,9 @@
       if (HasDefaultString) {
         size += 2 + pb::CodedOutputStream.ComputeStringSize(DefaultString);
       }
+      if (HasDefaultBytes) {
+        size += 2 + pb::CodedOutputStream.ComputeBytesSize(DefaultBytes);
+      }
       if (HasFieldname1) {
         size += 2 + pb::CodedOutputStream.ComputeInt32Size(Fieldname1);
       }
@@ -4366,6 +4409,9 @@
       if (other.HasDefaultString) {
         DefaultString = other.DefaultString;
       }
+      if (other.HasDefaultBytes) {
+        DefaultBytes = other.DefaultBytes;
+      }
       if (other.HasFieldname1) {
         Fieldname1 = other.Fieldname1;
       }
@@ -4988,6 +5034,10 @@
             DefaultString = input.ReadString();
             break;
           }
+          case 2042: {
+            DefaultBytes = input.ReadBytes();
+            break;
+          }
           case 3208: {
             Fieldname1 = input.ReadInt32();
             break;
@@ -5594,6 +5644,10 @@
             DefaultString = input.ReadString();
             break;
           }
+          case 2042: {
+            DefaultBytes = input.ReadBytes();
+            break;
+          }
           case 3208: {
             Fieldname1 = input.ReadInt32();
             break;
@@ -8043,6 +8097,209 @@
 
   }
 
+  public sealed partial class OneStringProto2 : pb::IMessage<OneStringProto2>
+  #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      , pb::IBufferMessage
+  #endif
+  {
+    private static readonly pb::MessageParser<OneStringProto2> _parser = new pb::MessageParser<OneStringProto2>(() => new OneStringProto2());
+    private pb::UnknownFieldSet _unknownFields;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pb::MessageParser<OneStringProto2> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes[5]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public OneStringProto2() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public OneStringProto2(OneStringProto2 other) : this() {
+      data_ = other.data_;
+      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public OneStringProto2 Clone() {
+      return new OneStringProto2(this);
+    }
+
+    /// <summary>Field number for the "data" field.</summary>
+    public const int DataFieldNumber = 1;
+    private readonly static string DataDefaultValue = "";
+
+    private string data_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public string Data {
+      get { return data_ ?? DataDefaultValue; }
+      set {
+        data_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+    /// <summary>Gets whether the "data" field is set</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool HasData {
+      get { return data_ != null; }
+    }
+    /// <summary>Clears the value of the "data" field</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void ClearData() {
+      data_ = null;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override bool Equals(object other) {
+      return Equals(other as OneStringProto2);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool Equals(OneStringProto2 other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Data != other.Data) return false;
+      return Equals(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (HasData) hash ^= Data.GetHashCode();
+      if (_unknownFields != null) {
+        hash ^= _unknownFields.GetHashCode();
+      }
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void WriteTo(pb::CodedOutputStream output) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      output.WriteRawMessage(this);
+    #else
+      if (HasData) {
+        output.WriteRawTag(10);
+        output.WriteString(Data);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(output);
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+      if (HasData) {
+        output.WriteRawTag(10);
+        output.WriteString(Data);
+      }
+      if (_unknownFields != null) {
+        _unknownFields.WriteTo(ref output);
+      }
+    }
+    #endif
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public int CalculateSize() {
+      int size = 0;
+      if (HasData) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Data);
+      }
+      if (_unknownFields != null) {
+        size += _unknownFields.CalculateSize();
+      }
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(OneStringProto2 other) {
+      if (other == null) {
+        return;
+      }
+      if (other.HasData) {
+        Data = other.Data;
+      }
+      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void MergeFrom(pb::CodedInputStream input) {
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+      input.ReadRawMessage(this);
+    #else
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+            break;
+          case 10: {
+            Data = input.ReadString();
+            break;
+          }
+        }
+      }
+    #endif
+    }
+
+    #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+            break;
+          case 10: {
+            Data = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+    #endif
+
+  }
+
   #endregion
 
 }
diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
index 8d39856..956c798 100644
--- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
@@ -113,52 +113,53 @@
             "CgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRIRCgltYXBfZW50cnkYByABKAgS",
             "QwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3Rv",
             "YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAkoECAQQBUoECAUQ",
-            "BkoECAYQB0oECAgQCUoECAkQCiKeAwoMRmllbGRPcHRpb25zEjoKBWN0eXBl",
+            "BkoECAYQB0oECAgQCUoECAkQCiK+AwoMRmllbGRPcHRpb25zEjoKBWN0eXBl",
             "GAEgASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZToG",
             "U1RSSU5HEg4KBnBhY2tlZBgCIAEoCBI/CgZqc3R5cGUYBiABKA4yJC5nb29n",
             "bGUucHJvdG9idWYuRmllbGRPcHRpb25zLkpTVHlwZToJSlNfTk9STUFMEhMK",
-            "BGxhenkYBSABKAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNl",
-            "EhMKBHdlYWsYCiABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9u",
-            "GOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9u",
-            "Ii8KBUNUeXBlEgoKBlNUUklORxAAEggKBENPUkQQARIQCgxTVFJJTkdfUElF",
-            "Q0UQAiI1CgZKU1R5cGUSDQoJSlNfTk9STUFMEAASDQoJSlNfU1RSSU5HEAES",
-            "DQoJSlNfTlVNQkVSEAIqCQjoBxCAgICAAkoECAQQBSJeCgxPbmVvZk9wdGlv",
-            "bnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnBy",
-            "b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKTAQoLRW51",
-            "bU9wdGlvbnMSEwoLYWxsb3dfYWxpYXMYAiABKAgSGQoKZGVwcmVjYXRlZBgD",
-            "IAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQu",
-            "Z29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICA",
-            "AkoECAUQBiJ9ChBFbnVtVmFsdWVPcHRpb25zEhkKCmRlcHJlY2F0ZWQYASAB",
-            "KAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
-            "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi",
-            "ewoOU2VydmljZU9wdGlvbnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2US",
-            "QwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3Rv",
-            "YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKtAgoNTWV0aG9k",
-            "T3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJfChFpZGVtcG90",
-            "ZW5jeV9sZXZlbBgiIAEoDjIvLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RPcHRp",
-            "b25zLklkZW1wb3RlbmN5TGV2ZWw6E0lERU1QT1RFTkNZX1VOS05PV04SQwoU",
+            "BGxhenkYBSABKAg6BWZhbHNlEh4KD3VudmVyaWZpZWRfbGF6eRgPIAEoCDoF",
+            "ZmFsc2USGQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USEwoEd2VhaxgKIAEo",
+            "CDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29v",
+            "Z2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24iLwoFQ1R5cGUSCgoG",
+            "U1RSSU5HEAASCAoEQ09SRBABEhAKDFNUUklOR19QSUVDRRACIjUKBkpTVHlw",
+            "ZRINCglKU19OT1JNQUwQABINCglKU19TVFJJTkcQARINCglKU19OVU1CRVIQ",
+            "AioJCOgHEICAgIACSgQIBBAFIl4KDE9uZW9mT3B0aW9ucxJDChR1bmludGVy",
+            "cHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRl",
+            "cnByZXRlZE9wdGlvbioJCOgHEICAgIACIpMBCgtFbnVtT3B0aW9ucxITCgth",
+            "bGxvd19hbGlhcxgCIAEoCBIZCgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRJD",
+            "ChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9i",
+            "dWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACSgQIBRAGIn0KEEVu",
+            "dW1WYWx1ZU9wdGlvbnMSGQoKZGVwcmVjYXRlZBgBIAEoCDoFZmFsc2USQwoU",
             "dW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVm",
-            "LlVuaW50ZXJwcmV0ZWRPcHRpb24iUAoQSWRlbXBvdGVuY3lMZXZlbBIXChNJ",
-            "REVNUE9URU5DWV9VTktOT1dOEAASEwoPTk9fU0lERV9FRkZFQ1RTEAESDgoK",
-            "SURFTVBPVEVOVBACKgkI6AcQgICAgAIingIKE1VuaW50ZXJwcmV0ZWRPcHRp",
-            "b24SOwoEbmFtZRgCIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl",
-            "dGVkT3B0aW9uLk5hbWVQYXJ0EhgKEGlkZW50aWZpZXJfdmFsdWUYAyABKAkS",
-            "GgoScG9zaXRpdmVfaW50X3ZhbHVlGAQgASgEEhoKEm5lZ2F0aXZlX2ludF92",
-            "YWx1ZRgFIAEoAxIUCgxkb3VibGVfdmFsdWUYBiABKAESFAoMc3RyaW5nX3Zh",
-            "bHVlGAcgASgMEhcKD2FnZ3JlZ2F0ZV92YWx1ZRgIIAEoCRozCghOYW1lUGFy",
-            "dBIRCgluYW1lX3BhcnQYASACKAkSFAoMaXNfZXh0ZW5zaW9uGAIgAigIItUB",
-            "Cg5Tb3VyY2VDb2RlSW5mbxI6Cghsb2NhdGlvbhgBIAMoCzIoLmdvb2dsZS5w",
-            "cm90b2J1Zi5Tb3VyY2VDb2RlSW5mby5Mb2NhdGlvbhqGAQoITG9jYXRpb24S",
-            "EAoEcGF0aBgBIAMoBUICEAESEAoEc3BhbhgCIAMoBUICEAESGAoQbGVhZGlu",
-            "Z19jb21tZW50cxgDIAEoCRIZChF0cmFpbGluZ19jb21tZW50cxgEIAEoCRIh",
-            "ChlsZWFkaW5nX2RldGFjaGVkX2NvbW1lbnRzGAYgAygJIqcBChFHZW5lcmF0",
-            "ZWRDb2RlSW5mbxJBCgphbm5vdGF0aW9uGAEgAygLMi0uZ29vZ2xlLnByb3Rv",
-            "YnVmLkdlbmVyYXRlZENvZGVJbmZvLkFubm90YXRpb24aTwoKQW5ub3RhdGlv",
-            "bhIQCgRwYXRoGAEgAygFQgIQARITCgtzb3VyY2VfZmlsZRgCIAEoCRINCgVi",
-            "ZWdpbhgDIAEoBRILCgNlbmQYBCABKAVCfgoTY29tLmdvb2dsZS5wcm90b2J1",
-            "ZkIQRGVzY3JpcHRvclByb3Rvc0gBWi1nb29nbGUuZ29sYW5nLm9yZy9wcm90",
-            "b2J1Zi90eXBlcy9kZXNjcmlwdG9ycGL4AQGiAgNHUEKqAhpHb29nbGUuUHJv",
-            "dG9idWYuUmVmbGVjdGlvbg=="));
+            "LlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiJ7Cg5TZXJ2aWNlT3B0",
+            "aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJl",
+            "dGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnBy",
+            "ZXRlZE9wdGlvbioJCOgHEICAgIACIq0CCg1NZXRob2RPcHRpb25zEhkKCmRl",
+            "cHJlY2F0ZWQYISABKAg6BWZhbHNlEl8KEWlkZW1wb3RlbmN5X2xldmVsGCIg",
+            "ASgOMi8uZ29vZ2xlLnByb3RvYnVmLk1ldGhvZE9wdGlvbnMuSWRlbXBvdGVu",
+            "Y3lMZXZlbDoTSURFTVBPVEVOQ1lfVU5LTk9XThJDChR1bmludGVycHJldGVk",
+            "X29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRl",
+            "ZE9wdGlvbiJQChBJZGVtcG90ZW5jeUxldmVsEhcKE0lERU1QT1RFTkNZX1VO",
+            "S05PV04QABITCg9OT19TSURFX0VGRkVDVFMQARIOCgpJREVNUE9URU5UEAIq",
+            "CQjoBxCAgICAAiKeAgoTVW5pbnRlcnByZXRlZE9wdGlvbhI7CgRuYW1lGAIg",
+            "AygLMi0uZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24uTmFt",
+            "ZVBhcnQSGAoQaWRlbnRpZmllcl92YWx1ZRgDIAEoCRIaChJwb3NpdGl2ZV9p",
+            "bnRfdmFsdWUYBCABKAQSGgoSbmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDEhQK",
+            "DGRvdWJsZV92YWx1ZRgGIAEoARIUCgxzdHJpbmdfdmFsdWUYByABKAwSFwoP",
+            "YWdncmVnYXRlX3ZhbHVlGAggASgJGjMKCE5hbWVQYXJ0EhEKCW5hbWVfcGFy",
+            "dBgBIAIoCRIUCgxpc19leHRlbnNpb24YAiACKAgi1QEKDlNvdXJjZUNvZGVJ",
+            "bmZvEjoKCGxvY2F0aW9uGAEgAygLMiguZ29vZ2xlLnByb3RvYnVmLlNvdXJj",
+            "ZUNvZGVJbmZvLkxvY2F0aW9uGoYBCghMb2NhdGlvbhIQCgRwYXRoGAEgAygF",
+            "QgIQARIQCgRzcGFuGAIgAygFQgIQARIYChBsZWFkaW5nX2NvbW1lbnRzGAMg",
+            "ASgJEhkKEXRyYWlsaW5nX2NvbW1lbnRzGAQgASgJEiEKGWxlYWRpbmdfZGV0",
+            "YWNoZWRfY29tbWVudHMYBiADKAkipwEKEUdlbmVyYXRlZENvZGVJbmZvEkEK",
+            "CmFubm90YXRpb24YASADKAsyLS5nb29nbGUucHJvdG9idWYuR2VuZXJhdGVk",
+            "Q29kZUluZm8uQW5ub3RhdGlvbhpPCgpBbm5vdGF0aW9uEhAKBHBhdGgYASAD",
+            "KAVCAhABEhMKC3NvdXJjZV9maWxlGAIgASgJEg0KBWJlZ2luGAMgASgFEgsK",
+            "A2VuZBgEIAEoBUJ+ChNjb20uZ29vZ2xlLnByb3RvYnVmQhBEZXNjcmlwdG9y",
+            "UHJvdG9zSAFaLWdvb2dsZS5nb2xhbmcub3JnL3Byb3RvYnVmL3R5cGVzL2Rl",
+            "c2NyaXB0b3JwYvgBAaICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0",
+            "aW9u"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
@@ -175,7 +176,7 @@
             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, 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", "PhpGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "SwiftPrefix", "PhpClassPrefix", "PhpNamespace", "PhpMetadataNamespace", "RubyPackage", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null, 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, 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, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "UnverifiedLazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.OneofOptions), global::Google.Protobuf.Reflection.OneofOptions.Parser, new[]{ "UninterpretedOption" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueOptions), global::Google.Protobuf.Reflection.EnumValueOptions.Parser, new[]{ "Deprecated", "UninterpretedOption" }, null, null, null, null),
@@ -2507,7 +2508,6 @@
     /// 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>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -6943,6 +6943,7 @@
       packed_ = other.packed_;
       jstype_ = other.jstype_;
       lazy_ = other.lazy_;
+      unverifiedLazy_ = other.unverifiedLazy_;
       deprecated_ = other.deprecated_;
       weak_ = other.weak_;
       uninterpretedOption_ = other.uninterpretedOption_.Clone();
@@ -7096,6 +7097,12 @@
     /// implementation must either *always* check its required fields, or *never*
     /// check its required fields, regardless of whether or not the message has
     /// been parsed.
+    ///
+    /// As of 2021, lazy does no correctness checks on the byte stream during
+    /// parsing.  This may lead to crashes if and when an invalid byte stream is
+    /// finally parsed upon access.
+    ///
+    /// TODO(b/211906113):  Enable validation on lazy fields.
     /// </summary>
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
     [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -7119,6 +7126,38 @@
       _hasBits0 &= ~8;
     }
 
+    /// <summary>Field number for the "unverified_lazy" field.</summary>
+    public const int UnverifiedLazyFieldNumber = 15;
+    private readonly static bool UnverifiedLazyDefaultValue = false;
+
+    private bool unverifiedLazy_;
+    /// <summary>
+    /// unverified_lazy does no correctness checks on the byte stream. This should
+    /// only be used where lazy with verification is prohibitive for performance
+    /// reasons.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool UnverifiedLazy {
+      get { if ((_hasBits0 & 64) != 0) { return unverifiedLazy_; } else { return UnverifiedLazyDefaultValue; } }
+      set {
+        _hasBits0 |= 64;
+        unverifiedLazy_ = value;
+      }
+    }
+    /// <summary>Gets whether the "unverified_lazy" field is set</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public bool HasUnverifiedLazy {
+      get { return (_hasBits0 & 64) != 0; }
+    }
+    /// <summary>Clears the value of the "unverified_lazy" field</summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+    public void ClearUnverifiedLazy() {
+      _hasBits0 &= ~64;
+    }
+
     /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 3;
     private readonly static bool DeprecatedDefaultValue = false;
@@ -7215,6 +7254,7 @@
       if (Packed != other.Packed) return false;
       if (Jstype != other.Jstype) return false;
       if (Lazy != other.Lazy) return false;
+      if (UnverifiedLazy != other.UnverifiedLazy) return false;
       if (Deprecated != other.Deprecated) return false;
       if (Weak != other.Weak) return false;
       if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false;
@@ -7232,6 +7272,7 @@
       if (HasPacked) hash ^= Packed.GetHashCode();
       if (HasJstype) hash ^= Jstype.GetHashCode();
       if (HasLazy) hash ^= Lazy.GetHashCode();
+      if (HasUnverifiedLazy) hash ^= UnverifiedLazy.GetHashCode();
       if (HasDeprecated) hash ^= Deprecated.GetHashCode();
       if (HasWeak) hash ^= Weak.GetHashCode();
       hash ^= uninterpretedOption_.GetHashCode();
@@ -7280,6 +7321,10 @@
         output.WriteRawTag(80);
         output.WriteBool(Weak);
       }
+      if (HasUnverifiedLazy) {
+        output.WriteRawTag(120);
+        output.WriteBool(UnverifiedLazy);
+      }
       uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec);
       if (_extensions != null) {
         _extensions.WriteTo(output);
@@ -7318,6 +7363,10 @@
         output.WriteRawTag(80);
         output.WriteBool(Weak);
       }
+      if (HasUnverifiedLazy) {
+        output.WriteRawTag(120);
+        output.WriteBool(UnverifiedLazy);
+      }
       uninterpretedOption_.WriteTo(ref output, _repeated_uninterpretedOption_codec);
       if (_extensions != null) {
         _extensions.WriteTo(ref output);
@@ -7344,6 +7393,9 @@
       if (HasLazy) {
         size += 1 + 1;
       }
+      if (HasUnverifiedLazy) {
+        size += 1 + 1;
+      }
       if (HasDeprecated) {
         size += 1 + 1;
       }
@@ -7378,6 +7430,9 @@
       if (other.HasLazy) {
         Lazy = other.Lazy;
       }
+      if (other.HasUnverifiedLazy) {
+        UnverifiedLazy = other.UnverifiedLazy;
+      }
       if (other.HasDeprecated) {
         Deprecated = other.Deprecated;
       }
@@ -7427,6 +7482,10 @@
             Weak = input.ReadBool();
             break;
           }
+          case 120: {
+            UnverifiedLazy = input.ReadBool();
+            break;
+          }
           case 7994: {
             uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec);
             break;
@@ -7472,6 +7531,10 @@
             Weak = input.ReadBool();
             break;
           }
+          case 120: {
+            UnverifiedLazy = input.ReadBool();
+            break;
+          }
           case 7994: {
             uninterpretedOption_.AddEntriesFrom(ref input, _repeated_uninterpretedOption_codec);
             break;
diff --git a/java/core/BUILD b/java/core/BUILD
index a698fc8..cf4ae7c 100644
--- a/java/core/BUILD
+++ b/java/core/BUILD
@@ -27,6 +27,7 @@
     "src/main/java/com/google/protobuf/CodedInputStreamReader.java",
     "src/main/java/com/google/protobuf/CodedOutputStream.java",
     "src/main/java/com/google/protobuf/CodedOutputStreamWriter.java",
+    "src/main/java/com/google/protobuf/CompileTimeConstant.java",
     "src/main/java/com/google/protobuf/DoubleArrayList.java",
     "src/main/java/com/google/protobuf/ExperimentalApi.java",
     "src/main/java/com/google/protobuf/ExtensionLite.java",
@@ -41,6 +42,7 @@
     "src/main/java/com/google/protobuf/FloatArrayList.java",
     "src/main/java/com/google/protobuf/GeneratedMessageInfoFactory.java",
     "src/main/java/com/google/protobuf/GeneratedMessageLite.java",
+    "src/main/java/com/google/protobuf/InlineMe.java",
     "src/main/java/com/google/protobuf/IntArrayList.java",
     "src/main/java/com/google/protobuf/Internal.java",
     "src/main/java/com/google/protobuf/InvalidProtocolBufferException.java",
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
index db44a15..bad6f19 100644
--- a/java/core/generate-test-sources-build.xml
+++ b/java/core/generate-test-sources-build.xml
@@ -4,6 +4,7 @@
         <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/map_lite_unittest.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_custom_options.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_enormous_descriptor.proto"/>
@@ -22,6 +23,7 @@
         <arg value="${test.proto.dir}/com/google/protobuf/any_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/cached_field_size_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/deprecated_file.proto"/>
+        <arg value="${test.proto.dir}/com/google/protobuf/dynamic_message_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/field_presence_test.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"/>
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 1364fce..b36c94f 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -224,7 +224,7 @@
   }
 
   /**
-   * Compares two set of fields. This method is used to implement {@link
+   * Compares two sets of fields. This method is used to implement {@link
    * AbstractMessage#equals(Object)} and {@link AbstractMutableMessage#equals(Object)}. It takes
    * special care of bytes fields because immutable messages and mutable messages use different Java
    * type to represent a bytes field and this method should be able to compare immutable messages,
@@ -242,8 +242,8 @@
       Object value2 = b.get(descriptor);
       if (descriptor.getType() == FieldDescriptor.Type.BYTES) {
         if (descriptor.isRepeated()) {
-          List list1 = (List) value1;
-          List list2 = (List) value2;
+          List<?> list1 = (List) value1;
+          List<?> list2 = (List) value2;
           if (list1.size() != list2.size()) {
             return false;
           }
@@ -383,8 +383,6 @@
       //   them to insure that they don't change after verification (since
       //   the Message interface itself cannot enforce immutability of
       //   implementations).
-      // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
-      //   which allows people to make secure deep copies of messages.
 
       for (final Map.Entry<FieldDescriptor, Object> entry : allFields.entrySet()) {
         final FieldDescriptor field = entry.getKey();
@@ -568,17 +566,6 @@
         final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
       return (BuilderType) super.mergeFrom(input, extensionRegistry);
     }
-
-    @Override
-    public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
-      return super.mergeDelimitedFrom(input);
-    }
-
-    @Override
-    public boolean mergeDelimitedFrom(
-        final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
-      return super.mergeDelimitedFrom(input, extensionRegistry);
-    }
   }
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 4e3cf42..7ad2a85 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -89,9 +89,9 @@
     final int serialized = getSerializedSize();
     final int bufferSize =
         CodedOutputStream.computePreferredBufferSize(
-            CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
+            CodedOutputStream.computeUInt32SizeNoTag(serialized) + serialized);
     final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output, bufferSize);
-    codedOutput.writeRawVarint32(serialized);
+    codedOutput.writeUInt32NoTag(serialized);
     writeTo(codedOutput);
     codedOutput.flush();
   }
@@ -316,8 +316,11 @@
 
       @Override
       public long skip(final long n) throws IOException {
-        final long result = super.skip(Math.min(n, limit));
+        // because we take the minimum of an int and a long, result is guaranteed to be
+        // less than or equal to Integer.MAX_INT so this cast is safe
+        int result = (int) super.skip(Math.min(n, limit));
         if (result >= 0) {
+          // if the superclass adheres to the contract for skip, this condition is always true
           limit -= result;
         }
         return result;
diff --git a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
index a01a6c1..94b0994 100644
--- a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
+++ b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
@@ -38,6 +38,7 @@
  * A buffer that was allocated by a {@link BufferAllocator}. For every buffer, it is guaranteed that
  * at least one of {@link #hasArray()} or {@link #hasNioBuffer()} will be {@code true}.
  */
+@CheckReturnValue
 @ExperimentalApi
 abstract class AllocatedBuffer {
   /**
@@ -106,6 +107,7 @@
    * @return This buffer
    * @throws IllegalArgumentException If the preconditions on {@code position} do not hold
    */
+  @CanIgnoreReturnValue
   public abstract AllocatedBuffer position(int position);
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
index 1217e11..65bbfd1 100644
--- a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
+++ b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
@@ -43,6 +43,7 @@
  * IndexOutOfBoundsException and convert it to protobuf's InvalidProtocolBufferException when
  * crossing protobuf public API boundaries.
  */
+@CheckReturnValue
 final class ArrayDecoders {
   /**
    * A helper used to return multiple values in a Java function. Java doesn't natively support
@@ -548,7 +549,6 @@
   }
 
   /** Decodes a packed sint64 field. Returns the position after all read values. */
-  @SuppressWarnings("unchecked")
   static int decodePackedSInt64List(
       byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException {
     final LongArrayList output = (LongArrayList) list;
diff --git a/java/core/src/main/java/com/google/protobuf/BinaryReader.java b/java/core/src/main/java/com/google/protobuf/BinaryReader.java
index d64574c..85e8616 100644
--- a/java/core/src/main/java/com/google/protobuf/BinaryReader.java
+++ b/java/core/src/main/java/com/google/protobuf/BinaryReader.java
@@ -48,6 +48,7 @@
  * A {@link Reader} that reads from a buffer containing a message serialized with the binary
  * protocol.
  */
+@CheckReturnValue
 @ExperimentalApi
 abstract class BinaryReader implements Reader {
   private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1;
@@ -271,6 +272,7 @@
       }
     }
 
+    @Deprecated
     @Override
     public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry)
         throws IOException {
@@ -278,6 +280,7 @@
       return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry);
     }
 
+    @Deprecated
     @Override
     public <T> T readGroupBySchemaWithCheck(
         Schema<T> schema, ExtensionRegistryLite extensionRegistry) throws IOException {
@@ -956,6 +959,7 @@
       }
     }
 
+    @Deprecated
     @Override
     public <T> void readGroupList(
         List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry)
@@ -964,6 +968,7 @@
       readGroupList(target, schema, extensionRegistry);
     }
 
+    @Deprecated
     @Override
     public <T> void readGroupList(
         List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
diff --git a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
index 94259ec..cf394e3 100644
--- a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
+++ b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
@@ -65,6 +65,7 @@
  * The {@link #getTotalBytesWritten()} will continue to reflect the total of the write and will not
  * be reset.
  */
+@CheckReturnValue
 @ExperimentalApi
 abstract class BinaryWriter extends ByteOutput implements Writer {
   public static final int DEFAULT_CHUNK_SIZE = 4096;
@@ -162,6 +163,7 @@
    * <p>After calling this method, the writer can not be reused. Create a new writer for future
    * writes.
    */
+  @CanIgnoreReturnValue
   public final Queue<AllocatedBuffer> complete() {
     finishCurrentBuffer();
     return buffers;
@@ -808,6 +810,7 @@
     }
   }
 
+  @Deprecated
   @Override
   public final void writeGroupList(int fieldNumber, List<?> list) throws IOException {
     for (int i = list.size() - 1; i >= 0; i--) {
@@ -815,6 +818,7 @@
     }
   }
 
+  @Deprecated
   @Override
   public final void writeGroupList(int fieldNumber, List<?> list, Schema schema)
       throws IOException {
@@ -1080,6 +1084,7 @@
       writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
     }
 
+    @Deprecated
     @Override
     public void writeGroup(int fieldNumber, Object value) throws IOException {
       writeTag(fieldNumber, WIRETYPE_END_GROUP);
@@ -1497,8 +1502,8 @@
       this.allocatedBuffer = allocatedBuffer;
       this.buffer = allocatedBuffer.array();
       int arrayOffset = allocatedBuffer.arrayOffset();
-      this.limit = arrayOffset + allocatedBuffer.limit();
-      this.offset = arrayOffset + allocatedBuffer.position();
+      this.limit = (long) arrayOffset + allocatedBuffer.limit();
+      this.offset = (long) arrayOffset + allocatedBuffer.position();
       this.offsetMinusOne = offset - 1;
       this.limitMinusOne = limit - 1;
       this.pos = limitMinusOne;
@@ -2148,6 +2153,7 @@
       writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
     }
 
+    @Deprecated
     @Override
     public void writeGroup(int fieldNumber, Object value) throws IOException {
       writeTag(fieldNumber, WIRETYPE_END_GROUP);
@@ -2162,11 +2168,13 @@
       writeTag(fieldNumber, WIRETYPE_START_GROUP);
     }
 
+    @Deprecated
     @Override
     public void writeStartGroup(int fieldNumber) {
       writeTag(fieldNumber, WIRETYPE_START_GROUP);
     }
 
+    @Deprecated
     @Override
     public void writeEndGroup(int fieldNumber) {
       writeTag(fieldNumber, WIRETYPE_END_GROUP);
@@ -2719,11 +2727,13 @@
       writeTag(fieldNumber, WIRETYPE_START_GROUP);
     }
 
+    @Deprecated
     @Override
     public void writeStartGroup(int fieldNumber) {
       writeTag(fieldNumber, WIRETYPE_START_GROUP);
     }
 
+    @Deprecated
     @Override
     public void writeEndGroup(int fieldNumber) {
       writeTag(fieldNumber, WIRETYPE_END_GROUP);
diff --git a/java/core/src/main/java/com/google/protobuf/BufferAllocator.java b/java/core/src/main/java/com/google/protobuf/BufferAllocator.java
index bfd9c72..a229539 100644
--- a/java/core/src/main/java/com/google/protobuf/BufferAllocator.java
+++ b/java/core/src/main/java/com/google/protobuf/BufferAllocator.java
@@ -36,6 +36,7 @@
  * An object responsible for allocation of buffers. This is an extension point to enable buffer
  * pooling within an application.
  */
+@CheckReturnValue
 @ExperimentalApi
 abstract class BufferAllocator {
   private static final BufferAllocator UNPOOLED =
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
index b46df5a..cd270ed 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -236,6 +236,11 @@
     return size() == 0;
   }
 
+  /** Returns an empty {@code ByteString} of size {@code 0}. */
+  public static final ByteString empty() {
+    return EMPTY;
+  }
+
   // =================================================================
   // Comparison
 
@@ -253,6 +258,38 @@
     return value & UNSIGNED_BYTE_MASK;
   }
 
+  /** Returns the numeric value of the given character in hex, or -1 if invalid. */
+  private static int hexDigit(char c) {
+    if (c >= '0' && c <= '9') {
+      return c - '0';
+    } else if (c >= 'A' && c <= 'F') {
+      return c - 'A' + 10;
+    } else if (c >= 'a' && c <= 'f') {
+      return c - 'a' + 10;
+    } else {
+      return -1;
+    }
+  }
+
+  /**
+   * Returns the numeric value of the given character at index in hexString.
+   *
+   * @throws NumberFormatException if the hexString character is invalid.
+   */
+  private static int extractHexDigit(String hexString, int index) {
+    int digit = hexDigit(hexString.charAt(index));
+    if (digit == -1) {
+      throw new NumberFormatException(
+          "Invalid hexString "
+              + hexString
+              + " must only contain [0-9a-fA-F] but contained "
+              + hexString.charAt(index)
+              + " at index "
+              + index);
+    }
+    return digit;
+  }
+
   /**
    * Compares two {@link ByteString}s lexicographically, treating their contents as unsigned byte
    * values between 0 and 255 (inclusive).
@@ -279,8 +316,8 @@
       };
 
   /**
-   * Returns a {@link Comparator} which compares {@link ByteString}-s lexicographically
-   * as sequences of unsigned byte values between 0 and 255, inclusive.
+   * Returns a {@link Comparator} which compares {@link ByteString}-s lexicographically as sequences
+   * of unsigned bytes (i.e. values between 0 and 255, inclusive).
    *
    * <p>For example, {@code (byte) -1} is considered to be greater than {@code (byte) 1} because it
    * is interpreted as an unsigned value, {@code 255}:
@@ -344,6 +381,30 @@
   }
 
   // =================================================================
+  // String -> ByteString
+
+  /**
+   * Returns a {@code ByteString} from a hexadecimal String. Alternative CharSequences should use
+   * {@link ByteStrings#decode(CharSequence, BaseEncoding)}
+   *
+   * @param hexString String of hexadecimal digits to create {@code ByteString} from.
+   * @throws NumberFormatException if the hexString does not contain a parsable hex String.
+   */
+  public static ByteString fromHex(@CompileTimeConstant String hexString) {
+    if (hexString.length() % 2 != 0) {
+      throw new NumberFormatException(
+          "Invalid hexString " + hexString + " of length " + hexString.length() + " must be even.");
+    }
+    byte[] bytes = new byte[hexString.length() / 2];
+    for (int i = 0; i < bytes.length; i++) {
+      int d1 = extractHexDigit(hexString, 2 * i);
+      int d2 = extractHexDigit(hexString, 2 * i + 1);
+      bytes[i] = (byte) (d1 << 4 | d2);
+    }
+    return new LiteralByteString(bytes);
+  }
+
+  // =================================================================
   // byte[] -> ByteString
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index 6e9c0f6..b3074b5 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -680,33 +680,33 @@
         case WireFormat.WIRETYPE_VARINT:
           {
             long value = readInt64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeUInt64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_FIXED64:
           {
             long value = readRawLittleEndian64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
           {
             ByteString value = readBytes();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeBytesNoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_START_GROUP:
           {
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             skipMessage(output);
             int endtag =
                 WireFormat.makeTag(
                     WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
             checkLastTagWas(endtag);
-            output.writeRawVarint32(endtag);
+            output.writeUInt32NoTag(endtag);
             return true;
           }
         case WireFormat.WIRETYPE_END_GROUP:
@@ -716,7 +716,7 @@
         case WireFormat.WIRETYPE_FIXED32:
           {
             int value = readRawLittleEndian32();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed32NoTag(value);
             return true;
           }
@@ -1395,33 +1395,33 @@
         case WireFormat.WIRETYPE_VARINT:
           {
             long value = readInt64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeUInt64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_FIXED64:
           {
             long value = readRawLittleEndian64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
           {
             ByteString value = readBytes();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeBytesNoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_START_GROUP:
           {
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             skipMessage(output);
             int endtag =
                 WireFormat.makeTag(
                     WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
             checkLastTagWas(endtag);
-            output.writeRawVarint32(endtag);
+            output.writeUInt32NoTag(endtag);
             return true;
           }
         case WireFormat.WIRETYPE_END_GROUP:
@@ -1431,7 +1431,7 @@
         case WireFormat.WIRETYPE_FIXED32:
           {
             int value = readRawLittleEndian32();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed32NoTag(value);
             return true;
           }
@@ -2163,33 +2163,33 @@
         case WireFormat.WIRETYPE_VARINT:
           {
             long value = readInt64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeUInt64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_FIXED64:
           {
             long value = readRawLittleEndian64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
           {
             ByteString value = readBytes();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeBytesNoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_START_GROUP:
           {
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             skipMessage(output);
             int endtag =
                 WireFormat.makeTag(
                     WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
             checkLastTagWas(endtag);
-            output.writeRawVarint32(endtag);
+            output.writeUInt32NoTag(endtag);
             return true;
           }
         case WireFormat.WIRETYPE_END_GROUP:
@@ -2199,7 +2199,7 @@
         case WireFormat.WIRETYPE_FIXED32:
           {
             int value = readRawLittleEndian32();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed32NoTag(value);
             return true;
           }
@@ -3284,33 +3284,33 @@
         case WireFormat.WIRETYPE_VARINT:
           {
             long value = readInt64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeUInt64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_FIXED64:
           {
             long value = readRawLittleEndian64();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed64NoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
           {
             ByteString value = readBytes();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeBytesNoTag(value);
             return true;
           }
         case WireFormat.WIRETYPE_START_GROUP:
           {
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             skipMessage(output);
             int endtag =
                 WireFormat.makeTag(
                     WireFormat.getTagFieldNumber(tag), WireFormat.WIRETYPE_END_GROUP);
             checkLastTagWas(endtag);
-            output.writeRawVarint32(endtag);
+            output.writeUInt32NoTag(endtag);
             return true;
           }
         case WireFormat.WIRETYPE_END_GROUP:
@@ -3320,7 +3320,7 @@
         case WireFormat.WIRETYPE_FIXED32:
           {
             int value = readRawLittleEndian32();
-            output.writeRawVarint32(tag);
+            output.writeUInt32NoTag(tag);
             output.writeFixed32NoTag(value);
             return true;
           }
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
index 7658f62..9736034 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStreamReader.java
@@ -44,6 +44,7 @@
 import java.util.Map;
 
 /** An adapter between the {@link Reader} interface and {@link CodedInputStream}. */
+@CheckReturnValue
 @ExperimentalApi
 final class CodedInputStreamReader implements Reader {
   private static final int FIXED32_MULTIPLE_MASK = FIXED32_SIZE - 1;
@@ -165,7 +166,6 @@
     return input.readStringRequireUtf8();
   }
 
-  @SuppressWarnings("unchecked")
   @Override
   public <T> T readMessage(Class<T> clazz, ExtensionRegistryLite extensionRegistry)
       throws IOException {
@@ -181,7 +181,7 @@
     return readMessage(schema, extensionRegistry);
   }
 
-  @SuppressWarnings("unchecked")
+  @Deprecated
   @Override
   public <T> T readGroup(Class<T> clazz, ExtensionRegistryLite extensionRegistry)
       throws IOException {
@@ -189,7 +189,7 @@
     return readGroup(Protobuf.getInstance().schemaFor(clazz), extensionRegistry);
   }
 
-  @SuppressWarnings("unchecked")
+  @Deprecated
   @Override
   public <T> T readGroupBySchemaWithCheck(Schema<T> schema, ExtensionRegistryLite extensionRegistry)
       throws IOException {
@@ -821,6 +821,7 @@
     }
   }
 
+  @Deprecated
   @Override
   public <T> void readGroupList(
       List<T> target, Class<T> targetType, ExtensionRegistryLite extensionRegistry)
@@ -829,6 +830,7 @@
     readGroupList(target, schema, extensionRegistry);
   }
 
+  @Deprecated
   @Override
   public <T> void readGroupList(
       List<T> target, Schema<T> schema, ExtensionRegistryLite extensionRegistry)
@@ -1314,7 +1316,7 @@
       case UINT64:
         return readUInt64();
       default:
-        throw new RuntimeException("unsupported field type.");
+        throw new IllegalArgumentException("unsupported field type.");
     }
   }
 
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 12f2097..a05c504 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -1056,7 +1056,7 @@
    */
   @Deprecated
   public static int computeGroupSize(final int fieldNumber, final MessageLite value) {
-    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+    return computeTagSize(fieldNumber) * 2 + value.getSerializedSize();
   }
 
   /**
@@ -1072,6 +1072,7 @@
 
   /** Compute the number of bytes that would be needed to encode a {@code group} field. */
   @Deprecated
+  @InlineMe(replacement = "value.getSerializedSize()")
   public static int computeGroupSizeNoTag(final MessageLite value) {
     return value.getSerializedSize();
   }
@@ -1089,6 +1090,7 @@
    * @deprecated use {@link #writeUInt32NoTag} instead.
    */
   @Deprecated
+  @InlineMe(replacement = "this.writeUInt32NoTag(value)")
   public final void writeRawVarint32(int value) throws IOException {
     writeUInt32NoTag(value);
   }
@@ -1099,6 +1101,7 @@
    * @deprecated use {@link #writeUInt64NoTag} instead.
    */
   @Deprecated
+  @InlineMe(replacement = "this.writeUInt64NoTag(value)")
   public final void writeRawVarint64(long value) throws IOException {
     writeUInt64NoTag(value);
   }
@@ -1110,6 +1113,9 @@
    * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead.
    */
   @Deprecated
+  @InlineMe(
+      replacement = "CodedOutputStream.computeUInt32SizeNoTag(value)",
+      imports = "com.google.protobuf.CodedOutputStream")
   public static int computeRawVarint32Size(final int value) {
     return computeUInt32SizeNoTag(value);
   }
@@ -1120,6 +1126,9 @@
    * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead.
    */
   @Deprecated
+  @InlineMe(
+      replacement = "CodedOutputStream.computeUInt64SizeNoTag(value)",
+      imports = "com.google.protobuf.CodedOutputStream")
   public static int computeRawVarint64Size(long value) {
     return computeUInt64SizeNoTag(value);
   }
@@ -1130,6 +1139,7 @@
    * @deprecated Use {@link #writeFixed32NoTag} instead.
    */
   @Deprecated
+  @InlineMe(replacement = "this.writeFixed32NoTag(value)")
   public final void writeRawLittleEndian32(final int value) throws IOException {
     writeFixed32NoTag(value);
   }
@@ -1140,6 +1150,7 @@
    * @deprecated Use {@link #writeFixed64NoTag} instead.
    */
   @Deprecated
+  @InlineMe(replacement = "this.writeFixed64NoTag(value)")
   public final void writeRawLittleEndian64(final long value) throws IOException {
     writeFixed64NoTag(value);
   }
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java
index 0d1983c..3f796fa 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStreamWriter.java
@@ -39,6 +39,7 @@
 import java.util.Map;
 
 /** An adapter between the {@link Writer} interface and {@link CodedOutputStream}. */
+@CheckReturnValue
 @ExperimentalApi
 final class CodedOutputStreamWriter implements Writer {
   private final CodedOutputStream output;
@@ -154,6 +155,7 @@
     output.writeMessage(fieldNumber, (MessageLite) value, schema);
   }
 
+  @Deprecated
   @Override
   public void writeGroup(int fieldNumber, Object value) throws IOException {
     output.writeGroup(fieldNumber, (MessageLite) value);
@@ -164,11 +166,13 @@
     output.writeGroup(fieldNumber, (MessageLite) value, schema);
   }
 
+  @Deprecated
   @Override
   public void writeStartGroup(int fieldNumber) throws IOException {
     output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
   }
 
+  @Deprecated
   @Override
   public void writeEndGroup(int fieldNumber) throws IOException {
     output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
@@ -561,6 +565,7 @@
     }
   }
 
+  @Deprecated
   @Override
   public void writeGroupList(int fieldNumber, List<?> value) throws IOException {
     for (int i = 0; i < value.size(); ++i) {
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
similarity index 74%
copy from java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
copy to java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
index baa6d08..dde7cf1 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
@@ -30,18 +30,18 @@
 
 package com.google.protobuf;
 
-/**
- * A prerun for a test suite that allows running the full protocol buffer tests in a mode that
- * disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
- * SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
- * code paths and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
+import static java.lang.annotation.RetentionPolicy.CLASS;
 
-  @Override
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-  }
-}
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for method parameter and class field declarations, which denotes that corresponding
+ * actual values must be compile-time constant expressions.
+ */
+@Documented
+@Retention(CLASS)
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@interface CompileTimeConstant {}
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index 0c10774..99d088a 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -278,14 +278,13 @@
     /**
      * Construct a {@code FileDescriptor}.
      *
-     * @param proto The protocol message form of the FileDescriptor.
-     * @param dependencies {@code FileDescriptor}s corresponding to all of the file's dependencies.
+     * @param proto the protocol message form of the FileDescriptort
+     * @param dependencies {@code FileDescriptor}s corresponding to all of the file's dependencies
      * @throws DescriptorValidationException {@code proto} is not a valid descriptor. This can occur
-     *     for a number of reasons, e.g. because a field has an undefined type or because two
-     *     messages were defined with the same name.
+     *     for a number of reasons; for instance, because a field has an undefined type or because
+     *     two messages were defined with the same name.
      */
-    public static FileDescriptor buildFrom(
-        final FileDescriptorProto proto, final FileDescriptor[] dependencies)
+    public static FileDescriptor buildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies)
         throws DescriptorValidationException {
       return buildFrom(proto, dependencies, false);
     }
@@ -293,18 +292,19 @@
     /**
      * Construct a {@code FileDescriptor}.
      *
-     * @param proto The protocol message form of the FileDescriptor.
-     * @param dependencies {@code FileDescriptor}s corresponding to all of the file's dependencies.
-     * @param allowUnknownDependencies If true, non-exist dependenncies will be ignored and
-     *     undefined message types will be replaced with a placeholder type.
+     * @param proto the protocol message form of the FileDescriptor
+     * @param dependencies {@code FileDescriptor}s corresponding to all of the file's dependencies
+     * @param allowUnknownDependencies if true, non-existing dependencies will be ignored and
+     *     undefined message types will be replaced with a placeholder type. Undefined enum types
+     *     still cause a DescriptorValidationException.
      * @throws DescriptorValidationException {@code proto} is not a valid descriptor. This can occur
-     *     for a number of reasons, e.g. because a field has an undefined type or because two
-     *     messages were defined with the same name.
+     *     for a number of reasons; for instance, because a field has an undefined type or because
+     *     two messages were defined with the same name.
      */
     public static FileDescriptor buildFrom(
-        final FileDescriptorProto proto,
-        final FileDescriptor[] dependencies,
-        final boolean allowUnknownDependencies)
+        FileDescriptorProto proto,
+        FileDescriptor[] dependencies,
+        boolean allowUnknownDependencies)
         throws DescriptorValidationException {
       // Building descriptors involves two steps:  translating and linking.
       // In the translation step (implemented by FileDescriptor's
@@ -315,8 +315,8 @@
       // FieldDescriptor for an embedded message contains a pointer directly
       // to the Descriptor for that message's type.  We also detect undefined
       // types in the linking step.
-      final DescriptorPool pool = new DescriptorPool(dependencies, allowUnknownDependencies);
-      final FileDescriptor result =
+      DescriptorPool pool = new DescriptorPool(dependencies, allowUnknownDependencies);
+      FileDescriptor result =
           new FileDescriptor(proto, dependencies, pool, allowUnknownDependencies);
       result.crossLink();
       return result;
@@ -1837,8 +1837,8 @@
       // The number represents an unknown enum value.
       synchronized (this) {
         if (cleanupQueue == null) {
-          cleanupQueue = new ReferenceQueue<EnumValueDescriptor>();
-          unknownValues = new HashMap<Integer, WeakReference<EnumValueDescriptor>>();
+          cleanupQueue = new ReferenceQueue<>();
+          unknownValues = new HashMap<>();
         } else {
           while (true) {
             UnknownEnumValueReference toClean = (UnknownEnumValueReference) cleanupQueue.poll();
@@ -2415,7 +2415,7 @@
     }
 
     private final Set<FileDescriptor> dependencies;
-    private boolean allowUnknownDependencies;
+    private final boolean allowUnknownDependencies;
 
     private final Map<String, GenericDescriptor> descriptorsByName = new HashMap<>();
 
@@ -2475,7 +2475,6 @@
         final GenericDescriptor relativeTo,
         final DescriptorPool.SearchFilter filter)
         throws DescriptorValidationException {
-      // TODO(kenton):  This could be optimized in a number of ways.
 
       GenericDescriptor result;
       String fullname;
@@ -2547,11 +2546,11 @@
           logger.warning(
               "The descriptor for message type \""
                   + name
-                  + "\" can not be found and a placeholder is created for it");
+                  + "\" cannot be found and a placeholder is created for it");
           // We create a dummy message descriptor here regardless of the
           // expected type. If the type should be message, this dummy
           // descriptor will work well and if the type should be enum, a
-          // DescriptorValidationException will be thrown latter. In either
+          // DescriptorValidationException will be thrown later. In either
           // case, the code works as expected: we allow unknown message types
           // but not unknown enum types.
           result = new Descriptor(fullname);
@@ -2766,8 +2765,7 @@
         final OneofDescriptorProto proto,
         final FileDescriptor file,
         final Descriptor parent,
-        final int index)
-        throws DescriptorValidationException {
+        final int index) {
       this.proto = proto;
       fullName = computeFullName(file, parent, proto.getName());
       this.file = file;
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index 8beebba..fee643f 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -38,6 +38,7 @@
 import com.google.protobuf.Descriptors.OneofDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -318,14 +319,14 @@
   /** Builder for {@link DynamicMessage}s. */
   public static final class Builder extends AbstractMessage.Builder<Builder> {
     private final Descriptor type;
-    private FieldSet<FieldDescriptor> fields;
+    private FieldSet.Builder<FieldDescriptor> fields;
     private final FieldDescriptor[] oneofCases;
     private UnknownFieldSet unknownFields;
 
     /** Construct a {@code Builder} for the given type. */
     private Builder(Descriptor type) {
       this.type = type;
-      this.fields = FieldSet.newFieldSet();
+      this.fields = FieldSet.newBuilder();
       this.unknownFields = UnknownFieldSet.getDefaultInstance();
       this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
     }
@@ -335,11 +336,7 @@
 
     @Override
     public Builder clear() {
-      if (fields.isImmutable()) {
-        fields = FieldSet.newFieldSet();
-      } else {
-        fields.clear();
-      }
+      fields = FieldSet.newBuilder();
       unknownFields = UnknownFieldSet.getDefaultInstance();
       return this;
     }
@@ -353,7 +350,6 @@
           throw new IllegalArgumentException(
               "mergeFrom(Message) can only merge messages of the same type.");
         }
-        ensureIsMutable();
         fields.mergeFrom(otherDynamicMessage.fields);
         mergeUnknownFields(otherDynamicMessage.unknownFields);
         for (int i = 0; i < oneofCases.length; i++) {
@@ -378,10 +374,7 @@
       if (!isInitialized()) {
         throw newUninitializedMessageException(
             new DynamicMessage(
-                type,
-                fields,
-                java.util.Arrays.copyOf(oneofCases, oneofCases.length),
-                unknownFields));
+                type, fields.build(), Arrays.copyOf(oneofCases, oneofCases.length), unknownFields));
       }
       return buildPartial();
     }
@@ -395,8 +388,8 @@
         throw newUninitializedMessageException(
                 new DynamicMessage(
                     type,
-                    fields,
-                    java.util.Arrays.copyOf(oneofCases, oneofCases.length),
+                    fields.build(),
+                    Arrays.copyOf(oneofCases, oneofCases.length),
                     unknownFields))
             .asInvalidProtocolBufferException();
       }
@@ -418,17 +411,16 @@
         }
       }
 
-      fields.makeImmutable();
       DynamicMessage result =
           new DynamicMessage(
-              type, fields, java.util.Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
+              type, fields.build(), Arrays.copyOf(oneofCases, oneofCases.length), unknownFields);
       return result;
     }
 
     @Override
     public Builder clone() {
       Builder result = new Builder(type);
-      result.fields.mergeFrom(fields);
+      result.fields.mergeFrom(fields.build());
       result.mergeUnknownFields(unknownFields);
       System.arraycopy(oneofCases, 0, result.oneofCases, 0, oneofCases.length);
       return result;
@@ -436,7 +428,17 @@
 
     @Override
     public boolean isInitialized() {
-      return DynamicMessage.isInitialized(type, fields);
+      // Check that all required fields are present.
+      for (FieldDescriptor field : type.getFields()) {
+        if (field.isRequired()) {
+          if (!fields.hasField(field)) {
+            return false;
+          }
+        }
+      }
+
+      // Check that embedded messages are initialized.
+      return fields.isInitialized();
     }
 
     @Override
@@ -517,15 +519,12 @@
     @Override
     public Builder setField(FieldDescriptor field, Object value) {
       verifyContainingType(field);
-      ensureIsMutable();
       // TODO(xiaofeng): This check should really be put in FieldSet.setField()
       // where all other such checks are done. However, currently
       // FieldSet.setField() permits Integer value for enum fields probably
       // because of some internal features we support. Should figure it out
       // and move this check to a more appropriate place.
-      if (field.getType() == FieldDescriptor.Type.ENUM) {
-        ensureEnumValueDescriptor(field, value);
-      }
+      verifyType(field, value);
       OneofDescriptor oneofDescriptor = field.getContainingOneof();
       if (oneofDescriptor != null) {
         int index = oneofDescriptor.getIndex();
@@ -550,7 +549,6 @@
     @Override
     public Builder clearField(FieldDescriptor field) {
       verifyContainingType(field);
-      ensureIsMutable();
       OneofDescriptor oneofDescriptor = field.getContainingOneof();
       if (oneofDescriptor != null) {
         int index = oneofDescriptor.getIndex();
@@ -577,7 +575,7 @@
     @Override
     public Builder setRepeatedField(FieldDescriptor field, int index, Object value) {
       verifyContainingType(field);
-      ensureIsMutable();
+      verifySingularValueType(field, value);
       fields.setRepeatedField(field, index, value);
       return this;
     }
@@ -585,7 +583,7 @@
     @Override
     public Builder addRepeatedField(FieldDescriptor field, Object value) {
       verifyContainingType(field);
-      ensureIsMutable();
+      verifySingularValueType(field, value);
       fields.addRepeatedField(field, value);
       return this;
     }
@@ -622,53 +620,116 @@
       }
     }
 
-    /** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
-    private void ensureSingularEnumValueDescriptor(FieldDescriptor field, Object value) {
-      checkNotNull(value);
-      if (!(value instanceof EnumValueDescriptor)) {
-        throw new IllegalArgumentException(
-            "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
+    /**
+     * Verifies that {@code value} is of the appropriate type, in addition to the checks already
+     * performed by {@link FieldSet.Builder}.
+     */
+    private void verifySingularValueType(FieldDescriptor field, Object value) {
+      // Most type checks are performed by FieldSet.Builder, but FieldSet.Builder is more permissive
+      // than generated Message.Builder subclasses, so we perform extra checks in this class so that
+      // DynamicMessage.Builder's semantics more closely match the semantics of generated builders.
+      switch (field.getType()) {
+        case ENUM:
+          checkNotNull(value);
+          // FieldSet.Builder accepts Integer values for enum fields.
+          if (!(value instanceof EnumValueDescriptor)) {
+            throw new IllegalArgumentException(
+                "DynamicMessage should use EnumValueDescriptor to set Enum Value.");
+          }
+          // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
+          // set incorrect EnumValueDescriptors.
+          // EnumDescriptor fieldType = field.getEnumType();
+          // EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
+          // if (fieldType != fieldValueType) {
+          //  throw new IllegalArgumentException(String.format(
+          //      "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
+          //      fieldType.getFullName(), fieldValueType.getFullName()));
+          // }
+          break;
+        case MESSAGE:
+          // FieldSet.Builder accepts Message.Builder values for message fields.
+          if (value instanceof Message.Builder) {
+            throw new IllegalArgumentException(
+                String.format(
+                    "Wrong object type used with protocol message reflection.\n"
+                        + "Field number: %d, field java type: %s, value type: %s\n",
+                    field.getNumber(),
+                    field.getLiteType().getJavaType(),
+                    value.getClass().getName()));
+          }
+          break;
+        default:
+          break;
       }
-      // TODO(xiaofeng): Re-enable this check after Orgstore is fixed to not
-      // set incorrect EnumValueDescriptors.
-      // EnumDescriptor fieldType = field.getEnumType();
-      // EnumDescriptor fieldValueType = ((EnumValueDescriptor) value).getType();
-      // if (fieldType != fieldValueType) {
-      //  throw new IllegalArgumentException(String.format(
-      //      "EnumDescriptor %s of field doesn't match EnumDescriptor %s of field value",
-      //      fieldType.getFullName(), fieldValueType.getFullName()));
-      // }
     }
 
-    /** Verifies the value for an enum field. */
-    private void ensureEnumValueDescriptor(FieldDescriptor field, Object value) {
+    /**
+     * Verifies that {@code value} is of the appropriate type, in addition to the checks already
+     * performed by {@link FieldSet.Builder}.
+     */
+    private void verifyType(FieldDescriptor field, Object value) {
       if (field.isRepeated()) {
-        for (Object item : (List) value) {
-          ensureSingularEnumValueDescriptor(field, item);
+        for (Object item : (List<?>) value) {
+          verifySingularValueType(field, item);
         }
       } else {
-        ensureSingularEnumValueDescriptor(field, value);
-      }
-    }
-
-    private void ensureIsMutable() {
-      if (fields.isImmutable()) {
-        fields = fields.clone();
+        verifySingularValueType(field, value);
       }
     }
 
     @Override
     public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
-      // TODO(xiangl): need implementation for dynamic message
-      throw new UnsupportedOperationException(
-          "getFieldBuilder() called on a dynamic message type.");
+      verifyContainingType(field);
+      // Error messages chosen for parity with GeneratedMessage.getFieldBuilder.
+      if (field.isMapField()) {
+        throw new UnsupportedOperationException("Nested builder not supported for map fields.");
+      }
+      if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+        throw new UnsupportedOperationException("getFieldBuilder() called on a non-Message type.");
+      }
+
+      Object existingValue = fields.getFieldAllowBuilders(field);
+      Message.Builder builder =
+          existingValue == null
+              ? new Builder(field.getMessageType())
+              : toMessageBuilder(existingValue);
+      fields.setField(field, builder);
+      return builder;
     }
 
     @Override
     public com.google.protobuf.Message.Builder getRepeatedFieldBuilder(
         FieldDescriptor field, int index) {
-      throw new UnsupportedOperationException(
-          "getRepeatedFieldBuilder() called on a dynamic message type.");
+      verifyContainingType(field);
+      // Error messages chosen for parity with GeneratedMessage.getRepeatedFieldBuilder.
+      if (field.isMapField()) {
+        throw new UnsupportedOperationException("Map fields cannot be repeated");
+      }
+      if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+        throw new UnsupportedOperationException(
+            "getRepeatedFieldBuilder() called on a non-Message type.");
+      }
+
+      Message.Builder builder =
+          toMessageBuilder(fields.getRepeatedFieldAllowBuilders(field, index));
+      fields.setRepeatedField(field, index, builder);
+      return builder;
+    }
+
+    private static Message.Builder toMessageBuilder(Object o) {
+      if (o instanceof Message.Builder) {
+        return (Message.Builder) o;
+      }
+
+      if (o instanceof LazyField) {
+        o = ((LazyField) o).getValue();
+      }
+      if (o instanceof Message) {
+        return ((Message) o).toBuilder();
+      }
+
+      throw new IllegalArgumentException(
+          String.format("Cannot convert %s to Message.Builder", o.getClass()));
     }
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
index aeeaee5..f0f1564 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -154,7 +154,7 @@
     return mutableExtensionsByName.get(fullName);
   }
 
-  /** Deprecated. Use {@link #findImmutableExtensionByNumber( Descriptors.Descriptor, int)} */
+  /** Deprecated. Use {@link #findImmutableExtensionByNumber(Descriptors.Descriptor, int)} */
   @Deprecated
   public ExtensionInfo findExtensionByNumber(
       final Descriptor containingType, final int fieldNumber) {
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
index 2eae22d..296d558 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchema.java
@@ -33,6 +33,7 @@
 import java.io.IOException;
 import java.util.Map;
 
+@CheckReturnValue
 abstract class ExtensionSchema<T extends FieldSet.FieldDescriptorLite<T>> {
 
   /** Returns true for messages that support extensions. */
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
index 9055851..698fc0e 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaFull.java
@@ -497,7 +497,7 @@
   Object findExtensionByNumber(
       ExtensionRegistryLite extensionRegistry, MessageLite defaultInstance, int number) {
     return ((ExtensionRegistry) extensionRegistry)
-        .findExtensionByNumber(((Message) defaultInstance).getDescriptorForType(), number);
+        .findImmutableExtensionByNumber(((Message) defaultInstance).getDescriptorForType(), number);
   }
 
   @Override
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
index 437cca2..e199ed4 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemaLite.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.Map;
 
+@CheckReturnValue
 @SuppressWarnings("unchecked")
 final class ExtensionSchemaLite extends ExtensionSchema<ExtensionDescriptor> {
 
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java b/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java
index 46ce327..2652fa5 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionSchemas.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+@CheckReturnValue
 final class ExtensionSchemas {
   private static final ExtensionSchema<?> LITE_SCHEMA = new ExtensionSchemaLite();
   private static final ExtensionSchema<?> FULL_SCHEMA = loadSchemaForFullRuntime();
diff --git a/java/core/src/main/java/com/google/protobuf/FieldInfo.java b/java/core/src/main/java/com/google/protobuf/FieldInfo.java
index 71a307a..59472df 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldInfo.java
@@ -36,6 +36,7 @@
 import java.lang.reflect.Field;
 
 /** Information for a single field in a protobuf message class. */
+@CheckReturnValue
 @ExperimentalApi
 final class FieldInfo implements Comparable<FieldInfo> {
   private final Field field;
diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
index 8d11360..0597ef7 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -387,17 +387,10 @@
    * (For repeated fields, this checks if the object is the right type to be one element of the
    * field.)
    *
-   * @throws IllegalArgumentException The value is not of the right type.
+   * @throws IllegalArgumentException the value is not of the right type
    */
   private void verifyType(final T descriptor, final Object value) {
     if (!isValidType(descriptor.getLiteType(), value)) {
-      // TODO(kenton):  When chaining calls to setField(), it can be hard to
-      //   tell from the stack trace which exact call failed, since the whole
-      //   chain is considered one line of code.  It would be nice to print
-      //   more information here, e.g. naming the field.  We used to do that.
-      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
-      //   isn't a big deal, though, since it would only really apply when using
-      //   reflection and generally people don't chain reflection setters.
       throw new IllegalArgumentException(
           String.format(
               "Wrong object type used with protocol message reflection.\n"
@@ -427,10 +420,8 @@
       case BYTE_STRING:
         return value instanceof ByteString || value instanceof byte[];
       case ENUM:
-        // TODO(kenton):  Caller must do type checking here, I guess.
         return (value instanceof Integer || value instanceof Internal.EnumLite);
       case MESSAGE:
-        // TODO(kenton):  Caller must do type checking here, I guess.
         return (value instanceof MessageLite) || (value instanceof LazyField);
     }
     return false;
@@ -458,34 +449,36 @@
     return true;
   }
 
-  @SuppressWarnings("unchecked")
   private static <T extends FieldDescriptorLite<T>> boolean isInitialized(
       final Map.Entry<T, Object> entry) {
     final T descriptor = entry.getKey();
     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
       if (descriptor.isRepeated()) {
-        for (final MessageLite element : (List<MessageLite>) entry.getValue()) {
-          if (!element.isInitialized()) {
+        for (final Object element : (List<?>) entry.getValue()) {
+          if (!isMessageFieldValueInitialized(element)) {
             return false;
           }
         }
       } else {
-        Object value = entry.getValue();
-        if (value instanceof MessageLite) {
-          if (!((MessageLite) value).isInitialized()) {
-            return false;
-          }
-        } else if (value instanceof LazyField) {
-          return true;
-        } else {
-          throw new IllegalArgumentException(
-              "Wrong object type used with protocol message reflection.");
-        }
+        return isMessageFieldValueInitialized(entry.getValue());
       }
     }
     return true;
   }
 
+  private static boolean isMessageFieldValueInitialized(Object value) {
+    if (value instanceof MessageLiteOrBuilder) {
+      // Message fields cannot have builder values in FieldSet, but can in FieldSet.Builder, and
+      // this method is used by FieldSet.Builder.isInitialized.
+      return ((MessageLiteOrBuilder) value).isInitialized();
+    } else if (value instanceof LazyField) {
+      return true;
+    } else {
+      throw new IllegalArgumentException(
+          "Wrong object type used with protocol message reflection.");
+    }
+  }
+
   /**
    * Given a field type, return the wire type.
    *
@@ -554,18 +547,15 @@
     }
   }
 
-  // TODO(kenton):  Move static parsing and serialization methods into some
-  //   other class.  Probably WireFormat.
-
   /**
    * Read a field of any primitive type for immutable messages from a CodedInputStream. Enums,
    * groups, and embedded messages are not handled by this method.
    *
-   * @param input The stream from which to read.
-   * @param type Declared type of the field.
-   * @param checkUtf8 When true, check that the input is valid utf8.
-   * @return An object representing the field's value, of the exact type which would be returned by
-   *     {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
+   * @param input the stream from which to read
+   * @param type declared type of the field
+   * @param checkUtf8 When true, check that the input is valid UTF-8
+   * @return an object representing the field's value, of the exact type which would be returned by
+   *     {@link Message#getField(Descriptors.FieldDescriptor)} for this field
    */
   public static Object readPrimitiveField(
       CodedInputStream input, final WireFormat.FieldType type, boolean checkUtf8)
@@ -737,7 +727,7 @@
         for (final Object element : valueList) {
           dataSize += computeElementSizeNoTag(type, element);
         }
-        output.writeRawVarint32(dataSize);
+        output.writeUInt32NoTag(dataSize);
         // Write the data itself, without any tags.
         for (final Object element : valueList) {
           writeElementNoTag(output, type, element);
@@ -903,7 +893,7 @@
         }
         return dataSize
             + CodedOutputStream.computeTagSize(number)
-            + CodedOutputStream.computeRawVarint32Size(dataSize);
+            + CodedOutputStream.computeUInt32SizeNoTag(dataSize);
       } else {
         int size = 0;
         for (final Object element : (List<?>) value) {
@@ -1114,10 +1104,10 @@
     public int getRepeatedFieldCount(final T descriptor) {
       if (!descriptor.isRepeated()) {
         throw new IllegalArgumentException(
-            "getRepeatedField() can only be called on repeated fields.");
+            "getRepeatedFieldCount() can only be called on repeated fields.");
       }
 
-      final Object value = getField(descriptor);
+      final Object value = getFieldAllowBuilders(descriptor);
       if (value == null) {
         return 0;
       } else {
@@ -1169,7 +1159,7 @@
 
       hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
 
-      final Object list = getField(descriptor);
+      final Object list = getFieldAllowBuilders(descriptor);
       if (list == null) {
         throw new IndexOutOfBoundsException();
       }
@@ -1194,7 +1184,7 @@
 
       verifyType(descriptor, value);
 
-      final Object existingValue = getField(descriptor);
+      final Object existingValue = getFieldAllowBuilders(descriptor);
       List<Object> list;
       if (existingValue == null) {
         list = new ArrayList<>();
@@ -1262,7 +1252,7 @@
       }
     }
 
-    @SuppressWarnings({"unchecked", "rawtypes"})
+    @SuppressWarnings("unchecked")
     private void mergeFromField(final Map.Entry<T, Object> entry) {
       final T descriptor = entry.getKey();
       Object otherValue = entry.getValue();
@@ -1271,16 +1261,16 @@
       }
 
       if (descriptor.isRepeated()) {
-        Object value = getField(descriptor);
+        List<Object> value = (List<Object>) getFieldAllowBuilders(descriptor);
         if (value == null) {
           value = new ArrayList<>();
+          fields.put(descriptor, value);
         }
-        for (Object element : (List) otherValue) {
-          ((List) value).add(FieldSet.cloneIfMutable(element));
+        for (Object element : (List<?>) otherValue) {
+          value.add(FieldSet.cloneIfMutable(element));
         }
-        fields.put(descriptor, value);
       } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
-        Object value = getField(descriptor);
+        Object value = getFieldAllowBuilders(descriptor);
         if (value == null) {
           fields.put(descriptor, FieldSet.cloneIfMutable(otherValue));
         } else {
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 7db8f32..f5cf885 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -985,7 +985,6 @@
 
     /** Get one element of a repeated extension. */
     @Override
-    @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
         final ExtensionLite<MessageType, List<Type>> extension, final int index) {
       return instance.getExtension(extension, index);
@@ -1342,7 +1341,6 @@
      *
      * @return a GeneratedMessage of the type that was serialized
      */
-    @SuppressWarnings("unchecked")
     protected Object readResolve() throws ObjectStreamException {
       try {
         Class<?> messageClass = resolveMessageClass();
@@ -1542,6 +1540,8 @@
         e = new InvalidProtocolBufferException(e);
       }
       throw e.setUnfinishedMessage(result);
+    } catch (UninitializedMessageException e) {
+      throw e.asInvalidProtocolBufferException().setUnfinishedMessage(result);
     } catch (IOException e) {
       if (e.getCause() instanceof InvalidProtocolBufferException) {
         throw (InvalidProtocolBufferException) e.getCause();
@@ -1557,7 +1557,7 @@
   }
 
   /** A static helper method for parsing a partial from byte array. */
-  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
       T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     @SuppressWarnings("unchecked") // Guaranteed by protoc
@@ -1575,6 +1575,8 @@
         e = new InvalidProtocolBufferException(e);
       }
       throw e.setUnfinishedMessage(result);
+    } catch (UninitializedMessageException e) {
+      throw e.asInvalidProtocolBufferException().setUnfinishedMessage(result);
     } catch (IOException e) {
       if (e.getCause() instanceof InvalidProtocolBufferException) {
         throw (InvalidProtocolBufferException) e.getCause();
@@ -1641,28 +1643,14 @@
   private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
       T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
-    T message;
+    CodedInputStream input = data.newCodedInput();
+    T message = parsePartialFrom(defaultInstance, input, extensionRegistry);
     try {
-      CodedInputStream input = data.newCodedInput();
-      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
-      try {
-        input.checkLastTagWas(0);
-      } catch (InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(message);
-      }
-      return message;
+      input.checkLastTagWas(0);
     } catch (InvalidProtocolBufferException e) {
-      throw e;
+      throw e.setUnfinishedMessage(message);
     }
-  }
-
-  // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
-  // ByteString.
-  private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
-      T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    return checkMessageInitialized(
-        parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
+    return message;
   }
 
   // Validates last tag.
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index 46427b3..4bad7e8 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -2726,8 +2726,7 @@
 
       @Override
       public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
-        throw new UnsupportedOperationException(
-            "Nested builder not supported for map fields.");
+        throw new UnsupportedOperationException("Map fields cannot be repeated");
       }
     }
 
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/main/java/com/google/protobuf/InlineMe.java
similarity index 61%
copy from java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
copy to java/core/src/main/java/com/google/protobuf/InlineMe.java
index baa6d08..6c81d18 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/main/java/com/google/protobuf/InlineMe.java
@@ -30,18 +30,30 @@
 
 package com.google.protobuf;
 
-/**
- * A prerun for a test suite that allows running the full protocol buffer tests in a mode that
- * disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
- * SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
- * code paths and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
 
-  @Override
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-  }
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that callers of this API should be inlined. That is, this API is trivially expressible
+ * in terms of another API, for example a method that just calls another method.
+ */
+@Documented
+@Target({METHOD, CONSTRUCTOR})
+@interface InlineMe {
+  /**
+   * What the caller should be replaced with. Local parameter names can be used in the replacement
+   * string. If you are invoking an instance method or constructor, you must include the implicit
+   * {@code this} in the replacement body. If you are invoking a static method, you must include the
+   * implicit {@code ClassName} in the replacement body.
+   */
+  String replacement();
+
+  /** The new imports to (optionally) add to the caller. */
+  String[] imports() default {};
+
+  /** The new static imports to (optionally) add to the caller. */
+  String[] staticImports() default {};
 }
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index 07e8dd1..f2f194f 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -31,6 +31,7 @@
 package com.google.protobuf;
 
 import java.lang.reflect.Method;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.AbstractList;
@@ -139,10 +140,12 @@
     ByteBuffer temp = source.duplicate();
     // We want to copy all the data in the source ByteBuffer, not just the
     // remaining bytes.
-    temp.clear();
+    // View ByteBuffer as Buffer to avoid issue with covariant return types
+    // See https://issues.apache.org/jira/browse/MRESOLVER-85
+    ((Buffer) temp).clear();
     ByteBuffer result = ByteBuffer.allocate(temp.capacity());
     result.put(temp);
-    result.clear();
+    ((Buffer) result).clear();
     return result;
   }
 
@@ -450,7 +453,6 @@
       this.valueConverter = valueConverter;
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public V get(Object key) {
       RealValue result = realMap.get(key);
@@ -549,7 +551,6 @@
         if (!(o instanceof Map.Entry)) {
           return false;
         }
-        @SuppressWarnings("unchecked")
         Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
         return getKey().equals(other.getKey()) && getValue().equals(getValue());
       }
diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
index 118a1e8..7f36e09 100644
--- a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
@@ -33,8 +33,8 @@
 import java.io.IOException;
 
 /**
- * Thrown when a protocol message being parsed is invalid in some way, e.g. it contains a malformed
- * varint or a negative byte length.
+ * Thrown when a protocol message being parsed is invalid in some way. For instance,
+ * it contains a malformed varint or a negative byte length.
  *
  * @author kenton@google.com Kenton Varda
  */
@@ -43,15 +43,23 @@
   private MessageLite unfinishedMessage = null;
   private boolean wasThrownFromInputStream;
 
-  public InvalidProtocolBufferException(final String description) {
+  public InvalidProtocolBufferException(String description) {
     super(description);
   }
 
+  public InvalidProtocolBufferException(Exception e) {
+    super(e.getMessage(), e);
+  }
+
+  public InvalidProtocolBufferException(String description, Exception e) {
+    super(description, e);
+  }
+
   public InvalidProtocolBufferException(IOException e) {
     super(e.getMessage(), e);
   }
 
-  public InvalidProtocolBufferException(final String description, IOException e) {
+  public InvalidProtocolBufferException(String description, IOException e) {
     super(description, e);
   }
 
diff --git a/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java b/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java
index ebc8561..651e5fd 100644
--- a/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/ListFieldSchema.java
@@ -38,6 +38,7 @@
 /**
  * Utility class that aids in properly manipulating list fields for either the lite or full runtime.
  */
+@CheckReturnValue
 abstract class ListFieldSchema {
   // Disallow construction.
   private ListFieldSchema() {}
diff --git a/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java b/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java
index 84ca9ae..cbd39f5 100644
--- a/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/ManifestSchemaFactory.java
@@ -35,6 +35,7 @@
 /**
  * Dynamically generates a manifest-based (i.e. table-based) schema for a given protobuf message.
  */
+@CheckReturnValue
 @ExperimentalApi
 final class ManifestSchemaFactory implements SchemaFactory {
 
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
index ca0678e..d528e1a 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -437,7 +437,6 @@
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public Builder<K, V> clone() {
       return new Builder<>(metadata, key, value, hasKey, hasValue);
     }
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
index f487736..2fe8867 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -85,7 +85,7 @@
 
   private volatile boolean isMutable;
   private volatile StorageMode mode;
-  private MutatabilityAwareMap<K, V> mapData;
+  private MutabilityAwareMap<K, V> mapData;
   private List<Message> listData;
 
   // Convert between a map entry Message and a key-value pair.
@@ -129,7 +129,7 @@
     this.converter = converter;
     this.isMutable = true;
     this.mode = mode;
-    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+    this.mapData = new MutabilityAwareMap<K, V>(this, mapData);
     this.listData = null;
   }
 
@@ -154,12 +154,11 @@
     return converter.convertKeyAndValueToMessage(key, value);
   }
 
-  @SuppressWarnings("unchecked")
   private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
     converter.convertMessageToKeyAndValue(message, map);
   }
 
-  private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) {
+  private List<Message> convertMapToList(MutabilityAwareMap<K, V> mapData) {
     List<Message> listData = new ArrayList<Message>();
     for (Map.Entry<K, V> entry : mapData.entrySet()) {
       listData.add(convertKeyAndValueToMessage(entry.getKey(), entry.getValue()));
@@ -167,12 +166,12 @@
     return listData;
   }
 
-  private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) {
+  private MutabilityAwareMap<K, V> convertListToMap(List<Message> listData) {
     Map<K, V> mapData = new LinkedHashMap<K, V>();
     for (Message item : listData) {
       convertMessageToKeyAndValue(item, mapData);
     }
-    return new MutatabilityAwareMap<K, V>(this, mapData);
+    return new MutabilityAwareMap<K, V>(this, mapData);
   }
 
   /** Returns the content of this MapField as a read-only Map. */
@@ -205,7 +204,7 @@
   }
 
   public void clear() {
-    mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
+    mapData = new MutabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
     mode = StorageMode.MAP;
   }
 
@@ -283,11 +282,11 @@
   }
 
   /** An internal map that checks for mutability before delegating. */
-  private static class MutatabilityAwareMap<K, V> implements Map<K, V> {
+  private static class MutabilityAwareMap<K, V> implements Map<K, V> {
     private final MutabilityOracle mutabilityOracle;
     private final Map<K, V> delegate;
 
-    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
+    MutabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
       this.mutabilityOracle = mutabilityOracle;
       this.delegate = delegate;
     }
@@ -349,17 +348,17 @@
 
     @Override
     public Set<K> keySet() {
-      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
+      return new MutabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
     }
 
     @Override
     public Collection<V> values() {
-      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
+      return new MutabilityAwareCollection<V>(mutabilityOracle, delegate.values());
     }
 
     @Override
     public Set<java.util.Map.Entry<K, V>> entrySet() {
-      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
+      return new MutabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
     }
 
     @Override
@@ -378,11 +377,11 @@
     }
 
     /** An internal collection that checks for mutability before delegating. */
-    private static class MutatabilityAwareCollection<E> implements Collection<E> {
+    private static class MutabilityAwareCollection<E> implements Collection<E> {
       private final MutabilityOracle mutabilityOracle;
       private final Collection<E> delegate;
 
-      MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
+      MutabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
         this.mutabilityOracle = mutabilityOracle;
         this.delegate = delegate;
       }
@@ -404,7 +403,7 @@
 
       @Override
       public Iterator<E> iterator() {
-        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+        return new MutabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
       }
 
       @Override
@@ -475,11 +474,11 @@
     }
 
     /** An internal set that checks for mutability before delegating. */
-    private static class MutatabilityAwareSet<E> implements Set<E> {
+    private static class MutabilityAwareSet<E> implements Set<E> {
       private final MutabilityOracle mutabilityOracle;
       private final Set<E> delegate;
 
-      MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
+      MutabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
         this.mutabilityOracle = mutabilityOracle;
         this.delegate = delegate;
       }
@@ -501,7 +500,7 @@
 
       @Override
       public Iterator<E> iterator() {
-        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+        return new MutabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
       }
 
       @Override
@@ -572,11 +571,11 @@
     }
 
     /** An internal iterator that checks for mutability before delegating. */
-    private static class MutatabilityAwareIterator<E> implements Iterator<E> {
+    private static class MutabilityAwareIterator<E> implements Iterator<E> {
       private final MutabilityOracle mutabilityOracle;
       private final Iterator<E> delegate;
 
-      MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
+      MutabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
         this.mutabilityOracle = mutabilityOracle;
         this.delegate = delegate;
       }
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index f792ae9..72e03d1 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -57,15 +57,14 @@
     this.isMutable = true;
   }
 
-  @SuppressWarnings({"rawtypes", "unchecked"})
-  private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite<>();
+  private static final MapFieldLite<?, ?> EMPTY_MAP_FIELD = new MapFieldLite<>();
 
   static {
     EMPTY_MAP_FIELD.makeImmutable();
   }
 
   /** Returns a singleton immutable empty MapFieldLite instance. */
-  @SuppressWarnings({"unchecked", "cast"})
+  @SuppressWarnings("unchecked")
   public static <K, V> MapFieldLite<K, V> emptyMapField() {
     return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
   }
@@ -77,7 +76,6 @@
     }
   }
 
-  @SuppressWarnings({"unchecked", "cast"})
   @Override
   public Set<Map.Entry<K, V>> entrySet() {
     return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet();
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java
index 195126e..d92a3bb 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchema.java
@@ -32,6 +32,7 @@
 
 import java.util.Map;
 
+@CheckReturnValue
 interface MapFieldSchema {
   /** Returns the map data for mutation. */
   Map<?, ?> forMutableMapData(Object mapField);
@@ -56,6 +57,7 @@
   MapEntryLite.Metadata<?, ?> forMapMetadata(Object mapDefaultEntry);
 
   /** Merges {@code srcMapField} into {@code destMapField}, and returns the merged instance. */
+  @CanIgnoreReturnValue
   Object mergeFrom(Object destMapField, Object srcMapField);
 
   /** Compute the serialized size for the map with a given field number. */
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java
index 8a8c78d..aef8ad2 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchemaLite.java
@@ -33,6 +33,7 @@
 import com.google.protobuf.MapEntryLite.Metadata;
 import java.util.Map;
 
+@CheckReturnValue
 class MapFieldSchemaLite implements MapFieldSchema {
 
   @Override
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java b/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java
index b398c61..835f95c 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldSchemas.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+@CheckReturnValue
 final class MapFieldSchemas {
   private static final MapFieldSchema FULL_SCHEMA = loadSchemaForFullRuntime();
   private static final MapFieldSchema LITE_SCHEMA = new MapFieldSchemaLite();
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
index 9b3a015..3db1c77 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -28,9 +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.
 
-// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
-//   mergeFrom*() could return BuilderType for better type-safety.
-
 package com.google.protobuf;
 
 import java.io.IOException;
@@ -41,8 +38,8 @@
  * Abstract interface implemented by Protocol Message objects.
  *
  * <p>See also {@link MessageLite}, which defines most of the methods that typical users care about.
- * {@link Message} adds to it methods that are not available in the "lite" runtime. The biggest
- * added features are introspection and reflection -- i.e., getting descriptors for the message type
+ * {@link Message} adds methods that are not available in the "lite" runtime. The biggest added
+ * features are introspection and reflection; that is, getting descriptors for the message type
  * and accessing the field values dynamically.
  *
  * @author kenton@google.com Kenton Varda
@@ -165,16 +162,13 @@
      * Get a nested builder instance for the given field.
      *
      * <p>Normally, we hold a reference to the immutable message object for the message type field.
-     * Some implementations(the generated message builders), however, can also hold a reference to
+     * Some implementations (the generated message builders) can also hold a reference to
      * the builder object (a nested builder) for the field.
      *
-     * <p>If the field is already backed up by a nested builder, the nested builder will be
-     * returned. Otherwise, a new field builder will be created and returned. The original message
-     * field (if exist) will be merged into the field builder, which will then be nested into its
+     * <p>If the field is already backed up by a nested builder, the nested builder is
+     * returned. Otherwise, a new field builder is created and returned. The original message
+     * field (if one exists) is merged into the field builder, which is then nested into its
      * parent builder.
-     *
-     * <p>NOTE: implementations that do not support nested builders will throw <code>
-     * UnsupportedOperationException</code>.
      */
     Builder getFieldBuilder(Descriptors.FieldDescriptor field);
 
@@ -182,22 +176,19 @@
      * Get a nested builder instance for the given repeated field instance.
      *
      * <p>Normally, we hold a reference to the immutable message object for the message type field.
-     * Some implementations(the generated message builders), however, can also hold a reference to
+     * Some implementations (the generated message builders) can also hold a reference to
      * the builder object (a nested builder) for the field.
      *
-     * <p>If the field is already backed up by a nested builder, the nested builder will be
-     * returned. Otherwise, a new field builder will be created and returned. The original message
-     * field (if exist) will be merged into the field builder, which will then be nested into its
+     * <p>If the field is already backed up by a nested builder, the nested builder is
+     * returned. Otherwise, a new field builder is created and returned. The original message
+     * field (if one exists) is merged into the field builder, which is then nested into its
      * parent builder.
-     *
-     * <p>NOTE: implementations that do not support nested builders will throw <code>
-     * UnsupportedOperationException</code>.
      */
     Builder getRepeatedFieldBuilder(Descriptors.FieldDescriptor field, int index);
 
     /**
-     * Sets a field to the given value. The value must be of the correct type for this field, i.e.
-     * the same type that {@link Message#getField(Descriptors.FieldDescriptor)} would return.
+     * Sets a field to the given value. The value must be of the correct type for this field, that
+     * is, the same type that {@link Message#getField(Descriptors.FieldDescriptor)} returns.
      */
     Builder setField(Descriptors.FieldDescriptor field, Object value);
 
@@ -215,10 +206,10 @@
 
     /**
      * Sets an element of a repeated field to the given value. The value must be of the correct type
-     * for this field, i.e. the same type that {@link
-     * Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would return.
+     * for this field; that is, the same type that {@link
+     * Message#getRepeatedField(Descriptors.FieldDescriptor,int)} returns.
      *
-     * @throws IllegalArgumentException The field is not a repeated field, or {@code
+     * @throws IllegalArgumentException if the field is not a repeated field, or {@code
      *     field.getContainingType() != getDescriptorForType()}.
      */
     Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
@@ -226,8 +217,8 @@
     /**
      * Like {@code setRepeatedField}, but appends the value as a new element.
      *
-     * @throws IllegalArgumentException The field is not a repeated field, or {@code
-     *     field.getContainingType() != getDescriptorForType()}.
+     * @throws IllegalArgumentException if the field is not a repeated field, or {@code
+     *     field.getContainingType() != getDescriptorForType()}
      */
     Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
 
diff --git a/java/core/src/main/java/com/google/protobuf/MessageInfo.java b/java/core/src/main/java/com/google/protobuf/MessageInfo.java
index 69e3186..399ca62 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageInfo.java
@@ -30,7 +30,8 @@
 
 package com.google.protobuf;
 
-/** A MesageInfo object describes a proto message type. */
+/** A MessageInfo object describes a proto message type. */
+@CheckReturnValue
 interface MessageInfo {
   /** Gets syntax for this type. */
   ProtoSyntax getSyntax();
diff --git a/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java
index 005c26d..3732b8e 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageInfoFactory.java
@@ -32,6 +32,7 @@
 
 /** A factory that creates {@link MessageInfo} instances for message types. */
 @ExperimentalApi
+@CheckReturnValue
 interface MessageInfoFactory {
   /** Whether the message class is supported by this factory. */
   boolean isSupported(Class<?> clazz);
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java
index bbf3036..f9b2f66 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLite.java
@@ -28,9 +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.
 
-// TODO(kenton):  Use generics?  E.g. Builder<BuilderType extends Builder>, then
-//   mergeFrom*() could return BuilderType for better type-safety.
-
 package com.google.protobuf;
 
 import java.io.IOException;
@@ -109,10 +106,10 @@
    *
    * <p>NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write any more data to the
    * stream after the message, you must somehow ensure that the parser on the receiving end does not
-   * interpret this as being part of the protocol message. This can be done e.g. by writing the size
-   * of the message before the data, then making sure to limit the input to that size on the
-   * receiving end (e.g. by wrapping the InputStream in one which limits the input). Alternatively,
-   * just use {@link #writeDelimitedTo(OutputStream)}.
+   * interpret this as being part of the protocol message. This can be done, for instance, by
+   *  writing the size of the message before the data, then making sure to limit the input to that
+   * size on the receiving end by wrapping the InputStream in one which limits the input.
+   * Alternatively, just use {@link #writeDelimitedTo(OutputStream)}.
    */
   void writeTo(OutputStream output) throws IOException;
 
@@ -183,6 +180,11 @@
      *
      * <p>Note: The caller should call {@link CodedInputStream#checkLastTagWas(int)} after calling
      * this to verify that the last tag seen was the appropriate end-group tag, or zero for EOF.
+     *
+     * @throws InvalidProtocolBufferException the bytes read are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
+     * @throws IOException an I/O error reading from the stream
      */
     Builder mergeFrom(CodedInputStream input) throws IOException;
 
@@ -190,6 +192,11 @@
      * Like {@link Builder#mergeFrom(CodedInputStream)}, but also parses extensions. The extensions
      * that you want to be able to parse must be registered in {@code extensionRegistry}. Extensions
      * not in the registry will be treated as unknown fields.
+     *
+     * @throws InvalidProtocolBufferException the bytes read are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
+     * @throws IOException an I/O error reading from the stream
      */
     Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
         throws IOException;
@@ -201,6 +208,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
@@ -209,6 +219,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
@@ -218,6 +231,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
@@ -226,6 +242,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
@@ -234,6 +253,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
@@ -243,6 +265,9 @@
      * Parse {@code data} as a message of this type and merge it with the message being built. This
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
      *
+     * @throws InvalidProtocolBufferException the bytes in data are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
      * @return this
      */
     Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
@@ -258,6 +283,10 @@
      *
      * <p>Despite usually reading the entire input, this does not close the stream.
      *
+     * @throws InvalidProtocolBufferException the bytes read are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
+     * @throws IOException an I/O error reading from the stream
      * @return this
      */
     Builder mergeFrom(InputStream input) throws IOException;
@@ -295,12 +324,25 @@
      * message (encoded as a varint) is read first, then the message data. Use {@link
      * MessageLite#writeDelimitedTo(OutputStream)} to write messages in this format.
      *
-     * @return True if successful, or false if the stream is at EOF when the method starts. Any
-     *     other error (including reaching EOF during parsing) will cause an exception to be thrown.
+     * @return true if successful, or false if the stream is at EOF when the method starts. Any
+     *     other error (including reaching EOF during parsing) causes an exception to be thrown.
+     * @throws InvalidProtocolBufferException the bytes read are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
+     * @throws IOException an I/O error reading from the stream
      */
     boolean mergeDelimitedFrom(InputStream input) throws IOException;
 
-    /** Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions. */
+    /**
+     * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
+     *
+     * @return true if successful, or false if the stream is at EOF when the method starts. Any
+     *     other error (including reaching EOF during parsing) causes an exception to be thrown.
+     * @throws InvalidProtocolBufferException the bytes read are not syntactically correct
+     *     according to the protobuf wire format specification. The data is corrupt, incomplete,
+     *     or was never a protobuf in the first place.
+     * @throws IOException an I/O error reading from the stream
+     */
     boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
         throws IOException;
   }
diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
index 9ad6816..23be614 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java
@@ -47,13 +47,16 @@
   private static final String MAP_SUFFIX = "Map";
   private static final String BYTES_SUFFIX = "Bytes";
 
+  private MessageLiteToString() {
+    // Classes which are not intended to be instantiated should be made non-instantiable with a
+    // private constructor. This includes utility classes (classes with only static members).
+  }
+
   /**
    * Returns a {@link String} representation of the {@link MessageLite} object. The first line of
-   * the {@code String} representation representation includes a comment string to uniquely identify
+   * the {@code String} representation includes a comment string to uniquely identify
    * the object instance. This acts as an indicator that this should not be relied on for
    * comparisons.
-   *
-   * <p>For use by generated code only.
    */
   static String toString(MessageLite messageLite, String commentString) {
     StringBuilder buffer = new StringBuilder();
@@ -73,9 +76,9 @@
     // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
     // getFooList() and getFooMap() which might be useful for building an object's string
     // representation.
-    Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
-    Map<String, Method> nameToMethod = new HashMap<String, Method>();
-    Set<String> getters = new TreeSet<String>();
+    Map<String, Method> nameToNoArgMethod = new HashMap<>();
+    Map<String, Method> nameToMethod = new HashMap<>();
+    Set<String> getters = new TreeSet<>();
     for (Method method : messageLite.getClass().getDeclaredMethods()) {
       nameToMethod.put(method.getName(), method);
       if (method.getParameterTypes().length == 0) {
@@ -263,7 +266,7 @@
       }
       buffer.append("}");
     } else {
-      buffer.append(": ").append(object.toString());
+      buffer.append(": ").append(object);
     }
   }
 
diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
index 4170f4f..53548c8 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
@@ -82,6 +82,7 @@
 import java.util.Map;
 
 /** Schema used for standard messages. */
+@CheckReturnValue
 final class MessageSchema<T> implements Schema<T> {
   private static final int INTS_PER_FIELD = 3;
   private static final int OFFSET_BITS = 20;
@@ -2533,7 +2534,6 @@
     return (List<?>) UnsafeUtil.getObject(message, offset);
   }
 
-  @SuppressWarnings("unchecked")
   @Override
   // TODO(nathanmittler): Consider serializing oneof fields last so that only one entry per
   // oneof is actually serialized. This would mean that we would violate the serialization order
@@ -4875,6 +4875,7 @@
    * group (endGroup != 0), parsing ends when a tag == endGroup is encountered and the position
    * after that tag is returned.
    */
+  @CanIgnoreReturnValue
   int parseProto2Message(
       T message, byte[] data, int position, int limit, int endGroup, Registers registers)
       throws IOException {
@@ -5184,6 +5185,7 @@
   }
 
   /** Parses a proto3 message and returns the limit if parsing is successful. */
+  @CanIgnoreReturnValue
   private int parseProto3Message(
       T message, byte[] data, int position, int limit, Registers registers) throws IOException {
     final sun.misc.Unsafe unsafe = UNSAFE;
diff --git a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
index 187dc8b..71ad750 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
@@ -35,6 +35,7 @@
 import java.util.Map.Entry;
 
 /** Schema used for proto2 messages using message_set_wireformat. */
+@CheckReturnValue
 final class MessageSetSchema<T> implements Schema<T> {
   private final MessageLite defaultInstance;
   private final UnknownFieldSchema<?, ?> unknownFieldSchema;
@@ -231,7 +232,6 @@
    * A helper method for wildcard capture of {@code unknownFieldSchema}. See:
    * https://docs.oracle.com/javase/tutorial/java/generics/capture.html
    */
-  @SuppressWarnings("unchecked")
   private <UT, UB, ET extends FieldSet.FieldDescriptorLite<ET>> void mergeFromHelper(
       UnknownFieldSchema<UT, UB> unknownFieldSchema,
       ExtensionSchema<ET> extensionSchema,
diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java
index f2dbb8e..9bffd8e 100644
--- a/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchema.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+@CheckReturnValue
 interface NewInstanceSchema {
   /** Create a new message instance given the default instance of the message type. */
   Object newInstance(Object defaultInstance);
diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
index 9b92266..7ee9285 100644
--- a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
+++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemaLite.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+@CheckReturnValue
 final class NewInstanceSchemaLite implements NewInstanceSchema {
   @Override
   public Object newInstance(Object defaultInstance) {
diff --git a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java
index eff45f6..6e9031a 100644
--- a/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java
+++ b/java/core/src/main/java/com/google/protobuf/NewInstanceSchemas.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+@CheckReturnValue
 final class NewInstanceSchemas {
   private static final NewInstanceSchema FULL_SCHEMA = loadSchemaForFullRuntime();
   private static final NewInstanceSchema LITE_SCHEMA = new NewInstanceSchemaLite();
diff --git a/java/core/src/main/java/com/google/protobuf/OneofInfo.java b/java/core/src/main/java/com/google/protobuf/OneofInfo.java
index bc518fc..4301055 100644
--- a/java/core/src/main/java/com/google/protobuf/OneofInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/OneofInfo.java
@@ -35,6 +35,7 @@
 /** Information for a oneof within a protobuf message. */
 // TODO(nathanmittler): make this private once all of experimental code is migrated to protobuf.
 @ExperimentalApi
+@CheckReturnValue
 final class OneofInfo {
   private final int id;
   private final Field caseField;
diff --git a/java/core/src/main/java/com/google/protobuf/Protobuf.java b/java/core/src/main/java/com/google/protobuf/Protobuf.java
index 0affac5..74624c3 100644
--- a/java/core/src/main/java/com/google/protobuf/Protobuf.java
+++ b/java/core/src/main/java/com/google/protobuf/Protobuf.java
@@ -41,6 +41,7 @@
  * than directly accessing internal APIs) in order to perform operations on protobuf messages.
  */
 @ExperimentalApi
+@CheckReturnValue
 final class Protobuf {
   private static final Protobuf INSTANCE = new Protobuf();
 
@@ -127,6 +128,7 @@
    * @return the previously registered schema, or {@code null} if no schema was registered
    *     previously.
    */
+  @CanIgnoreReturnValue
   public Schema<?> registerSchemaOverride(Class<?> messageType, Schema<?> schema) {
     checkNotNull(messageType, "messageType");
     checkNotNull(schema, "schema");
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufLists.java b/java/core/src/main/java/com/google/protobuf/ProtobufLists.java
index 271c849..018c911 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtobufLists.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufLists.java
@@ -39,6 +39,7 @@
 
 /** Utility class for construction of lists that extend {@link ProtobufList}. */
 @ExperimentalApi
+@CheckReturnValue
 final class ProtobufLists {
   private ProtobufLists() {}
 
diff --git a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
index 1735a08..2e58574 100644
--- a/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/RawMessageInfo.java
@@ -34,6 +34,7 @@
  * RawMessageInfo stores the same amount of information as {@link MessageInfo} but in a more compact
  * format.
  */
+@CheckReturnValue
 final class RawMessageInfo implements MessageInfo {
 
   private final MessageLite defaultInstance;
diff --git a/java/core/src/main/java/com/google/protobuf/Reader.java b/java/core/src/main/java/com/google/protobuf/Reader.java
index 705096f..7497eea 100644
--- a/java/core/src/main/java/com/google/protobuf/Reader.java
+++ b/java/core/src/main/java/com/google/protobuf/Reader.java
@@ -37,6 +37,7 @@
 /** A reader of fields from a serialized protobuf message. */
 // TODO(nathanmittler): Refactor to allow the reader to allocate properly sized lists.
 @ExperimentalApi
+@CheckReturnValue
 interface Reader {
   /** Value used to indicate that the end of input has been reached. */
   int READ_DONE = Integer.MAX_VALUE;
diff --git a/java/core/src/main/java/com/google/protobuf/Schema.java b/java/core/src/main/java/com/google/protobuf/Schema.java
index d0e1e26..efb3c1e 100644
--- a/java/core/src/main/java/com/google/protobuf/Schema.java
+++ b/java/core/src/main/java/com/google/protobuf/Schema.java
@@ -38,6 +38,7 @@
  * such as serialization/deserialization.
  */
 @ExperimentalApi
+@CheckReturnValue
 interface Schema<T> {
   /** Writes the given message to the target {@link Writer}. */
   void writeTo(T message, Writer writer) throws IOException;
diff --git a/java/core/src/main/java/com/google/protobuf/SchemaFactory.java b/java/core/src/main/java/com/google/protobuf/SchemaFactory.java
index cf38dd6..33d9c9d 100644
--- a/java/core/src/main/java/com/google/protobuf/SchemaFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/SchemaFactory.java
@@ -32,6 +32,7 @@
 
 /** A factory that manufactures {@link Schema} instances for protobuf messages. */
 @ExperimentalApi
+@CheckReturnValue
 interface SchemaFactory {
   /** Creates a schema instance for the given protobuf message type. */
   <T> Schema<T> createSchema(Class<T> messageType);
diff --git a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
index 1d5e6ba..06f3ab7 100644
--- a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java
@@ -41,6 +41,7 @@
 
 /** Helper methods used by schemas. */
 @ExperimentalApi
+@CheckReturnValue
 final class SchemaUtil {
   private static final Class<?> GENERATED_MESSAGE_CLASS = getGeneratedMessageClass();
   private static final UnknownFieldSchema<?, ?> PROTO2_UNKNOWN_FIELD_SET_SCHEMA =
@@ -980,6 +981,7 @@
   }
 
   /** Stores an unrecognized enum value as an unknown value. */
+  @CanIgnoreReturnValue
   static <UT, UB> UB storeUnknownEnum(
       int number, int enumValue, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema) {
     if (unknownFields == null) {
diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
index 546e56e..db635345 100644
--- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
+++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java
@@ -374,7 +374,6 @@
    * @return a {@link SortedMap} to which overflow entries mappings can be added or removed.
    * @throws UnsupportedOperationException if {@link #makeImmutable()} has been called.
    */
-  @SuppressWarnings("unchecked")
   private SortedMap<K, V> getOverflowEntriesMutable() {
     checkMutable();
     if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) {
@@ -441,7 +440,6 @@
       if (!(o instanceof Map.Entry)) {
         return false;
       }
-      @SuppressWarnings("unchecked")
       Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
       return equals(key, other.getKey()) && equals(value, other.getValue());
     }
diff --git a/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java b/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java
index a32b143..defb53e 100644
--- a/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java
+++ b/java/core/src/main/java/com/google/protobuf/StructuralMessageInfo.java
@@ -41,6 +41,7 @@
  * contained within a message.
  */
 @ExperimentalApi
+@CheckReturnValue
 final class StructuralMessageInfo implements MessageInfo {
   private final ProtoSyntax syntax;
   private final boolean messageSetWireFormat;
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index eff10af..d9ca03e 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -68,6 +68,9 @@
    * @deprecated Use {@code printer().print(MessageOrBuilder, Appendable)}
    */
   @Deprecated
+  @InlineMe(
+      replacement = "TextFormat.printer().print(message, output)",
+      imports = "com.google.protobuf.TextFormat")
   public static void print(final MessageOrBuilder message, final Appendable output)
       throws IOException {
     printer().print(message, output);
@@ -90,6 +93,9 @@
    * @deprecated Use {@code printer().escapingNonAscii(false).print(MessageOrBuilder, Appendable)}
    */
   @Deprecated
+  @InlineMe(
+      replacement = "TextFormat.printer().escapingNonAscii(false).print(message, output)",
+      imports = "com.google.protobuf.TextFormat")
   public static void printUnicode(final MessageOrBuilder message, final Appendable output)
       throws IOException {
     printer().escapingNonAscii(false).print(message, output);
@@ -143,6 +149,9 @@
    * @deprecated Use {@code message.toString()}
    */
   @Deprecated
+  @InlineMe(
+      replacement = "TextFormat.printer().printToString(message)",
+      imports = "com.google.protobuf.TextFormat")
   public static String printToString(final MessageOrBuilder message) {
     return printer().printToString(message);
   }
@@ -164,6 +173,9 @@
    * @deprecated Use {@code printer().escapingNonAscii(false).printToString(MessageOrBuilder)}
    */
   @Deprecated
+  @InlineMe(
+      replacement = "TextFormat.printer().escapingNonAscii(false).printToString(message)",
+      imports = "com.google.protobuf.TextFormat")
   public static String printToUnicodeString(final MessageOrBuilder message) {
     return printer().escapingNonAscii(false).printToString(message);
   }
@@ -225,6 +237,9 @@
    * @throws IOException if there is an exception writing to the output
    */
   @Deprecated
+  @InlineMe(
+      replacement = "TextFormat.printer().printFieldValue(field, value, output)",
+      imports = "com.google.protobuf.TextFormat")
   public static void printFieldValue(
       final FieldDescriptor field, final Object value, final Appendable output) throws IOException {
     printer().printFieldValue(field, value, output);
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
index e736d5c..681b824 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
@@ -33,6 +33,7 @@
 import java.io.IOException;
 
 @ExperimentalApi
+@CheckReturnValue
 abstract class UnknownFieldSchema<T, B> {
 
   /** Whether unknown fields should be dropped. */
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
index ffd7232..7b70fca 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLiteSchema.java
@@ -32,6 +32,7 @@
 
 import java.io.IOException;
 
+@CheckReturnValue
 class UnknownFieldSetLiteSchema
     extends UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> {
 
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
index bcaf1d2..16521e1 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -35,7 +35,7 @@
 
 /**
  * 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
+ * performance requirements. These methods are referred to as "unsafe" because 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
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 7c9133e..c878751 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -102,10 +102,10 @@
    * State value indicating that the byte sequence is well-formed and complete (no further bytes are
    * needed to complete a character).
    */
-  public static final int COMPLETE = 0;
+  static final int COMPLETE = 0;
 
   /** State value indicating that the byte sequence is definitely not well-formed. */
-  public static final int MALFORMED = -1;
+  static final int MALFORMED = -1;
 
   /**
    * Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length
@@ -143,7 +143,7 @@
    * <p>This is a convenience method, equivalent to a call to {@code isValidUtf8(bytes, 0,
    * bytes.length)}.
    */
-  public static boolean isValidUtf8(byte[] bytes) {
+  static boolean isValidUtf8(byte[] bytes) {
     return processor.isValidUtf8(bytes, 0, bytes.length);
   }
 
@@ -155,7 +155,7 @@
    * <p>This is a convenience method, equivalent to {@code partialIsValidUtf8(bytes, index, limit)
    * == Utf8.COMPLETE}.
    */
-  public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
+  static boolean isValidUtf8(byte[] bytes, int index, int limit) {
     return processor.isValidUtf8(bytes, index, limit);
   }
 
@@ -172,7 +172,7 @@
    *     "state" value containing enough information to decode the character when passed to a
    *     subsequent invocation of a partial decoding method.
    */
-  public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
+  static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) {
     return processor.partialIsValidUtf8(state, bytes, index, limit);
   }
 
@@ -572,7 +572,7 @@
             return incompleteStateFor(buffer, byte1, index, limit - index);
           }
 
-          final byte byte2 = buffer.get(index++);
+          byte byte2 = buffer.get(index++);
           if (byte2 > (byte) 0xBF
               // overlong? 5 most significant bits must not all be zero
               || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
@@ -591,7 +591,7 @@
           }
 
           // TODO(nathanmittler): Consider using getInt() to improve performance.
-          final int byte2 = buffer.get(index++);
+          int byte2 = buffer.get(index++);
           if (byte2 > (byte) 0xBF
               // Check that 1 <= plane <= 16.  Tricky optimized form of:
               // if (byte1 > (byte) 0xF4 ||
@@ -611,7 +611,7 @@
     /**
      * Decodes the given byte array slice into a {@link String}.
      *
-     * @throws InvalidProtocolBufferException if the byte array slice is not valid UTF-8.
+     * @throws InvalidProtocolBufferException if the byte array slice is not valid UTF-8
      */
     abstract String decodeUtf8(byte[] bytes, int index, int size)
         throws InvalidProtocolBufferException;
@@ -619,7 +619,7 @@
     /**
      * Decodes the given portion of the {@link ByteBuffer} into a {@link String}.
      *
-     * @throws InvalidProtocolBufferException if the portion of the buffer is not valid UTF-8.
+     * @throws InvalidProtocolBufferException if the portion of the buffer is not valid UTF-8
      */
     final String decodeUtf8(ByteBuffer buffer, int index, int size)
         throws InvalidProtocolBufferException {
@@ -649,7 +649,7 @@
       }
 
       int offset = index;
-      final int limit = offset + size;
+      int limit = offset + size;
 
       // The longest possible resulting String is the same as the number of input bytes, when it is
       // all ASCII. For other cases, this over-allocates and we will truncate in the end.
@@ -1907,12 +1907,24 @@
       return b >= 0;
     }
 
-    /** Returns whether this is a two-byte codepoint with the form '10XXXXXX'. */
+    /**
+     * Returns whether this is a two-byte codepoint with the form '10XXXXXX' iff
+     * {@link #isOneByte(byte)} is false. This private method works in the limited use in
+     * this class where this method is only called when {@link #isOneByte(byte)} has already
+     * returned false. It is not suitable for general or public use.
+     */
     private static boolean isTwoBytes(byte b) {
       return b < (byte) 0xE0;
     }
 
-    /** Returns whether this is a three-byte codepoint with the form '110XXXXX'. */
+    /**
+     * Returns whether this is a three-byte codepoint with the form '110XXXXX' iff
+     * {@link #isOneByte(byte)} and {@link #isTwoBytes(byte)} are false.
+     * This private method works in the limited use in
+     * this class where this method is only called when {@link #isOneByte(byte)} an
+     * {@link #isTwoBytes(byte)} have already returned false. It is not suitable for general
+     * or public use.
+     */
     private static boolean isThreeBytes(byte b) {
       return b < (byte) 0xF0;
     }
diff --git a/java/core/src/main/java/com/google/protobuf/Writer.java b/java/core/src/main/java/com/google/protobuf/Writer.java
index 3f95c32..3550058 100644
--- a/java/core/src/main/java/com/google/protobuf/Writer.java
+++ b/java/core/src/main/java/com/google/protobuf/Writer.java
@@ -36,6 +36,7 @@
 
 /** A writer that performs serialization of protobuf message fields. */
 @ExperimentalApi
+@CheckReturnValue
 interface Writer {
 
   /** The order in which the fields are written by a {@link Writer}. */
diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
index 3f97e31..f0035be 100644
--- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java
@@ -69,16 +69,16 @@
     return result;
   }
 
-  private byte[] getTestBytes(int size) {
+  private static byte[] getTestBytes(int size) {
     return getTestBytes(size, 445566L);
   }
 
-  private byte[] getTestBytes() {
+  private static byte[] getTestBytes() {
     return getTestBytes(1000);
   }
 
   // Compare the entire left array with a subset of the right array.
-  private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
+  private static boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
     boolean stillEqual = (left.length == length);
     for (int i = 0; (stillEqual && i < length); ++i) {
       stillEqual = (left[i] == right[rightOffset + i]);
@@ -87,7 +87,7 @@
   }
 
   // Returns true only if the given two arrays have identical contents.
-  private boolean isArray(byte[] left, byte[] right) {
+  private static boolean isArray(byte[] left, byte[] right) {
     return left.length == right.length && isArrayRange(left, right, 0, left.length);
   }
 
@@ -134,7 +134,7 @@
   }
 
   @Test
-  public void testSubstring_BeginIndex() {
+  public void testSubstring_beginIndex() {
     byte[] bytes = getTestBytes();
     ByteString substring = ByteString.copyFrom(bytes).substring(500);
     assertWithMessage("substring must contain the tail of the string")
@@ -143,7 +143,66 @@
   }
 
   @Test
-  public void testCopyFrom_BytesOffsetSize() {
+  public void testEmpty_isEmpty() {
+    ByteString byteString = ByteString.empty();
+    assertThat(byteString.isEmpty()).isTrue();
+    assertWithMessage("ByteString.empty() must return empty byte array")
+        .that(isArray(byteString.toByteArray(), new byte[] {}))
+        .isTrue();
+  }
+
+  @Test
+  public void testEmpty_referenceEquality() {
+    assertThat(ByteString.empty()).isSameInstanceAs(ByteString.EMPTY);
+    assertThat(ByteString.empty()).isSameInstanceAs(ByteString.empty());
+  }
+
+  @Test
+  public void testFromHex_hexString() {
+    ByteString byteString;
+    byteString = ByteString.fromHex("0a0b0c");
+    assertWithMessage("fromHex must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), new byte[] {0x0a, 0x0b, 0x0c}))
+        .isTrue();
+
+    byteString = ByteString.fromHex("0A0B0C");
+    assertWithMessage("fromHex must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), new byte[] {0x0a, 0x0b, 0x0c}))
+        .isTrue();
+
+    byteString = ByteString.fromHex("0a0b0c0d0e0f");
+    assertWithMessage("fromHex must contain the expected bytes")
+        .that(isArray(byteString.toByteArray(), new byte[] {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}))
+        .isTrue();
+  }
+
+  @Test
+  @SuppressWarnings("AlwaysThrows") // Verifying that indeed these calls do throw.
+  public void testFromHex_invalidHexString() {
+    try {
+      ByteString.fromHex("a0b0c");
+      assertWithMessage("Should throw").fail();
+    } catch (NumberFormatException expected) {
+      assertThat(expected).hasMessageThat().contains("even");
+    }
+
+    try {
+      ByteString.fromHex("0x0y0z");
+      assertWithMessage("Should throw").fail();
+    } catch (NumberFormatException expected) {
+      assertThat(expected).hasMessageThat().contains("[0-9a-fA-F]");
+    }
+
+    try {
+      ByteString.fromHex("0à««");
+      assertWithMessage("Should throw").fail();
+    } catch (NumberFormatException expected) {
+      assertThat(expected).hasMessageThat().contains("[0-9a-fA-F]");
+    }
+  }
+
+  @Test
+  public void testCopyFrom_bytesOffsetSize() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
     assertWithMessage("copyFrom sub-range must contain the expected bytes")
@@ -152,7 +211,7 @@
   }
 
   @Test
-  public void testCopyFrom_Bytes() {
+  public void testCopyFrom_bytes() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes);
     assertWithMessage("copyFrom must contain the expected bytes")
@@ -161,7 +220,7 @@
   }
 
   @Test
-  public void testCopyFrom_ByteBufferSize() {
+  public void testCopyFrom_byteBufferSize() {
     byte[] bytes = getTestBytes();
     ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
     byteBuffer.put(bytes);
@@ -173,7 +232,7 @@
   }
 
   @Test
-  public void testCopyFrom_ByteBuffer() {
+  public void testCopyFrom_byteBuffer() {
     byte[] bytes = getTestBytes();
     ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
     byteBuffer.put(bytes);
@@ -185,7 +244,7 @@
   }
 
   @Test
-  public void testCopyFrom_StringEncoding() {
+  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);
@@ -195,7 +254,7 @@
   }
 
   @Test
-  public void testCopyFrom_Utf8() {
+  public void testCopyFrom_utf8() {
     String testString = "I love unicode \u1234\u5678 characters";
     ByteString byteString = ByteString.copyFromUtf8(testString);
     byte[] testBytes = testString.getBytes(Internal.UTF_8);
@@ -205,7 +264,7 @@
   }
 
   @Test
-  public void testCopyFrom_Iterable() {
+  public void testCopyFrom_iterable() {
     byte[] testBytes = getTestBytes(77777, 113344L);
     final List<ByteString> pieces = makeConcretePieces(testBytes);
     // Call copyFrom() on a Collection
@@ -228,7 +287,7 @@
   }
 
   @Test
-  public void testCopyFrom_LengthTooBig() {
+  public void testCopyFrom_lengthTooBig() {
     byte[] testBytes = getTestBytes(100);
     try {
       ByteString.copyFrom(testBytes, 0, 200);
@@ -257,7 +316,7 @@
   }
 
   @Test
-  public void testCopyTo_TargetOffset() {
+  public void testCopyTo_targetOffset() {
     byte[] bytes = getTestBytes();
     ByteString byteString = ByteString.copyFrom(bytes);
     byte[] target = new byte[bytes.length + 1000];
@@ -353,7 +412,7 @@
 
   // Tests that IOExceptions propagate through ByteString.readFrom().
   @Test
-  public void testReadFrom_IOExceptions() {
+  public void testReadFrom_iOExceptions() {
     try {
       ByteString.readFrom(new FailStream());
       assertWithMessage("readFrom must throw the underlying IOException").fail();
@@ -547,7 +606,7 @@
   }
 
   @Test
-  public void testNewOutput_InitialCapacity() throws IOException {
+  public void testNewOutput_initialCapacity() throws IOException {
     byte[] bytes = getTestBytes();
     ByteString.Output output = ByteString.newOutput(bytes.length + 100);
     output.write(bytes);
@@ -560,7 +619,7 @@
   // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
   // write sizes
   @Test
-  public void testNewOutput_ArrayWrite() {
+  public void testNewOutput_arrayWrite() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
     int[] bufferSizes = {
@@ -586,7 +645,7 @@
   // Test newOutput() using a variety of buffer sizes, but writing all the
   // characters using write(byte);
   @Test
-  public void testNewOutput_WriteChar() {
+  public void testNewOutput_writeChar() {
     byte[] bytes = getTestBytes();
     int length = bytes.length;
     int[] bufferSizes = {
@@ -607,7 +666,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.
   @Test
-  public void testNewOutput_Mixed() {
+  public void testNewOutput_mixed() {
     Random rng = new Random(1);
     byte[] bytes = getTestBytes();
     int length = bytes.length;
@@ -649,7 +708,7 @@
   }
 
   @Test
-  public void testNewOutput_Mutating() throws IOException {
+  public void testNewOutput_mutating() throws IOException {
     Output os = ByteString.newOutput(5);
     os.write(new byte[] {1, 2, 3, 4, 5});
     EvilOutputStream eos = new EvilOutputStream();
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index f5bb31f..1ebf457 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -540,8 +540,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(0x7FFFFFFF);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(0x7FFFFFFF);
     output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
     output.flush();
 
@@ -747,11 +747,11 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.writeRawByte(4);
     output.flush();
@@ -796,8 +796,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.flush();
 
@@ -851,8 +851,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.flush();
 
@@ -878,8 +878,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.flush();
 
@@ -902,8 +902,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
@@ -926,8 +926,8 @@
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
 
     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    output.writeRawVarint32(tag);
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(tag);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 0x80});
     output.flush();
 
@@ -985,19 +985,19 @@
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
     // Zero-sized bytes field.
-    output.writeRawVarint32(0);
+    output.writeUInt32NoTag(0);
     // One one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
     bytes[0] = (byte) 67;
     bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
+    output.writeUInt32NoTag(bytesLength);
     output.writeRawBytes(bytes);
 
     output.flush();
@@ -1029,7 +1029,7 @@
     }
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.flush();
     byte[] data = rawOutput.toByteString().toByteArray();
@@ -1054,7 +1054,7 @@
     }
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
-    output.writeRawVarint32(bytes.length);
+    output.writeUInt32NoTag(bytes.length);
     output.writeRawBytes(bytes);
     output.flush();
     byte[] data = rawOutput.toByteString().toByteArray();
@@ -1076,19 +1076,19 @@
     ByteString.Output rawOutput = ByteString.newOutput();
     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
     // Zero-sized bytes field.
-    output.writeRawVarint32(0);
+    output.writeUInt32NoTag(0);
     // One one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
     bytes[0] = (byte) 67;
     bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
+    output.writeUInt32NoTag(bytesLength);
     output.writeRawBytes(bytes);
 
     output.flush();
@@ -1118,19 +1118,19 @@
     ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
     // Zero-sized bytes field.
-    output.writeRawVarint32(0);
+    output.writeUInt32NoTag(0);
     // One one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 23});
     // Another one-byte bytes field
-    output.writeRawVarint32(1);
+    output.writeUInt32NoTag(1);
     output.writeRawBytes(new byte[] {(byte) 45});
     // A bytes field large enough that won't fit into the 4K buffer.
     final int bytesLength = 16 * 1024;
     byte[] bytes = new byte[bytesLength];
     bytes[0] = (byte) 67;
     bytes[bytesLength - 1] = (byte) 89;
-    output.writeRawVarint32(bytesLength);
+    output.writeUInt32NoTag(bytesLength);
     output.writeRawBytes(bytes);
     output.flush();
 
diff --git a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
index 9934ca1..eb24dde 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -399,7 +399,7 @@
   public void testWriteMessageWithNegativeEnumValue() throws Exception {
     SparseEnumMessage message =
         SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build();
-    assertThat(message.getSparseEnum().getNumber() < 0).isTrue();
+    assertThat(message.getSparseEnum().getNumber()).isLessThan(0);
     for (OutputType outputType : OutputType.values()) {
       Coder coder = outputType.newCoder(message.getSerializedSize());
       message.writeTo(coder.stream());
@@ -427,11 +427,9 @@
     String string =
         "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
     // Ensure we take the slower fast path.
-    assertThat(
-            CodedOutputStream.computeUInt32SizeNoTag(string.length())
-                != CodedOutputStream.computeUInt32SizeNoTag(
-                    string.length() * Utf8.MAX_BYTES_PER_CHAR))
-        .isTrue();
+    assertThat(CodedOutputStream.computeUInt32SizeNoTag(string.length()))
+        .isNotEqualTo(
+            CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR));
 
     coder.stream().writeStringNoTag(string);
     coder.stream().flush();
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index 6cb0bae..a88baca 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -460,6 +460,33 @@
     }
   }
 
+  /** Tests that parsing an unknown enum throws an exception */
+  @Test
+  public void testParseUnknownEnum() {
+    FieldDescriptorProto.Builder field = FieldDescriptorProto.newBuilder()
+        .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+        .setTypeName("UnknownEnum")
+        .setType(FieldDescriptorProto.Type.TYPE_ENUM)
+        .setName("bar")
+        .setNumber(1);
+    DescriptorProto.Builder messageType = DescriptorProto.newBuilder()
+        .setName("Foo")
+        .addField(field);
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addDependency("bar.proto")
+            .addMessageType(messageType)
+            .build();
+    try {
+      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
+      assertWithMessage("DescriptorValidationException expected").fail();
+    } catch (DescriptorValidationException expected) {
+      assertThat(expected.getMessage()).contains("\"UnknownEnum\" is not an enum type.");
+    }
+  }
+
+
   /**
    * Tests the translate/crosslink for an example where a message field's name and type name are the
    * same.
diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
index 3aacdcc..8e1abc0 100644
--- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -31,10 +31,13 @@
 package com.google.protobuf;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
 
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.OneofDescriptor;
+import dynamicmessagetest.DynamicMessageTestProto.EmptyMessage;
+import dynamicmessagetest.DynamicMessageTestProto.MessageWithMapFields;
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -42,6 +45,7 @@
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
@@ -335,4 +339,52 @@
     DynamicMessage message = builder.build();
     assertThat(message.getField(repeatedEnumField)).isEqualTo(enumDescriptor.getValues());
   }
+
+  @Test
+  public void testBuilderGetFieldBuilder_mapField_throwsUnsupportedOperationException() {
+    final DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(MessageWithMapFields.getDescriptor());
+    final FieldDescriptor mapField =
+        MessageWithMapFields.getDescriptor().findFieldByName("string_message_map");
+
+    Message.Builder entryBuilder = builder.newBuilderForField(mapField);
+    entryBuilder.setField(entryBuilder.getDescriptorForType().findFieldByNumber(1), "foo");
+    entryBuilder.setField(
+        entryBuilder.getDescriptorForType().findFieldByNumber(2),
+        EmptyMessage.getDefaultInstance());
+    builder.addRepeatedField(mapField, entryBuilder.build());
+
+    assertThrows(
+        UnsupportedOperationException.class,
+        new ThrowingRunnable() {
+          @Override
+          public void run() throws Throwable {
+            builder.getFieldBuilder(mapField);
+          }
+        });
+  }
+
+  @Test
+  public void testBuilderGetRepeatedFieldBuilder_mapField_throwsUnsupportedOperationException() {
+    final DynamicMessage.Builder builder =
+        DynamicMessage.newBuilder(MessageWithMapFields.getDescriptor());
+    final FieldDescriptor mapField =
+        MessageWithMapFields.getDescriptor().findFieldByName("string_message_map");
+
+    Message.Builder entryBuilder = builder.newBuilderForField(mapField);
+    entryBuilder.setField(entryBuilder.getDescriptorForType().findFieldByNumber(1), "foo");
+    entryBuilder.setField(
+        entryBuilder.getDescriptorForType().findFieldByNumber(2),
+        EmptyMessage.getDefaultInstance());
+    builder.addRepeatedField(mapField, entryBuilder.build());
+
+    assertThrows(
+        UnsupportedOperationException.class,
+        new ThrowingRunnable() {
+          @Override
+          public void run() throws Throwable {
+            builder.getFieldBuilder(mapField);
+          }
+        });
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index e504766..eb5b739 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -85,6 +85,20 @@
 @SuppressWarnings({"ProtoBuilderReturnValueIgnored", "ReturnValueIgnored"})
 @RunWith(JUnit4.class)
 public class GeneratedMessageTest {
+
+  private static final TestOneof2 EXPECTED_MERGED_MESSAGE =
+      TestOneof2.newBuilder()
+          .setFooMessage(TestOneof2.NestedMessage.newBuilder().addCorgeInt(1).addCorgeInt(2))
+          .build();
+
+  private static final TestOneof2 MESSAGE_TO_MERGE_FROM =
+      TestOneof2.newBuilder()
+          .setFooMessage(TestOneof2.NestedMessage.newBuilder().addCorgeInt(2))
+          .build();
+
+  private static final FieldDescriptor NESTED_MESSAGE_BB_FIELD =
+      UnittestProto.TestAllTypes.NestedMessage.getDescriptor().findFieldByName("bb");
+
   TestUtil.ReflectionTester reflectionTester =
       new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
@@ -1036,9 +1050,8 @@
   public void testRecursiveMessageDefaultInstance() throws Exception {
     UnittestProto.TestRecursiveMessage message =
         UnittestProto.TestRecursiveMessage.getDefaultInstance();
-    assertThat(message != null).isTrue();
-    assertThat(message.getA()).isNotNull();
-    assertThat(message.getA().equals(message)).isTrue();
+    assertThat(message).isNotNull();
+    assertThat(message.getA()).isEqualTo(message);
   }
 
   @Test
@@ -1047,11 +1060,8 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
     TestAllTypes expected = builder.build();
-    ObjectOutputStream out = new ObjectOutputStream(baos);
-    try {
+    try (ObjectOutputStream out = new ObjectOutputStream(baos)) {
       out.writeObject(expected);
-    } finally {
-      out.close();
     }
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream in = new ObjectInputStream(bais);
@@ -1317,9 +1327,7 @@
         builder1
             .newBuilderForField(fieldDescriptor)
             .mergeFrom((Message) builder1.getField(fieldDescriptor));
-    FieldDescriptor subFieldDescriptor1 =
-        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder1.setField(subFieldDescriptor1, 1);
+    fieldBuilder1.setField(NESTED_MESSAGE_BB_FIELD, 1);
     builder1.setField(fieldDescriptor, fieldBuilder1.build());
 
     // Mutate foreign message
@@ -1348,9 +1356,7 @@
     // Mutate nested message
     TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
     Message.Builder fieldBuilder2 = builder2.getFieldBuilder(fieldDescriptor);
-    FieldDescriptor subFieldDescriptor2 =
-        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder2.setField(subFieldDescriptor2, 1);
+    fieldBuilder2.setField(NESTED_MESSAGE_BB_FIELD, 1);
     builder2.setField(fieldDescriptor, fieldBuilder2.build());
 
     // Mutate foreign message
@@ -1650,7 +1656,7 @@
   }
 
   @Test
-  public void testOneofMerge() throws Exception {
+  public void testOneofMergeNonMessage() throws Exception {
     // Primitive Type
     {
       TestOneof2.Builder builder = TestOneof2.newBuilder();
@@ -1677,18 +1683,39 @@
       assertThat(message2.hasFooEnum()).isTrue();
       assertThat(message2.getFooEnum()).isEqualTo(TestOneof2.NestedEnum.BAR);
     }
+  }
 
-    // Message
-    {
-      TestOneof2.Builder builder = TestOneof2.newBuilder();
-      TestOneof2 message =
-          builder
-              .setFooMessage(TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build())
-              .build();
-      TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
-      assertThat(message2.hasFooMessage()).isTrue();
-      assertThat(message2.getFooMessage().getQuxInt()).isEqualTo(234);
-    }
+  @Test
+  public void testOneofMergeMessage_mergeIntoNewBuilder() {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    TestOneof2 message =
+        builder.setFooMessage(TestOneof2.NestedMessage.newBuilder().setQuxInt(234).build()).build();
+    TestOneof2 message2 = TestOneof2.newBuilder().mergeFrom(message).build();
+    assertThat(message2.hasFooMessage()).isTrue();
+    assertThat(message2.getFooMessage().getQuxInt()).isEqualTo(234);
+  }
+
+  @Test
+  public void testOneofMergeMessage_mergeWithGetMessageBuilder() {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    builder.getFooMessageBuilder().addCorgeInt(1);
+    assertThat(builder.mergeFrom(MESSAGE_TO_MERGE_FROM).build()).isEqualTo(EXPECTED_MERGED_MESSAGE);
+  }
+
+  @Test
+  public void testOneofMergeMessage_mergeIntoMessageBuiltWithGetMessageBuilder() {
+    TestOneof2.Builder builder = TestOneof2.newBuilder();
+    builder.getFooMessageBuilder().addCorgeInt(1);
+    TestOneof2 message = builder.build();
+    assertThat(message.toBuilder().mergeFrom(MESSAGE_TO_MERGE_FROM).build())
+        .isEqualTo(EXPECTED_MERGED_MESSAGE);
+  }
+
+  @Test
+  public void testOneofMergeMessage_mergeWithoutGetMessageBuilder() {
+    TestOneof2.Builder builder =
+        TestOneof2.newBuilder().setFooMessage(TestOneof2.NestedMessage.newBuilder().addCorgeInt(1));
+    assertThat(builder.mergeFrom(MESSAGE_TO_MERGE_FROM).build()).isEqualTo(EXPECTED_MERGED_MESSAGE);
   }
 
   @Test
@@ -1796,9 +1823,7 @@
     // Mutate nested message
     TestAllTypes.Builder builder1 = TestAllTypes.newBuilder();
     Message.Builder fieldBuilder1 = builder1.newBuilderForField(fieldDescriptor);
-    FieldDescriptor subFieldDescriptor1 =
-        fieldBuilder1.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder1.setField(subFieldDescriptor1, 1);
+    fieldBuilder1.setField(NESTED_MESSAGE_BB_FIELD, 1);
     builder1.addRepeatedField(fieldDescriptor, fieldBuilder1.build());
 
     // Mutate foreign message
@@ -1822,9 +1847,7 @@
     TestAllTypes.Builder builder2 = TestAllTypes.newBuilder();
     builder2.addRepeatedNestedMessageBuilder();
     Message.Builder fieldBuilder2 = builder2.getRepeatedFieldBuilder(fieldDescriptor, 0);
-    FieldDescriptor subFieldDescriptor2 =
-        fieldBuilder2.getDescriptorForType().findFieldByName("bb");
-    fieldBuilder2.setField(subFieldDescriptor2, 1);
+    fieldBuilder2.setField(NESTED_MESSAGE_BB_FIELD, 1);
 
     // Mutate foreign message
     Message.Builder foreignFieldBuilder2 = builder2.newBuilderForField(foreignFieldDescriptor);
@@ -1905,4 +1928,99 @@
       // We expect this exception.
     }
   }
+
+  private static final FieldDescriptor OPTIONAL_NESTED_MESSAGE_EXTENSION =
+      UnittestProto.getDescriptor().findExtensionByName("optional_nested_message_extension");
+  private static final FieldDescriptor REPEATED_NESTED_MESSAGE_EXTENSION =
+      UnittestProto.getDescriptor().findExtensionByName("repeated_nested_message_extension");
+  // A compile-time check that TestAllExtensions.Builder does in fact extend
+  // GeneratedMessageV3.ExtendableBuilder. The tests below assume that it does.
+  static {
+    @SuppressWarnings("unused")
+    Class<? extends GeneratedMessageV3.ExtendableBuilder<?, ?>> ignored =
+        TestAllExtensions.Builder.class;
+  }
+
+  @Test
+  public void
+  extendableBuilder_extensionFieldContainingBuilder_setRepeatedFieldOverwritesElement() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    builder.addRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, NestedMessage.getDefaultInstance());
+    // Calling getRepeatedFieldBuilder and ignoring the returned Builder should have no
+    // externally-visible effect, but internally it sets the stored field element to a builder.
+    builder.getRepeatedFieldBuilder(REPEATED_NESTED_MESSAGE_EXTENSION, 0);
+
+    NestedMessage setNestedMessage = NestedMessage.newBuilder().setBb(100).build();
+    builder.setRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, 0, setNestedMessage);
+
+    assertThat(builder.getRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, 0))
+        .isEqualTo(setNestedMessage);
+  }
+
+  @Test
+  public void extendableBuilder_extensionFieldContainingBuilder_addRepeatedFieldAppendsToField() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    builder.addRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, NestedMessage.getDefaultInstance());
+    // Calling getRepeatedFieldBuilder and ignoring the returned Builder should have no
+    // externally-visible effect, but internally it sets the stored field element to a builder.
+    builder.getRepeatedFieldBuilder(REPEATED_NESTED_MESSAGE_EXTENSION, 0);
+
+    builder.addRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, NestedMessage.getDefaultInstance());
+
+    assertThat((List<?>) builder.getField(REPEATED_NESTED_MESSAGE_EXTENSION)).hasSize(2);
+  }
+
+  @Test
+  public void extendableBuilder_mergeFrom_optionalField_changesReflectedInExistingBuilder() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    Message.Builder nestedMessageBuilder =
+        builder.getFieldBuilder(OPTIONAL_NESTED_MESSAGE_EXTENSION);
+
+    builder.mergeFrom(
+        TestAllExtensions.newBuilder()
+            .setField(OPTIONAL_NESTED_MESSAGE_EXTENSION, NestedMessage.newBuilder().setBb(100))
+            .build());
+
+    assertThat(nestedMessageBuilder.getField(NESTED_MESSAGE_BB_FIELD)).isEqualTo(100);
+  }
+
+  @Test
+  public void extendableBuilder_mergeFrom_optionalField_doesNotInvalidateExistingBuilder() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    Message.Builder nestedMessageBuilder =
+        builder.getFieldBuilder(OPTIONAL_NESTED_MESSAGE_EXTENSION);
+
+    builder.mergeFrom(
+        TestAllExtensions.newBuilder()
+            .setField(OPTIONAL_NESTED_MESSAGE_EXTENSION, NestedMessage.newBuilder().setBb(100))
+            .build());
+
+    // Changes to nestedMessageBuilder should still be reflected in the parent builder.
+    nestedMessageBuilder.setField(NESTED_MESSAGE_BB_FIELD, 200);
+
+    assertThat(builder.build())
+        .isEqualTo(
+            TestAllExtensions.newBuilder()
+                .setField(OPTIONAL_NESTED_MESSAGE_EXTENSION, NestedMessage.newBuilder().setBb(200))
+                .build());
+  }
+
+  @Test
+  public void extendableBuilder_mergeFrom_repeatedField_doesNotInvalidateExistingBuilder() {
+    TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+    builder.addRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, NestedMessage.getDefaultInstance());
+    Message.Builder nestedMessageBuilder =
+        builder.getRepeatedFieldBuilder(REPEATED_NESTED_MESSAGE_EXTENSION, 0);
+
+    builder.mergeFrom(
+        TestAllExtensions.newBuilder()
+            .addRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, NestedMessage.getDefaultInstance())
+            .build());
+
+    // Changes to nestedMessageBuilder should still be reflected in the parent builder.
+    nestedMessageBuilder.setField(NESTED_MESSAGE_BB_FIELD, 100);
+
+    assertThat(builder.getRepeatedField(REPEATED_NESTED_MESSAGE_EXTENSION, 0))
+        .isEqualTo(NestedMessage.newBuilder().setBb(100).build());
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/InvalidProtocolBufferExceptionTest.java
similarity index 75%
rename from java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
rename to java/core/src/test/java/com/google/protobuf/InvalidProtocolBufferExceptionTest.java
index baa6d08..564b8c2 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/test/java/com/google/protobuf/InvalidProtocolBufferExceptionTest.java
@@ -30,18 +30,20 @@
 
 package com.google.protobuf;
 
-/**
- * A prerun for a test suite that allows running the full protocol buffer tests in a mode that
- * disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
- * SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
- * code paths and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
+import static com.google.common.truth.Truth.assertThat;
 
-  @Override
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class InvalidProtocolBufferExceptionTest {
+
+  @Test
+  public void testWrapRuntimeException() {
+    ArrayIndexOutOfBoundsException root = new ArrayIndexOutOfBoundsException();
+    InvalidProtocolBufferException wrapper = new InvalidProtocolBufferException(root);
+    assertThat(wrapper).hasCauseThat().isEqualTo(root);
   }
+
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
index 576feea..7d6b0d6 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -254,7 +254,7 @@
     ByteString data1 = outer.toByteString();
 
     // The following should not alter the content of the 'outer' message.
-    LazyMessageLite.Builder merged = LazyMessageLite.newBuilder().mergeFrom(outer);
+    LazyMessageLite.Builder merged = outer.toBuilder();
     LazyInnerMessageLite anotherInner = LazyInnerMessageLite.newBuilder().setNum(12345).build();
     merged.setOneofInner(anotherInner);
 
diff --git a/java/core/src/test/java/com/google/protobuf/MapLiteTest.java b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
index 5f39893..349d576 100644
--- a/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapLiteTest.java
@@ -537,6 +537,7 @@
   }
 
   @Test
+  @SuppressWarnings("ProtoNewBuilderMergeFrom")
   public void testUnknownEnumValues() throws Exception {
     TestMap.Builder builder =
         TestMap.newBuilder()
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index 34df945..587ebbb 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -992,6 +992,7 @@
   }
 
   @Test
+  @SuppressWarnings("ProtoNewBuilderMergeFrom")
   public void testUnknownEnumValues() throws Exception {
     TestMap.Builder builder =
         TestMap.newBuilder()
diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
index c1660a8..81ced78 100644
--- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -218,11 +218,11 @@
   public void messageBuilder_mergeDelimitedFrom_InputStream_malformed() throws Exception {
     byte[] body = new byte[80];
     CodedOutputStream cos = CodedOutputStream.newInstance(body);
-    cos.writeRawVarint32(90); // Greater than bytes in stream
+    cos.writeUInt32NoTag(90); // Greater than bytes in stream
     cos.writeTag(DescriptorProto.ENUM_TYPE_FIELD_NUMBER, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    cos.writeRawVarint32(98); // Nested message with size larger than parent
+    cos.writeUInt32NoTag(98); // Nested message with size larger than parent
     cos.writeTag(1000, WireFormat.WIRETYPE_LENGTH_DELIMITED);
-    cos.writeRawVarint32(100); // Unknown field with size larger than parent
+    cos.writeUInt32NoTag(100); // Unknown field with size larger than parent
     ByteArrayInputStream bais = new ByteArrayInputStream(body);
     try {
       DescriptorProto.parseDelimitedFrom(bais);
diff --git a/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
index fd0bf45..6f6d26b 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserLiteTest.java
@@ -31,10 +31,15 @@
 package com.google.protobuf;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestMergeExceptionLite;
 import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 import com.google.protobuf.UnittestLite.TestParsingMergeLite;
+import protobuf_unittest.MapLiteUnittest;
+import protobuf_unittest.MapLiteUnittest.TestRequiredLite;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
@@ -200,4 +205,70 @@
     assertThat(parsingMerge.getRepeatedGroupCount()).isEqualTo(3);
     assertThat(parsingMerge.getExtensionCount(TestParsingMergeLite.repeatedExt)).isEqualTo(3);
   }
+
+  @Test
+  public void testExceptionWhenMergingExtendedMessagesMissingRequiredFieldsLite() {
+    // create a TestMergeExceptionLite message (missing required fields) that looks like
+    //   all_extensions {
+    //     [TestRequiredLite.single] {
+    //     }
+    //   }
+    TestMergeExceptionLite.Builder message = TestMergeExceptionLite.newBuilder();
+    message.setAllExtensions(
+        TestAllExtensionsLite.newBuilder()
+            .setExtension(TestRequiredLite.single, TestRequiredLite.newBuilder().buildPartial())
+            .buildPartial());
+    ByteString byteString = message.buildPartial().toByteString();
+
+    // duplicate the bytestring to make the `all_extensions` field repeat twice, so that it will
+    // need merging when parsing back
+    ByteString duplicatedByteString = byteString.concat(byteString);
+
+    byte[] bytes = duplicatedByteString.toByteArray();
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    MapLiteUnittest.registerAllExtensions(registry);
+
+    // `parseFrom` should throw InvalidProtocolBufferException, not UninitializedMessageException,
+    // for each of the 5 possible input types:
+
+    // parseFrom(ByteString)
+    try {
+      TestMergeExceptionLite.parseFrom(duplicatedByteString, registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(ByteArray)
+    try {
+      TestMergeExceptionLite.parseFrom(bytes, registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(InputStream)
+    try {
+      TestMergeExceptionLite.parseFrom(new ByteArrayInputStream(bytes), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(CodedInputStream)
+    try {
+      TestMergeExceptionLite.parseFrom(CodedInputStream.newInstance(bytes), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(ByteBuffer)
+    try {
+      TestMergeExceptionLite.parseFrom(duplicatedByteString.asReadOnlyByteBuffer(), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
index e78c671..f4cf529 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -40,6 +40,7 @@
 import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestMergeException;
 import protobuf_unittest.UnittestProto.TestParsingMerge;
 import protobuf_unittest.UnittestProto.TestRequired;
 import java.io.ByteArrayInputStream;
@@ -292,6 +293,71 @@
   }
 
   @Test
+  public void testExceptionWhenMergingExtendedMessagesMissingRequiredFields() {
+    // create a TestMergeException message (missing required fields) that looks like
+    //   all_extensions {
+    //     [TestRequired.single] {
+    //     }
+    //   }
+    TestMergeException.Builder message = TestMergeException.newBuilder();
+    message
+        .getAllExtensionsBuilder()
+        .setExtension(TestRequired.single, TestRequired.newBuilder().buildPartial());
+    ByteString byteString = message.buildPartial().toByteString();
+
+    // duplicate the bytestring to make the `all_extensions` field repeat twice, so that it will
+    // need merging when parsing back
+    ByteString duplicatedByteString = byteString.concat(byteString);
+
+    byte[] bytes = duplicatedByteString.toByteArray();
+    ExtensionRegistry registry = ExtensionRegistry.newInstance();
+    UnittestProto.registerAllExtensions(registry);
+
+    // `parseFrom` should throw InvalidProtocolBufferException, not UninitializedMessageException,
+    // for each of the 5 possible input types:
+
+    // parseFrom(ByteString)
+    try {
+      TestMergeException.parseFrom(duplicatedByteString, registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(ByteArray)
+    try {
+      TestMergeException.parseFrom(bytes, registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(InputStream)
+    try {
+      TestMergeException.parseFrom(new ByteArrayInputStream(bytes), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(CodedInputStream)
+    try {
+      TestMergeException.parseFrom(CodedInputStream.newInstance(bytes), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+
+    // parseFrom(ByteBuffer)
+    try {
+      TestMergeException.parseFrom(duplicatedByteString.asReadOnlyByteBuffer(), registry);
+      assertWithMessage("Expected InvalidProtocolBufferException").fail();
+    } catch (Exception e) {
+      assertThat(e.getClass()).isEqualTo(InvalidProtocolBufferException.class);
+    }
+  }
+
+  @Test
   public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
     try {
       TestAllTypes.parseDelimitedFrom(
diff --git a/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
index 07864a9..15097a0 100644
--- a/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
+++ b/java/core/src/test/java/com/google/protobuf/Proto2ExtensionLookupSchemaTest.java
@@ -52,7 +52,6 @@
   public void setup() {
     TestSchemas.registerGenericProto2Schemas();
 
-    Protobuf.getInstance().schemaFor(Proto2MessageWithExtensions.class);
     data = new Proto2MessageFactory(10, 20, 1, 1).newMessage().toByteArray();
     extensionRegistry = ExtensionRegistry.newInstance();
     Proto2Testing.registerAllExtensions(extensionRegistry);
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index b409268..377f34c 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -239,7 +239,7 @@
 import java.util.List;
 import java.util.logging.Handler;
 import java.util.logging.LogRecord;
-import junit.framework.Assert;
+import org.junit.Assert;
 
 /**
  * Contains methods for setting all fields of {@code TestAllTypes} to some values as well as
@@ -901,8 +901,8 @@
     Assert.assertEquals(208L, message.getRepeatedFixed64(0));
     Assert.assertEquals(209, message.getRepeatedSfixed32(0));
     Assert.assertEquals(210L, message.getRepeatedSfixed64(0));
-    Assert.assertEquals(211F, message.getRepeatedFloat(0));
-    Assert.assertEquals(212D, message.getRepeatedDouble(0));
+    Assert.assertEquals(211F, message.getRepeatedFloat(0), 0.0);
+    Assert.assertEquals(212D, message.getRepeatedDouble(0), 0.0);
     Assert.assertEquals(true, message.getRepeatedBool(0));
     Assert.assertEquals("215", message.getRepeatedString(0));
     Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
@@ -931,8 +931,8 @@
     Assert.assertEquals(508L, message.getRepeatedFixed64(1));
     Assert.assertEquals(509, message.getRepeatedSfixed32(1));
     Assert.assertEquals(510L, message.getRepeatedSfixed64(1));
-    Assert.assertEquals(511F, message.getRepeatedFloat(1));
-    Assert.assertEquals(512D, message.getRepeatedDouble(1));
+    Assert.assertEquals(511F, message.getRepeatedFloat(1), 0.0);
+    Assert.assertEquals(512D, message.getRepeatedDouble(1), 0.0);
     Assert.assertEquals(true, message.getRepeatedBool(1));
     Assert.assertEquals("515", message.getRepeatedString(1));
     Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index f9b7da4..32ca8a8 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -69,8 +69,6 @@
 
 /**
  * Test case for {@link TextFormat}.
- *
- * <p>TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
  */
 @RunWith(JUnit4.class)
 public class TextFormatTest {
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
index bf4af71..e66967d 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java
@@ -54,6 +54,7 @@
 public class UnknownEnumValueTest {
 
   @Test
+  @SuppressWarnings("ProtoNewBuilderMergeFrom")
   public void testUnknownEnumValues() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     builder.setOptionalNestedEnumValue(4321);
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
similarity index 73%
copy from java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
copy to java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
index baa6d08..a0f28ac 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
@@ -28,20 +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.
 
-package com.google.protobuf;
+syntax = "proto2";
 
-/**
- * A prerun for a test suite that allows running the full protocol buffer tests in a mode that
- * disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
- * SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
- * code paths and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
+package dynamic_message_test;
 
-  @Override
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-  }
+option java_package = "dynamicmessagetest";
+option java_outer_classname = "DynamicMessageTestProto";
+
+message EmptyMessage {}
+
+message MessageWithMapFields {
+  map<string, EmptyMessage> string_message_map = 1;
 }
diff --git a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
index 0f481f5..ce1363f 100644
--- a/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
+++ b/java/core/src/test/proto/com/google/protobuf/test_bad_identifiers.proto
@@ -35,8 +35,6 @@
 
 syntax = "proto2";
 
-// Some generic_services option(s) added automatically.
-// See:  http://go/proto2-generic-services-default
 package io_protocol_tests;
 
 option java_generic_services = true;  // auto-added
diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml
index 365194e..8123efb 100644
--- a/java/lite/generate-test-sources-build.xml
+++ b/java/lite/generate-test-sources-build.xml
@@ -5,6 +5,7 @@
         <arg value="--proto_path=${protobuf.source.dir}"/>
         <arg value="--proto_path=${protobuf.basedir}/java/core/${test.proto.dir}"/>
         <arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/map_lite_unittest.proto"/>
         <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_lite.proto"/>
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index 901ae67..c19d596 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -105,6 +105,7 @@
                     <include>CodedInputStreamReader.java</include>
                     <include>CodedOutputStream.java</include>
                     <include>CodedOutputStreamWriter.java</include>
+                    <include>CompileTimeConstant.java</include>
                     <include>DoubleArrayList.java</include>
                     <include>ExperimentalApi.java</include>
                     <include>ExtensionLite.java</include>
@@ -119,6 +120,7 @@
                     <include>FloatArrayList.java</include>
                     <include>GeneratedMessageInfoFactory.java</include>
                     <include>GeneratedMessageLite.java</include>
+                    <include>InlineMe.java</include>
                     <include>IntArrayList.java</include>
                     <include>Internal.java</include>
                     <include>InvalidProtocolBufferException.java</include>
diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
index b097211..6686a38 100644
--- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
@@ -1345,6 +1345,7 @@
   }
 
   @Test
+  @SuppressWarnings("ProtoNewBuilderMergeFrom")
   public void testBuilderMergeFromNull() throws Exception {
     try {
       TestAllTypesLite.newBuilder().mergeFrom((TestAllTypesLite) null);
@@ -1899,6 +1900,7 @@
   }
 
   @Test
+  @SuppressWarnings("ProtoNewBuilderMergeFrom")
   public void testMergeFromNoLazyFieldSharing() throws Exception {
     TestAllTypesLite.Builder sourceBuilder =
         TestAllTypesLite.newBuilder().setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1));
@@ -2487,9 +2489,9 @@
       assertWithMessage("expected exception").fail();
     } catch (InvalidProtocolBufferException expected) {
       assertThat(
-              TestAllExtensionsLite.newBuilder()
-                  .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
-                  .build())
+          TestAllExtensionsLite.newBuilder()
+              .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+              .build())
           .isEqualTo(expected.getUnfinishedMessage());
     }
   }
@@ -2782,7 +2784,7 @@
     assertThat(message1).isNotEqualTo(message2);
   }
 
-  private String encodeHex(ByteString bytes) {
+  private static String encodeHex(ByteString bytes) {
     String hexDigits = "0123456789abcdef";
     StringBuilder stringBuilder = new StringBuilder(bytes.size() * 2);
     for (byte b : bytes) {
@@ -2792,7 +2794,7 @@
     return stringBuilder.toString();
   }
 
-  private boolean contains(ByteString a, ByteString b) {
+  private static boolean contains(ByteString a, ByteString b) {
     for (int i = 0; i <= a.size() - b.size(); ++i) {
       if (a.substring(i, i + b.size()).equals(b)) {
         return true;
diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java
index f81da1f..1495f09 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Durations.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -238,13 +238,13 @@
   }
 
   /**
-   * Parse from a string to produce a duration.
+   * Parse a string to produce a duration.
    *
-   * @return A Duration parsed from the string.
-   * @throws ParseException if parsing fails.
+   * @return a Duration parsed from the string
+   * @throws ParseException if the string is not in the duration format
    */
   public static Duration parse(String value) throws ParseException {
-    // Must ended with "s".
+    // Must end with "s".
     if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
       throw new ParseException("Invalid duration string: " + value, 0);
     }
@@ -272,7 +272,9 @@
     try {
       return normalizedDuration(seconds, nanos);
     } catch (IllegalArgumentException e) {
-      throw new ParseException("Duration value is out of range.", 0);
+      ParseException ex = new ParseException("Duration value is out of range.", 0);
+      ex.initCause(e);
+      throw ex;
     }
   }
 
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
index 352376e..854c826 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -44,10 +44,11 @@
 import java.util.logging.Logger;
 
 /**
- * A tree representation of a FieldMask. Each leaf node in this tree represent
- * a field path in the FieldMask.
+ * A tree representation of a FieldMask. Each leaf node in this tree represent a field path in the
+ * FieldMask.
  *
  * <p>For example, FieldMask "foo.bar,foo.baz,bar.baz" as a tree will be:
+ *
  * <pre>
  *   [root] -+- foo -+- bar
  *           |       |
@@ -56,10 +57,9 @@
  *           +- bar --- baz
  * </pre>
  *
- * <p>By representing FieldMasks with this tree structure we can easily convert
- * a FieldMask to a canonical form, merge two FieldMasks, calculate the
- * intersection to two FieldMasks and traverse all fields specified by the
- * FieldMask in a message tree.
+ * <p>By representing FieldMasks with this tree structure we can easily convert a FieldMask to a
+ * canonical form, merge two FieldMasks, calculate the intersection to two FieldMasks and traverse
+ * all fields specified by the FieldMask in a message tree.
  */
 final class FieldMaskTree {
   private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
@@ -72,14 +72,10 @@
 
   private final Node root = new Node();
 
-  /**
-   * Creates an empty FieldMaskTree.
-   */
+  /** Creates an empty FieldMaskTree. */
   FieldMaskTree() {}
 
-  /**
-   * Creates a FieldMaskTree for a given FieldMask.
-   */
+  /** Creates a FieldMaskTree for a given FieldMask. */
   FieldMaskTree(FieldMask mask) {
     mergeFromFieldMask(mask);
   }
@@ -143,11 +139,10 @@
    *   When removing a field path from the tree:
    *   <li>All sub-paths will be removed. That is, after removing "foo.bar" from the tree,
    *       "foo.bar.baz" will be removed.
-   *   <li>If all children of a node has been removed, the node itself will be removed as well.
+   *   <li>If all children of a node have been removed, the node itself will be removed as well.
    *       That is, if "foo" only has one child "bar" and "foo.bar" only has one child "baz",
-   *       removing "foo.bar.barz" would remove both "foo" and "foo.bar".
-   *       If "foo" has both "bar" and "qux" as children, removing "foo.bar" would leave the path
-   *       "foo.qux" intact.
+   *       removing "foo.bar.barz" would remove both "foo" and "foo.bar". If "foo" has both "bar"
+   *       and "qux" as children, removing "foo.bar" would leave the path "foo.qux" intact.
    *   <li>If the field path to remove is a non-exist sub-path, nothing will be changed.
    * </ul>
    */
@@ -195,9 +190,7 @@
     return this;
   }
 
-  /**
-   * Converts this tree to a FieldMask.
-   */
+  /** Converts this tree to a FieldMask. */
   FieldMask toFieldMask() {
     if (root.children.isEmpty()) {
       return FieldMask.getDefaultInstance();
@@ -219,9 +212,7 @@
     }
   }
 
-  /**
-   * Adds the intersection of this tree with the given {@code path} to {@code output}.
-   */
+  /** Adds the intersection of this tree with the given {@code path} to {@code output}. */
   void intersectFieldPath(String path, FieldMaskTree output) {
     if (root.children.isEmpty()) {
       return;
@@ -262,21 +253,18 @@
     if (root.children.isEmpty()) {
       return;
     }
-    merge(root, "", source, destination, options);
+    merge(root, source, destination, options);
   }
 
   /** Merges all fields specified by a sub-tree from {@code source} to {@code destination}. */
   private static void merge(
-      Node node,
-      String path,
-      Message source,
-      Message.Builder destination,
-      FieldMaskUtil.MergeOptions options) {
+      Node node, Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
     if (source.getDescriptorForType() != destination.getDescriptorForType()) {
       throw new IllegalArgumentException(
           String.format(
               "source (%s) and destination (%s) descriptor must be equal",
-              source.getDescriptorForType(), destination.getDescriptorForType()));
+              source.getDescriptorForType().getFullName(),
+              destination.getDescriptorForType().getFullName()));
     }
 
     Descriptor descriptor = source.getDescriptorForType();
@@ -304,9 +292,8 @@
           // so we don't create unnecessary empty messages.
           continue;
         }
-        String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey();
         Message.Builder childBuilder = ((Message) destination.getField(field)).toBuilder();
-        merge(entry.getValue(), childPath, (Message) source.getField(field), childBuilder, options);
+        merge(entry.getValue(), (Message) source.getField(field), childBuilder, options);
         destination.setField(field, childBuilder.buildPartial());
         continue;
       }
@@ -331,9 +318,7 @@
               destination.setField(
                   field,
                   ((Message) destination.getField(field))
-                      .toBuilder()
-                      .mergeFrom((Message) source.getField(field))
-                      .build());
+                      .toBuilder().mergeFrom((Message) source.getField(field)).build());
             }
           }
         } else {
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 ddfbc9e..31a4a0a 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
@@ -91,13 +91,12 @@
 import javax.annotation.Nullable;
 
 /**
- * Utility classes to convert protobuf messages to/from JSON format. The JSON
- * format follows Proto3 JSON specification and only proto3 features are
- * supported. Proto2 only features (e.g., extensions and unknown fields) will
- * be discarded in the conversion. That is, when converting proto2 messages
- * to JSON format, extensions and unknown fields will be treated as if they
- * do not exist. This applies to proto2 messages embedded in proto3 messages
- * as well.
+ * Utility class to convert protobuf messages to/from the <a href=
+ * 'https://developers.google.com/protocol-buffers/docs/proto3#json'>Proto3 JSON format.</a>
+ * Only proto3 features are supported. Proto2 only features such as extensions and unknown fields
+ * are discarded in the conversion. That is, when converting proto2 messages to JSON format,
+ * extensions and unknown fields are treated as if they do not exist. This applies to proto2
+ * messages embedded in proto3 messages as well.
  */
 public class JsonFormat {
   private static final Logger logger = Logger.getLogger(JsonFormat.class.getName());
@@ -120,7 +119,7 @@
   }
 
   /**
-   * A Printer converts protobuf message to JSON format.
+   * A Printer converts a protobuf message to the proto3 JSON format.
    */
   public static class Printer {
     private final com.google.protobuf.TypeRegistry registry;
@@ -163,7 +162,7 @@
      * Creates a new {@link Printer} using the given registry. The new Printer clones all other
      * configurations from the current {@link Printer}.
      *
-     * @throws IllegalArgumentException if a registry is already set.
+     * @throws IllegalArgumentException if a registry is already set
      */
     public Printer usingTypeRegistry(TypeRegistry oldRegistry) {
       if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
@@ -185,7 +184,7 @@
      * Creates a new {@link Printer} using the given registry. The new Printer clones all other
      * configurations from the current {@link Printer}.
      *
-     * @throws IllegalArgumentException if a registry is already set.
+     * @throws IllegalArgumentException if a registry is already set
      */
     public Printer usingTypeRegistry(com.google.protobuf.TypeRegistry registry) {
       if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
@@ -223,10 +222,8 @@
     }
 
     /**
-     * Creates a new {@link Printer} that will print enum field values as integers instead of as
-     * string.
-     * The new Printer clones all other configurations from the current
-     * {@link Printer}.
+     * Creates a new {@link Printer} that prints enum field values as integers instead of as
+     * string. The new Printer clones all other configurations from the current {@link Printer}.
      */
     public Printer printingEnumsAsInts() {
       checkUnsetPrintingEnumsAsInts();
@@ -329,7 +326,7 @@
     /**
      * Create a new {@link Printer} that will sort the map keys in the JSON output.
      *
-     * <p>Use of this modifier is discouraged, the generated JSON messages are equivalent with and
+     * <p>Use of this modifier is discouraged. The generated JSON messages are equivalent with and
      * without this option set, but there are some corner use cases that demand a stable output,
      * while order of map keys is otherwise arbitrary.
      *
@@ -350,11 +347,11 @@
     }
 
     /**
-     * Converts a protobuf message to JSON format.
+     * Converts a protobuf message to the proto3 JSON format.
      *
      * @throws InvalidProtocolBufferException if the message contains Any types that can't be
-     *     resolved.
-     * @throws IOException if writing to the output fails.
+     *     resolved
+     * @throws IOException if writing to the output fails
      */
     public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
@@ -373,7 +370,7 @@
     }
 
     /**
-     * Converts a protobuf message to JSON format. Throws exceptions if there
+     * Converts a protobuf message to the proto3 JSON format. Throws exceptions if there
      * are unknown Any types in the message.
      */
     public String print(MessageOrBuilder message) throws InvalidProtocolBufferException {
@@ -402,7 +399,7 @@
   }
 
   /**
-   * A Parser parses JSON to protobuf message.
+   * A Parser parses the proto3 JSON format into a protobuf message.
    */
   public static class Parser {
     private final com.google.protobuf.TypeRegistry registry;
@@ -428,7 +425,7 @@
      * Creates a new {@link Parser} using the given registry. The new Parser clones all other
      * configurations from this Parser.
      *
-     * @throws IllegalArgumentException if a registry is already set.
+     * @throws IllegalArgumentException if a registry is already set
      */
     public Parser usingTypeRegistry(TypeRegistry oldRegistry) {
       if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
@@ -446,7 +443,7 @@
      * Creates a new {@link Parser} using the given registry. The new Parser clones all other
      * configurations from this Parser.
      *
-     * @throws IllegalArgumentException if a registry is already set.
+     * @throws IllegalArgumentException if a registry is already set
      */
     public Parser usingTypeRegistry(com.google.protobuf.TypeRegistry registry) {
       if (this.oldRegistry != TypeRegistry.getEmptyTypeRegistry()
@@ -465,10 +462,10 @@
     }
 
     /**
-     * Parses from JSON into a protobuf message.
+     * Parses from the proto3 JSON format into a protobuf message.
      *
      * @throws InvalidProtocolBufferException if the input is not valid JSON
-     *         format or there are unknown fields in the input.
+     *         proto3 format or there are unknown fields in the input.
      */
     public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
@@ -478,11 +475,11 @@
     }
 
     /**
-     * Parses from JSON into a protobuf message.
+     * Parses from the proto3 JSON encoding into a protobuf message.
      *
-     * @throws InvalidProtocolBufferException if the input is not valid JSON
-     *         format or there are unknown fields in the input.
-     * @throws IOException if reading from the input throws.
+     * @throws InvalidProtocolBufferException if the input is not valid proto3 JSON
+     *         format or there are unknown fields in the input
+     * @throws IOException if reading from the input throws
      */
     public void merge(Reader json, Message.Builder builder) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
@@ -606,15 +603,15 @@
         types.put(message.getFullName(), message);
       }
 
-      private final Set<String> files = new HashSet<String>();
-      private Map<String, Descriptor> types = new HashMap<String, Descriptor>();
+      private final Set<String> files = new HashSet<>();
+      private final Map<String, Descriptor> types = new HashMap<>();
       private boolean built = false;
     }
   }
 
   /**
-   * An interface for json formatting that can be used in
-   * combination with the omittingInsignificantWhitespace() method
+   * An interface for JSON formatting that can be used in
+   * combination with the omittingInsignificantWhitespace() method.
    */
   interface TextGenerator {
     void indent();
@@ -625,7 +622,7 @@
   }
 
   /**
-   * Format the json without indentation
+   * Format the JSON without indentation
    */
   private static final class CompactTextGenerator implements TextGenerator {
     private final Appendable output;
@@ -709,7 +706,7 @@
   }
 
   /**
-   * A Printer converts protobuf messages to JSON format.
+   * A Printer converts protobuf messages to the proto3 JSON format.
    */
   private static final class PrinterImpl {
     private final com.google.protobuf.TypeRegistry registry;
@@ -1068,7 +1065,6 @@
       generator.print("]");
     }
 
-    @SuppressWarnings("rawtypes")
     private void printMapFieldValue(FieldDescriptor field, Object value) throws IOException {
       Descriptor type = field.getMessageType();
       FieldDescriptor keyField = type.findFieldByName("key");
@@ -1093,7 +1089,7 @@
             }
           };
         }
-        TreeMap<Object, Object> tm = new TreeMap<Object, Object>(cmp);
+        TreeMap<Object, Object> tm = new TreeMap<>(cmp);
         for (Object element : elements) {
           Message entry = (Message) element;
           Object entryKey = entry.getField(keyField);
@@ -1129,10 +1125,10 @@
     }
 
     /**
-     * Prints a field's value in JSON format.
+     * Prints a field's value in the proto3 JSON format.
      *
      * @param alwaysWithQuotes whether to always add double-quotes to primitive
-     *        types.
+     *        types
      */
     private void printSingleFieldValue(
         final FieldDescriptor field, final Object value, boolean alwaysWithQuotes)
@@ -1318,8 +1314,6 @@
         JsonReader reader = new JsonReader(json);
         reader.setLenient(false);
         merge(JsonParser.parseReader(reader), builder);
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
       } catch (JsonIOException e) {
         // Unwrap IOException.
         if (e.getCause() instanceof IOException) {
@@ -1327,7 +1321,7 @@
         } else {
           throw new InvalidProtocolBufferException(e.getMessage());
         }
-      } catch (Exception e) {
+      } catch (RuntimeException e) {
         // We convert all exceptions from JSON parsing to our own exceptions.
         throw new InvalidProtocolBufferException(e.getMessage());
       }
@@ -1338,9 +1332,7 @@
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.setLenient(false);
         merge(JsonParser.parseReader(reader), builder);
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (Exception e) {
+      } catch (RuntimeException e) {
         // We convert all exceptions from JSON parsing to our own exceptions.
         InvalidProtocolBufferException toThrow = new InvalidProtocolBufferException(e.getMessage());
         toThrow.initCause(e);
@@ -1563,7 +1555,10 @@
         Timestamp value = Timestamps.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException | UnsupportedOperationException e) {
-        throw new InvalidProtocolBufferException("Failed to parse timestamp: " + json);
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Failed to parse timestamp: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1573,7 +1568,10 @@
         Duration value = Durations.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException | UnsupportedOperationException e) {
-        throw new InvalidProtocolBufferException("Failed to parse duration: " + json);
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Failed to parse duration: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1741,7 +1739,7 @@
     private int parseInt32(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Integer.parseInt(json.getAsString());
-      } catch (Exception e) {
+      } catch (RuntimeException e) {
         // Fall through.
       }
       // JSON doesn't distinguish between integer values and floating point values so "1" and
@@ -1750,15 +1748,18 @@
       try {
         BigDecimal value = new BigDecimal(json.getAsString());
         return value.intValueExact();
-      } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an int32 value: " + json);
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not an int32 value: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
     private long parseInt64(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Long.parseLong(json.getAsString());
-      } catch (Exception e) {
+      } catch (RuntimeException e) {
         // Fall through.
       }
       // JSON doesn't distinguish between integer values and floating point values so "1" and
@@ -1767,8 +1768,11 @@
       try {
         BigDecimal value = new BigDecimal(json.getAsString());
         return value.longValueExact();
-      } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an int64 value: " + json);
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not an int64 value: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1779,9 +1783,7 @@
           throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
         }
         return (int) result;
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (Exception e) {
+      } catch (RuntimeException e) {
         // Fall through.
       }
       // JSON doesn't distinguish between integer values and floating point values so "1" and
@@ -1794,10 +1796,11 @@
           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);
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not an uint32 value: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1811,10 +1814,11 @@
           throw new InvalidProtocolBufferException("Out of range uint64 value: " + json);
         }
         return value.longValue();
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an uint64 value: " + json);
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not an uint64 value: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1851,10 +1855,11 @@
           throw new InvalidProtocolBufferException("Out of range float value: " + json);
         }
         return (float) value;
-      } catch (InvalidProtocolBufferException e) {
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not a float value: " + json);
+        ex.initCause(e);
         throw e;
-      } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not a float value: " + json);
       }
     }
 
@@ -1884,10 +1889,11 @@
           throw new InvalidProtocolBufferException("Out of range double value: " + json);
         }
         return value.doubleValue();
-      } catch (InvalidProtocolBufferException e) {
-        throw e;
-      } catch (Exception e) {
-        throw new InvalidProtocolBufferException("Not an double value: " + json);
+      } catch (RuntimeException e) {
+        InvalidProtocolBufferException ex = new InvalidProtocolBufferException(
+            "Not a double value: " + json);
+        ex.initCause(e);
+        throw ex;
       }
     }
 
@@ -1923,6 +1929,8 @@
           // an exception later.
         }
 
+        // todo(elharo): if we are ignoring unknown fields, shouldn't we still
+        // throw InvalidProtocolBufferException for a non-numeric value here?
         if (result == null && !ignoringUnknownFields) {
           throw new InvalidProtocolBufferException(
               "Invalid enum value: " + value + " for enum type: " + enumDescriptor.getFullName());
diff --git a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
index c9276a0..95f3665 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -62,11 +62,11 @@
   // Timestamp for "9999-12-31T23:59:59Z"
   static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
 
-  static final long NANOS_PER_SECOND = 1000000000;
-  static final long NANOS_PER_MILLISECOND = 1000000;
-  static final long NANOS_PER_MICROSECOND = 1000;
-  static final long MILLIS_PER_SECOND = 1000;
-  static final long MICROS_PER_SECOND = 1000000;
+  static final int NANOS_PER_SECOND = 1000000000;
+  static final int NANOS_PER_MILLISECOND = 1000000;
+  static final int NANOS_PER_MICROSECOND = 1000;
+  static final int MILLIS_PER_SECOND = 1000;
+  static final int MICROS_PER_SECOND = 1000000;
 
   /** A constant holding the minimum valid {@link Timestamp}, {@code 0001-01-01T00:00:00Z}. */
   public static final Timestamp MIN_VALUE =
@@ -230,8 +230,8 @@
    *
    * <p>Example of accepted format: "1972-01-01T10:00:20.021-05:00"
    *
-   * @return A Timestamp parsed from the string.
-   * @throws ParseException if parsing fails.
+   * @return a Timestamp parsed from the string
+   * @throws ParseException if parsing fails
    */
   public static Timestamp parse(String value) throws ParseException {
     int dayOffset = value.indexOf('T');
@@ -281,7 +281,10 @@
     try {
       return normalizedTimestamp(seconds, nanos);
     } catch (IllegalArgumentException e) {
-      throw new ParseException("Failed to parse timestamp: timestamp is out of range.", 0);
+      ParseException ex = new ParseException(
+          "Failed to parse timestamp " + value + " Timestamp is out of range.", 0);
+      ex.initCause(e);
+      throw ex;
     }
   }
 
@@ -353,7 +356,7 @@
   /**
    * Convert a Timestamp to the number of milliseconds elapsed from the epoch.
    *
-   * <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
+   * <p>The result will be rounded down to the nearest millisecond. For instance, if the timestamp
    * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
    */
   @SuppressWarnings("GoodTime") // this is a legacy conversion API
diff --git a/java/util/src/test/java/com/google/protobuf/util/DurationsTest.java b/java/util/src/test/java/com/google/protobuf/util/DurationsTest.java
new file mode 100644
index 0000000..ffcd4dc
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/DurationsTest.java
@@ -0,0 +1,631 @@
+// 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.util;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.protobuf.util.Durations.toSecondsAsDouble;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.Lists;
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link Durations}. */
+@RunWith(JUnit4.class)
+public class DurationsTest {
+
+  private static final Duration INVALID_MAX =
+      Duration.newBuilder().setSeconds(Long.MAX_VALUE).setNanos(Integer.MAX_VALUE).build();
+  private static final Duration INVALID_MIN =
+      Duration.newBuilder().setSeconds(Long.MIN_VALUE).setNanos(Integer.MIN_VALUE).build();
+
+  @Test
+  public void testIsPositive() {
+    assertThat(Durations.isPositive(Durations.ZERO)).isFalse();
+    assertThat(Durations.isPositive(Durations.fromNanos(-1))).isFalse();
+    assertThat(Durations.isPositive(Durations.fromNanos(1))).isTrue();
+  }
+
+  @Test
+  public void testIsNegative() {
+    assertThat(Durations.isNegative(Durations.ZERO)).isFalse();
+    assertThat(Durations.isNegative(Durations.fromNanos(1))).isFalse();
+    assertThat(Durations.isNegative(Durations.fromNanos(-1))).isTrue();
+  }
+
+  @Test
+  public void testCheckNotNegative() {
+    Durations.checkNotNegative(Durations.ZERO);
+    Durations.checkNotNegative(Durations.fromNanos(1));
+    Durations.checkNotNegative(Durations.fromSeconds(1));
+
+    try {
+      Durations.checkNotNegative(Durations.fromNanos(-1));
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo(
+          "duration (-0.000000001s) must not be negative");
+    }
+    try {
+      Durations.checkNotNegative(Durations.fromSeconds(-1));
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("duration (-1s) must not be negative");
+    }
+  }
+
+  @Test
+  public void testCheckPositive() {
+    Durations.checkPositive(Durations.fromNanos(1));
+    Durations.checkPositive(Durations.fromSeconds(1));
+
+    try {
+      Durations.checkPositive(Durations.ZERO);
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("duration (0s) must be positive");
+    }
+
+    try {
+      Durations.checkPositive(Durations.fromNanos(-1));
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("duration (-0.000000001s) must be positive");
+    }
+
+    try {
+      Durations.checkPositive(Durations.fromSeconds(-1));
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("duration (-1s) must be positive");
+    }
+  }
+
+  @Test
+  public void testToSecondsAsDouble() {
+    assertThat(toSecondsAsDouble(duration(0, 1))).isEqualTo(1.0e-9);
+    assertThat(toSecondsAsDouble(Durations.fromMillis(999))).isEqualTo(0.999);
+    assertThat(toSecondsAsDouble(duration(1, 0))).isEqualTo(1.0);
+    assertWithMessage("Precision loss detected")
+        .that(toSecondsAsDouble(Durations.fromNanos(1234567890987654321L)))
+        .isWithin(1.0e-6)
+        .of(1234567890.9876544);
+  }
+
+  @Test
+  public void testRoundtripConversions() {
+    for (long value : Arrays.asList(-123456, -42, -1, 0, 1, 42, 123456)) {
+      assertThat(Durations.toDays(Durations.fromDays(value))).isEqualTo(value);
+      assertThat(Durations.toHours(Durations.fromHours(value))).isEqualTo(value);
+      assertThat(Durations.toMinutes(Durations.fromMinutes(value))).isEqualTo(value);
+      assertThat(Durations.toSeconds(Durations.fromSeconds(value))).isEqualTo(value);
+      assertThat(Durations.toMillis(Durations.fromMillis(value))).isEqualTo(value);
+      assertThat(Durations.toMicros(Durations.fromMicros(value))).isEqualTo(value);
+      assertThat(Durations.toNanos(Durations.fromNanos(value))).isEqualTo(value);
+    }
+  }
+
+  @Test
+  public void testStaticFactories() {
+    Duration[] durations = {
+      Durations.fromDays(1),
+      Durations.fromHours(24),
+      Durations.fromMinutes(1440),
+      Durations.fromSeconds(86_400L),
+      Durations.fromMillis(86_400_000L),
+      Durations.fromMicros(86_400_000_000L),
+      Durations.fromNanos(86_400_000_000_000L)
+    };
+
+    for (Duration d1 : durations) {
+      assertThat(d1).isNotEqualTo(null);
+      for (Duration d2 : durations) {
+        assertThat(d1).isEqualTo(d2);
+      }
+    }
+  }
+
+  @Test
+  public void testMinMaxAreValid() {
+    assertThat(Durations.isValid(Durations.MAX_VALUE)).isTrue();
+    assertThat(Durations.isValid(Durations.MIN_VALUE)).isTrue();
+  }
+
+  @Test
+  public void testIsValid_false() {
+    assertThat(Durations.isValid(-315576000001L, 0)).isFalse();
+    assertThat(Durations.isValid(315576000001L, 0)).isFalse();
+    assertThat(Durations.isValid(42L, -42)).isFalse();
+    assertThat(Durations.isValid(-42L, 42)).isFalse();
+  }
+
+  @Test
+  public void testIsValid_true() {
+    assertThat(Durations.isValid(0L, 42)).isTrue();
+    assertThat(Durations.isValid(0L, -42)).isTrue();
+    assertThat(Durations.isValid(42L, 0)).isTrue();
+    assertThat(Durations.isValid(42L, 42)).isTrue();
+    assertThat(Durations.isValid(-315576000000L, 0)).isTrue();
+    assertThat(Durations.isValid(315576000000L, 0)).isTrue();
+  }
+
+  @Test
+  public void testParse_outOfRange() throws ParseException {
+    try {
+      Duration x = Durations.parse("316576000000.123456789123456789s");
+      fail("expected ParseException");
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Duration value is out of range.");
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testDurationStringFormat() throws Exception {
+    Timestamp start = Timestamps.parse("0001-01-01T00:00:00Z");
+    Timestamp end = Timestamps.parse("9999-12-31T23:59:59.999999999Z");
+    Duration duration = Timestamps.between(start, end);
+    assertThat(Durations.toString(duration)).isEqualTo("315537897599.999999999s");
+    duration = Timestamps.between(end, start);
+    assertThat(Durations.toString(duration)).isEqualTo("-315537897599.999999999s");
+
+    // Generated output should contain 3, 6, or 9 fractional digits.
+    duration = Duration.newBuilder().setSeconds(1).build();
+    assertThat(Durations.toString(duration)).isEqualTo("1s");
+    duration = Duration.newBuilder().setNanos(10000000).build();
+    assertThat(Durations.toString(duration)).isEqualTo("0.010s");
+    duration = Duration.newBuilder().setNanos(10000).build();
+    assertThat(Durations.toString(duration)).isEqualTo("0.000010s");
+    duration = Duration.newBuilder().setNanos(10).build();
+    assertThat(Durations.toString(duration)).isEqualTo("0.000000010s");
+
+    // Parsing accepts an fractional digits as long as they fit into nano
+    // precision.
+    duration = Durations.parse("0.1s");
+    assertThat(duration.getNanos()).isEqualTo(100000000);
+    duration = Durations.parse("0.0001s");
+    assertThat(duration.getNanos()).isEqualTo(100000);
+    duration = Durations.parse("0.0000001s");
+    assertThat(duration.getNanos()).isEqualTo(100);
+    // Repeat using parseUnchecked().
+    duration = Durations.parseUnchecked("0.1s");
+    assertThat(duration.getNanos()).isEqualTo(100000000);
+    duration = Durations.parseUnchecked("0.0001s");
+    assertThat(duration.getNanos()).isEqualTo(100000);
+    duration = Durations.parseUnchecked("0.0000001s");
+    assertThat(duration.getNanos()).isEqualTo(100);
+
+    // Duration must support range from -315,576,000,000s to +315576000000s
+    // which includes negative values.
+    duration = Durations.parse("315576000000.999999999s");
+    assertThat(duration.getSeconds()).isEqualTo(315576000000L);
+    assertThat(duration.getNanos()).isEqualTo(999999999);
+    duration = Durations.parse("-315576000000.999999999s");
+    assertThat(duration.getSeconds()).isEqualTo(-315576000000L);
+    assertThat(duration.getNanos()).isEqualTo(-999999999);
+    // Repeat using parseUnchecked().
+    duration = Durations.parseUnchecked("315576000000.999999999s");
+    assertThat(duration.getSeconds()).isEqualTo(315576000000L);
+    assertThat(duration.getNanos()).isEqualTo(999999999);
+    duration = Durations.parseUnchecked("-315576000000.999999999s");
+    assertThat(duration.getSeconds()).isEqualTo(-315576000000L);
+    assertThat(duration.getNanos()).isEqualTo(-999999999);
+  }
+
+  @Test
+  public void testDurationInvalidFormat() {
+    // Value too small.
+    try {
+      Durations.toString(
+                Duration.newBuilder().setSeconds(Durations.DURATION_SECONDS_MIN - 1).build());
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    try {
+      Durations.toString(
+                Duration.newBuilder().setSeconds(Durations.DURATION_SECONDS_MAX + 1).build());
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Invalid nanos value.
+    try {
+      Durations.toString(Duration.newBuilder().setSeconds(1).setNanos(-1).build());
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Invalid seconds value.
+    try {
+      Durations.toString(Duration.newBuilder().setSeconds(-1).setNanos(1).build());
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Value too small.
+    try {
+      Durations.parse("-315576000001s");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("-315576000001s");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Value too large.
+    try {
+      Durations.parse("315576000001s");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("315576000001s");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Empty.
+    try {
+      Durations.parse("");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Missing "s".
+    try {
+      Durations.parse("0");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("0");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Invalid trailing data.
+    try {
+      Durations.parse("0s0");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("0s0");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+
+    // Invalid prefix.
+    try {
+      Durations.parse("--1s");
+      fail();
+    } catch (ParseException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+    try {
+      Durations.parseUnchecked("--1s");
+      fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testDurationConversion() throws Exception {
+    Duration duration = Durations.parse("1.111111111s");
+    assertThat(Durations.toNanos(duration)).isEqualTo(1111111111);
+    assertThat(Durations.toMicros(duration)).isEqualTo(1111111);
+    assertThat(Durations.toMillis(duration)).isEqualTo(1111);
+    assertThat(Durations.toSeconds(duration)).isEqualTo(1);
+    duration = Durations.fromNanos(1111111111);
+    assertThat(Durations.toString(duration)).isEqualTo("1.111111111s");
+    duration = Durations.fromMicros(1111111);
+    assertThat(Durations.toString(duration)).isEqualTo("1.111111s");
+    duration = Durations.fromMillis(1111);
+    assertThat(Durations.toString(duration)).isEqualTo("1.111s");
+    duration = Durations.fromSeconds(1);
+    assertThat(Durations.toString(duration)).isEqualTo("1s");
+
+    duration = Durations.parse("-1.111111111s");
+    assertThat(Durations.toNanos(duration)).isEqualTo(-1111111111);
+    assertThat(Durations.toMicros(duration)).isEqualTo(-1111111);
+    assertThat(Durations.toMillis(duration)).isEqualTo(-1111);
+    assertThat(Durations.toSeconds(duration)).isEqualTo(-1);
+    duration = Durations.fromNanos(-1111111111);
+    assertThat(Durations.toString(duration)).isEqualTo("-1.111111111s");
+    duration = Durations.fromMicros(-1111111);
+    assertThat(Durations.toString(duration)).isEqualTo("-1.111111s");
+    duration = Durations.fromMillis(-1111);
+    assertThat(Durations.toString(duration)).isEqualTo("-1.111s");
+    duration = Durations.fromSeconds(-1);
+    assertThat(Durations.toString(duration)).isEqualTo("-1s");
+  }
+
+  @Test
+  public void testTimeOperations() throws Exception {
+    Timestamp start = Timestamps.parse("0001-01-01T00:00:00Z");
+    Timestamp end = Timestamps.parse("9999-12-31T23:59:59.999999999Z");
+
+    Duration duration = Timestamps.between(start, end);
+    assertThat(Durations.toString(duration)).isEqualTo("315537897599.999999999s");
+    Timestamp value = Timestamps.add(start, duration);
+    assertThat(value).isEqualTo(end);
+    value = Timestamps.subtract(end, duration);
+    assertThat(value).isEqualTo(start);
+
+    duration = Timestamps.between(end, start);
+    assertThat(Durations.toString(duration)).isEqualTo("-315537897599.999999999s");
+    value = Timestamps.add(end, duration);
+    assertThat(value).isEqualTo(start);
+    value = Timestamps.subtract(start, duration);
+    assertThat(value).isEqualTo(end);
+
+    duration = Durations.parse("-1.125s");
+    assertThat(Durations.toString(duration)).isEqualTo("-1.125s");
+
+    duration = Durations.add(duration, duration);
+    assertThat(Durations.toString(duration)).isEqualTo("-2.250s");
+
+    duration = Durations.subtract(duration, Durations.parse("-1s"));
+    assertThat(Durations.toString(duration)).isEqualTo("-1.250s");
+  }
+
+  @Test
+  public void testToString() {
+    assertThat(Durations.toString(duration(1, 1))).isEqualTo("1.000000001s");
+    assertThat(Durations.toString(duration(-1, -1))).isEqualTo("-1.000000001s");
+    assertThat(Durations.toString(duration(1, 0))).isEqualTo("1s");
+    assertThat(Durations.toString(duration(-1, 0))).isEqualTo("-1s");
+    assertThat(Durations.toString(duration(0, 1))).isEqualTo("0.000000001s");
+    assertThat(Durations.toString(duration(0, -1))).isEqualTo("-0.000000001s");
+  }
+
+  @Test
+  public void testAdd() {
+    assertThat(Durations.add(duration(1, 10), duration(1, 20))).isEqualTo(duration(2, 30));
+    assertThat(Durations.add(duration(1, 999999999), duration(1, 2))).isEqualTo(duration(3, 1));
+    assertThat(Durations.add(duration(1, 999999999), duration(1, 1))).isEqualTo(duration(3, 0));
+    assertThat(Durations.add(duration(1, 999999999), duration(-2, -1))).isEqualTo(duration(0, -2));
+    assertThat(Durations.add(duration(1, 999999999), duration(-2, 0))).isEqualTo(duration(0, -1));
+    assertThat(Durations.add(duration(-1, -10), duration(-1, -20))).isEqualTo(duration(-2, -30));
+    assertThat(Durations.add(duration(-1, -999999999), duration(-1, -2)))
+        .isEqualTo(duration(-3, -1));
+    assertThat(Durations.add(duration(-1, -999999999), duration(-1, -1)))
+        .isEqualTo(duration(-3, 0));
+    assertThat(Durations.add(duration(-1, -999999999), duration(2, 1))).isEqualTo(duration(0, 2));
+    assertThat(Durations.add(duration(-1, -999999999), duration(2, 0))).isEqualTo(duration(0, 1));
+  }
+
+  @Test
+  public void testSubtract() {
+    assertThat(Durations.subtract(duration(3, 2), duration(1, 1))).isEqualTo(duration(2, 1));
+    assertThat(Durations.subtract(duration(3, 10), duration(1, 10))).isEqualTo(duration(2, 0));
+    assertThat(Durations.subtract(duration(3, 1), duration(1, 2)))
+        .isEqualTo(duration(1, 999999999));
+    assertThat(Durations.subtract(duration(3, 2), duration(4, 1)))
+        .isEqualTo(duration(0, -999999999));
+    assertThat(Durations.subtract(duration(1, 1), duration(3, 2))).isEqualTo(duration(-2, -1));
+    assertThat(Durations.subtract(duration(1, 10), duration(3, 10))).isEqualTo(duration(-2, 0));
+    assertThat(Durations.subtract(duration(1, 2), duration(3, 1)))
+        .isEqualTo(duration(-1, -999999999));
+    assertThat(Durations.subtract(duration(4, 1), duration(3, 2)))
+        .isEqualTo(duration(0, 999999999));
+  }
+
+  @Test
+  public void testComparator() {
+    assertThat(Durations.comparator().compare(duration(3, 2), duration(3, 2))).isEqualTo(0);
+    assertThat(Durations.comparator().compare(duration(0, 0), duration(0, 0))).isEqualTo(0);
+    assertThat(Durations.comparator().compare(duration(3, 1), duration(1, 1))).isGreaterThan(0);
+    assertThat(Durations.comparator().compare(duration(3, 2), duration(3, 1))).isGreaterThan(0);
+    assertThat(Durations.comparator().compare(duration(1, 1), duration(3, 1))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(3, 1), duration(3, 2))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(-3, -1), duration(-1, -1))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(-3, -2), duration(-3, -1))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(-1, -1), duration(-3, -1))).isGreaterThan(0);
+    assertThat(Durations.comparator().compare(duration(-3, -1), duration(-3, -2))).isGreaterThan(0);
+    assertThat(Durations.comparator().compare(duration(-10, -1), duration(1, 1))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(0, -1), duration(0, 1))).isLessThan(0);
+    assertThat(Durations.comparator().compare(duration(0x80000000L, 0), duration(0, 0)))
+        .isGreaterThan(0);
+    assertThat(Durations.comparator().compare(duration(0xFFFFFFFF00000000L, 0), duration(0, 0)))
+        .isLessThan(0);
+
+    Duration duration0 = duration(-50, -500);
+    Duration duration1 = duration(-50, -400);
+    Duration duration2 = duration(50, 500);
+    Duration duration3 = duration(100, 20);
+    Duration duration4 = duration(100, 50);
+    Duration duration5 = duration(100, 150);
+    Duration duration6 = duration(150, 40);
+
+    List<Duration> durations =
+        Lists.newArrayList(
+            duration5, duration3, duration1, duration4, duration6, duration2, duration0, duration3);
+
+    Collections.sort(durations, Durations.comparator());
+    assertThat(durations)
+        .containsExactly(
+            duration0, duration1, duration2, duration3, duration3, duration4, duration5, duration6)
+        .inOrder();
+  }
+
+  @Test
+  public void testCompare() {
+    assertThat(Durations.compare(duration(3, 2), duration(3, 2))).isEqualTo(0);
+    assertThat(Durations.compare(duration(0, 0), duration(0, 0))).isEqualTo(0);
+    assertThat(Durations.compare(duration(3, 1), duration(1, 1))).isGreaterThan(0);
+    assertThat(Durations.compare(duration(3, 2), duration(3, 1))).isGreaterThan(0);
+    assertThat(Durations.compare(duration(1, 1), duration(3, 1))).isLessThan(0);
+    assertThat(Durations.compare(duration(3, 1), duration(3, 2))).isLessThan(0);
+    assertThat(Durations.compare(duration(-3, -1), duration(-1, -1))).isLessThan(0);
+    assertThat(Durations.compare(duration(-3, -2), duration(-3, -1))).isLessThan(0);
+    assertThat(Durations.compare(duration(-1, -1), duration(-3, -1))).isGreaterThan(0);
+    assertThat(Durations.compare(duration(-3, -1), duration(-3, -2))).isGreaterThan(0);
+    assertThat(Durations.compare(duration(-10, -1), duration(1, 1))).isLessThan(0);
+    assertThat(Durations.compare(duration(0, -1), duration(0, 1))).isLessThan(0);
+    assertThat(Durations.compare(duration(0x80000000L, 0), duration(0, 0))).isGreaterThan(0);
+    assertThat(Durations.compare(duration(0xFFFFFFFF00000000L, 0), duration(0, 0))).isLessThan(0);
+  }
+
+  @Test
+  public void testOverflows() throws Exception {
+    try {
+      Durations.toNanos(duration(315576000000L, 999999999));
+      assertWithMessage("Expected an ArithmeticException to be thrown").fail();
+    } catch (ArithmeticException expected) {
+    }
+
+    try {
+      Durations.add(Durations.MAX_VALUE, Durations.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.subtract(Durations.MIN_VALUE, Durations.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    try {
+      Durations.toNanos(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toMicros(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toMillis(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toSeconds(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    try {
+      Durations.toNanos(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toMicros(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toMillis(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.toSeconds(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    assertThat(Durations.toString(Durations.fromNanos(Long.MAX_VALUE)))
+        .isEqualTo("9223372036.854775807s");
+    try {
+      Durations.fromMicros(Long.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.fromMillis(Long.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.fromSeconds(Long.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+
+    assertThat(Durations.toString(Durations.fromNanos(Long.MIN_VALUE)))
+        .isEqualTo("-9223372036.854775808s");
+    try {
+      Durations.fromMicros(Long.MIN_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.fromMillis(Long.MIN_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      Durations.fromSeconds(Long.MIN_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  static Duration duration(long seconds, int nanos) {
+    return Durations.checkValid(
+        Durations.checkValid(Duration.newBuilder().setSeconds(seconds).setNanos(nanos)));
+  }
+}
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 f00bbb1..a38ebeb 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
@@ -79,17 +79,29 @@
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
 public class JsonFormatTest {
-  public JsonFormatTest() {
+
+  private static Locale originalLocale;
+
+  @BeforeClass
+  public static void setLocale() {
+    originalLocale = Locale.getDefault();
     // Test that locale does not affect JsonFormat.
     Locale.setDefault(Locale.forLanguageTag("hi-IN"));
   }
 
+  @AfterClass
+  public static void resetLocale() {
+    Locale.setDefault(originalLocale);
+  }
+
   private void setAllFields(TestAllTypes.Builder builder) {
     builder.setOptionalInt32(1234);
     builder.setOptionalInt64(1234567890123456789L);
@@ -343,29 +355,94 @@
       assertThat(builder.getRepeatedInt64(i)).isEqualTo(expectedValues[i]);
       assertThat(builder.getRepeatedUint64(i)).isEqualTo(expectedValues[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) {
+  @Test
+  public void testRejectTooLargeFloat() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    double tooLarge = 2.0 * Float.MAX_VALUE;
+    try {
+      mergeFromJson("{\"" + "optionalFloat" + "\":" + tooLarge + "}", builder);
+      assertWithMessage("InvalidProtocolBufferException expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Out of range float value: " + tooLarge);
+    }
+  }
+
+  @Test
+  public void testRejectMalformedFloat() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"optionalFloat\":3.5aa}", builder);
+      assertWithMessage("InvalidProtocolBufferException expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testRejectFractionalInt64() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"" + "optionalInt64" + "\":" + "1.5" + "}", builder);
+      assertWithMessage("Exception is expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Not an int64 value: 1.5");
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testRejectFractionalInt32() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"" + "optionalInt32" + "\":" + "1.5" + "}", builder);
+      assertWithMessage("Exception is expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Not an int32 value: 1.5");
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testRejectFractionalUnsignedInt32() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"" + "optionalUint32" + "\":" + "1.5" + "}", builder);
+      assertWithMessage("Exception is expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Not an uint32 value: 1.5");
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  @Test
+  public void testRejectFractionalUnsignedInt64() throws IOException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"" + "optionalUint64" + "\":" + "1.5" + "}", builder);
+      assertWithMessage("Exception is expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("Not an uint64 value: 1.5");
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+  }
+
+  private void assertRejects(String name, String value) throws IOException {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
       // Numeric form is rejected.
       mergeFromJson("{\"" + name + "\":" + value + "}", builder);
       assertWithMessage("Exception is expected.").fail();
-    } catch (IOException e) {
-      // Expected.
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().contains(value);
     }
     try {
       // String form is also rejected.
       mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder);
       assertWithMessage("Exception is expected.").fail();
-    } catch (IOException e) {
-      // Expected.
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().contains(value);
     }
   }
 
@@ -833,6 +910,7 @@
       assertThat(e)
           .hasMessageThat()
           .isEqualTo("Failed to parse timestamp: " + incorrectTimestampString);
+      assertThat(e).hasCauseThat().isNotNull();
     }
   }
 
@@ -857,6 +935,7 @@
       assertThat(e)
           .hasMessageThat()
           .isEqualTo("Failed to parse duration: " + incorrectDurationString);
+      assertThat(e).hasCauseThat().isNotNull();
     }
   }
 
@@ -973,8 +1052,9 @@
     try {
       toJsonString(message);
       assertWithMessage("Exception is expected.").fail();
-    } catch (IOException e) {
-      // Expected.
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo(
+          "Cannot find type for url: type.googleapis.com/json_test.TestAllTypes");
     }
 
     JsonFormat.TypeRegistry registry =
@@ -1288,7 +1368,13 @@
 
   @Test
   public void testParserRejectInvalidBase64() throws Exception {
-    assertRejects("optionalBytes", "!@#$");
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      mergeFromJson("{\"" + "optionalBytes" + "\":" + "!@#$" + "}", builder);
+      assertWithMessage("Exception is expected.").fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
   }
 
   @Test
diff --git a/java/util/src/test/java/com/google/protobuf/util/TimestampsTest.java b/java/util/src/test/java/com/google/protobuf/util/TimestampsTest.java
new file mode 100644
index 0000000..ea90a6b
--- /dev/null
+++ b/java/util/src/test/java/com/google/protobuf/util/TimestampsTest.java
@@ -0,0 +1,829 @@
+// 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.util;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.protobuf.util.DurationsTest.duration;
+
+import com.google.common.collect.Lists;
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link Timestamps}. */
+@RunWith(JUnit4.class)
+public class TimestampsTest {
+  private static final int MILLIS_PER_SECOND = 1000;
+  private static final long MILLIS = 1409130915111L;
+  private static final long SECONDS = MILLIS / MILLIS_PER_SECOND;
+  private static final long MICROS = MILLIS * 1000;
+  private static final long NANOS = MICROS * 1000;
+
+  @SuppressWarnings("ConstantOverflow")
+  private static final long MAX_VALUE = Long.MAX_VALUE * MILLIS_PER_SECOND + MILLIS_PER_SECOND;
+
+  @SuppressWarnings("ConstantOverflow")
+  private static final long MIN_VALUE = Long.MIN_VALUE * MILLIS_PER_SECOND;
+
+  private static final Timestamp TIMESTAMP = timestamp(1409130915, 111000000);
+  private static final Timestamp ZERO_TIMESTAMP = timestamp(0, 0);
+  private static final Timestamp ONE_OF_TIMESTAMP = timestamp(-1, 999000000);
+
+  private static final Timestamp INVALID_MAX =
+      Timestamp.newBuilder().setSeconds(Long.MAX_VALUE).setNanos(Integer.MAX_VALUE).build();
+  private static final Timestamp INVALID_MIN =
+      Timestamp.newBuilder().setSeconds(Long.MIN_VALUE).setNanos(Integer.MIN_VALUE).build();
+
+  @Test
+  public void testMinMaxAreValid() {
+    assertThat(Timestamps.isValid(Timestamps.MAX_VALUE)).isTrue();
+    assertThat(Timestamps.isValid(Timestamps.MIN_VALUE)).isTrue();
+  }
+
+
+  @Test
+  public void testIsValid_false() {
+    assertThat(Timestamps.isValid(0L, -1)).isFalse();
+    assertThat(Timestamps.isValid(1L, -1)).isFalse();
+    assertThat(Timestamps.isValid(1L, (int) Timestamps.NANOS_PER_SECOND)).isFalse();
+    assertThat(Timestamps.isValid(-62135596801L, 0)).isFalse();
+    assertThat(Timestamps.isValid(253402300800L, 0)).isFalse();
+  }
+
+  @Test
+  public void testIsValid_true() {
+    assertThat(Timestamps.isValid(0L, 0)).isTrue();
+    assertThat(Timestamps.isValid(1L, 0)).isTrue();
+    assertThat(Timestamps.isValid(1L, 1)).isTrue();
+    assertThat(Timestamps.isValid(42L, 0)).isTrue();
+    assertThat(Timestamps.isValid(42L, 42)).isTrue();
+    assertThat(Timestamps.isValid(-62135596800L, 0)).isTrue();
+    assertThat(Timestamps.isValid(-62135596800L, 1)).isTrue();
+    assertThat(Timestamps.isValid(62135596799L, 1)).isTrue();
+    assertThat(Timestamps.isValid(253402300799L, 0)).isTrue();
+    assertThat(Timestamps.isValid(253402300798L, 1)).isTrue();
+    assertThat(Timestamps.isValid(253402300798L, (int) (Timestamps.NANOS_PER_SECOND - 1))).isTrue();
+  }
+
+  @Test
+  public void testTimestampStringFormat() throws Exception {
+    Timestamp start = Timestamps.parse("0001-01-01T00:00:00Z");
+    Timestamp end = Timestamps.parse("9999-12-31T23:59:59.999999999Z");
+    assertThat(start.getSeconds()).isEqualTo(Timestamps.TIMESTAMP_SECONDS_MIN);
+    assertThat(start.getNanos()).isEqualTo(0);
+    assertThat(end.getSeconds()).isEqualTo(Timestamps.TIMESTAMP_SECONDS_MAX);
+    assertThat(end.getNanos()).isEqualTo(999999999);
+    assertThat(Timestamps.toString(start)).isEqualTo("0001-01-01T00:00:00Z");
+    assertThat(Timestamps.toString(end)).isEqualTo("9999-12-31T23:59:59.999999999Z");
+
+    Timestamp value = Timestamps.parse("1970-01-01T00:00:00Z");
+    assertThat(value.getSeconds()).isEqualTo(0);
+    assertThat(value.getNanos()).isEqualTo(0);
+    value = Timestamps.parseUnchecked("1970-01-01T00:00:00Z");
+    assertThat(value.getSeconds()).isEqualTo(0);
+    assertThat(value.getNanos()).isEqualTo(0);
+
+    // Test negative timestamps.
+    value = Timestamps.parse("1969-12-31T23:59:59.999Z");
+    assertThat(value.getSeconds()).isEqualTo(-1);
+    // Nano part is in the range of [0, 999999999] for Timestamp.
+    assertThat(value.getNanos()).isEqualTo(999000000);
+    value = Timestamps.parseUnchecked("1969-12-31T23:59:59.999Z");
+    assertThat(value.getSeconds()).isEqualTo(-1);
+    // Nano part is in the range of [0, 999999999] for Timestamp.
+    assertThat(value.getNanos()).isEqualTo(999000000);
+
+    // Test that 3, 6, or 9 digits are used for the fractional part.
+    value = Timestamp.newBuilder().setNanos(10).build();
+    assertThat(Timestamps.toString(value)).isEqualTo("1970-01-01T00:00:00.000000010Z");
+    value = Timestamp.newBuilder().setNanos(10000).build();
+    assertThat(Timestamps.toString(value)).isEqualTo("1970-01-01T00:00:00.000010Z");
+    value = Timestamp.newBuilder().setNanos(10000000).build();
+    assertThat(Timestamps.toString(value)).isEqualTo("1970-01-01T00:00:00.010Z");
+
+    // Test that parsing accepts timezone offsets.
+    value = Timestamps.parse("1970-01-01T00:00:00.010+08:00");
+    assertThat(Timestamps.toString(value)).isEqualTo("1969-12-31T16:00:00.010Z");
+    value = Timestamps.parse("1970-01-01T00:00:00.010-08:00");
+    assertThat(Timestamps.toString(value)).isEqualTo("1970-01-01T08:00:00.010Z");
+    value = Timestamps.parseUnchecked("1970-01-01T00:00:00.010+08:00");
+    assertThat(Timestamps.toString(value)).isEqualTo("1969-12-31T16:00:00.010Z");
+    value = Timestamps.parseUnchecked("1970-01-01T00:00:00.010-08:00");
+    assertThat(Timestamps.toString(value)).isEqualTo("1970-01-01T08:00:00.010Z");
+  }
+
+  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 = Timestamps.parse(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;
+      }
+    }
+  }
+
+  @Test
+  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] = Timestamps.parse(timestampStrings[i]);
+    }
+
+    final int threadCount = 16;
+    final int runningTime = 5000; // in milliseconds.
+    final List<Thread> threads = new ArrayList<>();
+
+    stopParsingThreads = false;
+    errorMessage = "";
+    for (int i = 0; i < threadCount; i++) {
+      Thread thread = new ParseTimestampThread(timestampStrings, timestampValues);
+      thread.start();
+      threads.add(thread);
+    }
+    Thread.sleep(runningTime);
+    stopParsingThreads = true;
+    for (Thread thread : threads) {
+      thread.join();
+    }
+    assertThat(errorMessage).isEmpty();
+  }
+
+  @Test
+  public void testTimestampInvalidFormatValueTooSmall() throws Exception {
+    try {
+      // Value too small.
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(Timestamps.TIMESTAMP_SECONDS_MIN - 1).build();
+      Timestamps.toString(value);
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatValueTooLarge() throws Exception {
+    try {
+      // Value too large.
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(Timestamps.TIMESTAMP_SECONDS_MAX + 1).build();
+      Timestamps.toString(value);
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatNanosTooSmall() throws Exception {
+    try {
+      // Invalid nanos value.
+      Timestamp value = Timestamp.newBuilder().setNanos(-1).build();
+      Timestamps.toString(value);
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatNanosTooLarge() throws Exception {
+    try {
+      // Invalid nanos value.
+      Timestamp value = Timestamp.newBuilder().setNanos(1000000000).build();
+      Timestamps.toString(value);
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatDateTooSmall() {
+    try {
+      Timestamps.parse("0000-01-01T00:00:00Z");
+      Assert.fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+      assertThat(expected).hasCauseThat().isNotNull();
+    }
+    try {
+      Timestamps.parseUnchecked("0000-01-01T00:00:00Z");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatDateTooLarge() {
+    try {
+      Timestamps.parse("10000-01-01T00:00:00Z");
+      Assert.fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("10000-01-01T00:00:00Z");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatMissingT() {
+    try {
+      Timestamps.parse("1970-01-01 00:00:00Z");
+      Assert.fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("1970-01-01 00:00:00Z");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidFormatMissingZ() {
+    try {
+      Timestamps.parse("1970-01-01T00:00:00");
+      assertWithMessage("ParseException is expected.").fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("1970-01-01T00:00:00");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidOffset() {
+    try {
+      Timestamps.parse("1970-01-01T00:00:00+0000");
+      assertWithMessage("ParseException is expected.").fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("1970-01-01T00:00:00+0000");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidTrailingText() {
+    try {
+      Timestamps.parse("1970-01-01T00:00:00Z0");
+      assertWithMessage("ParseException is expected.").fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("1970-01-01T00:00:00Z0");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampInvalidNanoSecond() {
+    try {
+      Timestamps.parse("1970-01-01T00:00:00.ABCZ");
+      assertWithMessage("ParseException is expected.").fail();
+    } catch (ParseException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+    try {
+      Timestamps.parseUnchecked("1970-01-01T00:00:00.ABCZ");
+      assertWithMessage("IllegalArgumentException is expected.").fail();
+    } catch (IllegalArgumentException expected) {
+      Assert.assertNotNull(expected.getMessage());
+    }
+  }
+
+  @Test
+  public void testTimestampConversion() throws Exception {
+    Timestamp timestamp = Timestamps.parse("1970-01-01T00:00:01.111111111Z");
+    assertThat(Timestamps.toNanos(timestamp)).isEqualTo(1111111111);
+    assertThat(Timestamps.toMicros(timestamp)).isEqualTo(1111111);
+    assertThat(Timestamps.toMillis(timestamp)).isEqualTo(1111);
+    assertThat(Timestamps.toSeconds(timestamp)).isEqualTo(1);
+    timestamp = Timestamps.fromNanos(1111111111);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111111111Z");
+    timestamp = Timestamps.fromMicros(1111111);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111111Z");
+    timestamp = Timestamps.fromMillis(1111);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111Z");
+    timestamp = Timestamps.fromSeconds(1);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01Z");
+
+    timestamp = Timestamps.parse("1969-12-31T23:59:59.111111111Z");
+    assertThat(Timestamps.toNanos(timestamp)).isEqualTo(-888888889);
+    assertThat(Timestamps.toMicros(timestamp)).isEqualTo(-888889);
+    assertThat(Timestamps.toMillis(timestamp)).isEqualTo(-889);
+    assertThat(Timestamps.toSeconds(timestamp)).isEqualTo(-1);
+    timestamp = Timestamps.fromNanos(-888888889);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1969-12-31T23:59:59.111111111Z");
+    timestamp = Timestamps.fromMicros(-888889);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1969-12-31T23:59:59.111111Z");
+    timestamp = Timestamps.fromMillis(-889);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1969-12-31T23:59:59.111Z");
+    timestamp = Timestamps.fromSeconds(-1);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1969-12-31T23:59:59Z");
+  }
+
+  @Test
+  public void testFromDate() {
+    Date date = new Date(1111);
+    Timestamp timestamp = Timestamps.fromDate(date);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111Z");
+  }
+
+  @Test
+  public void testFromDate_after9999CE() {
+    // protobuf still requires Java 7 so no java.time :-(
+    Calendar calendar = Calendar.getInstance();
+    calendar.clear(); // avoid random number of milliseconds
+    calendar.setTimeZone(TimeZone.getTimeZone("GMT-0"));
+    calendar.set(20000, Calendar.OCTOBER, 20, 5, 4, 3);
+    Date date = calendar.getTime();
+    try {
+      Timestamps.fromDate(date);
+      Assert.fail("should have thrown IllegalArgumentException");
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().startsWith("Timestamp is not valid.");
+    }
+  }
+
+  @Test
+  public void testFromDate_beforeYear1() {
+    // protobuf still requires Java 7 so no java.time :-(
+    Calendar calendar = Calendar.getInstance();
+    calendar.clear(); // avoid random number of milliseconds
+    calendar.setTimeZone(TimeZone.getTimeZone("GMT-0"));
+    calendar.set(-32, Calendar.OCTOBER, 20, 5, 4, 3);
+    Date date = calendar.getTime();
+    try {
+      Timestamps.fromDate(date);
+      Assert.fail("should have thrown IllegalArgumentException");
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().startsWith("Timestamp is not valid.");
+    }
+  }
+
+  @Test
+  public void testFromDate_after2262CE() {
+    // protobuf still requires Java 7 so no java.time :-(
+    Calendar calendar = Calendar.getInstance();
+    calendar.clear(); // avoid random number of milliseconds
+    calendar.setTimeZone(TimeZone.getTimeZone("GMT-0"));
+    calendar.set(2299, Calendar.OCTOBER, 20, 5, 4, 3);
+    Date date = calendar.getTime();
+    Timestamp timestamp = Timestamps.fromDate(date);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("2299-10-20T05:04:03Z");
+  }
+
+  /* Timestamp only stores integral seconds in the Date parent class and stores the nanosecond
+   * adjustment in the Timestamp class. */
+  @Test
+  public void testFromSqlTimestampSubMillisecondPrecision() {
+    java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(1111);
+    sqlTimestamp.setNanos(sqlTimestamp.getNanos() + 234567);
+    Timestamp timestamp = Timestamps.fromDate(sqlTimestamp);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111234567Z");
+  }
+
+  @Test
+  public void testFromSqlTimestamp() {
+    Date date = new java.sql.Timestamp(1111);
+    Timestamp timestamp = Timestamps.fromDate(date);
+    assertThat(Timestamps.toString(timestamp)).isEqualTo("1970-01-01T00:00:01.111Z");
+  }
+
+  @Test
+  public void testTimeOperations() throws Exception {
+    Timestamp start = Timestamps.parse("0001-01-01T00:00:00Z");
+    Timestamp end = Timestamps.parse("9999-12-31T23:59:59.999999999Z");
+
+    Duration duration = Timestamps.between(start, end);
+    assertThat(Durations.toString(duration)).isEqualTo("315537897599.999999999s");
+    Timestamp value = Timestamps.add(start, duration);
+    assertThat(value).isEqualTo(end);
+    value = Timestamps.subtract(end, duration);
+    assertThat(value).isEqualTo(start);
+
+    duration = Timestamps.between(end, start);
+    assertThat(Durations.toString(duration)).isEqualTo("-315537897599.999999999s");
+    value = Timestamps.add(end, duration);
+    assertThat(value).isEqualTo(start);
+    value = Timestamps.subtract(start, duration);
+    assertThat(value).isEqualTo(end);
+  }
+
+  @Test
+  public void testComparator() {
+    assertThat(Timestamps.compare(timestamp(3, 2), timestamp(3, 2))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(0, 0), timestamp(0, 0))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(3, 1), timestamp(1, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(3, 2), timestamp(3, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(1, 1), timestamp(3, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(3, 1), timestamp(3, 2))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 1), timestamp(-1, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 2), timestamp(-3, 3))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-1, 1), timestamp(-3, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 1), timestamp(-3, 2))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-10, 1), timestamp(1, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(0, 1), timestamp(0, 1))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(0x80000000L, 0), timestamp(0, 0))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(0xFFFFFFFF00000000L, 0), timestamp(0, 0)))
+        .isLessThan(0);
+
+    Timestamp timestamp0 = timestamp(-50, 400);
+    Timestamp timestamp1 = timestamp(-50, 500);
+    Timestamp timestamp2 = timestamp(50, 500);
+    Timestamp timestamp3 = timestamp(100, 20);
+    Timestamp timestamp4 = timestamp(100, 50);
+    Timestamp timestamp5 = timestamp(100, 150);
+    Timestamp timestamp6 = timestamp(150, 40);
+
+    List<Timestamp> timestamps =
+        Lists.newArrayList(
+            timestamp5,
+            timestamp3,
+            timestamp1,
+            timestamp4,
+            timestamp6,
+            timestamp2,
+            timestamp0,
+            timestamp3);
+
+    Collections.sort(timestamps, Timestamps.comparator());
+    assertThat(timestamps)
+        .containsExactly(
+            timestamp0,
+            timestamp1,
+            timestamp2,
+            timestamp3,
+            timestamp3,
+            timestamp4,
+            timestamp5,
+            timestamp6)
+        .inOrder();
+  }
+
+  @Test
+  public void testCompare() {
+    assertThat(Timestamps.compare(timestamp(3, 2), timestamp(3, 2))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(0, 0), timestamp(0, 0))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(3, 1), timestamp(1, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(3, 2), timestamp(3, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(1, 1), timestamp(3, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(3, 1), timestamp(3, 2))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 1), timestamp(-1, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 2), timestamp(-3, 3))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-1, 1), timestamp(-3, 1))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(-3, 1), timestamp(-3, 2))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(-10, 1), timestamp(1, 1))).isLessThan(0);
+    assertThat(Timestamps.compare(timestamp(0, 1), timestamp(0, 1))).isEqualTo(0);
+    assertThat(Timestamps.compare(timestamp(0x80000000L, 0), timestamp(0, 0))).isGreaterThan(0);
+    assertThat(Timestamps.compare(timestamp(0xFFFFFFFF00000000L, 0), timestamp(0, 0)))
+        .isLessThan(0);
+  }
+
+  @Test
+  public void testOverflowsArithmeticException() throws Exception {
+    try {
+      Timestamps.toNanos(Timestamps.parse("9999-12-31T23:59:59.999999999Z"));
+      assertWithMessage("Expected an ArithmeticException to be thrown").fail();
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  @Test
+  public void testPositiveOverflow() {
+    try {
+      Timestamps.add(Timestamps.MAX_VALUE, Durations.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testNegativeOverflow() {
+    try {
+      Timestamps.subtract(Timestamps.MIN_VALUE, Durations.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMaxNanosecondsOverflow() {
+    try {
+      Timestamps.toNanos(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+  @Test
+  public void testInvalidMaxMicrosecondsOverflow() {
+    try {
+      Timestamps.toMicros(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMaxMillisecondsOverflow() {
+    try {
+      Timestamps.toMillis(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMaxSecondsOverflow() {
+    try {
+      Timestamps.toSeconds(INVALID_MAX);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMinNanosecondsOverflow() {
+    try {
+      Timestamps.toNanos(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMicrosecondsMinOverflow() {
+    try {
+      Timestamps.toMicros(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testInvalidMinMillisecondsOverflow() {
+    try {
+      Timestamps.toMillis(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testOverInvalidMinSecondsflow() {
+    try {
+      Timestamps.toSeconds(INVALID_MIN);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testMaxNanosecondsConversion() {
+    assertThat(Timestamps.toString(Timestamps.fromNanos(Long.MAX_VALUE)))
+        .isEqualTo("2262-04-11T23:47:16.854775807Z");
+  }
+
+  @Test
+  public void testIllegalArgumentExceptionForMaxMicroseconds() {
+   try {
+      Timestamps.fromMicros(Long.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+
+  @Test
+  public void testIllegalArgumentExceptionForMaxMilliseconds() {
+    try {
+      Durations.fromMillis(Long.MAX_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testMinNanosecondsConversion() {
+    assertThat(Timestamps.toString(Timestamps.fromNanos(Long.MIN_VALUE)))
+        .isEqualTo("1677-09-21T00:12:43.145224192Z");
+  }
+
+  @Test
+  public void testIllegalArgumentExceptionForMinMicroseconds() {
+    try {
+      Timestamps.fromMicros(Long.MIN_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+
+  @Test
+  public void testIllegalArgumentExceptionForMinMilliseconds() {
+    try {
+      Timestamps.fromMillis(Long.MIN_VALUE);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testConvertFromSeconds() {
+    assertThat(Timestamps.fromSeconds(SECONDS).getSeconds()).isEqualTo(TIMESTAMP.getSeconds());
+    assertThat(Timestamps.EPOCH).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromSeconds(MAX_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromSeconds(MIN_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+  }
+
+  @Test
+  public void testConvertFromMillis() {
+    assertThat(Timestamps.fromMillis(MILLIS)).isEqualTo(TIMESTAMP);
+    assertThat(Timestamps.EPOCH).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromMillis(-1)).isEqualTo(ONE_OF_TIMESTAMP);
+    assertThat(Timestamps.fromMillis(MAX_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromMillis(MIN_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+  }
+
+  @Test
+  public void testConvertFromMicros() {
+    assertThat(Timestamps.fromMicros(MICROS)).isEqualTo(TIMESTAMP);
+    assertThat(Timestamps.EPOCH).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromMicros(-1000)).isEqualTo(ONE_OF_TIMESTAMP);
+    assertThat(Timestamps.fromMicros(MAX_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromMicros(MIN_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+  }
+
+  @Test
+  public void testConvertToSeconds() {
+    assertThat(Timestamps.toSeconds(TIMESTAMP)).isEqualTo(SECONDS);
+    assertThat(Timestamps.toSeconds(ZERO_TIMESTAMP)).isEqualTo(0);
+    assertThat(Timestamps.toSeconds(ONE_OF_TIMESTAMP)).isEqualTo(-1);
+  }
+
+  @Test
+  public void testConvertToMillis() {
+    assertThat(Timestamps.toMillis(TIMESTAMP)).isEqualTo(MILLIS);
+    assertThat(Timestamps.toMillis(ZERO_TIMESTAMP)).isEqualTo(0);
+    assertThat(Timestamps.toMillis(ONE_OF_TIMESTAMP)).isEqualTo(-1);
+  }
+
+  @Test
+  public void testConvertToMicros() {
+    assertThat(Timestamps.toMicros(TIMESTAMP)).isEqualTo(MICROS);
+    assertThat(Timestamps.toMicros(ZERO_TIMESTAMP)).isEqualTo(0);
+    assertThat(Timestamps.toMicros(ONE_OF_TIMESTAMP)).isEqualTo(-1000);
+  }
+
+  @Test
+  public void testConvertFromMillisAboveTimestampMaxLimit() {
+    long timestampMaxSeconds = 253402300799L;
+    try {
+      Timestamps.fromMillis((timestampMaxSeconds + 1) * MILLIS_PER_SECOND);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testConvertFromMillisBelowTimestampMaxLimit() {
+    long timestampMinSeconds = -62135596800L;
+    try {
+      Timestamps.fromMillis((timestampMinSeconds - 1) * MILLIS_PER_SECOND);
+      assertWithMessage("Expected an IllegalArgumentException to be thrown").fail();
+    } catch (IllegalArgumentException expected) {
+    }
+  }
+
+  @Test
+  public void testConvertFromNanos() {
+    assertThat(Timestamps.fromNanos(NANOS)).isEqualTo(TIMESTAMP);
+    assertThat(Timestamps.fromNanos(0)).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromNanos(-1000000)).isEqualTo(ONE_OF_TIMESTAMP);
+    assertThat(Timestamps.fromNanos(MAX_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+    assertThat(Timestamps.fromNanos(MIN_VALUE)).isEqualTo(ZERO_TIMESTAMP);
+  }
+
+  @Test
+  public void testConvertToNanos() {
+    assertThat(Timestamps.toNanos(TIMESTAMP)).isEqualTo(NANOS);
+    assertThat(Timestamps.toNanos(ZERO_TIMESTAMP)).isEqualTo(0);
+    assertThat(Timestamps.toNanos(ONE_OF_TIMESTAMP)).isEqualTo(-1000000);
+  }
+
+  @Test
+  public void testAdd() {
+    assertThat(Timestamps.add(timestamp(1, 10), duration(1, 20))).isEqualTo(timestamp(2, 30));
+    assertThat(Timestamps.add(timestamp(1, 10), duration(-1, -11)))
+        .isEqualTo(timestamp(-1, 999999999));
+    assertThat(Timestamps.add(timestamp(10, 10), duration(-1, -11)))
+        .isEqualTo(timestamp(8, 999999999));
+    assertThat(Timestamps.add(timestamp(1, 1), duration(1, 999999999))).isEqualTo(timestamp(3, 0));
+    assertThat(Timestamps.add(timestamp(1, 2), duration(1, 999999999))).isEqualTo(timestamp(3, 1));
+  }
+
+  @Test
+  public void testSubtractDuration() {
+    assertThat(Timestamps.subtract(timestamp(1, 10), duration(-1, -20)))
+        .isEqualTo(timestamp(2, 30));
+    assertThat(Timestamps.subtract(timestamp(1, 10), duration(1, 11)))
+        .isEqualTo(timestamp(-1, 999999999));
+    assertThat(Timestamps.subtract(timestamp(10, 10), duration(1, 11)))
+        .isEqualTo(timestamp(8, 999999999));
+    assertThat(Timestamps.subtract(timestamp(1, 1), duration(-1, -999999999)))
+        .isEqualTo(timestamp(3, 0));
+    assertThat(Timestamps.subtract(timestamp(1, 2), duration(-1, -999999999)))
+        .isEqualTo(timestamp(3, 1));
+  }
+
+  static Timestamp timestamp(long seconds, int nanos) {
+    return Timestamps.checkValid(
+        Timestamps.checkValid(Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos)));
+  }
+}
diff --git a/js/commonjs/export.js b/js/commonjs/export.js
index 2025d9a..29a8713 100644
--- a/js/commonjs/export.js
+++ b/js/commonjs/export.js
@@ -15,7 +15,7 @@
 goog.require('jspb.Message');
 goog.require('jspb.Map');
 
-if ( typeof exports === 'object' ) {
+if (typeof exports === 'object') {
   exports.Map = jspb.Map;
   exports.Message = jspb.Message;
   exports.BinaryReader = jspb.BinaryReader;
@@ -23,7 +23,8 @@
   exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
   exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo;
 
-  // These are used by generated code but should not be used directly by clients.
+  // 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/php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php b/php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php
index ea0edc5..d71def9 100644
--- a/php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php
+++ b/php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php
@@ -184,6 +184,7 @@
             ->optional('packed', \Google\Protobuf\Internal\GPBType::BOOL, 2)
             ->optional('jstype', \Google\Protobuf\Internal\GPBType::ENUM, 6, 'google.protobuf.internal.FieldOptions.JSType')
             ->optional('lazy', \Google\Protobuf\Internal\GPBType::BOOL, 5)
+            ->optional('unverified_lazy', \Google\Protobuf\Internal\GPBType::BOOL, 15)
             ->optional('deprecated', \Google\Protobuf\Internal\GPBType::BOOL, 3)
             ->optional('weak', \Google\Protobuf\Internal\GPBType::BOOL, 10)
             ->repeated('uninterpreted_option', \Google\Protobuf\Internal\GPBType::MESSAGE, 999, 'google.protobuf.internal.UninterpretedOption')
diff --git a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
index 9cf6f10..5e99bff 100644
--- a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
@@ -58,7 +58,6 @@
      * 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?
      *
      * Generated from protobuf field <code>optional string default_value = 7;</code>
      */
@@ -133,7 +132,6 @@
      *           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?
      *     @type int $oneof_index
      *           If set, gives the index of a oneof in the containing type's oneof_decl
      *           list.  This field is a member of that oneof.
@@ -390,7 +388,6 @@
      * 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?
      *
      * Generated from protobuf field <code>optional string default_value = 7;</code>
      * @return string
@@ -415,7 +412,6 @@
      * 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?
      *
      * Generated from protobuf field <code>optional string default_value = 7;</code>
      * @param string $var
diff --git a/php/src/Google/Protobuf/Internal/FieldOptions.php b/php/src/Google/Protobuf/Internal/FieldOptions.php
index c6c63a9..5fe7a19 100644
--- a/php/src/Google/Protobuf/Internal/FieldOptions.php
+++ b/php/src/Google/Protobuf/Internal/FieldOptions.php
@@ -74,11 +74,23 @@
      * implementation must either *always* check its required fields, or *never*
      * check its required fields, regardless of whether or not the message has
      * been parsed.
+     * As of 2021, lazy does no correctness checks on the byte stream during
+     * parsing.  This may lead to crashes if and when an invalid byte stream is
+     * finally parsed upon access.
+     * TODO(b/211906113):  Enable validation on lazy fields.
      *
      * Generated from protobuf field <code>optional bool lazy = 5 [default = false];</code>
      */
     protected $lazy = null;
     /**
+     * unverified_lazy does no correctness checks on the byte stream. This should
+     * only be used where lazy with verification is prohibitive for performance
+     * reasons.
+     *
+     * Generated from protobuf field <code>optional bool unverified_lazy = 15 [default = false];</code>
+     */
+    protected $unverified_lazy = null;
+    /**
      * 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
@@ -153,6 +165,14 @@
      *           implementation must either *always* check its required fields, or *never*
      *           check its required fields, regardless of whether or not the message has
      *           been parsed.
+     *           As of 2021, lazy does no correctness checks on the byte stream during
+     *           parsing.  This may lead to crashes if and when an invalid byte stream is
+     *           finally parsed upon access.
+     *           TODO(b/211906113):  Enable validation on lazy fields.
+     *     @type bool $unverified_lazy
+     *           unverified_lazy does no correctness checks on the byte stream. This should
+     *           only be used where lazy with verification is prohibitive for performance
+     *           reasons.
      *     @type bool $deprecated
      *           Is this field deprecated?
      *           Depending on the target platform, this can emit Deprecated annotations
@@ -334,6 +354,10 @@
      * implementation must either *always* check its required fields, or *never*
      * check its required fields, regardless of whether or not the message has
      * been parsed.
+     * As of 2021, lazy does no correctness checks on the byte stream during
+     * parsing.  This may lead to crashes if and when an invalid byte stream is
+     * finally parsed upon access.
+     * TODO(b/211906113):  Enable validation on lazy fields.
      *
      * Generated from protobuf field <code>optional bool lazy = 5 [default = false];</code>
      * @return bool
@@ -378,6 +402,10 @@
      * implementation must either *always* check its required fields, or *never*
      * check its required fields, regardless of whether or not the message has
      * been parsed.
+     * As of 2021, lazy does no correctness checks on the byte stream during
+     * parsing.  This may lead to crashes if and when an invalid byte stream is
+     * finally parsed upon access.
+     * TODO(b/211906113):  Enable validation on lazy fields.
      *
      * Generated from protobuf field <code>optional bool lazy = 5 [default = false];</code>
      * @param bool $var
@@ -392,6 +420,46 @@
     }
 
     /**
+     * unverified_lazy does no correctness checks on the byte stream. This should
+     * only be used where lazy with verification is prohibitive for performance
+     * reasons.
+     *
+     * Generated from protobuf field <code>optional bool unverified_lazy = 15 [default = false];</code>
+     * @return bool
+     */
+    public function getUnverifiedLazy()
+    {
+        return isset($this->unverified_lazy) ? $this->unverified_lazy : false;
+    }
+
+    public function hasUnverifiedLazy()
+    {
+        return isset($this->unverified_lazy);
+    }
+
+    public function clearUnverifiedLazy()
+    {
+        unset($this->unverified_lazy);
+    }
+
+    /**
+     * unverified_lazy does no correctness checks on the byte stream. This should
+     * only be used where lazy with verification is prohibitive for performance
+     * reasons.
+     *
+     * Generated from protobuf field <code>optional bool unverified_lazy = 15 [default = false];</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setUnverifiedLazy($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->unverified_lazy = $var;
+
+        return $this;
+    }
+
+    /**
      * 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
diff --git a/python/.repo-metadata.json b/python/.repo-metadata.json
deleted file mode 100644
index c8d71a8..0000000
--- a/python/.repo-metadata.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "protobuf",
-  "name_pretty": "Protocol Buffers",
-  "product_documentation": "https://developers.google.com/protocol-buffers ",
-  "client_documentation": "https://developers.google.com/protocol-buffers/docs/pythontutorial",
-  "issue_tracker": "https://github.com/protocolbuffers/protobuf/issues",
-  "release_level": "ga",
-  "language": "python",
-  "repo": "protocolbuffers/protobuf ",
-  "distribution_name": "protobuf"
-}
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 7e98293..ad70be9 100644
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -617,6 +617,26 @@
       self._camelcase_name = _ToCamelCase(self.name)
     return self._camelcase_name
 
+  @property
+  def has_presence(self):
+    """Whether the field distinguishes between unpopulated and default values.
+
+    Raises:
+      RuntimeError: singular field that is not linked with message nor file.
+    """
+    if self.label == FieldDescriptor.LABEL_REPEATED:
+      return False
+    if (self.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE or
+        self.containing_oneof):
+      return True
+    if hasattr(self.file, 'syntax'):
+      return self.file.syntax == 'proto2'
+    if hasattr(self.message_type, 'syntax'):
+      return self.message_type.syntax == 'proto2'
+    raise RuntimeError(
+        'has_presence is not ready to use because field %s is not'
+        ' linked with message type nor file' % self.full_name)
+
   @staticmethod
   def ProtoTypeToCppProtoType(proto_type):
     """Converts from a Python proto type to a C++ Proto Type.
@@ -879,6 +899,8 @@
       accepts.
     output_type (Descriptor): The descriptor of the message that this method
       returns.
+    client_streaming (bool): Whether this method uses client streaming.
+    server_streaming (bool): Whether this method uses server streaming.
     options (descriptor_pb2.MethodOptions or None): Method options message, or
       None to use default method options.
   """
@@ -886,14 +908,32 @@
   if _USE_C_DESCRIPTORS:
     _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
 
-    def __new__(cls, name, full_name, index, containing_service,
-                input_type, output_type, options=None, serialized_options=None,
+    def __new__(cls,
+                name,
+                full_name,
+                index,
+                containing_service,
+                input_type,
+                output_type,
+                client_streaming=False,
+                server_streaming=False,
+                options=None,
+                serialized_options=None,
                 create_key=None):
       _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
       return _message.default_pool.FindMethodByName(full_name)
 
-  def __init__(self, name, full_name, index, containing_service,
-               input_type, output_type, options=None, serialized_options=None,
+  def __init__(self,
+               name,
+               full_name,
+               index,
+               containing_service,
+               input_type,
+               output_type,
+               client_streaming=False,
+               server_streaming=False,
+               options=None,
+               serialized_options=None,
                create_key=None):
     """The arguments are as described in the description of MethodDescriptor
     attributes above.
@@ -911,6 +951,8 @@
     self.containing_service = containing_service
     self.input_type = input_type
     self.output_type = output_type
+    self.client_streaming = client_streaming
+    self.server_streaming = server_streaming
 
   def CopyToProto(self, proto):
     """Copies this to a descriptor_pb2.MethodDescriptorProto.
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index a6955ce..62b4307 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -1213,6 +1213,8 @@
         containing_service=None,
         input_type=input_type,
         output_type=output_type,
+        client_streaming=method_proto.client_streaming,
+        server_streaming=method_proto.server_streaming,
         options=_OptionsOrNone(method_proto),
         # pylint: disable=protected-access
         create_key=descriptor._internal_create_key)
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py
index deafab3..afdbb78 100755
--- a/python/google/protobuf/internal/_parameterized.py
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -354,7 +354,7 @@
 
   def __new__(mcs, class_name, bases, dct):
     dct['_id_suffix'] = id_suffix = {}
-    for name, obj in dct.items():
+    for name, obj in dct.copy().items():
       if (name.startswith(unittest.TestLoader.testMethodPrefix) and
           _NonStringIterable(obj)):
         iterator = iter(obj)
@@ -386,9 +386,8 @@
     id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
 
 
-class TestCase(unittest.TestCase):
+class TestCase(unittest.TestCase, metaclass=TestGeneratorMetaclass):
   """Base class for test cases using the parameters decorator."""
-  __metaclass__ = TestGeneratorMetaclass
 
   def _OriginalName(self):
     return self._testMethodName.split(_SEPARATOR)[0]
diff --git a/python/google/protobuf/internal/api_implementation.cc b/python/google/protobuf/internal/api_implementation.cc
index 8023224..33f5b04 100644
--- a/python/google/protobuf/internal/api_implementation.cc
+++ b/python/google/protobuf/internal/api_implementation.cc
@@ -82,24 +82,24 @@
                                      kModuleName,
                                      kModuleDocstring,
                                      -1,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     NULL};
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr};
 
 extern "C" {
 PyMODINIT_FUNC PyInit__api_implementation() {
   PyObject* module = PyModule_Create(&_module);
-  if (module == NULL) {
-    return NULL;
+  if (module == nullptr) {
+    return nullptr;
   }
 
   // Adds the module variable "api_version".
   if (PyModule_AddIntConstant(module, const_cast<char*>(kImplVersionName),
                               kImplVersion)) {
     Py_DECREF(module);
-    return NULL;
+    return nullptr;
   }
 
   return module;
diff --git a/python/google/protobuf/internal/builder.py b/python/google/protobuf/internal/builder.py
new file mode 100644
index 0000000..64353ee
--- /dev/null
+++ b/python/google/protobuf/internal/builder.py
@@ -0,0 +1,130 @@
+# 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.
+
+"""Builds descriptors, message classes and services for generated _pb2.py.
+
+This file is only called in python generated _pb2.py files. It builds
+descriptors, message classes and services that users can directly use
+in generated code.
+"""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+
+_sym_db = _symbol_database.Default()
+
+
+def BuildMessageAndEnumDescriptors(file_des, module):
+  """Builds message and enum descriptors.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module: Generated _pb2 module
+  """
+
+  def BuildNestedDescriptors(msg_des, prefix):
+    for (name, nested_msg) in msg_des.nested_types_by_name.items():
+      module_name = prefix + name.upper()
+      module[module_name] = nested_msg
+      BuildNestedDescriptors(nested_msg, module_name + '_')
+    for enum_des in msg_des.enum_types:
+      module[prefix + enum_des.name.upper()] = enum_des
+
+  for (name, msg_des) in file_des.message_types_by_name.items():
+    module_name = '_' + name.upper()
+    module[module_name] = msg_des
+    BuildNestedDescriptors(msg_des, module_name + '_')
+
+
+def BuildTopDescriptorsAndMessages(file_des, module_name, module):
+  """Builds top level descriptors and message classes.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module_name: str, the name of generated _pb2 module
+    module: Generated _pb2 module
+  """
+
+  def BuildMessage(msg_des):
+    create_dict = {}
+    for (name, nested_msg) in msg_des.nested_types_by_name.items():
+      create_dict[name] = BuildMessage(nested_msg)
+    create_dict['DESCRIPTOR'] = msg_des
+    create_dict['__module__'] = module_name
+    message_class = _reflection.GeneratedProtocolMessageType(
+        msg_des.name, (_message.Message,), create_dict)
+    _sym_db.RegisterMessage(message_class)
+    return message_class
+
+  # top level enums
+  for (name, enum_des) in file_des.enum_types_by_name.items():
+    module['_' + name.upper()] = enum_des
+    module[name] = enum_type_wrapper.EnumTypeWrapper(enum_des)
+    for enum_value in enum_des.values:
+      module[enum_value.name] = enum_value.number
+
+  # top level extensions
+  for (name, extension_des) in file_des.extensions_by_name.items():
+    module[name.upper() + '_FIELD_NUMBER'] = extension_des.number
+    module[name] = extension_des
+
+  # services
+  for (name, service) in file_des.services_by_name.items():
+    module['_' + name.upper()] = service
+
+  # Build messages.
+  for (name, msg_des) in file_des.message_types_by_name.items():
+    module[name] = BuildMessage(msg_des)
+
+
+def BuildServices(file_des, module_name, module):
+  """Builds services classes and services stub class.
+
+  Args:
+    file_des: FileDescriptor of the .proto file
+    module_name: str, the name of generated _pb2 module
+    module: Generated _pb2 module
+  """
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf import service as _service
+  from google.protobuf import service_reflection
+  # pylint: enable=g-import-not-at-top
+  for (name, service) in file_des.services_by_name.items():
+    module[name] = service_reflection.GeneratedServiceType(
+        name, (_service.Service,),
+        dict(DESCRIPTOR=service, __module__=module_name))
+    stub_name = name + '_Stub'
+    module[stub_name] = service_reflection.GeneratedServiceStubType(
+        stub_name, (module[name],),
+        dict(DESCRIPTOR=service, __module__=module_name))
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index f0c06df..29fbb53 100644
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -40,19 +40,37 @@
     includes groups and nested messages.
 """
 
-__author__ = 'petar@google.com (Petar Petrov)'
-
 import collections.abc
+import copy
+import pickle
+from typing import (
+    Any,
+    Iterable,
+    Iterator,
+    List,
+    MutableMapping,
+    MutableSequence,
+    NoReturn,
+    Optional,
+    Sequence,
+    TypeVar,
+    Union,
+    overload,
+)
 
 
-class BaseContainer(object):
+_T = TypeVar('_T')
+_K = TypeVar('_K')
+_V = TypeVar('_V')
 
+
+class BaseContainer(Sequence[_T]):
   """Base container class."""
 
   # Minimizes memory usage and disallows assignment to other attributes.
   __slots__ = ['_message_listener', '_values']
 
-  def __init__(self, message_listener):
+  def __init__(self, message_listener: Any) -> None:
     """
     Args:
       message_listener: A MessageListener implementation.
@@ -62,26 +80,33 @@
     self._message_listener = message_listener
     self._values = []
 
+  @overload
+  def __getitem__(self, key: int) -> _T:
+    ...
+
+  @overload
+  def __getitem__(self, key: slice) -> List[_T]:
+    ...
+
   def __getitem__(self, key):
     """Retrieves item by the specified key."""
     return self._values[key]
 
-  def __len__(self):
+  def __len__(self) -> int:
     """Returns the number of elements in the container."""
     return len(self._values)
 
-  def __ne__(self, other):
+  def __ne__(self, other: Any) -> bool:
     """Checks if another instance isn't equal to this one."""
     # The concrete classes should define __eq__.
     return not self == other
 
-  def __hash__(self):
-    raise TypeError('unhashable object')
+  __hash__ = None
 
-  def __repr__(self):
+  def __repr__(self) -> str:
     return repr(self._values)
 
-  def sort(self, *args, **kwargs):
+  def sort(self, *args, **kwargs) -> None:
     # Continue to support the old sort_function keyword argument.
     # This is expected to be a rare occurrence, so use LBYL to avoid
     # the overhead of actually catching KeyError.
@@ -89,20 +114,26 @@
       kwargs['cmp'] = kwargs.pop('sort_function')
     self._values.sort(*args, **kwargs)
 
-  def reverse(self):
+  def reverse(self) -> None:
     self._values.reverse()
 
 
+# TODO(slebedev): Remove this. BaseContainer does *not* conform to
+# MutableSequence, only its subclasses do.
 collections.abc.MutableSequence.register(BaseContainer)
 
 
-class RepeatedScalarFieldContainer(BaseContainer):
+class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]):
   """Simple, type-checked, list-like container for holding repeated scalars."""
 
   # Disallows assignment to other attributes.
   __slots__ = ['_type_checker']
 
-  def __init__(self, message_listener, type_checker):
+  def __init__(
+      self,
+      message_listener: Any,
+      type_checker: Any,
+  ) -> None:
     """Args:
 
       message_listener: A MessageListener implementation. The
@@ -111,24 +142,23 @@
       type_checker: A type_checkers.ValueChecker instance to run on elements
       inserted into this container.
     """
-    super(RepeatedScalarFieldContainer, self).__init__(message_listener)
+    super().__init__(message_listener)
     self._type_checker = type_checker
 
-  def append(self, value):
+  def append(self, value: _T) -> None:
     """Appends an item to the list. Similar to list.append()."""
     self._values.append(self._type_checker.CheckValue(value))
     if not self._message_listener.dirty:
       self._message_listener.Modified()
 
-  def insert(self, key, value):
+  def insert(self, key: int, value: _T) -> None:
     """Inserts the item at the specified position. Similar to list.insert()."""
     self._values.insert(key, self._type_checker.CheckValue(value))
     if not self._message_listener.dirty:
       self._message_listener.Modified()
 
-  def extend(self, elem_seq):
+  def extend(self, elem_seq: Iterable[_T]) -> None:
     """Extends by appending the given iterable. Similar to list.extend()."""
-
     if elem_seq is None:
       return
     try:
@@ -145,57 +175,52 @@
       self._values.extend(new_values)
     self._message_listener.Modified()
 
-  def MergeFrom(self, other):
+  def MergeFrom(
+      self,
+      other: Union['RepeatedScalarFieldContainer[_T]', Iterable[_T]],
+  ) -> None:
     """Appends the contents of another repeated field of the same type to this
     one. We do not check the types of the individual fields.
     """
-    self._values.extend(other._values)
+    self._values.extend(other)
     self._message_listener.Modified()
 
-  def remove(self, elem):
+  def remove(self, elem: _T):
     """Removes an item from the list. Similar to list.remove()."""
     self._values.remove(elem)
     self._message_listener.Modified()
 
-  def pop(self, key=-1):
+  def pop(self, key: Optional[int] = -1) -> _T:
     """Removes and returns an item at a given index. Similar to list.pop()."""
     value = self._values[key]
     self.__delitem__(key)
     return value
 
-  def __setitem__(self, key, value):
+  @overload
+  def __setitem__(self, key: int, value: _T) -> None:
+    ...
+
+  @overload
+  def __setitem__(self, key: slice, value: Iterable[_T]) -> None:
+    ...
+
+  def __setitem__(self, key, value) -> None:
     """Sets the item on the specified position."""
-    if isinstance(key, slice):  # PY3
+    if isinstance(key, slice):
       if key.step is not None:
         raise ValueError('Extended slices not supported')
-      self.__setslice__(key.start, key.stop, value)
+      self._values[key] = map(self._type_checker.CheckValue, value)
+      self._message_listener.Modified()
     else:
       self._values[key] = self._type_checker.CheckValue(value)
       self._message_listener.Modified()
 
-  def __getslice__(self, start, stop):
-    """Retrieves the subset of items from between the specified indices."""
-    return self._values[start:stop]
-
-  def __setslice__(self, start, stop, values):
-    """Sets the subset of items from between the specified indices."""
-    new_values = []
-    for value in values:
-      new_values.append(self._type_checker.CheckValue(value))
-    self._values[start:stop] = new_values
-    self._message_listener.Modified()
-
-  def __delitem__(self, key):
+  def __delitem__(self, key: Union[int, slice]) -> None:
     """Deletes the item at the specified position."""
     del self._values[key]
     self._message_listener.Modified()
 
-  def __delslice__(self, start, stop):
-    """Deletes the subset of items from between the specified indices."""
-    del self._values[start:stop]
-    self._message_listener.Modified()
-
-  def __eq__(self, other):
+  def __eq__(self, other: Any) -> bool:
     """Compares the current instance with another one."""
     if self is other:
       return True
@@ -205,15 +230,28 @@
     # We are presumably comparing against some other sequence type.
     return other == self._values
 
+  def __deepcopy__(
+      self,
+      unused_memo: Any = None,
+  ) -> 'RepeatedScalarFieldContainer[_T]':
+    clone = RepeatedScalarFieldContainer(
+        copy.deepcopy(self._message_listener), self._type_checker)
+    clone.MergeFrom(self)
+    return clone
 
-class RepeatedCompositeFieldContainer(BaseContainer):
+  def __reduce__(self, **kwargs) -> NoReturn:
+    raise pickle.PickleError(
+        "Can't pickle repeated scalar fields, convert to list first")
 
+
+# TODO(slebedev): Constrain T to be a subtype of Message.
+class RepeatedCompositeFieldContainer(BaseContainer[_T], MutableSequence[_T]):
   """Simple, list-like container for holding repeated composite fields."""
 
   # Disallows assignment to other attributes.
   __slots__ = ['_message_descriptor']
 
-  def __init__(self, message_listener, message_descriptor):
+  def __init__(self, message_listener: Any, message_descriptor: Any) -> None:
     """
     Note that we pass in a descriptor instead of the generated directly,
     since at the time we construct a _RepeatedCompositeFieldContainer we
@@ -228,10 +266,10 @@
         that should be present in this container.  We'll use the
         _concrete_class field of this descriptor when the client calls add().
     """
-    super(RepeatedCompositeFieldContainer, self).__init__(message_listener)
+    super().__init__(message_listener)
     self._message_descriptor = message_descriptor
 
-  def add(self, **kwargs):
+  def add(self, **kwargs: Any) -> _T:
     """Adds a new element at the end of the list and returns it. Keyword
     arguments may be used to initialize the element.
     """
@@ -242,7 +280,7 @@
       self._message_listener.Modified()
     return new_element
 
-  def append(self, value):
+  def append(self, value: _T) -> None:
     """Appends one element by copying the message."""
     new_element = self._message_descriptor._concrete_class()
     new_element._SetListener(self._message_listener)
@@ -251,7 +289,7 @@
     if not self._message_listener.dirty:
       self._message_listener.Modified()
 
-  def insert(self, key, value):
+  def insert(self, key: int, value: _T) -> None:
     """Inserts the item at the specified position by copying."""
     new_element = self._message_descriptor._concrete_class()
     new_element._SetListener(self._message_listener)
@@ -260,7 +298,7 @@
     if not self._message_listener.dirty:
       self._message_listener.Modified()
 
-  def extend(self, elem_seq):
+  def extend(self, elem_seq: Iterable[_T]) -> None:
     """Extends by appending the given sequence of elements of the same type
 
     as this one, copying each individual message.
@@ -275,38 +313,47 @@
       values.append(new_element)
     listener.Modified()
 
-  def MergeFrom(self, other):
+  def MergeFrom(
+      self,
+      other: Union['RepeatedCompositeFieldContainer[_T]', Iterable[_T]],
+  ) -> None:
     """Appends the contents of another repeated field of the same type to this
     one, copying each individual message.
     """
-    self.extend(other._values)
+    self.extend(other)
 
-  def remove(self, elem):
+  def remove(self, elem: _T) -> None:
     """Removes an item from the list. Similar to list.remove()."""
     self._values.remove(elem)
     self._message_listener.Modified()
 
-  def pop(self, key=-1):
+  def pop(self, key: Optional[int] = -1) -> _T:
     """Removes and returns an item at a given index. Similar to list.pop()."""
     value = self._values[key]
     self.__delitem__(key)
     return value
 
-  def __getslice__(self, start, stop):
-    """Retrieves the subset of items from between the specified indices."""
-    return self._values[start:stop]
+  @overload
+  def __setitem__(self, key: int, value: _T) -> None:
+    ...
 
-  def __delitem__(self, key):
+  @overload
+  def __setitem__(self, key: slice, value: Iterable[_T]) -> None:
+    ...
+
+  def __setitem__(self, key, value):
+    # This method is implemented to make RepeatedCompositeFieldContainer
+    # structurally compatible with typing.MutableSequence. It is
+    # otherwise unsupported and will always raise an error.
+    raise TypeError(
+        f'{self.__class__.__name__} object does not support item assignment')
+
+  def __delitem__(self, key: Union[int, slice]) -> None:
     """Deletes the item at the specified position."""
     del self._values[key]
     self._message_listener.Modified()
 
-  def __delslice__(self, start, stop):
-    """Deletes the subset of items from between the specified indices."""
-    del self._values[start:stop]
-    self._message_listener.Modified()
-
-  def __eq__(self, other):
+  def __eq__(self, other: Any) -> bool:
     """Compares the current instance with another one."""
     if self is other:
       return True
@@ -316,16 +363,20 @@
     return self._values == other._values
 
 
-class ScalarMap(collections.abc.MutableMapping):
-
+class ScalarMap(MutableMapping[_K, _V]):
   """Simple, type-checked, dict-like container for holding repeated scalars."""
 
   # Disallows assignment to other attributes.
   __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener',
                '_entry_descriptor']
 
-  def __init__(self, message_listener, key_checker, value_checker,
-               entry_descriptor):
+  def __init__(
+      self,
+      message_listener: Any,
+      key_checker: Any,
+      value_checker: Any,
+      entry_descriptor: Any,
+  ) -> None:
     """
     Args:
       message_listener: A MessageListener implementation.
@@ -343,7 +394,7 @@
     self._entry_descriptor = entry_descriptor
     self._values = {}
 
-  def __getitem__(self, key):
+  def __getitem__(self, key: _K) -> _V:
     try:
       return self._values[key]
     except KeyError:
@@ -352,12 +403,20 @@
       self._values[key] = val
       return val
 
-  def __contains__(self, item):
+  def __contains__(self, item: _K) -> bool:
     # 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
 
+  @overload
+  def get(self, key: _K) -> Optional[_V]:
+    ...
+
+  @overload
+  def get(self, key: _K, default: _T) -> Union[_V, _T]:
+    ...
+
   # We need to override this explicitly, because our defaultdict-like behavior
   # will make the default implementation (from our base class) always insert
   # the key.
@@ -367,30 +426,30 @@
     else:
       return default
 
-  def __setitem__(self, key, value):
+  def __setitem__(self, key: _K, value: _V) -> _T:
     checked_key = self._key_checker.CheckValue(key)
     checked_value = self._value_checker.CheckValue(value)
     self._values[checked_key] = checked_value
     self._message_listener.Modified()
 
-  def __delitem__(self, key):
+  def __delitem__(self, key: _K) -> None:
     del self._values[key]
     self._message_listener.Modified()
 
-  def __len__(self):
+  def __len__(self) -> int:
     return len(self._values)
 
-  def __iter__(self):
+  def __iter__(self) -> Iterator[_K]:
     return iter(self._values)
 
-  def __repr__(self):
+  def __repr__(self) -> str:
     return repr(self._values)
 
-  def MergeFrom(self, other):
+  def MergeFrom(self, other: 'ScalarMap[_K, _V]') -> None:
     self._values.update(other._values)
     self._message_listener.Modified()
 
-  def InvalidateIterators(self):
+  def InvalidateIterators(self) -> None:
     # It appears that the only way to reliably invalidate iterators to
     # self._values is to ensure that its size changes.
     original = self._values
@@ -398,24 +457,28 @@
     original[None] = None
 
   # This is defined in the abstract base, but we can do it much more cheaply.
-  def clear(self):
+  def clear(self) -> None:
     self._values.clear()
     self._message_listener.Modified()
 
-  def GetEntryClass(self):
+  def GetEntryClass(self) -> Any:
     return self._entry_descriptor._concrete_class
 
 
-class MessageMap(collections.abc.MutableMapping):
-
+class MessageMap(MutableMapping[_K, _V]):
   """Simple, type-checked, dict-like container for with submessage values."""
 
   # Disallows assignment to other attributes.
   __slots__ = ['_key_checker', '_values', '_message_listener',
                '_message_descriptor', '_entry_descriptor']
 
-  def __init__(self, message_listener, message_descriptor, key_checker,
-               entry_descriptor):
+  def __init__(
+      self,
+      message_listener: Any,
+      message_descriptor: Any,
+      key_checker: Any,
+      entry_descriptor: Any,
+  ) -> None:
     """
     Args:
       message_listener: A MessageListener implementation.
@@ -433,7 +496,7 @@
     self._entry_descriptor = entry_descriptor
     self._values = {}
 
-  def __getitem__(self, key):
+  def __getitem__(self, key: _K) -> _V:
     key = self._key_checker.CheckValue(key)
     try:
       return self._values[key]
@@ -442,10 +505,9 @@
       new_element._SetListener(self._message_listener)
       self._values[key] = new_element
       self._message_listener.Modified()
-
       return new_element
 
-  def get_or_create(self, key):
+  def get_or_create(self, key: _K) -> _V:
     """get_or_create() is an alias for getitem (ie. map[key]).
 
     Args:
@@ -459,6 +521,14 @@
     """
     return self[key]
 
+  @overload
+  def get(self, key: _K) -> Optional[_V]:
+    ...
+
+  @overload
+  def get(self, key: _K, default: _T) -> Union[_V, _T]:
+    ...
+
   # We need to override this explicitly, because our defaultdict-like behavior
   # will make the default implementation (from our base class) always insert
   # the key.
@@ -468,28 +538,28 @@
     else:
       return default
 
-  def __contains__(self, item):
+  def __contains__(self, item: _K) -> bool:
     item = self._key_checker.CheckValue(item)
     return item in self._values
 
-  def __setitem__(self, key, value):
+  def __setitem__(self, key: _K, value: _V) -> NoReturn:
     raise ValueError('May not set values directly, call my_map[key].foo = 5')
 
-  def __delitem__(self, key):
+  def __delitem__(self, key: _K) -> None:
     key = self._key_checker.CheckValue(key)
     del self._values[key]
     self._message_listener.Modified()
 
-  def __len__(self):
+  def __len__(self) -> int:
     return len(self._values)
 
-  def __iter__(self):
+  def __iter__(self) -> Iterator[_K]:
     return iter(self._values)
 
-  def __repr__(self):
+  def __repr__(self) -> str:
     return repr(self._values)
 
-  def MergeFrom(self, other):
+  def MergeFrom(self, other: 'MessageMap[_K, _V]') -> None:
     # pylint: disable=protected-access
     for key in other._values:
       # According to documentation: "When parsing from the wire or when merging,
@@ -500,7 +570,7 @@
     # self._message_listener.Modified() not required here, because
     # mutations to submessages already propagate.
 
-  def InvalidateIterators(self):
+  def InvalidateIterators(self) -> None:
     # It appears that the only way to reliably invalidate iterators to
     # self._values is to ensure that its size changes.
     original = self._values
@@ -508,16 +578,15 @@
     original[None] = None
 
   # This is defined in the abstract base, but we can do it much more cheaply.
-  def clear(self):
+  def clear(self) -> None:
     self._values.clear()
     self._message_listener.Modified()
 
-  def GetEntryClass(self):
+  def GetEntryClass(self) -> Any:
     return self._entry_descriptor._concrete_class
 
 
-class _UnknownField(object):
-
+class _UnknownField:
   """A parsed unknown field."""
 
   # Disallows assignment to other attributes.
@@ -542,12 +611,11 @@
             self._data == other._data)
 
 
-class UnknownFieldRef(object):
+class UnknownFieldRef:  # pylint: disable=missing-class-docstring
 
   def __init__(self, parent, index):
     self._parent = parent
     self._index = index
-    return
 
   def _check_valid(self):
     if not self._parent:
@@ -576,8 +644,7 @@
     return self._parent._internal_get(self._index)._data
 
 
-class UnknownFieldSet(object):
-
+class UnknownFieldSet:
   """UnknownField container"""
 
   # Disallows assignment to other attributes.
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index 057b6b0..d026a74 100644
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -144,8 +144,8 @@
     self.assertEqual(self.my_service, self.my_method.containing_service)
 
   @unittest.skipIf(
-    api_implementation.Type() != 'cpp',
-    'GetDebugString is only available with the cpp implementation',
+      api_implementation.Type() != 'cpp',
+      'GetDebugString is only available with the cpp implementation',
   )
   def testGetDebugString(self):
     self.assertEqual(self.my_file.GetDebugString(), TEST_FILE_DESCRIPTOR_DEBUG)
@@ -552,6 +552,7 @@
     self.assertIn(field_descriptor, {field_descriptor: None})
     self.assertEqual(None, field_descriptor.extension_scope)
     self.assertEqual(None, field_descriptor.enum_type)
+    self.assertTrue(field_descriptor.has_presence)
     if api_implementation.Type() == 'cpp':
       # For test coverage only
       self.assertEqual(field_descriptor.id, field_descriptor.id)
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 092dfdb..cb533c1 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -697,8 +697,7 @@
       json_format.MessageToJson(message, True, descriptor_pool=empty_pool)
     self.assertEqual(
         'Can not find message descriptor by type_url:'
-        ' type.googleapis.com/protobuf_unittest.OneString.',
-        str(cm.exception))
+        ' type.googleapis.com/protobuf_unittest.OneString', str(cm.exception))
 
   def testWellKnownInAnyMessage(self):
     message = any_pb2.Any()
@@ -815,14 +814,15 @@
     # Null is not allowed to be used as an element in repeated field.
     self.assertRaisesRegex(
         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)
-    self.CheckError('{"repeatedMessageValue":[null]}',
-                    'Failed to parse repeatedMessageValue field: null is not'
-                    ' allowed to be used as an element in a repeated field.')
+        r'Failed to parse repeatedInt32Value field: '
+        r'null is not allowed to be used as an element in a repeated field '
+        r'at TestMessage.repeatedInt32Value\[1\].', json_format.Parse,
+        '{"repeatedInt32Value":[1, null]}', parsed_message)
+    self.CheckError(
+        '{"repeatedMessageValue":[null]}',
+        r'Failed to parse repeatedMessageValue field: null is not'
+        r' allowed to be used as an element in a repeated field '
+        r'at TestMessage.repeatedMessageValue\[0\].')
 
   def testNanFloat(self):
     message = json_format_proto3_pb2.TestMessage()
@@ -840,9 +840,9 @@
     self.assertEqual(message.repeated_double_value[0], 3.4028235e+39)
     self.assertEqual(message.repeated_double_value[1], 1.4028235e-39)
     text = ('{"repeatedFloatValue": [3.4028235e+39, 1.4028235e-39]\n}')
-    self.CheckError(text,
-                    'Failed to parse repeatedFloatValue field: '
-                    'Float value too large.')
+    self.CheckError(
+        text, r'Failed to parse repeatedFloatValue field: '
+        r'Float value too large at TestMessage.repeatedFloatValue\[0\].')
 
   def testFloatPrecision(self):
     message = json_format_proto3_pb2.TestMessage()
@@ -895,7 +895,7 @@
     self.CheckError(
         '{"enumValue": "baz"}',
         'Failed to parse enumValue field: Invalid enum value baz '
-        'for enum type proto3.EnumType.')
+        'for enum type proto3.EnumType at TestMessage.enumValue.')
     # Proto3 accepts numeric unknown enums.
     text = '{"enumValue": 12345}'
     json_format.Parse(text, message)
@@ -904,8 +904,9 @@
     self.assertRaisesRegex(
         json_format.ParseError,
         'Failed to parse optionalNestedEnum field: Invalid enum value 12345 '
-        'for enum type protobuf_unittest.TestAllTypes.NestedEnum.',
-        json_format.Parse, '{"optionalNestedEnum": 12345}', message)
+        'for enum type protobuf_unittest.TestAllTypes.NestedEnum at '
+        'TestAllTypes.optionalNestedEnum.', json_format.Parse,
+        '{"optionalNestedEnum": 12345}', message)
 
   def testBytes(self):
     message = json_format_proto3_pb2.TestMessage()
@@ -928,9 +929,10 @@
     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".')
+    self.CheckError(
+        '{"unknownName": 1}',
+        'Message type "proto3.TestMessage" has no field named '
+        '"unknownName" at "TestMessage".')
 
   def testIgnoreUnknownField(self):
     text = '{"unknownName": 1}'
@@ -950,33 +952,34 @@
                     '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.')
+    self.CheckError(
+        '{"boolValue": 1}', 'Failed to parse boolValue field: '
+        'Expected true or false without quotes at TestMessage.boolValue.')
+    self.CheckError(
+        '{"boolValue": "true"}', 'Failed to parse boolValue field: '
+        'Expected true or false without quotes at TestMessage.boolValue.')
 
   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": 1.5}',
-                    'Failed to parse int32Value field: '
-                    'Couldn\'t parse integer: 1.5.')
+    self.CheckError(
+        '{"int32Value": 1.5}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: 1.5 at TestMessage.int32Value.')
     self.CheckError('{"int32Value": 012345}',
                     (r'Failed to load JSON: Expecting \'?,\'? delimiter: '
                      r'line 1.'))
-    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": false}',
-                    'Failed to parse int32Value field: Bool value False '
-                    'is not acceptable for integer field.')
+    self.CheckError(
+        '{"int32Value": " 1 "}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: " 1 " at TestMessage.int32Value.')
+    self.CheckError(
+        '{"int32Value": "1 "}', 'Failed to parse int32Value field: '
+        'Couldn\'t parse integer: "1 " at TestMessage.int32Value.')
+    self.CheckError(
+        '{"int32Value": false}',
+        'Failed to parse int32Value field: Bool value False '
+        'is not acceptable for integer field at TestMessage.int32Value.')
     self.CheckError('{"int32Value": 12345678901234567890}',
                     'Failed to parse int32Value field: Value out of range: '
                     '12345678901234567890.')
@@ -985,9 +988,9 @@
                     '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.')
+    self.CheckError(
+        '{"floatValue": "nan"}', 'Failed to parse floatValue field: Couldn\'t '
+        'parse float "nan", use "NaN" instead at TestMessage.floatValue.')
     self.CheckError('{"floatValue": NaN}',
                     'Failed to parse floatValue field: Couldn\'t '
                     'parse NaN, use quoted "NaN" instead.')
@@ -1008,9 +1011,10 @@
                     'Failed to parse floatValue field: Float value too small.')
 
   def testInvalidRepeated(self):
-    self.CheckError('{"repeatedInt32Value": 12345}',
-                    (r'Failed to parse repeatedInt32Value field: repeated field'
-                     r' repeatedInt32Value must be in \[\] which is 12345.'))
+    self.CheckError(
+        '{"repeatedInt32Value": 12345}',
+        (r'Failed to parse repeatedInt32Value field: repeated field'
+         r' repeatedInt32Value must be in \[\] which is 12345 at TestMessage.'))
 
   def testInvalidMap(self):
     message = json_format_proto3_pb2.TestMap()
@@ -1028,8 +1032,8 @@
     text = '{"boolMap": {"null": 1}}'
     self.assertRaisesRegex(
         json_format.ParseError,
-        'Failed to parse boolMap field: Expected "true" or "false", not null.',
-        json_format.Parse, text, message)
+        'Failed to parse boolMap field: Expected "true" or "false", not null at '
+        'TestMap.boolMap.key', json_format.Parse, text, message)
     text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
     self.assertRaisesRegex(
         json_format.ParseError,
@@ -1039,17 +1043,16 @@
     self.assertRaisesRegex(
         json_format.ParseError,
         'Failed to parse stringMap field: Map field string_map must be '
-        'in a dict which is 0.',
-        json_format.Parse, text, message)
+        'in a dict which is 0 at TestMap.stringMap.', json_format.Parse, text,
+        message)
 
   def testInvalidTimestamp(self):
     message = json_format_proto3_pb2.TestTimestamp()
     text = '{"value": "10000-01-01T00:00:00.00Z"}'
-    self.assertRaisesRegex(
-        json_format.ParseError,
-        'Failed to parse value field: '
+    self.assertRaisesRegexp(
+        json_format.ParseError, 'Failed to parse value field: '
         'time data \'10000-01-01T00:00:00\' does not match'
-        ' format \'%Y-%m-%dT%H:%M:%S\'.',
+        ' format \'%Y-%m-%dT%H:%M:%S\' at TestTimestamp.value.',
         json_format.Parse, text, message)
     text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
     self.assertRaisesRegex(
@@ -1080,16 +1083,15 @@
     self.assertEqual(
         'Failed to parse value field: '
         'time data \'0001-01-01t00:00:00\' does not match format '
-        '\'%Y-%m-%dT%H:%M:%S\', lowercase \'t\' is not accepted.',
-        str(e.exception))
+        '\'%Y-%m-%dT%H:%M:%S\', lowercase \'t\' is not accepted '
+        'at TestTimestamp.value.', str(e.exception))
 
   def testInvalidOneof(self):
     message = json_format_proto3_pb2.TestOneof()
     text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
-    self.assertRaisesRegex(
-        json_format.ParseError,
-        'Message type "proto3.TestOneof"'
-        ' should not have multiple "oneof_value" oneof fields.',
+    self.assertRaisesRegexp(
+        json_format.ParseError, 'Message type "proto3.TestOneof"'
+        ' should not have multiple "oneof_value" oneof fields at "TestOneof".',
         json_format.Parse, text, message)
 
   def testInvalidListValue(self):
@@ -1097,15 +1099,27 @@
     text = '{"value": 1234}'
     self.assertRaisesRegex(
         json_format.ParseError,
-        r'Failed to parse value field: ListValue must be in \[\] which is 1234',
+        r'Failed to parse value field: ListValue must be in \[\] which is '
+        '1234 at TestListValue.value.',
         json_format.Parse, text, message)
 
+    class UnknownClass(object):
+
+      def __str__(self):
+        return 'v'
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        r' at TestListValue.value\[1\].fake.',
+        json_format.ParseDict,
+        {'value': ['hello', {'fake': UnknownClass()}]}, message)
+
   def testInvalidStruct(self):
     message = json_format_proto3_pb2.TestStruct()
     text = '{"value": 1234}'
     self.assertRaisesRegex(
         json_format.ParseError,
-        'Failed to parse value field: Struct must be in a dict which is 1234',
+        'Failed to parse value field: Struct must be in a dict which is '
+        '1234 at TestStruct.value',
         json_format.Parse, text, message)
 
   def testTimestampInvalidStringValue(self):
@@ -1140,16 +1154,14 @@
         'value',
         json_format.Parse, text, message)
     text = '{"value": 1234}'
-    self.assertRaisesRegex(
-        json_format.ParseError,
-        '@type is missing when parsing any message.',
-        json_format.Parse, text, message)
+    self.assertRaisesRegex(json_format.ParseError,
+                           '@type is missing when parsing any message at Any',
+                           json_format.Parse, text, message)
     text = '{"@type": "type.googleapis.com/MessageNotExist", "value": 1234}'
     self.assertRaisesRegex(
-        TypeError,
-        'Can not find message descriptor by type_url: '
-        'type.googleapis.com/MessageNotExist.',
-        json_format.Parse, text, message)
+        json_format.ParseError, 'Can not find message descriptor by type_url: '
+        'type.googleapis.com/MessageNotExist at Any', json_format.Parse, text,
+        message)
     # Only last part is to be used: b/25630112
     text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",'
             r'"value": 1234}')
@@ -1225,7 +1237,9 @@
     self.assertEqual(
         str(cm.exception),
         'Failed to parse any_value field: Can not find message descriptor by'
-        ' type_url: type.googleapis.com/proto3.MessageType..')
+        ' type_url: type.googleapis.com/proto3.MessageType at '
+        'TestAny.any_value.'
+    )
 
   def testParseDictUnknownValueType(self):
     class UnknownClass(object):
@@ -1271,6 +1285,18 @@
                     'uint32Value': 4, 'stringValue': 'bla'},
                    indent=2, sort_keys=True))
 
+  def testNestedRecursiveLimit(self):
+    message = unittest_pb2.NestedTestAllTypes()
+    self.assertRaisesRegex(
+        json_format.ParseError,
+        'Message too deep. Max recursion depth is 3',
+        json_format.Parse,
+        '{"child": {"child": {"child" : {}}}}',
+        message,
+        max_recursion_depth=3)
+    # The following one can pass
+    json_format.Parse('{"payload": {}, "child": {"child":{}}}',
+                      message, max_recursion_depth=3)
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index dea5d82..2c3091e 100644
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -59,6 +59,7 @@
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import descriptor_pb2
+from google.protobuf import descriptor
 from google.protobuf import descriptor_pool
 from google.protobuf import message_factory
 from google.protobuf import text_format
@@ -1147,16 +1148,32 @@
     m.repeated_string.extend(MessageTest.TestIterable(['3', '4']))
     self.assertSequenceEqual(['', '1', '2', '3', '4'], m.repeated_string)
 
+  class TestIndex(object):
+    """This index object mimics the behavior of numpy.int64 and other types."""
+
+    def __init__(self, value=None):
+      self.value = value
+
+    def __index__(self):
+      return self.value
+
+  def testRepeatedIndexingWithIntIndex(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(1, msg.repeated_int32[MessageTest.TestIndex(0)])
+
+  def testRepeatedIndexingWithNegative1IntIndex(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(3, msg.repeated_int32[MessageTest.TestIndex(-1)])
+
+  def testRepeatedIndexingWithNegative1Int(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertEqual(3, msg.repeated_int32[-1])
+
   def testPickleRepeatedScalarContainer(self, message_module):
-    # TODO(tibell): The pure-Python implementation support pickling of
-    #   scalar containers in *some* cases. For now the cpp2 version
-    #   throws an exception to avoid a segfault. Investigate if we
-    #   want to support pickling of these fields.
-    #
-    # For more information see: https://b2.corp.google.com/u/0/issues/18677897
-    if (api_implementation.Type() != 'cpp' or
-        api_implementation.Version() == 2):
-      return
+    # Pickle repeated scalar container is not supported.
     m = message_module.TestAllTypes()
     with self.assertRaises(pickle.PickleError) as _:
       pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
@@ -1658,6 +1675,26 @@
 
     self.assertEqual(msg.WhichOneof('_optional_int32'), None)
 
+    # Test has presence:
+    for field in test_proto3_optional_pb2.TestProto3Optional.DESCRIPTOR.fields:
+      self.assertTrue(field.has_presence)
+    for field in unittest_pb2.TestAllTypes.DESCRIPTOR.fields:
+      if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        self.assertFalse(field.has_presence)
+      else:
+        self.assertTrue(field.has_presence)
+    proto3_descriptor = unittest_proto3_arena_pb2.TestAllTypes.DESCRIPTOR
+    repeated_field = proto3_descriptor.fields_by_name['repeated_int32']
+    self.assertFalse(repeated_field.has_presence)
+    singular_field = proto3_descriptor.fields_by_name['optional_int32']
+    self.assertFalse(singular_field.has_presence)
+    optional_field = proto3_descriptor.fields_by_name['proto3_optional_int32']
+    self.assertTrue(optional_field.has_presence)
+    message_field = proto3_descriptor.fields_by_name['optional_nested_message']
+    self.assertTrue(message_field.has_presence)
+    oneof_field = proto3_descriptor.fields_by_name['oneof_uint32']
+    self.assertTrue(oneof_field.has_presence)
+
   def testAssignUnknownEnum(self):
     """Assigning an unknown enum value is allowed and preserves the value."""
     m = unittest_proto3_arena_pb2.TestAllTypes()
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
index 5c0f499..37baca7 100644
--- a/python/google/protobuf/internal/missing_enum_values.proto
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -44,9 +44,7 @@
 }
 
 message TestMissingEnumValues {
-  enum NestedEnum {
-    TWO = 2;
-  }
+  enum NestedEnum { TWO = 2; }
   optional NestedEnum optional_nested_enum = 1;
   repeated NestedEnum repeated_nested_enum = 2;
   repeated NestedEnum packed_nested_enum = 3 [packed = true];
@@ -55,3 +53,4 @@
 message JustString {
   required string dummy = 1;
 }
+
diff --git a/python/google/protobuf/internal/python_protobuf.cc b/python/google/protobuf/internal/python_protobuf.cc
index e823bf2..26e3a8b 100644
--- a/python/google/protobuf/internal/python_protobuf.cc
+++ b/python/google/protobuf/internal/python_protobuf.cc
@@ -36,8 +36,12 @@
 namespace protobuf {
 namespace python {
 
-static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) { return NULL; }
-static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) { return NULL; }
+static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) {
+  return nullptr;
+}
+static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) {
+  return nullptr;
+}
 
 // This is initialized with a default, stub implementation.
 // If python-google.protobuf.cc is loaded, the function pointer is overridden
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
index 30ff125..b581ab7 100644
--- a/python/google/protobuf/internal/well_known_types.py
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -42,8 +42,7 @@
 
 import calendar
 import collections.abc
-from datetime import datetime
-from datetime import timedelta
+import datetime
 
 from google.protobuf.descriptor import FieldDescriptor
 
@@ -89,7 +88,9 @@
     return '/' in self.type_url and self.TypeName() == descriptor.full_name
 
 
-_EPOCH_DATETIME = datetime.utcfromtimestamp(0)
+_EPOCH_DATETIME_NAIVE = datetime.datetime.utcfromtimestamp(0)
+_EPOCH_DATETIME_AWARE = datetime.datetime.fromtimestamp(
+    0, tz=datetime.timezone.utc)
 
 
 class Timestamp(object):
@@ -109,7 +110,7 @@
     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)
+    dt = datetime.datetime(1970, 1, 1) + datetime.timedelta(days, seconds)
 
     result = dt.isoformat()
     if (nanos % 1e9) == 0:
@@ -159,8 +160,8 @@
       raise ValueError(
           'time data \'{0}\' does not match format \'%Y-%m-%dT%H:%M:%S\', '
           'lowercase \'t\' is not accepted'.format(second_value))
-    date_object = datetime.strptime(second_value, _TIMESTAMPFOMAT)
-    td = date_object - datetime(1970, 1, 1)
+    date_object = datetime.datetime.strptime(second_value, _TIMESTAMPFOMAT)
+    td = date_object - datetime.datetime(1970, 1, 1)
     seconds = td.seconds + td.days * _SECONDS_PER_DAY
     if len(nano_value) > 9:
       raise ValueError(
@@ -191,7 +192,7 @@
 
   def GetCurrentTime(self):
     """Get the current UTC into Timestamp."""
-    self.FromDatetime(datetime.utcnow())
+    self.FromDatetime(datetime.datetime.utcnow())
 
   def ToNanoseconds(self):
     """Converts Timestamp to nanoseconds since epoch."""
@@ -231,14 +232,32 @@
     self.seconds = seconds
     self.nanos = 0
 
-  def ToDatetime(self):
-    """Converts Timestamp to datetime."""
-    return _EPOCH_DATETIME + timedelta(
-        seconds=self.seconds, microseconds=_RoundTowardZero(
-            self.nanos, _NANOS_PER_MICROSECOND))
+  def ToDatetime(self, tzinfo=None):
+    """Converts Timestamp to a datetime.
+
+    Args:
+      tzinfo: A datetime.tzinfo subclass; defaults to None.
+
+    Returns:
+      If tzinfo is None, returns a timezone-naive UTC datetime (with no timezone
+      information, i.e. not aware that it's UTC).
+
+      Otherwise, returns a timezone-aware datetime in the input timezone.
+    """
+    delta = datetime.timedelta(
+        seconds=self.seconds,
+        microseconds=_RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND))
+    if tzinfo is None:
+      return _EPOCH_DATETIME_NAIVE + delta
+    else:
+      return _EPOCH_DATETIME_AWARE.astimezone(tzinfo) + delta
 
   def FromDatetime(self, dt):
-    """Converts datetime to Timestamp."""
+    """Converts datetime to Timestamp.
+
+    Args:
+      dt: A datetime. If it's timezone-naive, it's assumed to be in UTC.
+    """
     # Using this guide: http://wiki.python.org/moin/WorkingWithTime
     # And this conversion guide: http://docs.python.org/library/time.html
 
@@ -363,7 +382,7 @@
 
   def ToTimedelta(self):
     """Converts Duration to timedelta."""
-    return timedelta(
+    return datetime.timedelta(
         seconds=self.seconds, microseconds=_RoundTowardZero(
             self.nanos, _NANOS_PER_MICROSECOND))
 
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
index 796886c..6653596 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -48,9 +48,10 @@
 from google.protobuf.internal import well_known_types
 from google.protobuf import descriptor
 from google.protobuf import text_format
+from google.protobuf.internal import _parameterized
 
 
-class TimeUtilTestBase(unittest.TestCase):
+class TimeUtilTestBase(_parameterized.TestCase):
 
   def CheckTimestampConversion(self, message, text):
     self.assertEqual(text, message.ToJsonString())
@@ -233,23 +234,36 @@
     message.FromNanoseconds(-1999)
     self.assertEqual(-1, message.ToMicroseconds())
 
-  def testDatetimeConverison(self):
+  def testTimezoneNaiveDatetimeConversion(self):
     message = timestamp_pb2.Timestamp()
-    dt = datetime.datetime(1970, 1, 1)
-    message.FromDatetime(dt)
-    self.assertEqual(dt, message.ToDatetime())
+    naive_utc_epoch = datetime.datetime(1970, 1, 1)
+    message.FromDatetime(naive_utc_epoch)
+    self.assertEqual(0, message.seconds)
+    self.assertEqual(0, message.nanos)
+
+    self.assertEqual(naive_utc_epoch, message.ToDatetime())
+
+    naive_epoch_morning = datetime.datetime(1970, 1, 1, 8, 0, 0, 1)
+    message.FromDatetime(naive_epoch_morning)
+    self.assertEqual(8 * 3600, message.seconds)
+    self.assertEqual(1000, message.nanos)
+
+    self.assertEqual(naive_epoch_morning, message.ToDatetime())
 
     message.FromMilliseconds(1999)
+    self.assertEqual(1, message.seconds)
+    self.assertEqual(999_000_000, message.nanos)
+
     self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0, 1, 999000),
                      message.ToDatetime())
 
-    dt = datetime.datetime(2555, 2, 22, 1, 2, 3, 456789)
-    message.FromDatetime(dt)
-    self.assertEqual(dt, message.ToDatetime())
+    naive_future = datetime.datetime(2555, 2, 22, 1, 2, 3, 456789)
+    message.FromDatetime(naive_future)
+    self.assertEqual(naive_future, message.ToDatetime())
 
-    dt = datetime.datetime.max
-    message.FromDatetime(dt)
-    self.assertEqual(dt, message.ToDatetime())
+    naive_end_of_time = datetime.datetime.max
+    message.FromDatetime(naive_end_of_time)
+    self.assertEqual(naive_end_of_time, message.ToDatetime())
 
   def testDatetimeConversionWithTimezone(self):
     class TZ(datetime.tzinfo):
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index 21eb749..bf2a17d 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -395,12 +395,16 @@
     message_descriptor = pool.FindMessageTypeByName(type_name)
   except KeyError:
     raise TypeError(
-        'Can not find message descriptor by type_url: {0}.'.format(type_url))
+        'Can not find message descriptor by type_url: {0}'.format(type_url))
   message_class = db.GetPrototype(message_descriptor)
   return message_class()
 
 
-def Parse(text, message, ignore_unknown_fields=False, descriptor_pool=None):
+def Parse(text,
+          message,
+          ignore_unknown_fields=False,
+          descriptor_pool=None,
+          max_recursion_depth=100):
   """Parses a JSON representation of a protocol message into a message.
 
   Args:
@@ -408,7 +412,10 @@
     message: A protocol buffer message to merge into.
     ignore_unknown_fields: If True, do not raise errors for unknown fields.
     descriptor_pool: A Descriptor Pool for resolving types. If None use the
-        default.
+      default.
+    max_recursion_depth: max recursion depth of JSON message to be
+      deserialized. JSON messages over this depth will fail to be
+      deserialized. Default value is 100.
 
   Returns:
     The same message passed as argument.
@@ -422,13 +429,15 @@
     js = json.loads(text, object_pairs_hook=_DuplicateChecker)
   except ValueError as e:
     raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
-  return ParseDict(js, message, ignore_unknown_fields, descriptor_pool)
+  return ParseDict(js, message, ignore_unknown_fields, descriptor_pool,
+                   max_recursion_depth)
 
 
 def ParseDict(js_dict,
               message,
               ignore_unknown_fields=False,
-              descriptor_pool=None):
+              descriptor_pool=None,
+              max_recursion_depth=100):
   """Parses a JSON dictionary representation into a message.
 
   Args:
@@ -437,12 +446,15 @@
     ignore_unknown_fields: If True, do not raise errors for unknown fields.
     descriptor_pool: A Descriptor Pool for resolving types. If None use the
       default.
+    max_recursion_depth: max recursion depth of JSON message to be
+      deserialized. JSON messages over this depth will fail to be
+      deserialized. Default value is 100.
 
   Returns:
     The same message passed as argument.
   """
-  parser = _Parser(ignore_unknown_fields, descriptor_pool)
-  parser.ConvertMessage(js_dict, message)
+  parser = _Parser(ignore_unknown_fields, descriptor_pool, max_recursion_depth)
+  parser.ConvertMessage(js_dict, message, '')
   return message
 
 
@@ -452,35 +464,47 @@
 class _Parser(object):
   """JSON format parser for protocol message."""
 
-  def __init__(self, ignore_unknown_fields, descriptor_pool):
+  def __init__(self, ignore_unknown_fields, descriptor_pool,
+               max_recursion_depth):
     self.ignore_unknown_fields = ignore_unknown_fields
     self.descriptor_pool = descriptor_pool
+    self.max_recursion_depth = max_recursion_depth
+    self.recursion_depth = 0
 
-  def ConvertMessage(self, value, message):
+  def ConvertMessage(self, value, message, path):
     """Convert a JSON object into a message.
 
     Args:
       value: A JSON object.
       message: A WKT or regular protocol message to record the data.
+      path: parent path to log parse error info.
 
     Raises:
       ParseError: In case of convert problems.
     """
+    self.recursion_depth += 1
+    if self.recursion_depth > self.max_recursion_depth:
+      raise ParseError('Message too deep. Max recursion depth is {0}'.format(
+          self.max_recursion_depth))
     message_descriptor = message.DESCRIPTOR
     full_name = message_descriptor.full_name
+    if not path:
+      path = message_descriptor.name
     if _IsWrapperMessage(message_descriptor):
-      self._ConvertWrapperMessage(value, message)
+      self._ConvertWrapperMessage(value, message, path)
     elif full_name in _WKTJSONMETHODS:
-      methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
+      methodcaller(_WKTJSONMETHODS[full_name][1], value, message, path)(self)
     else:
-      self._ConvertFieldValuePair(value, message)
+      self._ConvertFieldValuePair(value, message, path)
+    self.recursion_depth -= 1
 
-  def _ConvertFieldValuePair(self, js, message):
+  def _ConvertFieldValuePair(self, js, message, path):
     """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.
+      path: parent path to log parse error info.
 
     Raises:
       ParseError: In case of problems converting.
@@ -496,8 +520,9 @@
           field = message_descriptor.fields_by_name.get(name, None)
         if not field and _VALID_EXTENSION_NAME.match(name):
           if not message_descriptor.is_extendable:
-            raise ParseError('Message type {0} does not have extensions'.format(
-                message_descriptor.full_name))
+            raise ParseError(
+                'Message type {0} does not have extensions at {1}'.format(
+                    message_descriptor.full_name, path))
           identifier = name[1:-1]  # strip [] brackets
           # pylint: disable=protected-access
           field = message.Extensions._FindExtensionByName(identifier)
@@ -513,14 +538,14 @@
           if self.ignore_unknown_fields:
             continue
           raise ParseError(
-              ('Message type "{0}" has no field named "{1}".\n'
-               ' Available Fields(except extensions): {2}').format(
-                   message_descriptor.full_name, name,
+              ('Message type "{0}" has no field named "{1}" at "{2}".\n'
+               ' Available Fields(except extensions): "{3}"').format(
+                   message_descriptor.full_name, name, path,
                    [f.json_name for f in message_descriptor.fields]))
         if name in names:
           raise ParseError('Message type "{0}" should not have multiple '
-                           '"{1}" fields.'.format(
-                               message.DESCRIPTOR.full_name, name))
+                           '"{1}" fields at "{2}".'.format(
+                               message.DESCRIPTOR.full_name, name, path))
         names.append(name)
         value = js[name]
         # Check no other oneof field is parsed.
@@ -528,8 +553,9 @@
           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))
+                             '"{1}" oneof fields at "{2}".'.format(
+                                 message.DESCRIPTOR.full_name, oneof_name,
+                                 path))
           names.append(oneof_name)
 
         if value is None:
@@ -547,42 +573,51 @@
         # Parse field value.
         if _IsMapEntry(field):
           message.ClearField(field.name)
-          self._ConvertMapFieldValue(value, message, field)
+          self._ConvertMapFieldValue(value, message, field,
+                                     '{0}.{1}'.format(path, name))
         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))
+                             '{1} at {2}'.format(name, value, path))
           if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
             # Repeated message field.
-            for item in value:
+            for index, item in enumerate(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.')
-              self.ConvertMessage(item, sub_message)
+                                 ' in a repeated field at {0}.{1}[{2}]'.format(
+                                     path, name, index))
+              self.ConvertMessage(item, sub_message,
+                                  '{0}.{1}[{2}]'.format(path, name, index))
           else:
             # Repeated scalar field.
-            for item in value:
+            for index, item in enumerate(value):
               if item is None:
                 raise ParseError('null is not allowed to be used as an element'
-                                 ' in a repeated field.')
+                                 ' in a repeated field at {0}.{1}[{2}]'.format(
+                                     path, name, index))
               getattr(message, field.name).append(
-                  _ConvertScalarFieldValue(item, field))
+                  _ConvertScalarFieldValue(
+                      item, field, '{0}.{1}[{2}]'.format(path, name, index)))
         elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
           if field.is_extension:
             sub_message = message.Extensions[field]
           else:
             sub_message = getattr(message, field.name)
           sub_message.SetInParent()
-          self.ConvertMessage(value, sub_message)
+          self.ConvertMessage(value, sub_message, '{0}.{1}'.format(path, name))
         else:
           if field.is_extension:
-            message.Extensions[field] = _ConvertScalarFieldValue(value, field)
+            message.Extensions[field] = _ConvertScalarFieldValue(
+                value, field, '{0}.{1}'.format(path, name))
           else:
-            setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+            setattr(
+                message, field.name,
+                _ConvertScalarFieldValue(value, field,
+                                         '{0}.{1}'.format(path, name)))
       except ParseError as e:
         if field and field.containing_oneof is None:
           raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
@@ -593,46 +628,52 @@
       except TypeError as e:
         raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
 
-  def _ConvertAnyMessage(self, value, message):
+  def _ConvertAnyMessage(self, value, message, path):
     """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.')
+      raise ParseError(
+          '@type is missing when parsing any message at {0}'.format(path))
 
-    sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool)
+    try:
+      sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool)
+    except TypeError as e:
+      raise ParseError('{0} at {1}'.format(e, path))
     message_descriptor = sub_message.DESCRIPTOR
     full_name = message_descriptor.full_name
     if _IsWrapperMessage(message_descriptor):
-      self._ConvertWrapperMessage(value['value'], sub_message)
+      self._ConvertWrapperMessage(value['value'], sub_message,
+                                  '{0}.value'.format(path))
     elif full_name in _WKTJSONMETHODS:
-      methodcaller(
-          _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self)
+      methodcaller(_WKTJSONMETHODS[full_name][1], value['value'], sub_message,
+                   '{0}.value'.format(path))(
+                       self)
     else:
       del value['@type']
-      self._ConvertFieldValuePair(value, sub_message)
+      self._ConvertFieldValuePair(value, sub_message, path)
       value['@type'] = type_url
     # Sets Any message
     message.value = sub_message.SerializeToString()
     message.type_url = type_url
 
-  def _ConvertGenericMessage(self, value, message):
+  def _ConvertGenericMessage(self, value, message, path):
     """Convert a JSON representation into message with FromJsonString."""
     # Duration, Timestamp, FieldMask have a FromJsonString method to do the
     # conversion. Users can also call the method directly.
     try:
       message.FromJsonString(value)
     except ValueError as e:
-      raise ParseError(e)
+      raise ParseError('{0} at {1}'.format(e, path))
 
-  def _ConvertValueMessage(self, value, message):
+  def _ConvertValueMessage(self, value, message, path):
     """Convert a JSON representation into Value message."""
     if isinstance(value, dict):
-      self._ConvertStructMessage(value, message.struct_value)
+      self._ConvertStructMessage(value, message.struct_value, path)
     elif isinstance(value, list):
-      self. _ConvertListValueMessage(value, message.list_value)
+      self._ConvertListValueMessage(value, message.list_value, path)
     elif value is None:
       message.null_value = 0
     elif isinstance(value, bool):
@@ -642,68 +683,76 @@
     elif isinstance(value, _INT_OR_FLOAT):
       message.number_value = value
     else:
-      raise ParseError('Value {0} has unexpected type {1}.'.format(
-          value, type(value)))
+      raise ParseError('Value {0} has unexpected type {1} at {2}'.format(
+          value, type(value), path))
 
-  def _ConvertListValueMessage(self, value, message):
+  def _ConvertListValueMessage(self, value, message, path):
     """Convert a JSON representation into ListValue message."""
     if not isinstance(value, list):
-      raise ParseError(
-          'ListValue must be in [] which is {0}.'.format(value))
+      raise ParseError('ListValue must be in [] which is {0} at {1}'.format(
+          value, path))
     message.ClearField('values')
-    for item in value:
-      self._ConvertValueMessage(item, message.values.add())
+    for index, item in enumerate(value):
+      self._ConvertValueMessage(item, message.values.add(),
+                                '{0}[{1}]'.format(path, index))
 
-  def _ConvertStructMessage(self, value, message):
+  def _ConvertStructMessage(self, value, message, path):
     """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))
+      raise ParseError('Struct must be in a dict which is {0} at {1}'.format(
+          value, path))
     # Clear will mark the struct as modified so it will be created even if
     # there are no values.
     message.Clear()
     for key in value:
-      self._ConvertValueMessage(value[key], message.fields[key])
+      self._ConvertValueMessage(value[key], message.fields[key],
+                                '{0}.{1}'.format(path, key))
     return
 
-  def _ConvertWrapperMessage(self, value, message):
+  def _ConvertWrapperMessage(self, value, message, path):
     """Convert a JSON representation into Wrapper message."""
     field = message.DESCRIPTOR.fields_by_name['value']
-    setattr(message, 'value', _ConvertScalarFieldValue(value, field))
+    setattr(
+        message, 'value',
+        _ConvertScalarFieldValue(value, field, path='{0}.value'.format(path)))
 
-  def _ConvertMapFieldValue(self, value, message, field):
+  def _ConvertMapFieldValue(self, value, message, field, path):
     """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.
+      path: parent path to log parse error info.
 
     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))
+          'Map field {0} must be in a dict which is {1} at {2}'.format(
+              field.name, value, path))
     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)
+      key_value = _ConvertScalarFieldValue(key, key_field,
+                                           '{0}.key'.format(path), True)
       if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-        self.ConvertMessage(value[key], getattr(
-            message, field.name)[key_value])
+        self.ConvertMessage(value[key],
+                            getattr(message, field.name)[key_value],
+                            '{0}[{1}]'.format(path, key_value))
       else:
         getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
-            value[key], value_field)
+            value[key], value_field, path='{0}[{1}]'.format(path, key_value))
 
 
-def _ConvertScalarFieldValue(value, field, require_str=False):
+def _ConvertScalarFieldValue(value, field, path, 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.
+    path: parent path to log parse error info.
     require_str: If True, the field value must be a str.
 
   Returns:
@@ -712,44 +761,47 @@
   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, field)
-  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:
-      if isinstance(value, str):
-        encoded = value.encode('utf-8')
+  try:
+    if field.cpp_type in _INT_TYPES:
+      return _ConvertInteger(value)
+    elif field.cpp_type in _FLOAT_TYPES:
+      return _ConvertFloat(value, field)
+    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:
+        if isinstance(value, str):
+          encoded = value.encode('utf-8')
+        else:
+          encoded = value
+        # Add extra padding '='
+        padded_value = encoded + b'=' * (4 - len(encoded) % 4)
+        return base64.urlsafe_b64decode(padded_value)
       else:
-        encoded = value
-      # Add extra padding '='
-      padded_value = encoded + b'=' * (4 - len(encoded) % 4)
-      return base64.urlsafe_b64decode(padded_value)
-    else:
-      # Checking for unpaired surrogates appears to be unreliable,
-      # depending on the specific Python version, so we check manually.
-      if _UNPAIRED_SURROGATE_PATTERN.search(value):
-        raise ParseError('Unpaired surrogate')
-      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:
-      try:
-        number = int(value)
-        enum_value = field.enum_type.values_by_number.get(number, None)
-      except ValueError:
-        raise ParseError('Invalid enum value {0} for enum type {1}.'.format(
-            value, field.enum_type.full_name))
+        # Checking for unpaired surrogates appears to be unreliable,
+        # depending on the specific Python version, so we check manually.
+        if _UNPAIRED_SURROGATE_PATTERN.search(value):
+          raise ParseError('Unpaired surrogate')
+        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:
-        if field.file.syntax == 'proto3':
-          # Proto3 accepts unknown enums.
-          return number
-        raise ParseError('Invalid enum value {0} for enum type {1}.'.format(
-            value, field.enum_type.full_name))
-    return enum_value.number
+        try:
+          number = int(value)
+          enum_value = field.enum_type.values_by_number.get(number, None)
+        except ValueError:
+          raise ParseError('Invalid enum value {0} for enum type {1}'.format(
+              value, field.enum_type.full_name))
+        if enum_value is None:
+          if field.file.syntax == 'proto3':
+            # Proto3 accepts unknown enums.
+            return number
+          raise ParseError('Invalid enum value {0} for enum type {1}'.format(
+              value, field.enum_type.full_name))
+      return enum_value.number
+  except ParseError as e:
+    raise ParseError('{0} at {1}'.format(e, path))
 
 
 def _ConvertInteger(value):
@@ -765,14 +817,14 @@
     ParseError: If an integer couldn't be consumed.
   """
   if isinstance(value, float) and not value.is_integer():
-    raise ParseError('Couldn\'t parse integer: {0}.'.format(value))
+    raise ParseError('Couldn\'t parse integer: {0}'.format(value))
 
   if isinstance(value, str) and value.find(' ') != -1:
-    raise ParseError('Couldn\'t parse integer: "{0}".'.format(value))
+    raise ParseError('Couldn\'t parse integer: "{0}"'.format(value))
 
   if isinstance(value, bool):
     raise ParseError('Bool value {0} is not acceptable for '
-                     'integer field.'.format(value))
+                     'integer field'.format(value))
 
   return int(value)
 
@@ -781,14 +833,14 @@
   """Convert an floating point number."""
   if isinstance(value, float):
     if math.isnan(value):
-      raise ParseError('Couldn\'t parse NaN, use quoted "NaN" instead.')
+      raise ParseError('Couldn\'t parse NaN, use quoted "NaN" instead')
     if math.isinf(value):
       if value > 0:
         raise ParseError('Couldn\'t parse Infinity or value too large, '
-                         'use quoted "Infinity" instead.')
+                         'use quoted "Infinity" instead')
       else:
         raise ParseError('Couldn\'t parse -Infinity or value too small, '
-                         'use quoted "-Infinity" instead.')
+                         'use quoted "-Infinity" instead')
     if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
       # pylint: disable=protected-access
       if value > type_checkers._FLOAT_MAX:
@@ -797,7 +849,7 @@
       if value < type_checkers._FLOAT_MIN:
         raise ParseError('Float value too small')
   if value == 'nan':
-    raise ParseError('Couldn\'t parse float "nan", use "NaN" instead.')
+    raise ParseError('Couldn\'t parse float "nan", use "NaN" instead')
   try:
     # Assume Python compatible syntax.
     return float(value)
@@ -810,7 +862,7 @@
     elif value == _NAN:
       return float('nan')
     else:
-      raise ParseError('Couldn\'t parse float: {0}.'.format(value))
+      raise ParseError('Couldn\'t parse float: {0}'.format(value))
 
 
 def _ConvertBool(value, require_str):
@@ -832,10 +884,10 @@
     elif value == 'false':
       return False
     else:
-      raise ParseError('Expected "true" or "false", not {0}.'.format(value))
+      raise ParseError('Expected "true" or "false", not {0}'.format(value))
 
   if not isinstance(value, bool):
-    raise ParseError('Expected true or false without quotes.')
+    raise ParseError('Expected true or false without quotes')
   return value
 
 _WKTJSONMETHODS = {
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 2101c29..7ad341b 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -50,12 +50,13 @@
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/hash.h>
 
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -95,17 +96,17 @@
   // This check is not critical and is somewhat difficult to implement correctly
   // in PyPy.
   PyFrameObject* frame = PyEval_GetFrame();
-  if (frame == NULL) {
+  if (frame == nullptr) {
     return false;
   }
   while (stacklevel-- > 0) {
     frame = frame->f_back;
-    if (frame == NULL) {
+    if (frame == nullptr) {
       return false;
     }
   }
 
-  if (frame->f_code->co_filename == NULL) {
+  if (frame->f_code->co_filename == nullptr) {
     return false;
   }
   char* filename;
@@ -236,23 +237,23 @@
   const Descriptor *message_type = options.GetDescriptor();
   CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
       message_factory, message_type);
-  if (message_class == NULL) {
+  if (message_class == nullptr) {
     PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
                  message_type->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   ScopedPyObjectPtr args(PyTuple_New(0));
   ScopedPyObjectPtr value(
-      PyObject_Call(message_class->AsPyObject(), args.get(), NULL));
+      PyObject_Call(message_class->AsPyObject(), args.get(), nullptr));
   Py_DECREF(message_class);
-  if (value == NULL) {
-    return NULL;
+  if (value == nullptr) {
+    return nullptr;
   }
   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;
+      return nullptr;
   }
   CMessage* cmsg = reinterpret_cast<CMessage*>(value.get());
 
@@ -264,7 +265,7 @@
     // Reparse options string!  XXX call cmessage::MergeFromString
     if (!Reparse(message_factory, options, cmsg->message)) {
       PyErr_Format(PyExc_ValueError, "Error reparsing Options message");
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -288,7 +289,7 @@
       message->message->GetDescriptor() != self_descriptor) {
     PyErr_Format(PyExc_TypeError, "Not a %s message",
                  self_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   cmessage::AssureWritable(message);
   DescriptorProtoClass* descriptor_message =
@@ -324,7 +325,7 @@
 typedef struct PyFileDescriptor {
   PyBaseDescriptor base;
 
-  // The cached version of serialized pb. Either NULL, or a Bytes string.
+  // The cached version of serialized pb. Either null, or a Bytes string.
   // We own the reference.
   PyObject *serialized_pb;
 } PyFileDescriptor;
@@ -345,9 +346,9 @@
   if (was_created) {
     *was_created = false;
   }
-  if (descriptor == NULL) {
+  if (descriptor == nullptr) {
     PyErr_BadInternalCall();
-    return NULL;
+    return nullptr;
   }
 
   // See if the object is in the map of interned descriptors
@@ -361,8 +362,8 @@
   // Create a new descriptor object
   PyBaseDescriptor* py_descriptor = PyObject_GC_New(
       PyBaseDescriptor, type);
-  if (py_descriptor == NULL) {
-    return NULL;
+  if (py_descriptor == nullptr) {
+    return nullptr;
   }
   py_descriptor->descriptor = descriptor;
 
@@ -373,10 +374,10 @@
   // Ensures that the DescriptorPool stays alive.
   PyDescriptorPool* pool = GetDescriptorPool_FromPool(
       GetFileDescriptor(descriptor)->pool());
-  if (pool == NULL) {
+  if (pool == nullptr) {
     // Don't DECREF, the object is not fully initialized.
     PyObject_Del(py_descriptor);
-    return NULL;
+    return nullptr;
   }
   Py_INCREF(pool);
   py_descriptor->pool = pool;
@@ -410,7 +411,7 @@
 }
 
 static PyGetSetDef Getters[] = {
-  {NULL}
+    {nullptr},
 };
 
 PyTypeObject PyBaseDescriptor_Type = {
@@ -420,29 +421,29 @@
     0,                                        // tp_itemsize
     (destructor)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
+    nullptr,                                  // tp_getattr
+    nullptr,                                  // tp_setattr
+    nullptr,                                  // tp_compare
+    nullptr,                                  // tp_repr
+    nullptr,                                  // tp_as_number
+    nullptr,                                  // tp_as_sequence
+    nullptr,                                  // tp_as_mapping
+    nullptr,                                  // tp_hash
+    nullptr,                                  // tp_call
+    nullptr,                                  // tp_str
+    nullptr,                                  // tp_getattro
+    nullptr,                                  // tp_setattro
+    nullptr,                                  // tp_as_buffer
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
     "Descriptors base class",                 // tp_doc
     GcTraverse,                               // tp_traverse
     GcClear,                                  // tp_clear
-    0,                                        // tp_richcompare
+    nullptr,                                  // tp_richcompare
     0,                                        // tp_weaklistoffset
-    0,                                        // tp_iter
-    0,                                        // tp_iternext
-    0,                                        // tp_methods
-    0,                                        // tp_members
+    nullptr,                                  // tp_iter
+    nullptr,                                  // tp_iternext
+    nullptr,                                  // tp_methods
+    nullptr,                                  // tp_members
     Getters,                                  // tp_getset
 };
 
@@ -451,7 +452,7 @@
 const void* PyDescriptor_AsVoidPtr(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &descriptor::PyBaseDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a BaseDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor;
 }
@@ -613,19 +614,18 @@
 static PyObject* EnumValueName(PyBaseDescriptor *self, PyObject *args) {
   const char *enum_name;
   int number;
-  if (!PyArg_ParseTuple(args, "si", &enum_name, &number))
-    return NULL;
+  if (!PyArg_ParseTuple(args, "si", &enum_name, &number)) return nullptr;
   const EnumDescriptor *enum_type =
       _GetDescriptor(self)->FindEnumTypeByName(enum_name);
-  if (enum_type == NULL) {
+  if (enum_type == nullptr) {
     PyErr_SetString(PyExc_KeyError, enum_name);
-    return NULL;
+    return nullptr;
   }
   const EnumValueDescriptor *enum_value =
       enum_type->FindValueByNumber(number);
-  if (enum_value == NULL) {
+  if (enum_value == nullptr) {
     PyErr_Format(PyExc_KeyError, "%d", number);
-    return NULL;
+    return nullptr;
   }
   return PyString_FromCppString(enum_value->name());
 }
@@ -636,94 +636,98 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "name", (getter)GetName, NULL, "Last name"},
-  { "full_name", (getter)GetFullName, NULL, "Full name"},
-  { "_concrete_class", (getter)GetConcreteClass, NULL, "concrete class"},
-  { "file", (getter)GetFile, NULL, "File descriptor"},
+    {"name", (getter)GetName, nullptr, "Last name"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"_concrete_class", (getter)GetConcreteClass, nullptr, "concrete class"},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
 
-  { "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,
-    "Nested types by name"},
-  { "extensions", (getter)GetExtensions, NULL, "Extensions Sequence"},
-  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
-    "Extensions by name"},
-  { "extension_ranges", (getter)GetExtensionRanges, NULL, "Extension ranges"},
-  { "enum_types", (getter)GetEnumsSeq, NULL, "Enum sequence"},
-  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL,
-    "Enum types by name"},
-  { "enum_values_by_name", (getter)GetEnumValuesByName, NULL,
-    "Enum values by name"},
-  { "oneofs_by_name", (getter)GetOneofsByName, NULL, "Oneofs by name"},
-  { "oneofs", (getter)GetOneofsSeq, NULL, "Oneofs by name"},
-  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
-    "Containing type"},
-  { "is_extendable", (getter)IsExtendable, (setter)NULL},
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
-  {NULL}
+    {"fields", (getter)GetFieldsSeq, nullptr, "Fields sequence"},
+    {"fields_by_name", (getter)GetFieldsByName, nullptr, "Fields by name"},
+    {"fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, nullptr,
+     "Fields by camelCase name"},
+    {"fields_by_number", (getter)GetFieldsByNumber, nullptr,
+     "Fields by number"},
+    {"nested_types", (getter)GetNestedTypesSeq, nullptr,
+     "Nested types sequence"},
+    {"nested_types_by_name", (getter)GetNestedTypesByName, nullptr,
+     "Nested types by name"},
+    {"extensions", (getter)GetExtensions, nullptr, "Extensions Sequence"},
+    {"extensions_by_name", (getter)GetExtensionsByName, nullptr,
+     "Extensions by name"},
+    {"extension_ranges", (getter)GetExtensionRanges, nullptr,
+     "Extension ranges"},
+    {"enum_types", (getter)GetEnumsSeq, nullptr, "Enum sequence"},
+    {"enum_types_by_name", (getter)GetEnumTypesByName, nullptr,
+     "Enum types by name"},
+    {"enum_values_by_name", (getter)GetEnumValuesByName, nullptr,
+     "Enum values by name"},
+    {"oneofs_by_name", (getter)GetOneofsByName, nullptr, "Oneofs by name"},
+    {"oneofs", (getter)GetOneofsSeq, nullptr, "Oneofs by name"},
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"is_extendable", (getter)IsExtendable, (setter) nullptr},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
-  { "EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS, },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {"EnumValueName", (PyCFunction)EnumValueName, METH_VARARGS},
+    {nullptr},
 };
 
 }  // namespace message_descriptor
 
 PyTypeObject PyMessageDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".MessageDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Message Descriptor",               // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  message_descriptor::Methods,          // tp_methods
-  0,                                    // tp_members
-  message_descriptor::Getters,          // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MessageDescriptor",                // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Message Descriptor",              // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    message_descriptor::Methods,         // tp_methods
+    nullptr,                             // tp_members
+    message_descriptor::Getters,         // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyMessageDescriptor_FromDescriptor(
     const Descriptor* message_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyMessageDescriptor_Type, message_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyMessageDescriptor_Type,
+                                           message_descriptor, nullptr);
 }
 
 const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &PyMessageDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a MessageDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<const Descriptor*>(
       reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
@@ -851,7 +855,7 @@
     default:
       PyErr_Format(PyExc_NotImplementedError, "default value for %s",
                    _GetDescriptor(self)->full_name().c_str());
-      return NULL;
+      return nullptr;
   }
   return result;
 }
@@ -942,6 +946,14 @@
   return CheckCalledFromGeneratedFile("has_options");
 }
 
+static PyObject* GetHasPresence(PyBaseDescriptor* self, void* closure) {
+  if (_GetDescriptor(self)->has_presence()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+
 static PyObject* GetOptions(PyBaseDescriptor *self) {
   return GetOrBuildOptions(_GetDescriptor(self));
 }
@@ -957,89 +969,91 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "full_name", (getter)GetFullName, NULL, "Full name"},
-  { "name", (getter)GetName, NULL, "Unqualified name"},
-  { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
-  { "json_name", (getter)GetJsonName, NULL, "Json name"},
-  { "file", (getter)GetFile, NULL, "File Descriptor"},
-  { "type", (getter)GetType, NULL, "C++ Type"},
-  { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
-  { "label", (getter)GetLabel, NULL, "Label"},
-  { "number", (getter)GetNumber, NULL, "Number"},
-  { "index", (getter)GetIndex, NULL, "Index"},
-  { "default_value", (getter)GetDefaultValue, NULL, "Default Value"},
-  { "has_default_value", (getter)HasDefaultValue},
-  { "is_extension", (getter)IsExtension, NULL, "ID"},
-  { "id", (getter)GetID, NULL, "ID"},
-  { "_cdescriptor", (getter)GetCDescriptor, NULL, "HAACK REMOVE ME"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"name", (getter)GetName, nullptr, "Unqualified name"},
+    {"camelcase_name", (getter)GetCamelcaseName, nullptr, "Camelcase name"},
+    {"json_name", (getter)GetJsonName, nullptr, "Json name"},
+    {"file", (getter)GetFile, nullptr, "File Descriptor"},
+    {"type", (getter)GetType, nullptr, "C++ Type"},
+    {"cpp_type", (getter)GetCppType, nullptr, "C++ Type"},
+    {"label", (getter)GetLabel, nullptr, "Label"},
+    {"number", (getter)GetNumber, nullptr, "Number"},
+    {"index", (getter)GetIndex, nullptr, "Index"},
+    {"default_value", (getter)GetDefaultValue, nullptr, "Default Value"},
+    {"has_default_value", (getter)HasDefaultValue},
+    {"is_extension", (getter)IsExtension, nullptr, "ID"},
+    {"id", (getter)GetID, nullptr, "ID"},
+    {"_cdescriptor", (getter)GetCDescriptor, nullptr, "HAACK REMOVE ME"},
 
-  { "message_type", (getter)GetMessageType, (setter)SetMessageType,
-    "Message type"},
-  { "enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"},
-  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
-    "Containing type"},
-  { "extension_scope", (getter)GetExtensionScope, (setter)NULL,
-    "Extension scope"},
-  { "containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof,
-    "Containing oneof"},
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  {NULL}
+    {"message_type", (getter)GetMessageType, (setter)SetMessageType,
+     "Message type"},
+    {"enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"},
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"extension_scope", (getter)GetExtensionScope, (setter) nullptr,
+     "Extension scope"},
+    {"containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof,
+     "Containing oneof"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"has_presence", (getter)GetHasPresence, (setter) nullptr, "Has Presence"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
 };
 
 }  // namespace field_descriptor
 
 PyTypeObject PyFieldDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".FieldDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Field Descriptor",                 // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  field_descriptor::Methods,            // tp_methods
-  0,                                    // tp_members
-  field_descriptor::Getters,            // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".FieldDescriptor",                  // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Field Descriptor",                // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    field_descriptor::Methods,           // tp_methods
+    nullptr,                             // tp_members
+    field_descriptor::Getters,           // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyFieldDescriptor_FromDescriptor(
     const FieldDescriptor* field_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyFieldDescriptor_Type, field_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyFieldDescriptor_Type,
+                                           field_descriptor, nullptr);
 }
 
 const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &PyFieldDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a FieldDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<const FieldDescriptor*>(
       reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
@@ -1125,76 +1139,77 @@
 }
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
 };
 
 static PyGetSetDef Getters[] = {
-  { "full_name", (getter)GetFullName, NULL, "Full name"},
-  { "name", (getter)GetName, NULL, "last name"},
-  { "file", (getter)GetFile, NULL, "File descriptor"},
-  { "values", (getter)GetEnumvaluesSeq, NULL, "values"},
-  { "values_by_name", (getter)GetEnumvaluesByName, NULL,
-    "Enum values by name"},
-  { "values_by_number", (getter)GetEnumvaluesByNumber, NULL,
-    "Enum values by number"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"name", (getter)GetName, nullptr, "last name"},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
+    {"values", (getter)GetEnumvaluesSeq, nullptr, "values"},
+    {"values_by_name", (getter)GetEnumvaluesByName, nullptr,
+     "Enum values by name"},
+    {"values_by_number", (getter)GetEnumvaluesByNumber, nullptr,
+     "Enum values by number"},
 
-  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
-    "Containing type"},
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  {NULL}
+    {"containing_type", (getter)GetContainingType, (setter)SetContainingType,
+     "Containing type"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
 };
 
 }  // namespace enum_descriptor
 
 PyTypeObject PyEnumDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".EnumDescriptor",   // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Enum Descriptor",                  // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  enum_descriptor::Methods,             // tp_methods
-  0,                                    // tp_members
-  enum_descriptor::Getters,             // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".EnumDescriptor",                   // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Enum Descriptor",                 // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    enum_descriptor::Methods,            // tp_methods
+    nullptr,                             // tp_members
+    enum_descriptor::Getters,            // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyEnumDescriptor_FromDescriptor(
     const EnumDescriptor* enum_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyEnumDescriptor_Type, enum_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyEnumDescriptor_Type,
+                                           enum_descriptor, nullptr);
 }
 
 const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<const EnumDescriptor*>(
       reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
@@ -1252,63 +1267,64 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "name", (getter)GetName, NULL, "name"},
-  { "number", (getter)GetNumber, NULL, "number"},
-  { "index", (getter)GetIndex, NULL, "index"},
-  { "type", (getter)GetType, NULL, "index"},
+    {"name", (getter)GetName, nullptr, "name"},
+    {"number", (getter)GetNumber, nullptr, "number"},
+    {"index", (getter)GetIndex, nullptr, "index"},
+    {"type", (getter)GetType, nullptr, "index"},
 
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  {NULL}
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
 };
 
 }  // namespace enumvalue_descriptor
 
 PyTypeObject PyEnumValueDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".EnumValueDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 EnumValue Descriptor",             // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  enumvalue_descriptor::Methods,        // tp_methods
-  0,                                    // tp_members
-  enumvalue_descriptor::Getters,        // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".EnumValueDescriptor",              // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A EnumValue Descriptor",            // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    enumvalue_descriptor::Methods,       // tp_methods
+    nullptr,                             // tp_members
+    enumvalue_descriptor::Getters,       // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyEnumValueDescriptor_FromDescriptor(
     const EnumValueDescriptor* enumvalue_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyEnumValueDescriptor_Type,
+                                           enumvalue_descriptor, nullptr);
 }
 
 namespace file_descriptor {
@@ -1340,7 +1356,7 @@
 
 static PyObject* GetSerializedPb(PyFileDescriptor *self, void *closure) {
   PyObject *serialized_pb = self->serialized_pb;
-  if (serialized_pb != NULL) {
+  if (serialized_pb != nullptr) {
     Py_INCREF(serialized_pb);
     return serialized_pb;
   }
@@ -1350,8 +1366,8 @@
   file_proto.SerializePartialToString(&contents);
   self->serialized_pb = PyBytes_FromStringAndSize(
       contents.c_str(), contents.size());
-  if (self->serialized_pb == NULL) {
-    return NULL;
+  if (self->serialized_pb == nullptr) {
+    return nullptr;
   }
   Py_INCREF(self->serialized_pb);
   return self->serialized_pb;
@@ -1394,7 +1410,7 @@
   return CheckCalledFromGeneratedFile("has_options");
 }
 
-static PyObject* GetDebugString(PyFileDescriptor *self) {
+static PyObject* GetDebugString(PyFileDescriptor* self) {
   return PyString_FromCppString(_GetDescriptor(self)->DebugString());
 }
 
@@ -1422,32 +1438,36 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "pool", (getter)GetPool, NULL, "pool"},
-  { "name", (getter)GetName, NULL, "name"},
-  { "package", (getter)GetPackage, NULL, "package"},
-  { "serialized_pb", (getter)GetSerializedPb},
-  { "message_types_by_name", (getter)GetMessageTypesByName, NULL,
-    "Messages by name"},
-  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"},
-  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
-    "Extensions by name"},
-  { "services_by_name", (getter)GetServicesByName, NULL, "Services by name"},
-  { "dependencies", (getter)GetDependencies, NULL, "Dependencies"},
-  { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"},
+    {"pool", (getter)GetPool, nullptr, "pool"},
+    {"name", (getter)GetName, nullptr, "name"},
+    {"package", (getter)GetPackage, nullptr, "package"},
+    {"serialized_pb", (getter)GetSerializedPb},
+    {"message_types_by_name", (getter)GetMessageTypesByName, nullptr,
+     "Messages by name"},
+    {"enum_types_by_name", (getter)GetEnumTypesByName, nullptr,
+     "Enums by name"},
+    {"extensions_by_name", (getter)GetExtensionsByName, nullptr,
+     "Extensions by name"},
+    {"services_by_name", (getter)GetServicesByName, nullptr,
+     "Services by name"},
+    {"dependencies", (getter)GetDependencies, nullptr, "Dependencies"},
+    {"public_dependencies", (getter)GetPublicDependencies, nullptr,
+     "Dependencies"},
 
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
-  {NULL}
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"syntax", (getter)GetSyntax, (setter) nullptr, "Syntax"},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetDebugString", (PyCFunction)GetDebugString, METH_NOARGS, },
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
-  {NULL}
+    {"GetDebugString", (PyCFunction)GetDebugString, METH_NOARGS},
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
 };
 
 }  // namespace file_descriptor
@@ -1459,45 +1479,45 @@
     0,                                     // tp_itemsize
     (destructor)file_descriptor::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
+    nullptr,                               // tp_getattr
+    nullptr,                               // tp_setattr
+    nullptr,                               // tp_compare
+    nullptr,                               // tp_repr
+    nullptr,                               // tp_as_number
+    nullptr,                               // tp_as_sequence
+    nullptr,                               // tp_as_mapping
+    nullptr,                               // tp_hash
+    nullptr,                               // tp_call
+    nullptr,                               // tp_str
+    nullptr,                               // tp_getattro
+    nullptr,                               // tp_setattro
+    nullptr,                               // tp_as_buffer
     Py_TPFLAGS_DEFAULT,                    // tp_flags
     "A File Descriptor",                   // tp_doc
-    0,                                     // tp_traverse
-    0,                                     // tp_clear
-    0,                                     // tp_richcompare
+    nullptr,                               // tp_traverse
+    nullptr,                               // tp_clear
+    nullptr,                               // tp_richcompare
     0,                                     // tp_weaklistoffset
-    0,                                     // tp_iter
-    0,                                     // tp_iternext
+    nullptr,                               // tp_iter
+    nullptr,                               // tp_iternext
     file_descriptor::Methods,              // tp_methods
-    0,                                     // tp_members
+    nullptr,                               // tp_members
     file_descriptor::Getters,              // tp_getset
     &descriptor::PyBaseDescriptor_Type,    // tp_base
-    0,                                     // tp_dict
-    0,                                     // tp_descr_get
-    0,                                     // tp_descr_set
+    nullptr,                               // tp_dict
+    nullptr,                               // tp_descr_get
+    nullptr,                               // tp_descr_set
     0,                                     // tp_dictoffset
-    0,                                     // tp_init
-    0,                                     // tp_alloc
-    0,                                     // tp_new
+    nullptr,                               // tp_init
+    nullptr,                               // tp_alloc
+    nullptr,                               // tp_new
     PyObject_GC_Del,                       // tp_free
 };
 
 PyObject* PyFileDescriptor_FromDescriptor(
     const FileDescriptor* file_descriptor) {
   return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor,
-                                                         NULL);
+                                                         nullptr);
 }
 
 PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
@@ -1505,8 +1525,8 @@
   bool was_created;
   PyObject* py_descriptor = descriptor::NewInternedDescriptor(
       &PyFileDescriptor_Type, file_descriptor, &was_created);
-  if (py_descriptor == NULL) {
-    return NULL;
+  if (py_descriptor == nullptr) {
+    return nullptr;
   }
   if (was_created) {
     PyFileDescriptor* cfile_descriptor =
@@ -1523,7 +1543,7 @@
 const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<const FileDescriptor*>(
       reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
@@ -1571,6 +1591,7 @@
     Py_RETURN_FALSE;
   }
 }
+
 static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
                          void *closure) {
   return CheckCalledFromGeneratedFile("has_options");
@@ -1591,64 +1612,65 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "name", (getter)GetName, NULL, "Name"},
-  { "full_name", (getter)GetFullName, NULL, "Full name"},
-  { "index", (getter)GetIndex, NULL, "Index"},
+    {"name", (getter)GetName, nullptr, "Name"},
+    {"full_name", (getter)GetFullName, nullptr, "Full name"},
+    {"index", (getter)GetIndex, nullptr, "Index"},
 
-  { "containing_type", (getter)GetContainingType, NULL, "Containing type"},
-  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
-  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
-  { "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
-    "Serialized Options"},
-  { "fields", (getter)GetFields, NULL, "Fields"},
-  {NULL}
+    {"containing_type", (getter)GetContainingType, nullptr, "Containing type"},
+    {"has_options", (getter)GetHasOptions, (setter)SetHasOptions,
+     "Has Options"},
+    {"_options", (getter) nullptr, (setter)SetOptions, "Options"},
+    {"_serialized_options", (getter) nullptr, (setter)SetSerializedOptions,
+     "Serialized Options"},
+    {"fields", (getter)GetFields, nullptr, "Fields"},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {nullptr},
 };
 
 }  // namespace oneof_descriptor
 
 PyTypeObject PyOneofDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".OneofDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Oneof Descriptor",                 // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  oneof_descriptor::Methods,            // tp_methods
-  0,                                    // tp_members
-  oneof_descriptor::Getters,            // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".OneofDescriptor",                  // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Oneof Descriptor",                // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    oneof_descriptor::Methods,           // tp_methods
+    nullptr,                             // tp_members
+    oneof_descriptor::Getters,           // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyOneofDescriptor_FromDescriptor(
     const OneofDescriptor* oneof_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyOneofDescriptor_Type, oneof_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyOneofDescriptor_Type,
+                                           oneof_descriptor, nullptr);
 }
 
 namespace service_descriptor {
@@ -1687,14 +1709,14 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const MethodDescriptor* method_descriptor =
       _GetDescriptor(self)->FindMethodByName(StringParam(name, name_size));
-  if (method_descriptor == NULL) {
+  if (method_descriptor == nullptr) {
     PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
-    return NULL;
+    return nullptr;
   }
 
   return PyMethodDescriptor_FromDescriptor(method_descriptor);
@@ -1710,69 +1732,69 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "name", (getter)GetName, NULL, "Name", NULL},
-  { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
-  { "file", (getter)GetFile, NULL, "File descriptor"},
-  { "index", (getter)GetIndex, NULL, "Index", NULL},
-
-  { "methods", (getter)GetMethods, NULL, "Methods", NULL},
-  { "methods_by_name", (getter)GetMethodsByName, NULL, "Methods by name", NULL},
-  {NULL}
+    {"name", (getter)GetName, nullptr, "Name", nullptr},
+    {"full_name", (getter)GetFullName, nullptr, "Full name", nullptr},
+    {"file", (getter)GetFile, nullptr, "File descriptor"},
+    {"index", (getter)GetIndex, nullptr, "Index", nullptr},
+    {"methods", (getter)GetMethods, nullptr, "Methods", nullptr},
+    {"methods_by_name", (getter)GetMethodsByName, nullptr, "Methods by name",
+     nullptr},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
-  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
-  { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {"FindMethodByName", (PyCFunction)FindMethodByName, METH_O},
+    {nullptr},
 };
 
 }  // namespace service_descriptor
 
 PyTypeObject PyServiceDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".ServiceDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Service Descriptor",               // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  service_descriptor::Methods,          // tp_methods
-  0,                                    // tp_members
-  service_descriptor::Getters,          // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".ServiceDescriptor",                // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Service Descriptor",              // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    service_descriptor::Methods,         // tp_methods
+    nullptr,                             // tp_members
+    service_descriptor::Getters,         // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyServiceDescriptor_FromDescriptor(
     const ServiceDescriptor* service_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyServiceDescriptor_Type, service_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyServiceDescriptor_Type,
+                                           service_descriptor, nullptr);
 }
 
 const ServiceDescriptor* PyServiceDescriptor_AsDescriptor(PyObject* obj) {
   if (!PyObject_TypeCheck(obj, &PyServiceDescriptor_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a ServiceDescriptor");
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<const ServiceDescriptor*>(
       reinterpret_cast<PyBaseDescriptor*>(obj)->descriptor);
@@ -1814,6 +1836,14 @@
   return PyMessageDescriptor_FromDescriptor(output_type);
 }
 
+static PyObject* GetClientStreaming(PyBaseDescriptor* self, void* closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->client_streaming() ? 1 : 0);
+}
+
+static PyObject* GetServerStreaming(PyBaseDescriptor* self, void* closure) {
+  return PyBool_FromLong(_GetDescriptor(self)->server_streaming() ? 1 : 0);
+}
+
 static PyObject* GetOptions(PyBaseDescriptor *self) {
   return GetOrBuildOptions(_GetDescriptor(self));
 }
@@ -1823,62 +1853,66 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { "name", (getter)GetName, NULL, "Name", NULL},
-  { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
-  { "index", (getter)GetIndex, NULL, "Index", NULL},
-  { "containing_service", (getter)GetContainingService, NULL,
-    "Containing service", NULL},
-  { "input_type", (getter)GetInputType, NULL, "Input type", NULL},
-  { "output_type", (getter)GetOutputType, NULL, "Output type", NULL},
-  {NULL}
+    {"name", (getter)GetName, nullptr, "Name", nullptr},
+    {"full_name", (getter)GetFullName, nullptr, "Full name", nullptr},
+    {"index", (getter)GetIndex, nullptr, "Index", nullptr},
+    {"containing_service", (getter)GetContainingService, nullptr,
+     "Containing service", nullptr},
+    {"input_type", (getter)GetInputType, nullptr, "Input type", nullptr},
+    {"output_type", (getter)GetOutputType, nullptr, "Output type", nullptr},
+    {"client_streaming", (getter)GetClientStreaming, nullptr,
+     "Client streaming", nullptr},
+    {"server_streaming", (getter)GetServerStreaming, nullptr,
+     "Server streaming", nullptr},
+    {nullptr},
 };
 
 static PyMethodDef Methods[] = {
-  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
-  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
-  {NULL}
+    {"GetOptions", (PyCFunction)GetOptions, METH_NOARGS},
+    {"CopyToProto", (PyCFunction)CopyToProto, METH_O},
+    {nullptr},
 };
 
 }  // namespace method_descriptor
 
 PyTypeObject PyMethodDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".MethodDescriptor",  // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // 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 Method Descriptor",                // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  method_descriptor::Methods,           // tp_methods
-  0,                                    // tp_members
-  method_descriptor::Getters,           // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MethodDescriptor",                 // tp_name
+    sizeof(PyBaseDescriptor),            // tp_basicsize
+    0,                                   // tp_itemsize
+    nullptr,                             // tp_dealloc
+    0,                                   // tp_print
+    nullptr,                             // tp_getattr
+    nullptr,                             // tp_setattr
+    nullptr,                             // tp_compare
+    nullptr,                             // tp_repr
+    nullptr,                             // tp_as_number
+    nullptr,                             // tp_as_sequence
+    nullptr,                             // tp_as_mapping
+    nullptr,                             // tp_hash
+    nullptr,                             // tp_call
+    nullptr,                             // tp_str
+    nullptr,                             // tp_getattro
+    nullptr,                             // tp_setattro
+    nullptr,                             // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                  // tp_flags
+    "A Method Descriptor",               // tp_doc
+    nullptr,                             // tp_traverse
+    nullptr,                             // tp_clear
+    nullptr,                             // tp_richcompare
+    0,                                   // tp_weaklistoffset
+    nullptr,                             // tp_iter
+    nullptr,                             // tp_iternext
+    method_descriptor::Methods,          // tp_methods
+    nullptr,                             // tp_members
+    method_descriptor::Getters,          // tp_getset
+    &descriptor::PyBaseDescriptor_Type,  // tp_base
 };
 
 PyObject* PyMethodDescriptor_FromDescriptor(
     const MethodDescriptor* method_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyMethodDescriptor_Type, method_descriptor, NULL);
+  return descriptor::NewInternedDescriptor(&PyMethodDescriptor_Type,
+                                           method_descriptor, nullptr);
 }
 
 // Add a enum values to a type dictionary.
@@ -1887,7 +1921,7 @@
   for (int i = 0; i < enum_descriptor->value_count(); ++i) {
     const EnumValueDescriptor* value = enum_descriptor->value(i);
     ScopedPyObjectPtr obj(PyLong_FromLong(value->number()));
-    if (obj == NULL) {
+    if (obj == nullptr) {
       return false;
     }
     if (PyDict_SetItemString(type->tp_dict, value->name().c_str(), obj.get()) <
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 4caff69..532635b 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -58,12 +58,13 @@
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -158,59 +159,56 @@
 
 // Returns the C++ item descriptor for a given Python key.
 // When the descriptor is found, return true and set *item.
-// When the descriptor is not found, return true, but set *item to NULL.
+// When the descriptor is not found, return true, but set *item to null.
 // On error, returns false with an exception set.
 static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
   switch (self->kind) {
-    case PyContainer::KIND_BYNAME:
-      {
-        char* name;
-        Py_ssize_t name_size;
-        if (PyString_AsStringAndSize(key, &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;
+    case PyContainer::KIND_BYNAME: {
+      char* name;
+      Py_ssize_t name_size;
+      if (PyString_AsStringAndSize(key, &name, &name_size) < 0) {
+        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+          // Not a string, cannot be in the container.
+          PyErr_Clear();
+          *item = nullptr;
+          return true;
         }
-        *item = self->container_def->get_by_name_fn(
-            self, StringParam(name, name_size));
-        return true;
+        return false;
       }
-    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_name_fn(self,
+                                                  StringParam(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 = nullptr;
+          return true;
         }
-        *item = self->container_def->get_by_camelcase_name_fn(
-            self, StringParam(camelcase_name, name_size));
-        return true;
+        return false;
       }
-    case PyContainer::KIND_BYNUMBER:
-      {
-        Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
-        if (number == -1 && PyErr_Occurred()) {
-          if (PyErr_ExceptionMatches(PyExc_TypeError)) {
-            // Not a number, cannot be in the container.
-            PyErr_Clear();
-            *item = NULL;
-            return true;
-          }
-          return false;
+      *item = self->container_def->get_by_camelcase_name_fn(
+          self, StringParam(camelcase_name, name_size));
+      return true;
+    }
+    case PyContainer::KIND_BYNUMBER: {
+      Py_ssize_t number = PyNumber_AsSsize_t(key, nullptr);
+      if (number == -1 && PyErr_Occurred()) {
+        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+          // Not a number, cannot be in the container.
+          PyErr_Clear();
+          *item = nullptr;
+          return true;
         }
-        *item = self->container_def->get_by_number_fn(self, number);
-        return true;
+        return false;
       }
+      *item = self->container_def->get_by_number_fn(self, number);
+      return true;
+    }
     default:
       PyErr_SetNone(PyExc_NotImplementedError);
       return false;
@@ -222,25 +220,22 @@
 static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
   const void* item = self->container_def->get_by_index_fn(self, index);
   switch (self->kind) {
-    case PyContainer::KIND_BYNAME:
-      {
+    case PyContainer::KIND_BYNAME: {
       const std::string& name(self->container_def->get_item_name_fn(item));
       return PyUnicode_FromStringAndSize(name.c_str(), name.size());
-      }
-    case PyContainer::KIND_BYCAMELCASENAME:
-      {
+    }
+    case PyContainer::KIND_BYCAMELCASENAME: {
       const std::string& name(
           self->container_def->get_item_camelcase_name_fn(item));
       return PyUnicode_FromStringAndSize(name.c_str(), name.size());
-      }
-    case PyContainer::KIND_BYNUMBER:
-      {
-        int value = self->container_def->get_item_number_fn(item);
-        return PyLong_FromLong(value);
-      }
+    }
+    case PyContainer::KIND_BYNUMBER: {
+      int value = self->container_def->get_item_number_fn(item);
+      return PyLong_FromLong(value);
+    }
     default:
       PyErr_SetNone(PyExc_NotImplementedError);
-      return NULL;
+      return nullptr;
   }
 }
 
@@ -258,13 +253,13 @@
 // The DescriptorMapping type.
 
 static PyObject* Subscript(PyContainer* self, PyObject* key) {
-  const void* item = NULL;
+  const void* item = nullptr;
   if (!_GetItemByKey(self, key, &item)) {
-    return NULL;
+    return nullptr;
   }
   if (!item) {
     PyErr_SetObject(PyExc_KeyError, key);
-    return NULL;
+    return nullptr;
   }
   return self->container_def->new_object_from_item_fn(item);
 }
@@ -286,7 +281,7 @@
 };
 
 static int Contains(PyContainer* self, PyObject* key) {
-  const void* item = NULL;
+  const void* item = nullptr;
   if (!_GetItemByKey(self, key, &item)) {
     return -1;
   }
@@ -345,11 +340,11 @@
     }
     for (int index = 0; index < size; index++) {
       ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
-      if (value1 == NULL) {
+      if (value1 == nullptr) {
         return -1;
       }
       PyObject* value2 = PyList_GetItem(other, index);
-      if (value2 == NULL) {
+      if (value2 == nullptr) {
         return -1;
       }
       int cmp = PyObject_RichCompareBool(value1.get(), value2, Py_EQ);
@@ -389,15 +384,15 @@
     }
     for (int index = 0; index < size; index++) {
       ScopedPyObjectPtr key(_NewKey_ByIndex(self, index));
-      if (key == NULL) {
+      if (key == nullptr) {
         return -1;
       }
       ScopedPyObjectPtr value1(_NewObj_ByIndex(self, index));
-      if (value1 == NULL) {
+      if (value1 == nullptr) {
         return -1;
       }
       PyObject* value2 = PyDict_GetItem(other, key.get());
-      if (value2 == NULL) {
+      if (value2 == nullptr) {
         // Not found in the other dictionary
         return 0;
       }
@@ -427,7 +422,7 @@
     result = DescriptorMapping_Equal(self, other);
   }
   if (result < 0) {
-    return NULL;
+    return nullptr;
   }
   if (result ^ (opid == Py_NE)) {
     Py_RETURN_TRUE;
@@ -437,28 +432,28 @@
 }
 
 static PySequenceMethods MappingSequenceMethods = {
-    0,                      // sq_length
-    0,                      // sq_concat
-    0,                      // sq_repeat
-    0,                      // sq_item
-    0,                      // sq_slice
-    0,                      // sq_ass_item
-    0,                      // sq_ass_slice
-    (objobjproc)Contains,   // sq_contains
+    nullptr,               // sq_length
+    nullptr,               // sq_concat
+    nullptr,               // sq_repeat
+    nullptr,               // sq_item
+    nullptr,               // sq_slice
+    nullptr,               // sq_ass_item
+    nullptr,               // sq_ass_slice
+    (objobjproc)Contains,  // sq_contains
 };
 
 static PyObject* Get(PyContainer* self, PyObject* args) {
   PyObject* key;
   PyObject* default_value = Py_None;
   if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) {
-    return NULL;
+    return nullptr;
   }
 
   const void* item;
   if (!_GetItemByKey(self, key, &item)) {
-    return NULL;
+    return nullptr;
   }
-  if (item == NULL) {
+  if (item == nullptr) {
     Py_INCREF(default_value);
     return default_value;
   }
@@ -468,13 +463,13 @@
 static PyObject* Keys(PyContainer* self, PyObject* args) {
   Py_ssize_t count = Length(self);
   ScopedPyObjectPtr list(PyList_New(count));
-  if (list == NULL) {
-    return NULL;
+  if (list == nullptr) {
+    return nullptr;
   }
   for (Py_ssize_t index = 0; index < count; ++index) {
     PyObject* key = _NewKey_ByIndex(self, index);
-    if (key == NULL) {
-      return NULL;
+    if (key == nullptr) {
+      return nullptr;
     }
     PyList_SET_ITEM(list.get(), index, key);
   }
@@ -484,13 +479,13 @@
 static PyObject* Values(PyContainer* self, PyObject* args) {
   Py_ssize_t count = Length(self);
   ScopedPyObjectPtr list(PyList_New(count));
-  if (list == NULL) {
-    return NULL;
+  if (list == nullptr) {
+    return nullptr;
   }
   for (Py_ssize_t index = 0; index < count; ++index) {
     PyObject* value = _NewObj_ByIndex(self, index);
-    if (value == NULL) {
-      return NULL;
+    if (value == nullptr) {
+      return nullptr;
     }
     PyList_SET_ITEM(list.get(), index, value);
   }
@@ -500,22 +495,22 @@
 static PyObject* Items(PyContainer* self, PyObject* args) {
   Py_ssize_t count = Length(self);
   ScopedPyObjectPtr list(PyList_New(count));
-  if (list == NULL) {
-    return NULL;
+  if (list == nullptr) {
+    return nullptr;
   }
   for (Py_ssize_t index = 0; index < count; ++index) {
     ScopedPyObjectPtr obj(PyTuple_New(2));
-    if (obj == NULL) {
-      return NULL;
+    if (obj == nullptr) {
+      return nullptr;
     }
     PyObject* key = _NewKey_ByIndex(self, index);
-    if (key == NULL) {
-      return NULL;
+    if (key == nullptr) {
+      return nullptr;
     }
     PyTuple_SET_ITEM(obj.get(), 0, key);
     PyObject* value = _NewObj_ByIndex(self, index);
-    if (value == NULL) {
-      return NULL;
+    if (value == nullptr) {
+      return nullptr;
     }
     PyTuple_SET_ITEM(obj.get(), 1, value);
     PyList_SET_ITEM(list.get(), index, obj.release());
@@ -540,56 +535,55 @@
 }
 
 static PyMethodDef MappingMethods[] = {
-  { "get", (PyCFunction)Get, METH_VARARGS, },
-  { "keys", (PyCFunction)Keys, METH_NOARGS, },
-  { "values", (PyCFunction)Values, METH_NOARGS, },
-  { "items", (PyCFunction)Items, METH_NOARGS, },
-  { "iterkeys", (PyCFunction)IterKeys, METH_NOARGS, },
-  { "itervalues", (PyCFunction)IterValues, METH_NOARGS, },
-  { "iteritems", (PyCFunction)IterItems, METH_NOARGS, },
-  {NULL}
+    {"get", (PyCFunction)Get, METH_VARARGS},
+    {"keys", (PyCFunction)Keys, METH_NOARGS},
+    {"values", (PyCFunction)Values, METH_NOARGS},
+    {"items", (PyCFunction)Items, METH_NOARGS},
+    {"iterkeys", (PyCFunction)IterKeys, METH_NOARGS},
+    {"itervalues", (PyCFunction)IterValues, METH_NOARGS},
+    {"iteritems", (PyCFunction)IterItems, METH_NOARGS},
+    {nullptr},
 };
 
 PyTypeObject DescriptorMapping_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "DescriptorMapping",                  // tp_name
-  sizeof(PyContainer),                  // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // tp_dealloc
-  0,                                    // tp_print
-  0,                                    // tp_getattr
-  0,                                    // tp_setattr
-  0,                                    // tp_compare
-  (reprfunc)ContainerRepr,              // tp_repr
-  0,                                    // tp_as_number
-  &MappingSequenceMethods,              // tp_as_sequence
-  &MappingMappingMethods,               // 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
-  0,                                    // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  (richcmpfunc)RichCompare,             // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  (getiterfunc)Iter,                    // tp_iter
-  0,                                    // tp_iternext
-  MappingMethods,                       // 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
-  0,                                    // tp_alloc
-  0,                                    // tp_new
-  0,                                    // tp_free
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorMapping",  // tp_name
+    sizeof(PyContainer),                                         // tp_basicsize
+    0,                                                           // tp_itemsize
+    nullptr,                                                     // tp_dealloc
+    0,                                                           // tp_pkrint
+    nullptr,                                                     // tp_getattr
+    nullptr,                                                     // tp_setattr
+    nullptr,                                                     // tp_compare
+    (reprfunc)ContainerRepr,                                     // tp_repr
+    nullptr,                                                     // tp_as_number
+    &MappingSequenceMethods,   // tp_as_sequence
+    &MappingMappingMethods,    // tp_as_mapping
+    nullptr,                   // tp_hash
+    nullptr,                   // tp_call
+    nullptr,                   // tp_str
+    nullptr,                   // tp_getattro
+    nullptr,                   // tp_setattro
+    nullptr,                   // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,        // tp_flags
+    nullptr,                   // tp_doc
+    nullptr,                   // tp_traverse
+    nullptr,                   // tp_clear
+    (richcmpfunc)RichCompare,  // tp_richcompare
+    0,                         // tp_weaklistoffset
+    (getiterfunc)Iter,         // tp_iter
+    nullptr,                   // tp_iternext
+    MappingMethods,            // tp_methods
+    nullptr,                   // tp_members
+    nullptr,                   // tp_getset
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
+    0,                         // tp_dictoffset
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
+    nullptr,                   // tp_new
+    nullptr,                   // tp_free
 };
 
 // The DescriptorSequence type.
@@ -600,7 +594,7 @@
   }
   if (index < 0 || index >= Length(self)) {
     PyErr_SetString(PyExc_IndexError, "index out of range");
-    return NULL;
+    return nullptr;
   }
   return _NewObj_ByIndex(self, index);
 }
@@ -610,15 +604,14 @@
   if (PyIndex_Check(item)) {
       Py_ssize_t index;
       index = PyNumber_AsSsize_t(item, PyExc_IndexError);
-      if (index == -1 && PyErr_Occurred())
-          return NULL;
+      if (index == -1 && PyErr_Occurred()) return nullptr;
       return GetItem(self, index);
   }
   // Materialize the list and delegate the operation to it.
   ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs(
-      reinterpret_cast<PyObject*>(&PyList_Type), self, NULL));
-  if (list == NULL) {
-    return NULL;
+      reinterpret_cast<PyObject*>(&PyList_Type), self, nullptr));
+  if (list == nullptr) {
+    return nullptr;
   }
   return Py_TYPE(list.get())->tp_as_mapping->mp_subscript(list.get(), item);
 }
@@ -633,7 +626,7 @@
   // a specific item belongs to only one sequence, depending on its position in
   // the .proto file definition.
   const void* descriptor_ptr = PyDescriptor_AsVoidPtr(item);
-  if (descriptor_ptr == NULL) {
+  if (descriptor_ptr == nullptr) {
     PyErr_Clear();
     // Not a descriptor, it cannot be in the list.
     return -1;
@@ -669,7 +662,7 @@
   if (position < 0) {
     // Not found
     PyErr_SetNone(PyExc_ValueError);
-    return NULL;
+    return nullptr;
   } else {
     return PyLong_FromLong(position);
   }
@@ -702,7 +695,7 @@
   PyErr_Format(PyExc_TypeError,
                "'%.200s' object is not a mutable sequence",
                Py_TYPE(self)->tp_name);
-  return NULL;
+  return nullptr;
 }
 
 static PyObject* Reversed(PyContainer* self, PyObject* args) {
@@ -711,77 +704,76 @@
 }
 
 static PyMethodDef SeqMethods[] = {
-  { "index", (PyCFunction)Index, METH_O, },
-  { "count", (PyCFunction)Count, METH_O, },
-  { "append", (PyCFunction)Append, METH_O, },
-  { "__reversed__", (PyCFunction)Reversed, METH_NOARGS, },
-  {NULL}
+    {"index", (PyCFunction)Index, METH_O},
+    {"count", (PyCFunction)Count, METH_O},
+    {"append", (PyCFunction)Append, METH_O},
+    {"__reversed__", (PyCFunction)Reversed, METH_NOARGS},
+    {nullptr},
 };
 
 static PySequenceMethods SeqSequenceMethods = {
-  (lenfunc)Length,          // sq_length
-  0,                        // sq_concat
-  0,                        // sq_repeat
-  (ssizeargfunc)GetItem,    // sq_item
-  0,                        // sq_slice
-  0,                        // sq_ass_item
-  0,                        // sq_ass_slice
-  (objobjproc)SeqContains,  // sq_contains
+    (lenfunc)Length,          // sq_length
+    nullptr,                  // sq_concat
+    nullptr,                  // sq_repeat
+    (ssizeargfunc)GetItem,    // sq_item
+    nullptr,                  // sq_slice
+    nullptr,                  // sq_ass_item
+    nullptr,                  // sq_ass_slice
+    (objobjproc)SeqContains,  // sq_contains
 };
 
 static PyMappingMethods SeqMappingMethods = {
-  (lenfunc)Length,           // mp_length
-  (binaryfunc)SeqSubscript,  // mp_subscript
-  0,                         // mp_ass_subscript
+    (lenfunc)Length,           // mp_length
+    (binaryfunc)SeqSubscript,  // mp_subscript
+    nullptr,                   // mp_ass_subscript
 };
 
 PyTypeObject DescriptorSequence_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "DescriptorSequence",                 // tp_name
-  sizeof(PyContainer),                  // tp_basicsize
-  0,                                    // tp_itemsize
-  0,                                    // tp_dealloc
-  0,                                    // tp_print
-  0,                                    // tp_getattr
-  0,                                    // tp_setattr
-  0,                                    // tp_compare
-  (reprfunc)ContainerRepr,              // tp_repr
-  0,                                    // tp_as_number
-  &SeqSequenceMethods,                  // tp_as_sequence
-  &SeqMappingMethods,                   // 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
-  0,                                    // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  (richcmpfunc)RichCompare,             // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  SeqMethods,                           // 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
-  0,                                    // tp_alloc
-  0,                                    // tp_new
-  0,                                    // tp_free
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) "DescriptorSequence",  // tp_name
+    sizeof(PyContainer),       // tp_basicsize
+    0,                         // tp_itemsize
+    nullptr,                   // tp_dealloc
+    0,                         // tp_print
+    nullptr,                   // tp_getattr
+    nullptr,                   // tp_setattr
+    nullptr,                   // tp_compare
+    (reprfunc)ContainerRepr,   // tp_repr
+    nullptr,                   // tp_as_number
+    &SeqSequenceMethods,       // tp_as_sequence
+    &SeqMappingMethods,        // tp_as_mapping
+    nullptr,                   // tp_hash
+    nullptr,                   // tp_call
+    nullptr,                   // tp_str
+    nullptr,                   // tp_getattro
+    nullptr,                   // tp_setattro
+    nullptr,                   // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,        // tp_flags
+    nullptr,                   // tp_doc
+    nullptr,                   // tp_traverse
+    nullptr,                   // tp_clear
+    (richcmpfunc)RichCompare,  // tp_richcompare
+    0,                         // tp_weaklistoffset
+    nullptr,                   // tp_iter
+    nullptr,                   // tp_iternext
+    SeqMethods,                // tp_methods
+    nullptr,                   // tp_members
+    nullptr,                   // tp_getset
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
+    0,                         // tp_dictoffset
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
+    nullptr,                   // tp_new
+    nullptr,                   // tp_free
 };
 
 static PyObject* NewMappingByName(
     DescriptorContainerDef* container_def, const void* descriptor) {
   PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   self->descriptor = descriptor;
   self->container_def = container_def;
@@ -792,8 +784,8 @@
 static PyObject* NewMappingByCamelcaseName(
     DescriptorContainerDef* container_def, const void* descriptor) {
   PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   self->descriptor = descriptor;
   self->container_def = container_def;
@@ -803,14 +795,14 @@
 
 static PyObject* NewMappingByNumber(
     DescriptorContainerDef* container_def, const void* descriptor) {
-  if (container_def->get_by_number_fn == NULL ||
-      container_def->get_item_number_fn == NULL) {
+  if (container_def->get_by_number_fn == nullptr ||
+      container_def->get_item_number_fn == nullptr) {
     PyErr_SetNone(PyExc_NotImplementedError);
-    return NULL;
+    return nullptr;
   }
   PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   self->descriptor = descriptor;
   self->container_def = container_def;
@@ -821,8 +813,8 @@
 static PyObject* NewSequence(
     DescriptorContainerDef* container_def, const void* descriptor) {
   PyContainer* self = PyObject_New(PyContainer, &DescriptorSequence_Type);
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   self->descriptor = descriptor;
   self->container_def = container_def;
@@ -840,8 +832,8 @@
 static PyObject* Iterator_Next(PyContainerIterator* self) {
   int count = self->container->container_def->count_fn(self->container);
   if (self->index >= count) {
-    // Return NULL with no exception to indicate the end.
-    return NULL;
+    // Return null with no exception to indicate the end.
+    return nullptr;
   }
   int index = self->index;
   self->index += 1;
@@ -852,80 +844,79 @@
       return _NewObj_ByIndex(self->container, index);
     case PyContainerIterator::KIND_ITERVALUE_REVERSED:
       return _NewObj_ByIndex(self->container, count - index - 1);
-    case PyContainerIterator::KIND_ITERITEM:
-      {
-        PyObject* obj = PyTuple_New(2);
-        if (obj == NULL) {
-          return NULL;
-        }
-        PyObject* key = _NewKey_ByIndex(self->container, index);
-        if (key == NULL) {
-          Py_DECREF(obj);
-          return NULL;
-        }
-        PyTuple_SET_ITEM(obj, 0, key);
-        PyObject* value = _NewObj_ByIndex(self->container, index);
-        if (value == NULL) {
-          Py_DECREF(obj);
-          return NULL;
-        }
-        PyTuple_SET_ITEM(obj, 1, value);
-        return obj;
+    case PyContainerIterator::KIND_ITERITEM: {
+      PyObject* obj = PyTuple_New(2);
+      if (obj == nullptr) {
+        return nullptr;
       }
+      PyObject* key = _NewKey_ByIndex(self->container, index);
+      if (key == nullptr) {
+        Py_DECREF(obj);
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(obj, 0, key);
+      PyObject* value = _NewObj_ByIndex(self->container, index);
+      if (value == nullptr) {
+        Py_DECREF(obj);
+        return nullptr;
+      }
+      PyTuple_SET_ITEM(obj, 1, value);
+      return obj;
+    }
     default:
       PyErr_SetNone(PyExc_NotImplementedError);
-      return NULL;
+      return nullptr;
   }
 }
 
 static PyTypeObject ContainerIterator_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "DescriptorContainerIterator",        // tp_name
-  sizeof(PyContainerIterator),          // tp_basicsize
-  0,                                    // tp_itemsize
-  (destructor)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
-  0,                                    // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  PyObject_SelfIter,                    // tp_iter
-  (iternextfunc)Iterator_Next,          // 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
-  0,                                    // tp_alloc
-  0,                                    // tp_new
-  0,                                    // tp_free
+    PyVarObject_HEAD_INIT(&PyType_Type,
+                          0) "DescriptorContainerIterator",  // tp_name
+    sizeof(PyContainerIterator),                             // tp_basicsize
+    0,                                                       // tp_itemsize
+    (destructor)Iterator_Dealloc,                            // tp_dealloc
+    0,                                                       // tp_print
+    nullptr,                                                 // tp_getattr
+    nullptr,                                                 // tp_setattr
+    nullptr,                                                 // tp_compare
+    nullptr,                                                 // tp_repr
+    nullptr,                                                 // tp_as_number
+    nullptr,                                                 // tp_as_sequence
+    nullptr,                                                 // tp_as_mapping
+    nullptr,                                                 // tp_hash
+    nullptr,                                                 // tp_call
+    nullptr,                                                 // tp_str
+    nullptr,                                                 // tp_getattro
+    nullptr,                                                 // tp_setattro
+    nullptr,                                                 // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                                      // tp_flags
+    nullptr,                                                 // tp_doc
+    nullptr,                                                 // tp_traverse
+    nullptr,                                                 // tp_clear
+    nullptr,                                                 // tp_richcompare
+    0,                            // tp_weaklistoffset
+    PyObject_SelfIter,            // tp_iter
+    (iternextfunc)Iterator_Next,  // tp_iternext
+    nullptr,                      // tp_methods
+    nullptr,                      // tp_members
+    nullptr,                      // tp_getset
+    nullptr,                      // tp_base
+    nullptr,                      // tp_dict
+    nullptr,                      // tp_descr_get
+    nullptr,                      // tp_descr_set
+    0,                            // tp_dictoffset
+    nullptr,                      // tp_init
+    nullptr,                      // tp_alloc
+    nullptr,                      // tp_new
+    nullptr,                      // tp_free
 };
 
 static PyObject* NewContainerIterator(PyContainer* container,
                                       PyContainerIterator::IterKind kind) {
   PyContainerIterator* self = PyObject_New(PyContainerIterator,
                                            &ContainerIterator_Type);
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   Py_INCREF(container);
   self->container = container;
@@ -993,17 +984,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageFields",
-  Count,
-  GetByIndex,
-  GetByName,
-  GetByCamelcaseName,
-  GetByNumber,
-  NewObjectFromItem,
-  GetItemName,
-  GetItemCamelcaseName,
-  GetItemNumber,
-  GetItemIndex,
+    "MessageFields",      Count,         GetByIndex,        GetByName,
+    GetByCamelcaseName,   GetByNumber,   NewObjectFromItem, GetItemName,
+    GetItemCamelcaseName, GetItemNumber, GetItemIndex,
 };
 
 }  // namespace fields
@@ -1054,17 +1037,17 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageNestedTypes",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "MessageNestedTypes",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
 };
 
 }  // namespace nested_types
@@ -1106,17 +1089,17 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageNestedEnums",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "MessageNestedEnums",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
 };
 
 }  // namespace enums
@@ -1155,7 +1138,7 @@
 static const void* GetByIndex(PyContainer* self, int index) {
   // This is not optimal, but the number of enums *types* in a given message
   // is small.  This function is only used when iterating over the mapping.
-  const EnumDescriptor* enum_type = NULL;
+  const EnumDescriptor* enum_type = nullptr;
   int enum_type_count = GetDescriptor(self)->enum_type_count();
   for (int i = 0; i < enum_type_count; ++i) {
     enum_type = GetDescriptor(self)->enum_type(i);
@@ -1181,17 +1164,8 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageEnumValues",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  NULL,
+    "MessageEnumValues", Count,       GetByIndex, GetByName, nullptr, nullptr,
+    NewObjectFromItem,   GetItemName, nullptr,    nullptr,   nullptr,
 };
 
 }  // namespace enumvalues
@@ -1229,17 +1203,17 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageExtensions",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "MessageExtensions",
+    Count,
+    GetByIndex,
+    GetByName,
+    nullptr,
+    nullptr,
+    NewObjectFromItem,
+    GetItemName,
+    nullptr,
+    nullptr,
+    GetItemIndex,
 };
 
 }  // namespace extensions
@@ -1281,17 +1255,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "MessageOneofs",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "MessageOneofs", Count,   GetByIndex,        GetByName,
+    nullptr,         nullptr, NewObjectFromItem, GetItemName,
+    nullptr,         nullptr, GetItemIndex,
 };
 
 }  // namespace oneofs
@@ -1352,17 +1318,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "EnumValues",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  GetByNumber,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  GetItemNumber,
-  GetItemIndex,
+    "EnumValues", Count,         GetByIndex,        GetByName,
+    nullptr,      GetByNumber,   NewObjectFromItem, GetItemName,
+    nullptr,      GetItemNumber, GetItemIndex,
 };
 
 }  // namespace enumvalues
@@ -1410,17 +1368,8 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "OneofFields",
-  Count,
-  GetByIndex,
-  NULL,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  NULL,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "OneofFields",     Count,   GetByIndex, nullptr, nullptr,      nullptr,
+    NewObjectFromItem, nullptr, nullptr,    nullptr, GetItemIndex,
 };
 
 }  // namespace fields
@@ -1468,17 +1417,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "ServiceMethods",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "ServiceMethods", Count,   GetByIndex,        GetByName,
+    nullptr,          nullptr, NewObjectFromItem, GetItemName,
+    nullptr,          nullptr, GetItemIndex,
 };
 
 }  // namespace methods
@@ -1530,17 +1471,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FileMessages",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "FileMessages", Count,   GetByIndex,        GetByName,
+    nullptr,        nullptr, NewObjectFromItem, GetItemName,
+    nullptr,        nullptr, GetItemIndex,
 };
 
 }  // namespace messages
@@ -1578,17 +1511,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FileEnums",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "FileEnums", Count,   GetByIndex,        GetByName,
+    nullptr,     nullptr, NewObjectFromItem, GetItemName,
+    nullptr,     nullptr, GetItemIndex,
 };
 
 }  // namespace enums
@@ -1626,17 +1551,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FileExtensions",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "FileExtensions", Count,   GetByIndex,        GetByName,
+    nullptr,          nullptr, NewObjectFromItem, GetItemName,
+    nullptr,          nullptr, GetItemIndex,
 };
 
 }  // namespace extensions
@@ -1674,17 +1591,9 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FileServices",
-  Count,
-  GetByIndex,
-  GetByName,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  GetItemName,
-  NULL,
-  NULL,
-  GetItemIndex,
+    "FileServices", Count,   GetByIndex,        GetByName,
+    nullptr,        nullptr, NewObjectFromItem, GetItemName,
+    nullptr,        nullptr, GetItemIndex,
 };
 
 }  // namespace services
@@ -1710,17 +1619,8 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FileDependencies",
-  Count,
-  GetByIndex,
-  NULL,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+    "FileDependencies", Count,   GetByIndex, nullptr, nullptr, nullptr,
+    NewObjectFromItem,  nullptr, nullptr,    nullptr, nullptr,
 };
 
 }  // namespace dependencies
@@ -1746,17 +1646,8 @@
 }
 
 static DescriptorContainerDef ContainerDef = {
-  "FilePublicDependencies",
-  Count,
-  GetByIndex,
-  NULL,
-  NULL,
-  NULL,
-  NewObjectFromItem,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+    "FilePublicDependencies", Count,   GetByIndex, nullptr, nullptr, nullptr,
+    NewObjectFromItem,        nullptr, nullptr,    nullptr, nullptr,
 };
 
 }  // namespace public_dependencies
diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc
index da1c84a..f87f23d 100644
--- a/python/google/protobuf/pyext/descriptor_database.cc
+++ b/python/google/protobuf/pyext/descriptor_database.cc
@@ -56,7 +56,7 @@
 // Handles all kinds of Python errors, which are simply logged.
 static bool GetFileDescriptorProto(PyObject* py_descriptor,
                                    FileDescriptorProto* output) {
-  if (py_descriptor == NULL) {
+  if (py_descriptor == nullptr) {
     if (PyErr_ExceptionMatches(PyExc_KeyError)) {
       // Expected error: item was simply not found.
       PyErr_Clear();
@@ -83,8 +83,8 @@
     // 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) {
+        PyObject_CallMethod(py_descriptor, "SerializeToString", nullptr));
+    if (serialized_pb == nullptr) {
       GOOGLE_LOG(ERROR)
           << "DescriptorDatabase method did not return a FileDescriptorProto";
       PyErr_Print();
@@ -134,7 +134,7 @@
     FileDescriptorProto* output) {
   ScopedPyObjectPtr py_method(
       PyObject_GetAttrString(py_database_, "FindFileContainingExtension"));
-  if (py_method == NULL) {
+  if (py_method == nullptr) {
     // This method is not implemented, returns without error.
     PyErr_Clear();
     return false;
@@ -153,7 +153,7 @@
     const std::string& containing_type, std::vector<int>* output) {
   ScopedPyObjectPtr py_method(
       PyObject_GetAttrString(py_database_, "FindAllExtensionNumbers"));
-  if (py_method == NULL) {
+  if (py_method == nullptr) {
     // This method is not implemented, returns without error.
     PyErr_Clear();
     return false;
@@ -161,7 +161,7 @@
   ScopedPyObjectPtr py_list(
       PyObject_CallFunction(py_method.get(), "s#", containing_type.c_str(),
                             containing_type.size()));
-  if (py_list == NULL) {
+  if (py_list == nullptr) {
     PyErr_Print();
     return false;
   }
diff --git a/python/google/protobuf/pyext/descriptor_database.h b/python/google/protobuf/pyext/descriptor_database.h
index 3bc99e7..5621a22 100644
--- a/python/google/protobuf/pyext/descriptor_database.h
+++ b/python/google/protobuf/pyext/descriptor_database.h
@@ -43,17 +43,18 @@
 class PyDescriptorDatabase : public DescriptorDatabase {
  public:
   explicit PyDescriptorDatabase(PyObject* py_database);
-  ~PyDescriptorDatabase();
+  ~PyDescriptorDatabase() override;
 
   // Implement the abstract interface. All these functions fill the output
   // with a copy of FileDescriptorProto.
 
   // Find a file by file name.
-  bool FindFileByName(const std::string& filename, FileDescriptorProto* output);
+  bool FindFileByName(const std::string& filename,
+                      FileDescriptorProto* output) override;
 
   // Find the file that declares the given fully-qualified symbol name.
   bool FindFileContainingSymbol(const std::string& symbol_name,
-                                FileDescriptorProto* output);
+                                FileDescriptorProto* output) override;
 
   // Find the file which defines an extension extending the given message type
   // with the given field number.
@@ -61,14 +62,14 @@
   // Python objects are not required to implement this method.
   bool FindFileContainingExtension(const std::string& containing_type,
                                    int field_number,
-                                   FileDescriptorProto* output);
+                                   FileDescriptorProto* output) override;
 
   // Finds the tag numbers used by all known extensions of
   // containing_type, and appends them to output in an undefined
   // order.
   // Python objects are not required to implement this method.
   bool FindAllExtensionNumbers(const std::string& containing_type,
-                               std::vector<int>* output);
+                               std::vector<int>* output) override;
 
  private:
   // The python object that implements the database. The reference is owned.
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index f6bdb6e..f475b3e 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -44,12 +44,13 @@
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/hash.h>
 
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -99,13 +100,13 @@
 static PyDescriptorPool* _CreateDescriptorPool() {
   PyDescriptorPool* cpool = PyObject_GC_New(
       PyDescriptorPool, &PyDescriptorPool_Type);
-  if (cpool == NULL) {
-    return NULL;
+  if (cpool == nullptr) {
+    return nullptr;
   }
 
   cpool->error_collector = nullptr;
-  cpool->underlay = NULL;
-  cpool->database = NULL;
+  cpool->underlay = nullptr;
+  cpool->database = nullptr;
   cpool->is_owned = false;
   cpool->is_mutable = false;
 
@@ -113,9 +114,9 @@
 
   cpool->py_message_factory = message_factory::NewMessageFactory(
       &PyMessageFactory_Type, cpool);
-  if (cpool->py_message_factory == NULL) {
+  if (cpool->py_message_factory == nullptr) {
     Py_DECREF(cpool);
-    return NULL;
+    return nullptr;
   }
 
   PyObject_GC_Track(cpool);
@@ -131,8 +132,8 @@
 static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay(
     const DescriptorPool* underlay) {
   PyDescriptorPool* cpool = _CreateDescriptorPool();
-  if (cpool == NULL) {
-    return NULL;
+  if (cpool == nullptr) {
+    return nullptr;
   }
   cpool->pool = new DescriptorPool(underlay);
   cpool->is_owned = true;
@@ -143,7 +144,7 @@
       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 nullptr;
   }
 
   return cpool;
@@ -152,10 +153,10 @@
 static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
     DescriptorDatabase* database) {
   PyDescriptorPool* cpool = _CreateDescriptorPool();
-  if (cpool == NULL) {
-    return NULL;
+  if (cpool == nullptr) {
+    return nullptr;
   }
-  if (database != NULL) {
+  if (database != nullptr) {
     cpool->error_collector = new BuildFileErrorCollector();
     cpool->pool = new DescriptorPool(database, cpool->error_collector);
     cpool->is_mutable = false;
@@ -169,7 +170,7 @@
   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 nullptr;
   }
 
   return cpool;
@@ -178,13 +179,13 @@
 // The public DescriptorPool constructor.
 static PyObject* New(PyTypeObject* type,
                      PyObject* args, PyObject* kwargs) {
-  static const char* kwlist[] = {"descriptor_db", 0};
-  PyObject* py_database = NULL;
+  static const char* kwlist[] = {"descriptor_db", nullptr};
+  PyObject* py_database = nullptr;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
                                    const_cast<char**>(kwlist), &py_database)) {
-    return NULL;
+    return nullptr;
   }
-  DescriptorDatabase* database = NULL;
+  DescriptorDatabase* database = nullptr;
   if (py_database && py_database != Py_None) {
     database = new PyDescriptorDatabase(py_database);
   }
@@ -230,24 +231,24 @@
     PyErr_Format(PyExc_KeyError, "Couldn't build file for %s %.200s\n%s",
                  error_type, name, error_collector->error_message.c_str());
     error_collector->Clear();
-    return NULL;
+    return nullptr;
   }
   PyErr_Format(PyExc_KeyError, "Couldn't find %s %.200s", error_type, name);
-  return NULL;
+  return nullptr;
 }
 
 static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const Descriptor* message_descriptor =
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
           StringParam(name, name_size));
 
-  if (message_descriptor == NULL) {
+  if (message_descriptor == nullptr) {
     return SetErrorFromCollector(
         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
         "message");
@@ -264,14 +265,14 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   PyDescriptorPool* py_pool = reinterpret_cast<PyDescriptorPool*>(self);
   const FileDescriptor* file_descriptor =
       py_pool->pool->FindFileByName(StringParam(name, name_size));
 
-  if (file_descriptor == NULL) {
+  if (file_descriptor == nullptr) {
     return SetErrorFromCollector(py_pool->error_collector, name, "file");
   }
   return PyFileDescriptor_FromDescriptor(file_descriptor);
@@ -281,12 +282,12 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const FieldDescriptor* field_descriptor =
       self->pool->FindFieldByName(StringParam(name, name_size));
-  if (field_descriptor == NULL) {
+  if (field_descriptor == nullptr) {
     return SetErrorFromCollector(self->error_collector, name, "field");
   }
 
@@ -302,12 +303,12 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const FieldDescriptor* field_descriptor =
       self->pool->FindExtensionByName(StringParam(name, name_size));
-  if (field_descriptor == NULL) {
+  if (field_descriptor == nullptr) {
     return SetErrorFromCollector(self->error_collector, name,
                                  "extension field");
   }
@@ -324,12 +325,12 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const EnumDescriptor* enum_descriptor =
       self->pool->FindEnumTypeByName(StringParam(name, name_size));
-  if (enum_descriptor == NULL) {
+  if (enum_descriptor == nullptr) {
     return SetErrorFromCollector(self->error_collector, name, "enum");
   }
 
@@ -345,12 +346,12 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const OneofDescriptor* oneof_descriptor =
       self->pool->FindOneofByName(StringParam(name, name_size));
-  if (oneof_descriptor == NULL) {
+  if (oneof_descriptor == nullptr) {
     return SetErrorFromCollector(self->error_collector, name, "oneof");
   }
 
@@ -366,13 +367,13 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const ServiceDescriptor* service_descriptor =
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
           StringParam(name, name_size));
-  if (service_descriptor == NULL) {
+  if (service_descriptor == nullptr) {
     return SetErrorFromCollector(
         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
         "service");
@@ -386,13 +387,13 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const MethodDescriptor* method_descriptor =
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMethodByName(
           StringParam(name, name_size));
-  if (method_descriptor == NULL) {
+  if (method_descriptor == nullptr) {
     return SetErrorFromCollector(
         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
         "method");
@@ -406,13 +407,13 @@
   Py_ssize_t name_size;
   char* name;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   const FileDescriptor* file_descriptor =
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileContainingSymbol(
           StringParam(name, name_size));
-  if (file_descriptor == NULL) {
+  if (file_descriptor == nullptr) {
     return SetErrorFromCollector(
         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
         "symbol");
@@ -426,18 +427,18 @@
   PyObject* message_descriptor;
   int number;
   if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
-    return NULL;
+    return nullptr;
   }
   const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(
       message_descriptor);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
 
   const FieldDescriptor* extension_descriptor =
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByNumber(
           descriptor, number);
-  if (extension_descriptor == NULL) {
+  if (extension_descriptor == nullptr) {
     BuildFileErrorCollector* error_collector =
         reinterpret_cast<BuildFileErrorCollector*>(
             reinterpret_cast<PyDescriptorPool*>(self)->error_collector);
@@ -445,10 +446,10 @@
       PyErr_Format(PyExc_KeyError, "Couldn't build file for Extension %.d\n%s",
                    number, error_collector->error_message.c_str());
       error_collector->Clear();
-      return NULL;
+      return nullptr;
     }
     PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
-    return NULL;
+    return nullptr;
   }
 
 
@@ -457,8 +458,8 @@
 
 static PyObject* FindAllExtensions(PyObject* self, PyObject* arg) {
   const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(arg);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
 
   std::vector<const FieldDescriptor*> extensions;
@@ -466,13 +467,13 @@
       descriptor, &extensions);
 
   ScopedPyObjectPtr result(PyList_New(extensions.size()));
-  if (result == NULL) {
-    return NULL;
+  if (result == nullptr) {
+    return nullptr;
   }
   for (int i = 0; i < extensions.size(); i++) {
     PyObject* extension = PyFieldDescriptor_FromDescriptor(extensions[i]);
-    if (extension == NULL) {
-      return NULL;
+    if (extension == nullptr) {
+      return nullptr;
     }
     PyList_SET_ITEM(result.get(), i, extension);  // Steals the reference.
   }
@@ -492,7 +493,7 @@
   const FileDescriptor* file_descriptor =
       PyFileDescriptor_AsDescriptor(descriptor);
   if (!file_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (file_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileByName(
@@ -500,7 +501,7 @@
     PyErr_Format(PyExc_ValueError,
                  "The file descriptor %s does not belong to this pool",
                  file_descriptor->name().c_str());
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -509,7 +510,7 @@
   const Descriptor* message_descriptor =
       PyMessageDescriptor_AsDescriptor(descriptor);
   if (!message_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (message_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
@@ -517,7 +518,7 @@
     PyErr_Format(PyExc_ValueError,
                  "The message descriptor %s does not belong to this pool",
                  message_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -526,7 +527,7 @@
   const EnumDescriptor* enum_descriptor =
       PyEnumDescriptor_AsDescriptor(descriptor);
   if (!enum_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (enum_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindEnumTypeByName(
@@ -534,7 +535,7 @@
     PyErr_Format(PyExc_ValueError,
                  "The enum descriptor %s does not belong to this pool",
                  enum_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -543,7 +544,7 @@
   const FieldDescriptor* extension_descriptor =
       PyFieldDescriptor_AsDescriptor(descriptor);
   if (!extension_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (extension_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByName(
@@ -551,7 +552,7 @@
     PyErr_Format(PyExc_ValueError,
                  "The extension descriptor %s does not belong to this pool",
                  extension_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -560,7 +561,7 @@
   const ServiceDescriptor* service_descriptor =
       PyServiceDescriptor_AsDescriptor(descriptor);
   if (!service_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (service_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
@@ -568,7 +569,7 @@
     PyErr_Format(PyExc_ValueError,
                  "The service descriptor %s does not belong to this pool",
                  service_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -579,12 +580,12 @@
   char* message_type;
   Py_ssize_t message_len;
 
-  if (self->database != NULL) {
+  if (self->database != nullptr) {
     PyErr_SetString(
         PyExc_ValueError,
         "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
         "Add your file to the underlying database.");
-    return NULL;
+    return nullptr;
   }
   if (!self->is_mutable) {
     PyErr_SetString(
@@ -594,22 +595,22 @@
   }
 
   if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   FileDescriptorProto file_proto;
   if (!file_proto.ParseFromArray(message_type, message_len)) {
     PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
-    return NULL;
+    return nullptr;
   }
 
   // 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 = NULL;
+  const FileDescriptor* generated_file = nullptr;
   if (self->underlay) {
     generated_file = self->underlay->FindFileByName(file_proto.name());
   }
-  if (generated_file != NULL) {
+  if (generated_file != nullptr) {
     return PyFileDescriptor_FromDescriptorWithSerializedPb(
         generated_file, serialized_pb);
   }
@@ -619,11 +620,11 @@
       // Pool is mutable, we can remove the "const".
       const_cast<DescriptorPool*>(self->pool)
           ->BuildFileCollectingErrors(file_proto, &error_collector);
-  if (descriptor == NULL) {
+  if (descriptor == nullptr) {
     PyErr_Format(PyExc_TypeError,
                  "Couldn't build proto file into descriptor pool!\n%s",
                  error_collector.error_message.c_str());
-    return NULL;
+    return nullptr;
   }
 
 
@@ -633,56 +634,56 @@
 
 static PyObject* Add(PyObject* self, PyObject* file_descriptor_proto) {
   ScopedPyObjectPtr serialized_pb(
-      PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL));
-  if (serialized_pb == NULL) {
-    return NULL;
+      PyObject_CallMethod(file_descriptor_proto, "SerializeToString", nullptr));
+  if (serialized_pb == nullptr) {
+    return nullptr;
   }
   return AddSerializedFile(self, serialized_pb.get());
 }
 
 static PyMethodDef Methods[] = {
-  { "Add", Add, METH_O,
-    "Adds the FileDescriptorProto and its types to this pool." },
-  { "AddSerializedFile", AddSerializedFile, METH_O,
-    "Adds a serialized FileDescriptorProto to this pool." },
+    {"Add", Add, METH_O,
+     "Adds the FileDescriptorProto and its types to this pool."},
+    {"AddSerializedFile", 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", AddFileDescriptor, METH_O,
-    "No-op. Add() must have been called before." },
-  { "AddDescriptor", AddDescriptor, METH_O,
-    "No-op. Add() must have been called before." },
-  { "AddEnumDescriptor", AddEnumDescriptor, METH_O,
-    "No-op. Add() must have been called before." },
-  { "AddExtensionDescriptor", AddExtensionDescriptor, METH_O,
-    "No-op. Add() must have been called before." },
-  { "AddServiceDescriptor", AddServiceDescriptor, METH_O,
-    "No-op. Add() must have been called before." },
+    // TODO(amauryfa): Understand why the Python implementation differs from
+    // this one, ask users to use another API and deprecate these functions.
+    {"AddFileDescriptor", AddFileDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddDescriptor", AddDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddEnumDescriptor", AddEnumDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddExtensionDescriptor", AddExtensionDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
+    {"AddServiceDescriptor", AddServiceDescriptor, METH_O,
+     "No-op. Add() must have been called before."},
 
-  { "FindFileByName", FindFileByName, METH_O,
-    "Searches for a file descriptor by its .proto name." },
-  { "FindMessageTypeByName", FindMessageByName, METH_O,
-    "Searches for a message descriptor by full name." },
-  { "FindFieldByName", FindFieldByNameMethod, METH_O,
-    "Searches for a field descriptor by full name." },
-  { "FindExtensionByName", FindExtensionByNameMethod, METH_O,
-    "Searches for extension descriptor by full name." },
-  { "FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
-    "Searches for enum type descriptor by full name." },
-  { "FindOneofByName", FindOneofByNameMethod, METH_O,
-    "Searches for oneof descriptor by full name." },
-  { "FindServiceByName", FindServiceByName, METH_O,
-    "Searches for service descriptor by full name." },
-  { "FindMethodByName", FindMethodByName, METH_O,
-    "Searches for method descriptor by full name." },
+    {"FindFileByName", FindFileByName, METH_O,
+     "Searches for a file descriptor by its .proto name."},
+    {"FindMessageTypeByName", FindMessageByName, METH_O,
+     "Searches for a message descriptor by full name."},
+    {"FindFieldByName", FindFieldByNameMethod, METH_O,
+     "Searches for a field descriptor by full name."},
+    {"FindExtensionByName", FindExtensionByNameMethod, METH_O,
+     "Searches for extension descriptor by full name."},
+    {"FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
+     "Searches for enum type descriptor by full name."},
+    {"FindOneofByName", FindOneofByNameMethod, METH_O,
+     "Searches for oneof descriptor by full name."},
+    {"FindServiceByName", FindServiceByName, METH_O,
+     "Searches for service descriptor by full name."},
+    {"FindMethodByName", FindMethodByName, METH_O,
+     "Searches for method descriptor by full name."},
 
-  { "FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
-    "Gets the FileDescriptor containing the specified symbol." },
-  { "FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
-    "Gets the extension descriptor for the given number." },
-  { "FindAllExtensions", FindAllExtensions, METH_O,
-    "Gets all known extensions of the given message descriptor." },
-  {NULL}
+    {"FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
+     "Gets the FileDescriptor containing the specified symbol."},
+    {"FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
+     "Gets the extension descriptor for the given number."},
+    {"FindAllExtensions", FindAllExtensions, METH_O,
+     "Gets all known extensions of the given message descriptor."},
+    {nullptr},
 };
 
 }  // namespace cdescriptor_pool
@@ -694,44 +695,44 @@
     0,                                        // tp_itemsize
     cdescriptor_pool::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
+    nullptr,                                  // tp_getattr
+    nullptr,                                  // tp_setattr
+    nullptr,                                  // tp_compare
+    nullptr,                                  // tp_repr
+    nullptr,                                  // tp_as_number
+    nullptr,                                  // tp_as_sequence
+    nullptr,                                  // tp_as_mapping
+    nullptr,                                  // tp_hash
+    nullptr,                                  // tp_call
+    nullptr,                                  // tp_str
+    nullptr,                                  // tp_getattro
+    nullptr,                                  // tp_setattro
+    nullptr,                                  // tp_as_buffer
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
     "A Descriptor Pool",                      // tp_doc
     cdescriptor_pool::GcTraverse,             // tp_traverse
     cdescriptor_pool::GcClear,                // tp_clear
-    0,                                        // tp_richcompare
+    nullptr,                                  // tp_richcompare
     0,                                        // tp_weaklistoffset
-    0,                                        // tp_iter
-    0,                                        // tp_iternext
+    nullptr,                                  // tp_iter
+    nullptr,                                  // tp_iternext
     cdescriptor_pool::Methods,                // tp_methods
-    0,                                        // tp_members
-    0,                                        // tp_getset
-    0,                                        // tp_base
-    0,                                        // tp_dict
-    0,                                        // tp_descr_get
-    0,                                        // tp_descr_set
+    nullptr,                                  // tp_members
+    nullptr,                                  // tp_getset
+    nullptr,                                  // tp_base
+    nullptr,                                  // tp_dict
+    nullptr,                                  // tp_descr_get
+    nullptr,                                  // tp_descr_set
     0,                                        // tp_dictoffset
-    0,                                        // tp_init
-    0,                                        // tp_alloc
+    nullptr,                                  // tp_init
+    nullptr,                                  // tp_alloc
     cdescriptor_pool::New,                    // tp_new
     PyObject_GC_Del,                          // tp_free
 };
 
 // This is the DescriptorPool which contains all the definitions from the
 // generated _pb2.py modules.
-static PyDescriptorPool* python_generated_pool = NULL;
+static PyDescriptorPool* python_generated_pool = nullptr;
 
 bool InitDescriptorPool() {
   if (PyType_Ready(&PyDescriptorPool_Type) < 0)
@@ -744,7 +745,7 @@
       new std::unordered_map<const DescriptorPool*, PyDescriptorPool*>;
   python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
       DescriptorPool::generated_pool());
-  if (python_generated_pool == NULL) {
+  if (python_generated_pool == nullptr) {
     delete descriptor_pool_map;
     return false;
   }
@@ -775,7 +776,7 @@
       descriptor_pool_map->find(pool);
   if (it == descriptor_pool_map->end()) {
     PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
-    return NULL;
+    return nullptr;
   }
   return it->second;
 }
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index b36c723..760fc91 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -49,12 +49,13 @@
 #include <google/protobuf/pyext/repeated_scalar_container.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -130,11 +131,11 @@
 
 PyObject* subscript(ExtensionDict* self, PyObject* key) {
   const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
   if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
-    return NULL;
+    return nullptr;
   }
 
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
@@ -154,8 +155,8 @@
     // TODO(plabatut): consider building the class on the fly!
     ContainerBase* sub_message = cmessage::InternalGetSubMessage(
         self->parent, descriptor);
-    if (sub_message == NULL) {
-      return NULL;
+    if (sub_message == nullptr) {
+      return nullptr;
     }
     (*self->parent->composite_fields)[descriptor] = sub_message;
     return sub_message->AsPyObject();
@@ -178,33 +179,33 @@
           descriptor->message_type());
       ScopedPyObjectPtr message_class_handler(
         reinterpret_cast<PyObject*>(message_class));
-      if (message_class == NULL) {
-        return NULL;
+      if (message_class == nullptr) {
+        return nullptr;
       }
       ContainerBase* py_container = repeated_composite_container::NewContainer(
           self->parent, descriptor, message_class);
-      if (py_container == NULL) {
-        return NULL;
+      if (py_container == nullptr) {
+        return nullptr;
       }
       (*self->parent->composite_fields)[descriptor] = py_container;
       return py_container->AsPyObject();
     } else {
       ContainerBase* py_container = repeated_scalar_container::NewContainer(
           self->parent, descriptor);
-      if (py_container == NULL) {
-        return NULL;
+      if (py_container == nullptr) {
+        return nullptr;
       }
       (*self->parent->composite_fields)[descriptor] = py_container;
       return py_container->AsPyObject();
     }
   }
   PyErr_SetString(PyExc_ValueError, "control reached unexpected line");
-  return NULL;
+  return nullptr;
 }
 
 int ass_subscript(ExtensionDict* self, PyObject* key, PyObject* value) {
   const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
-  if (descriptor == NULL) {
+  if (descriptor == nullptr) {
     return -1;
   }
   if (!CheckFieldBelongsToMessage(descriptor, self->parent->message)) {
@@ -232,13 +233,13 @@
   char* name;
   Py_ssize_t name_size;
   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
   const FieldDescriptor* message_extension =
       pool->pool->FindExtensionByName(StringParam(name, name_size));
-  if (message_extension == NULL) {
+  if (message_extension == nullptr) {
     // Is is the name of a message set extension?
     const Descriptor* message_descriptor =
         pool->pool->FindMessageTypeByName(StringParam(name, name_size));
@@ -252,7 +253,7 @@
       }
     }
   }
-  if (message_extension == NULL) {
+  if (message_extension == nullptr) {
     Py_RETURN_NONE;
   }
 
@@ -262,13 +263,13 @@
 PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* arg) {
   int64_t number = PyLong_AsLong(arg);
   if (number == -1 && PyErr_Occurred()) {
-    return NULL;
+    return nullptr;
   }
 
   PyDescriptorPool* pool = cmessage::GetFactoryForMessage(self->parent)->pool;
   const FieldDescriptor* message_extension = pool->pool->FindExtensionByNumber(
       self->parent->message->GetDescriptor(), number);
-  if (message_extension == NULL) {
+  if (message_extension == nullptr) {
     Py_RETURN_NONE;
   }
 
@@ -307,8 +308,8 @@
 ExtensionDict* NewExtensionDict(CMessage *parent) {
   ExtensionDict* self = reinterpret_cast<ExtensionDict*>(
       PyType_GenericAlloc(&ExtensionDict_Type, 0));
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
 
   Py_INCREF(parent);
@@ -340,12 +341,12 @@
 }
 static PySequenceMethods SeqMethods = {
     (lenfunc)len,          // sq_length
-    0,                     // sq_concat
-    0,                     // sq_repeat
-    0,                     // sq_item
-    0,                     // sq_slice
-    0,                     // sq_ass_item
-    0,                     // sq_ass_slice
+    nullptr,               // sq_concat
+    nullptr,               // sq_repeat
+    nullptr,               // sq_item
+    nullptr,               // sq_slice
+    nullptr,               // sq_ass_item
+    nullptr,               // sq_ass_slice
     (objobjproc)Contains,  // sq_contains
 };
 
@@ -360,7 +361,7 @@
     EDMETHOD(_FindExtensionByName, METH_O, "Finds an extension by name."),
     EDMETHOD(_FindExtensionByNumber, METH_O,
              "Finds an extension by field number."),
-    {NULL, NULL},
+    {nullptr, nullptr},
 };
 
 }  // namespace extension_dict
@@ -372,36 +373,36 @@
     0,                                         //  tp_itemsize
     (destructor)extension_dict::dealloc,       //  tp_dealloc
     0,                                         //  tp_print
-    0,                                         //  tp_getattr
-    0,                                         //  tp_setattr
-    0,                                         //  tp_compare
-    0,                                         //  tp_repr
-    0,                                         //  tp_as_number
+    nullptr,                                   //  tp_getattr
+    nullptr,                                   //  tp_setattr
+    nullptr,                                   //  tp_compare
+    nullptr,                                   //  tp_repr
+    nullptr,                                   //  tp_as_number
     &extension_dict::SeqMethods,               //  tp_as_sequence
     &extension_dict::MpMethods,                //  tp_as_mapping
     PyObject_HashNotImplemented,               //  tp_hash
-    0,                                         //  tp_call
-    0,                                         //  tp_str
-    0,                                         //  tp_getattro
-    0,                                         //  tp_setattro
-    0,                                         //  tp_as_buffer
+    nullptr,                                   //  tp_call
+    nullptr,                                   //  tp_str
+    nullptr,                                   //  tp_getattro
+    nullptr,                                   //  tp_setattro
+    nullptr,                                   //  tp_as_buffer
     Py_TPFLAGS_DEFAULT,                        //  tp_flags
     "An extension dict",                       //  tp_doc
-    0,                                         //  tp_traverse
-    0,                                         //  tp_clear
+    nullptr,                                   //  tp_traverse
+    nullptr,                                   //  tp_clear
     (richcmpfunc)extension_dict::RichCompare,  //  tp_richcompare
     0,                                         //  tp_weaklistoffset
     extension_dict::GetIter,                   //  tp_iter
-    0,                                         //  tp_iternext
+    nullptr,                                   //  tp_iternext
     extension_dict::Methods,                   //  tp_methods
-    0,                                         //  tp_members
-    0,                                         //  tp_getset
-    0,                                         //  tp_base
-    0,                                         //  tp_dict
-    0,                                         //  tp_descr_get
-    0,                                         //  tp_descr_set
+    nullptr,                                   //  tp_members
+    nullptr,                                   //  tp_getset
+    nullptr,                                   //  tp_base
+    nullptr,                                   //  tp_dict
+    nullptr,                                   //  tp_descr_get
+    nullptr,                                   //  tp_descr_set
     0,                                         //  tp_dictoffset
-    0,                                         //  tp_init
+    nullptr,                                   //  tp_init
 };
 
 PyObject* IterNext(PyObject* _self) {
@@ -439,36 +440,36 @@
     0,                                          //  tp_itemsize
     extension_dict::DeallocExtensionIterator,   //  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
+    nullptr,                                    //  tp_getattr
+    nullptr,                                    //  tp_setattr
+    nullptr,                                    //  tp_compare
+    nullptr,                                    //  tp_repr
+    nullptr,                                    //  tp_as_number
+    nullptr,                                    //  tp_as_sequence
+    nullptr,                                    //  tp_as_mapping
+    nullptr,                                    //  tp_hash
+    nullptr,                                    //  tp_call
+    nullptr,                                    //  tp_str
+    nullptr,                                    //  tp_getattro
+    nullptr,                                    //  tp_setattro
+    nullptr,                                    //  tp_as_buffer
     Py_TPFLAGS_DEFAULT,                         //  tp_flags
     "A scalar map iterator",                    //  tp_doc
-    0,                                          //  tp_traverse
-    0,                                          //  tp_clear
-    0,                                          //  tp_richcompare
+    nullptr,                                    //  tp_traverse
+    nullptr,                                    //  tp_clear
+    nullptr,                                    //  tp_richcompare
     0,                                          //  tp_weaklistoffset
     PyObject_SelfIter,                          //  tp_iter
     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
+    nullptr,                                    //  tp_methods
+    nullptr,                                    //  tp_members
+    nullptr,                                    //  tp_getset
+    nullptr,                                    //  tp_base
+    nullptr,                                    //  tp_dict
+    nullptr,                                    //  tp_descr_get
+    nullptr,                                    //  tp_descr_set
     0,                                          //  tp_dictoffset
-    0,                                          //  tp_init
+    nullptr,                                    //  tp_init
 };
 }  // namespace python
 }  // namespace protobuf
diff --git a/python/google/protobuf/pyext/field.cc b/python/google/protobuf/pyext/field.cc
index 5eab3ef..611ac8a 100644
--- a/python/google/protobuf/pyext/field.cc
+++ b/python/google/protobuf/pyext/field.cc
@@ -47,7 +47,7 @@
 
 static PyObject* DescrGet(PyMessageFieldProperty* self, PyObject* obj,
                           PyObject* type) {
-  if (obj == NULL) {
+  if (obj == nullptr) {
     Py_INCREF(self);
     return reinterpret_cast<PyObject*>(self);
   }
@@ -57,7 +57,7 @@
 
 static int DescrSet(PyMessageFieldProperty* self, PyObject* obj,
                     PyObject* value) {
-  if (value == NULL) {
+  if (value == nullptr) {
     PyErr_SetString(PyExc_AttributeError, "Cannot delete field attribute");
     return -1;
   }
@@ -75,50 +75,51 @@
 }
 
 static PyGetSetDef Getters[] = {
-    {"DESCRIPTOR", (getter)GetDescriptor, NULL, "Field descriptor"},
-    {"__doc__", (getter)GetDoc, NULL, NULL},
-    {NULL}};
+    {"DESCRIPTOR", (getter)GetDescriptor, nullptr, "Field descriptor"},
+    {"__doc__", (getter)GetDoc, nullptr, nullptr},
+    {nullptr},
+};
 }  // namespace field
 
 static PyTypeObject _CFieldProperty_Type = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)    // head
-    FULL_MODULE_NAME ".FieldProperty",        // tp_name
-    sizeof(PyMessageFieldProperty),           // tp_basicsize
-    0,                                        // tp_itemsize
-    0,                                        // tp_dealloc
-    0,                                        // tp_print
-    0,                                        // tp_getattr
-    0,                                        // tp_setattr
-    0,                                        // tp_compare
-    (reprfunc)field::Repr,                    // 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
-    "Field property of a Message",            // tp_doc
-    0,                                        // tp_traverse
-    0,                                        // tp_clear
-    0,                                        // tp_richcompare
-    0,                                        // tp_weaklistoffset
-    0,                                        // tp_iter
-    0,                                        // tp_iternext
-    0,                                        // tp_methods
-    0,                                        // tp_members
-    field::Getters,                           // tp_getset
-    0,                                        // tp_base
-    0,                                        // tp_dict
-    (descrgetfunc)field::DescrGet,            // tp_descr_get
-    (descrsetfunc)field::DescrSet,            // tp_descr_set
-    0,                                        // tp_dictoffset
-    0,                                        // tp_init
-    0,                                        // tp_alloc
-    0,                                        // tp_new
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)  // head
+    FULL_MODULE_NAME ".FieldProperty",      // tp_name
+    sizeof(PyMessageFieldProperty),         // tp_basicsize
+    0,                                      // tp_itemsize
+    nullptr,                                // tp_dealloc
+    0,                                      // tp_print
+    nullptr,                                // tp_getattr
+    nullptr,                                // tp_setattr
+    nullptr,                                // tp_compare
+    (reprfunc)field::Repr,                  // tp_repr
+    nullptr,                                // tp_as_number
+    nullptr,                                // tp_as_sequence
+    nullptr,                                // tp_as_mapping
+    nullptr,                                // tp_hash
+    nullptr,                                // tp_call
+    nullptr,                                // tp_str
+    nullptr,                                // tp_getattro
+    nullptr,                                // tp_setattro
+    nullptr,                                // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                     // tp_flags
+    "Field property of a Message",          // tp_doc
+    nullptr,                                // tp_traverse
+    nullptr,                                // tp_clear
+    nullptr,                                // tp_richcompare
+    0,                                      // tp_weaklistoffset
+    nullptr,                                // tp_iter
+    nullptr,                                // tp_iternext
+    nullptr,                                // tp_methods
+    nullptr,                                // tp_members
+    field::Getters,                         // tp_getset
+    nullptr,                                // tp_base
+    nullptr,                                // tp_dict
+    (descrgetfunc)field::DescrGet,          // tp_descr_get
+    (descrsetfunc)field::DescrSet,          // tp_descr_set
+    0,                                      // tp_dictoffset
+    nullptr,                                // tp_init
+    nullptr,                                // tp_alloc
+    nullptr,                                // tp_new
 };
 PyTypeObject* CFieldProperty_Type = &_CFieldProperty_Type;
 
@@ -126,8 +127,8 @@
   // Create a new descriptor object
   PyMessageFieldProperty* property =
       PyObject_New(PyMessageFieldProperty, CFieldProperty_Type);
-  if (property == NULL) {
-    return NULL;
+  if (property == nullptr) {
+    return nullptr;
   }
   property->field_descriptor = field_descriptor;
   return reinterpret_cast<PyObject*>(property);
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 053a78e..c953c65 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -187,7 +187,7 @@
       PyErr_Format(
           PyExc_SystemError, "Couldn't convert type %d to value",
           field_descriptor->cpp_type());
-      return NULL;
+      return nullptr;
   }
 }
 
@@ -219,7 +219,7 @@
       PyErr_Format(
           PyExc_SystemError, "Couldn't convert type %d to value",
           field_descriptor->cpp_type());
-      return NULL;
+      return nullptr;
   }
 }
 
@@ -283,7 +283,7 @@
         const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
         const EnumValueDescriptor* enum_value =
             enum_descriptor->FindValueByNumber(value);
-        if (enum_value != NULL) {
+        if (enum_value != nullptr) {
           value_ref->SetEnumValue(value);
           return true;
         } else {
@@ -362,7 +362,7 @@
   MapKey map_key;
 
   if (!PythonToMapKey(self, key, &map_key)) {
-    return NULL;
+    return nullptr;
   }
 
   if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
@@ -378,14 +378,14 @@
 MapContainer* NewScalarMapContainer(
     CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
   if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
-    return NULL;
+    return nullptr;
   }
 
   PyObject* obj(PyType_GenericAlloc(ScalarMapContainer_Type, 0));
-  if (obj == NULL) {
+  if (obj == nullptr) {
     PyErr_Format(PyExc_RuntimeError,
                  "Could not allocate new container.");
-    return NULL;
+    return nullptr;
   }
 
   MapContainer* self = GetMap(obj);
@@ -408,7 +408,7 @@
   MapValueRef value;
 
   if (!PythonToMapKey(self, key, &map_key)) {
-    return NULL;
+    return nullptr;
   }
 
   if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
@@ -460,22 +460,22 @@
                               PyObject* kwargs) {
   static const char* kwlist[] = {"key", "default", nullptr};
   PyObject* key;
-  PyObject* default_value = NULL;
+  PyObject* default_value = nullptr;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
                                    const_cast<char**>(kwlist), &key,
                                    &default_value)) {
-    return NULL;
+    return nullptr;
   }
 
   ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
-  if (is_present.get() == NULL) {
-    return NULL;
+  if (is_present.get() == nullptr) {
+    return nullptr;
   }
 
   if (PyObject_IsTrue(is_present.get())) {
     return MapReflectionFriend::ScalarMapGetItem(self, key);
   } else {
-    if (default_value != NULL) {
+    if (default_value != nullptr) {
       Py_INCREF(default_value);
       return default_value;
     } else {
@@ -486,8 +486,8 @@
 
 PyObject* MapReflectionFriend::ScalarMapToStr(PyObject* _self) {
   ScopedPyObjectPtr dict(PyDict_New());
-  if (dict == NULL) {
-    return NULL;
+  if (dict == nullptr) {
+    return nullptr;
   }
   ScopedPyObjectPtr key;
   ScopedPyObjectPtr value;
@@ -500,15 +500,15 @@
        it != reflection->MapEnd(message, self->parent_field_descriptor);
        ++it) {
     key.reset(MapKeyToPython(self, it.GetKey()));
-    if (key == NULL) {
-      return NULL;
+    if (key == nullptr) {
+      return nullptr;
     }
     value.reset(MapValueRefToPython(self, it.GetValueRef()));
-    if (value == NULL) {
-      return NULL;
+    if (value == nullptr) {
+      return nullptr;
     }
     if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
-      return NULL;
+      return nullptr;
     }
   }
   return PyObject_Repr(dict.get());
@@ -542,7 +542,7 @@
     { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
       "Outputs picklable representation of the repeated field." },
     */
-    {NULL, NULL},
+    {nullptr, nullptr},
 };
 
 PyTypeObject* ScalarMapContainer_Type;
@@ -554,7 +554,7 @@
     {Py_tp_methods, (void*)ScalarMapMethods},
     {Py_tp_iter, (void*)MapReflectionFriend::GetIterator},
     {Py_tp_repr, (void*)MapReflectionFriend::ScalarMapToStr},
-    {0, 0},
+    {0, nullptr},
 };
 
 PyType_Spec ScalarMapContainer_Type_spec = {
@@ -579,13 +579,13 @@
     CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor,
     CMessageClass* message_class) {
   if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
-    return NULL;
+    return nullptr;
   }
 
   PyObject* obj = PyType_GenericAlloc(MessageMapContainer_Type, 0);
-  if (obj == NULL) {
+  if (obj == nullptr) {
     PyErr_SetString(PyExc_RuntimeError, "Could not allocate new container.");
-    return NULL;
+    return nullptr;
   }
 
   MessageMapContainer* self = GetMessageMap(obj);
@@ -660,7 +660,7 @@
   MapValueRef value;
 
   if (!PythonToMapKey(self, key, &map_key)) {
-    return NULL;
+    return nullptr;
   }
 
   if (reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
@@ -673,8 +673,8 @@
 
 PyObject* MapReflectionFriend::MessageMapToStr(PyObject* _self) {
   ScopedPyObjectPtr dict(PyDict_New());
-  if (dict == NULL) {
-    return NULL;
+  if (dict == nullptr) {
+    return nullptr;
   }
   ScopedPyObjectPtr key;
   ScopedPyObjectPtr value;
@@ -687,15 +687,15 @@
        it != reflection->MapEnd(message, self->parent_field_descriptor);
        ++it) {
     key.reset(MapKeyToPython(self, it.GetKey()));
-    if (key == NULL) {
-      return NULL;
+    if (key == nullptr) {
+      return nullptr;
     }
     value.reset(GetCMessage(self, it.MutableValueRef()->MutableMessageValue()));
-    if (value == NULL) {
-      return NULL;
+    if (value == nullptr) {
+      return nullptr;
     }
     if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
-      return NULL;
+      return nullptr;
     }
   }
   return PyObject_Repr(dict.get());
@@ -704,22 +704,22 @@
 PyObject* MessageMapGet(PyObject* self, PyObject* args, PyObject* kwargs) {
   static const char* kwlist[] = {"key", "default", nullptr};
   PyObject* key;
-  PyObject* default_value = NULL;
+  PyObject* default_value = nullptr;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
                                    const_cast<char**>(kwlist), &key,
                                    &default_value)) {
-    return NULL;
+    return nullptr;
   }
 
   ScopedPyObjectPtr is_present(MapReflectionFriend::Contains(self, key));
-  if (is_present.get() == NULL) {
-    return NULL;
+  if (is_present.get() == nullptr) {
+    return nullptr;
   }
 
   if (PyObject_IsTrue(is_present.get())) {
     return MapReflectionFriend::MessageMapGetItem(self, key);
   } else {
-    if (default_value != NULL) {
+    if (default_value != nullptr) {
       Py_INCREF(default_value);
       return default_value;
     } else {
@@ -759,7 +759,7 @@
     { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
       "Outputs picklable representation of the repeated field." },
     */
-    {NULL, NULL},
+    {nullptr, nullptr},
 };
 
 PyTypeObject* MessageMapContainer_Type;
@@ -771,7 +771,7 @@
     {Py_tp_methods, (void*)MessageMapMethods},
     {Py_tp_iter, (void*)MapReflectionFriend::GetIterator},
     {Py_tp_repr, (void*)MapReflectionFriend::MessageMapToStr},
-    {0, 0}};
+    {0, nullptr}};
 
 PyType_Spec MessageMapContainer_Type_spec = {
     FULL_MODULE_NAME ".MessageMapContainer", sizeof(MessageMapContainer), 0,
@@ -787,7 +787,7 @@
   MapContainer* self = GetMap(_self);
 
   ScopedPyObjectPtr obj(PyType_GenericAlloc(&MapIterator_Type, 0));
-  if (obj == NULL) {
+  if (obj == nullptr) {
     return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
   }
 
@@ -824,8 +824,8 @@
                         "Map cleared during iteration.");
   }
 
-  if (self->iter.get() == NULL) {
-    return NULL;
+  if (self->iter.get() == nullptr) {
+    return nullptr;
   }
 
   Message* message = self->container->GetMutableMessage();
@@ -833,7 +833,7 @@
 
   if (*self->iter ==
       reflection->MapEnd(message, self->container->parent_field_descriptor)) {
-    return NULL;
+    return nullptr;
   }
 
   PyObject* ret = MapKeyToPython(self->container, self->iter->GetKey());
@@ -852,60 +852,60 @@
 }
 
 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
+    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
+    nullptr,                        //  tp_getattr
+    nullptr,                        //  tp_setattr
+    nullptr,                        //  tp_compare
+    nullptr,                        //  tp_repr
+    nullptr,                        //  tp_as_number
+    nullptr,                        //  tp_as_sequence
+    nullptr,                        //  tp_as_mapping
+    nullptr,                        //  tp_hash
+    nullptr,                        //  tp_call
+    nullptr,                        //  tp_str
+    nullptr,                        //  tp_getattro
+    nullptr,                        //  tp_setattro
+    nullptr,                        //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,             //  tp_flags
+    "A scalar map iterator",        //  tp_doc
+    nullptr,                        //  tp_traverse
+    nullptr,                        //  tp_clear
+    nullptr,                        //  tp_richcompare
+    0,                              //  tp_weaklistoffset
+    PyObject_SelfIter,              //  tp_iter
+    MapReflectionFriend::IterNext,  //  tp_iternext
+    nullptr,                        //  tp_methods
+    nullptr,                        //  tp_members
+    nullptr,                        //  tp_getset
+    nullptr,                        //  tp_base
+    nullptr,                        //  tp_dict
+    nullptr,                        //  tp_descr_get
+    nullptr,                        //  tp_descr_set
+    0,                              //  tp_dictoffset
+    nullptr,                        //  tp_init
 };
 
 bool InitMapContainers() {
   // ScalarMapContainer_Type derives from our MutableMapping type.
   ScopedPyObjectPtr abc(PyImport_ImportModule("collections.abc"));
-  if (abc == NULL) {
+  if (abc == nullptr) {
     return false;
   }
 
   ScopedPyObjectPtr mutable_mapping(
       PyObject_GetAttrString(abc.get(), "MutableMapping"));
-  if (mutable_mapping == NULL) {
+  if (mutable_mapping == nullptr) {
     return false;
   }
 
   Py_INCREF(mutable_mapping.get());
   ScopedPyObjectPtr bases(PyTuple_Pack(1, mutable_mapping.get()));
-  if (bases == NULL) {
+  if (bases == nullptr) {
     return false;
   }
 
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 097d6bf..f7a69a7 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -79,12 +79,13 @@
 
 #define PyString_AsString(ob) \
   (PyUnicode_Check(ob) ? PyUnicode_AsUTF8(ob) : PyBytes_AsString(ob))
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -108,7 +109,7 @@
 PyObject* EnumTypeWrapper_class;
 static PyObject* PythonMessage_class;
 static PyObject* kEmptyWeakref;
-static PyObject* WKT_classes = NULL;
+static PyObject* WKT_classes = nullptr;
 
 namespace message_meta {
 
@@ -129,7 +130,7 @@
   for (int i = 0; i < descriptor->field_count(); ++i) {
     const FieldDescriptor* field_descriptor = descriptor->field(i);
     ScopedPyObjectPtr property(NewFieldProperty(field_descriptor));
-    if (property == NULL) {
+    if (property == nullptr) {
       return -1;
     }
     if (PyObject_SetAttrString(cls, field_descriptor->name().c_str(),
@@ -143,13 +144,13 @@
     const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
     ScopedPyObjectPtr enum_type(
         PyEnumDescriptor_FromDescriptor(enum_descriptor));
-    if (enum_type == NULL) {
+    if (enum_type == nullptr) {
       return -1;
     }
     // Add wrapped enum type to message class.
     ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs(
-        EnumTypeWrapper_class, enum_type.get(), NULL));
-    if (wrapped == NULL) {
+        EnumTypeWrapper_class, enum_type.get(), nullptr));
+    if (wrapped == nullptr) {
       return -1;
     }
     if (PyObject_SetAttrString(
@@ -163,7 +164,7 @@
           enum_descriptor->value(j);
       ScopedPyObjectPtr value_number(
           PyLong_FromLong(enum_value_descriptor->number()));
-      if (value_number == NULL) {
+      if (value_number == nullptr) {
         return -1;
       }
       if (PyObject_SetAttrString(cls, enum_value_descriptor->name().c_str(),
@@ -181,7 +182,7 @@
   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) {
+    if (extension_field == nullptr) {
       return -1;
     }
 
@@ -196,7 +197,7 @@
 }
 
 static PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
-  static const char* kwlist[] = {"name", "bases", "dict", 0};
+  static const char* kwlist[] = {"name", "bases", "dict", nullptr};
   PyObject *bases, *dict;
   const char* name;
 
@@ -204,7 +205,7 @@
   if (!PyArg_ParseTupleAndKeywords(
           args, kwargs, "sO!O!:type", const_cast<char**>(kwlist), &name,
           &PyTuple_Type, &bases, &PyDict_Type, &dict)) {
-    return NULL;
+    return nullptr;
   }
 
   // Check bases: only (), or (message.Message,) are allowed
@@ -213,7 +214,7 @@
          PyTuple_GET_ITEM(bases, 0) == PythonMessage_class))) {
     PyErr_SetString(PyExc_TypeError,
                     "A Message class can only inherit from Message");
-    return NULL;
+    return nullptr;
   }
 
   // Check dict['DESCRIPTOR']
@@ -236,25 +237,25 @@
   // Messages have no __dict__
   ScopedPyObjectPtr slots(PyTuple_New(0));
   if (PyDict_SetItemString(dict, "__slots__", slots.get()) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   // Build the arguments to the base metaclass.
   // We change the __bases__ classes.
   ScopedPyObjectPtr new_args;
 
-  if (WKT_classes == NULL) {
+  if (WKT_classes == nullptr) {
     ScopedPyObjectPtr well_known_types(PyImport_ImportModule(
         "google.protobuf.internal.well_known_types"));
-    GOOGLE_DCHECK(well_known_types != NULL);
+    GOOGLE_DCHECK(well_known_types != nullptr);
 
     WKT_classes = PyObject_GetAttrString(well_known_types.get(), "WKTBASES");
-    GOOGLE_DCHECK(WKT_classes != NULL);
+    GOOGLE_DCHECK(WKT_classes != nullptr);
   }
 
   PyObject* well_known_class = PyDict_GetItemString(
       WKT_classes, message_descriptor->full_name().c_str());
-  if (well_known_class == NULL) {
+  if (well_known_class == nullptr) {
     new_args.reset(Py_BuildValue("s(OO)O", name, CMessage_Type,
                                  PythonMessage_class, dict));
   } else {
@@ -262,21 +263,21 @@
                                  PythonMessage_class, well_known_class, dict));
   }
 
-  if (new_args == NULL) {
-    return NULL;
+  if (new_args == nullptr) {
+    return nullptr;
   }
   // Call the base metaclass.
-  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), NULL));
-  if (result == NULL) {
-    return NULL;
+  ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args.get(), nullptr));
+  if (result == nullptr) {
+    return nullptr;
   }
   CMessageClass* newtype = reinterpret_cast<CMessageClass*>(result.get());
 
   // Cache the descriptor, both as Python object and as C++ pointer.
   const Descriptor* descriptor =
       PyMessageDescriptor_AsDescriptor(py_descriptor);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
   Py_INCREF(py_descriptor);
   newtype->py_message_descriptor = py_descriptor;
@@ -285,8 +286,8 @@
   // use the MessageFactory optionally passed in the class dict.
   PyDescriptorPool* py_descriptor_pool =
       GetDescriptorPool_FromPool(descriptor->file()->pool());
-  if (py_descriptor_pool == NULL) {
-    return NULL;
+  if (py_descriptor_pool == nullptr) {
+    return nullptr;
   }
   newtype->py_message_factory = py_descriptor_pool->py_message_factory;
   Py_INCREF(newtype->py_message_factory);
@@ -296,12 +297,12 @@
   // MessageFactory is fully implemented in C++.
   if (message_factory::RegisterMessageClass(newtype->py_message_factory,
                                             descriptor, newtype) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   // Continue with type initialization: add other descriptors, enum values...
   if (AddDescriptors(result.get(), descriptor) < 0) {
-    return NULL;
+    return nullptr;
   }
   return result.release();
 }
@@ -329,11 +330,11 @@
 // The _extensions_by_name dictionary is built on every access.
 // TODO(amauryfa): Migrate all users to pool.FindAllExtensions()
 static PyObject* GetExtensionsByName(CMessageClass *self, void *closure) {
-  if (self->message_descriptor == NULL) {
+  if (self->message_descriptor == nullptr) {
     // This is the base Message object, simply raise AttributeError.
     PyErr_SetString(PyExc_AttributeError,
                     "Base Message class has no DESCRIPTOR");
-    return NULL;
+    return nullptr;
   }
 
   const PyDescriptorPool* pool = self->py_message_factory->pool;
@@ -345,12 +346,12 @@
   for (int i = 0; i < extensions.size(); i++) {
     ScopedPyObjectPtr extension(
         PyFieldDescriptor_FromDescriptor(extensions[i]));
-    if (extension == NULL) {
-      return NULL;
+    if (extension == nullptr) {
+      return nullptr;
     }
     if (PyDict_SetItemString(result.get(), extensions[i]->full_name().c_str(),
                              extension.get()) < 0) {
-      return NULL;
+      return nullptr;
     }
   }
   return result.release();
@@ -359,11 +360,11 @@
 // The _extensions_by_number dictionary is built on every access.
 // TODO(amauryfa): Migrate all users to pool.FindExtensionByNumber()
 static PyObject* GetExtensionsByNumber(CMessageClass *self, void *closure) {
-  if (self->message_descriptor == NULL) {
+  if (self->message_descriptor == nullptr) {
     // This is the base Message object, simply raise AttributeError.
     PyErr_SetString(PyExc_AttributeError,
                     "Base Message class has no DESCRIPTOR");
-    return NULL;
+    return nullptr;
   }
 
   const PyDescriptorPool* pool = self->py_message_factory->pool;
@@ -375,24 +376,24 @@
   for (int i = 0; i < extensions.size(); i++) {
     ScopedPyObjectPtr extension(
         PyFieldDescriptor_FromDescriptor(extensions[i]));
-    if (extension == NULL) {
-      return NULL;
+    if (extension == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr number(PyLong_FromLong(extensions[i]->number()));
-    if (number == NULL) {
-      return NULL;
+    if (number == nullptr) {
+      return nullptr;
     }
     if (PyDict_SetItem(result.get(), number.get(), extension.get()) < 0) {
-      return NULL;
+      return nullptr;
     }
   }
   return result.release();
 }
 
 static PyGetSetDef Getters[] = {
-  {"_extensions_by_name", (getter)GetExtensionsByName, NULL},
-  {"_extensions_by_number", (getter)GetExtensionsByNumber, NULL},
-  {NULL}
+    {"_extensions_by_name", (getter)GetExtensionsByName, nullptr},
+    {"_extensions_by_number", (getter)GetExtensionsByNumber, nullptr},
+    {nullptr},
 };
 
 // Compute some class attributes on the fly:
@@ -420,17 +421,17 @@
     }
   }
   PyErr_SetObject(PyExc_AttributeError, name);
-  return NULL;
+  return nullptr;
 }
 
 static PyObject* GetAttr(CMessageClass* self, PyObject* name) {
   PyObject* result = CMessageClass_Type->tp_base->tp_getattro(
       reinterpret_cast<PyObject*>(self), name);
-  if (result != NULL) {
+  if (result != nullptr) {
     return result;
   }
   if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
-    return NULL;
+    return nullptr;
   }
 
   PyErr_Clear();
@@ -458,37 +459,37 @@
     0,                                    // tp_itemsize
     message_meta::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
+    nullptr,                              // tp_getattr
+    nullptr,                              // tp_setattr
+    nullptr,                              // tp_compare
+    nullptr,                              // tp_repr
+    nullptr,                              // tp_as_number
+    nullptr,                              // tp_as_sequence
+    nullptr,                              // tp_as_mapping
+    nullptr,                              // tp_hash
+    nullptr,                              // tp_call
+    nullptr,                              // tp_str
     (getattrofunc)message_meta::GetAttr,  // tp_getattro
-    0,                                    // tp_setattro
-    0,                                    // tp_as_buffer
+    nullptr,                              // tp_setattro
+    nullptr,                              // tp_as_buffer
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
     "The metaclass of ProtocolMessages",                            // tp_doc
     message_meta::GcTraverse,  // tp_traverse
     message_meta::GcClear,     // tp_clear
-    0,                         // tp_richcompare
+    nullptr,                   // tp_richcompare
     0,                         // tp_weaklistoffset
-    0,                         // tp_iter
-    0,                         // tp_iternext
-    0,                         // tp_methods
-    0,                         // tp_members
+    nullptr,                   // tp_iter
+    nullptr,                   // tp_iternext
+    nullptr,                   // tp_methods
+    nullptr,                   // tp_members
     message_meta::Getters,     // tp_getset
-    0,                         // tp_base
-    0,                         // tp_dict
-    0,                         // tp_descr_get
-    0,                         // tp_descr_set
+    nullptr,                   // tp_base
+    nullptr,                   // tp_dict
+    nullptr,                   // tp_descr_get
+    nullptr,                   // tp_descr_set
     0,                         // tp_dictoffset
-    0,                         // tp_init
-    0,                         // tp_alloc
+    nullptr,                   // tp_init
+    nullptr,                   // tp_alloc
     message_meta::New,         // tp_new
 };
 PyTypeObject* CMessageClass_Type = &_CMessageClass_Type;
@@ -496,15 +497,15 @@
 static CMessageClass* CheckMessageClass(PyTypeObject* cls) {
   if (!PyObject_TypeCheck(cls, CMessageClass_Type)) {
     PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
-    return NULL;
+    return nullptr;
   }
   return reinterpret_cast<CMessageClass*>(cls);
 }
 
 static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
   CMessageClass* type = CheckMessageClass(cls);
-  if (type == NULL) {
-    return NULL;
+  if (type == nullptr) {
+    return nullptr;
   }
   return type->message_descriptor;
 }
@@ -607,7 +608,7 @@
     // Signed case.
     PY_LONG_LONG long_result;
     PyNumberMethods *nb;
-    if ((nb = arg->ob_type->tp_as_number) != NULL && nb->nb_int != NULL) {
+    if ((nb = arg->ob_type->tp_as_number) != nullptr && nb->nb_int != nullptr) {
       // PyLong_AsLongLong requires it to be a long or to have an __int__()
       // method.
       long_result = PyLong_AsLongLong(arg);
@@ -672,7 +673,7 @@
 // valid UTF-8.
 bool IsValidUTF8(PyObject* obj) {
   if (PyBytes_Check(obj)) {
-    PyObject* unicode = PyUnicode_FromEncodedObject(obj, "utf-8", NULL);
+    PyObject* unicode = PyUnicode_FromEncodedObject(obj, "utf-8", nullptr);
 
     // Clear the error indicator; we report our own error when desired.
     PyErr_Clear();
@@ -697,7 +698,7 @@
   if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
     if (!PyBytes_Check(arg) && !PyUnicode_Check(arg)) {
       FormatTypeError(arg, "bytes, unicode");
-      return NULL;
+      return nullptr;
     }
 
     if (!IsValidUTF8(arg) && !AllowInvalidUTF8(descriptor)) {
@@ -708,21 +709,21 @@
                    "unicode objects before being added.",
                    PyString_AsString(repr));
       Py_DECREF(repr);
-      return NULL;
+      return nullptr;
     }
   } else if (!PyBytes_Check(arg)) {
     FormatTypeError(arg, "bytes");
-    return NULL;
+    return nullptr;
   }
 
-  PyObject* encoded_string = NULL;
+  PyObject* encoded_string = nullptr;
   if (descriptor->type() == FieldDescriptor::TYPE_STRING) {
     if (PyBytes_Check(arg)) {
       // The bytes were already validated as correctly encoded UTF-8 above.
       encoded_string = arg;  // Already encoded.
       Py_INCREF(encoded_string);
     } else {
-      encoded_string = PyUnicode_AsEncodedString(arg, "utf-8", NULL);
+      encoded_string = PyUnicode_AsEncodedString(arg, "utf-8", nullptr);
     }
   } else {
     // In this case field type is "bytes".
@@ -741,7 +742,7 @@
     int index) {
   ScopedPyObjectPtr encoded_string(CheckString(arg, descriptor));
 
-  if (encoded_string.get() == NULL) {
+  if (encoded_string.get() == nullptr) {
     return false;
   }
 
@@ -769,12 +770,13 @@
     return PyBytes_FromStringAndSize(value.c_str(), value.length());
   }
 
-  PyObject* result = PyUnicode_DecodeUTF8(value.c_str(), value.length(), NULL);
+  PyObject* result =
+      PyUnicode_DecodeUTF8(value.c_str(), value.length(), nullptr);
   // If the string can't be decoded in UTF-8, just return a string object that
   // contains the raw bytes. This can't happen if the value was assigned using
   // the members of the Python message object, but can happen if the values were
   // parsed from the wire (binary).
-  if (result == NULL) {
+  if (result == nullptr) {
     PyErr_Clear();
     result = PyBytes_FromStringAndSize(value.c_str(), value.length());
   }
@@ -864,7 +866,7 @@
 // Making a message writable
 
 int AssureWritable(CMessage* self) {
-  if (self == NULL || !self->read_only) {
+  if (self == nullptr || !self->read_only) {
     return 0;
   }
 
@@ -887,7 +889,7 @@
   Message* mutable_message = reflection->MutableMessage(
       parent_message, self->parent_field_descriptor,
       GetFactoryForMessage(self->parent)->message_factory);
-  if (mutable_message == NULL) {
+  if (mutable_message == nullptr) {
     return -1;
   }
   self->message = mutable_message;
@@ -906,7 +908,7 @@
     // allow input which is not a field descriptor, and simply pretend it does
     // not exist.
     PyErr_SetObject(PyExc_KeyError, extension);
-    return NULL;
+    return nullptr;
   }
   return PyFieldDescriptor_AsDescriptor(extension);
 }
@@ -917,20 +919,20 @@
                                      PyObject* value) {
   if (PyUnicode_Check(value)) {
     const EnumDescriptor* enum_descriptor = descriptor.enum_type();
-    if (enum_descriptor == NULL) {
+    if (enum_descriptor == nullptr) {
       PyErr_SetString(PyExc_TypeError, "not an enum field");
-      return NULL;
+      return nullptr;
     }
     char* enum_label;
     Py_ssize_t size;
     if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) {
-      return NULL;
+      return nullptr;
     }
     const EnumValueDescriptor* enum_value_descriptor =
         enum_descriptor->FindValueByName(StringParam(enum_label, size));
-    if (enum_value_descriptor == NULL) {
+    if (enum_value_descriptor == nullptr) {
       PyErr_Format(PyExc_ValueError, "unknown enum label \"%s\"", enum_label);
-      return NULL;
+      return nullptr;
     }
     return PyLong_FromLong(enum_value_descriptor->number());
   }
@@ -1038,12 +1040,12 @@
 
 // Initializes fields of a message. Used in constructors.
 int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
-  if (args != NULL && PyTuple_Size(args) != 0) {
+  if (args != nullptr && PyTuple_Size(args) != 0) {
     PyErr_SetString(PyExc_TypeError, "No positional arguments allowed");
     return -1;
   }
 
-  if (kwargs == NULL) {
+  if (kwargs == nullptr) {
     return 0;
   }
 
@@ -1057,7 +1059,7 @@
     }
     ScopedPyObjectPtr property(
         PyObject_GetAttr(reinterpret_cast<PyObject*>(Py_TYPE(self)), name));
-    if (property == NULL ||
+    if (property == nullptr ||
         !PyObject_TypeCheck(property.get(), CFieldProperty_Type)) {
       PyErr_Format(PyExc_ValueError, "Protocol message %s has no \"%s\" field.",
                    self->message->GetDescriptor()->name().c_str(),
@@ -1077,20 +1079,21 @@
           descriptor->message_type()->map_value();
       if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
         ScopedPyObjectPtr iter(PyObject_GetIter(value));
-        if (iter == NULL) {
-          PyErr_Format(PyExc_TypeError, "Argument %s is not iterable", PyString_AsString(name));
+        if (iter == nullptr) {
+          PyErr_Format(PyExc_TypeError, "Argument %s is not iterable",
+                       PyString_AsString(name));
           return -1;
         }
         ScopedPyObjectPtr next;
-        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
           ScopedPyObjectPtr source_value(PyObject_GetItem(value, next.get()));
           ScopedPyObjectPtr dest_value(PyObject_GetItem(map.get(), next.get()));
-          if (source_value.get() == NULL || dest_value.get() == NULL) {
+          if (source_value.get() == nullptr || dest_value.get() == nullptr) {
             return -1;
           }
           ScopedPyObjectPtr ok(PyObject_CallMethod(
               dest_value.get(), "MergeFrom", "O", source_value.get()));
-          if (ok.get() == NULL) {
+          if (ok.get() == nullptr) {
             return -1;
           }
         }
@@ -1098,36 +1101,36 @@
         ScopedPyObjectPtr function_return;
         function_return.reset(
             PyObject_CallMethod(map.get(), "update", "O", value));
-        if (function_return.get() == NULL) {
+        if (function_return.get() == nullptr) {
           return -1;
         }
       }
     } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
       ScopedPyObjectPtr container(GetFieldValue(self, descriptor));
-      if (container == NULL) {
+      if (container == nullptr) {
         return -1;
       }
       if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
         RepeatedCompositeContainer* rc_container =
             reinterpret_cast<RepeatedCompositeContainer*>(container.get());
         ScopedPyObjectPtr iter(PyObject_GetIter(value));
-        if (iter == NULL) {
+        if (iter == nullptr) {
           PyErr_SetString(PyExc_TypeError, "Value must be iterable");
           return -1;
         }
         ScopedPyObjectPtr next;
-        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
-          PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : NULL);
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
+          PyObject* kwargs = (PyDict_Check(next.get()) ? next.get() : nullptr);
           ScopedPyObjectPtr new_msg(
-              repeated_composite_container::Add(rc_container, NULL, kwargs));
-          if (new_msg == NULL) {
+              repeated_composite_container::Add(rc_container, nullptr, kwargs));
+          if (new_msg == nullptr) {
             return -1;
           }
-          if (kwargs == NULL) {
+          if (kwargs == nullptr) {
             // next was not a dict, it's a message we need to merge
             ScopedPyObjectPtr merged(MergeFrom(
                 reinterpret_cast<CMessage*>(new_msg.get()), next.get()));
-            if (merged.get() == NULL) {
+            if (merged.get() == nullptr) {
               return -1;
             }
           }
@@ -1140,20 +1143,20 @@
         RepeatedScalarContainer* rs_container =
             reinterpret_cast<RepeatedScalarContainer*>(container.get());
         ScopedPyObjectPtr iter(PyObject_GetIter(value));
-        if (iter == NULL) {
+        if (iter == nullptr) {
           PyErr_SetString(PyExc_TypeError, "Value must be iterable");
           return -1;
         }
         ScopedPyObjectPtr next;
-        while ((next.reset(PyIter_Next(iter.get()))) != NULL) {
+        while ((next.reset(PyIter_Next(iter.get()))) != nullptr) {
           ScopedPyObjectPtr enum_value(
               GetIntegerEnumValue(*descriptor, next.get()));
-          if (enum_value == NULL) {
+          if (enum_value == nullptr) {
             return -1;
           }
           ScopedPyObjectPtr new_msg(repeated_scalar_container::Append(
               rs_container, enum_value.get()));
-          if (new_msg == NULL) {
+          if (new_msg == nullptr) {
             return -1;
           }
         }
@@ -1164,26 +1167,25 @@
       } else {
         if (ScopedPyObjectPtr(repeated_scalar_container::Extend(
                 reinterpret_cast<RepeatedScalarContainer*>(container.get()),
-                value)) ==
-            NULL) {
+                value)) == nullptr) {
           return -1;
         }
       }
     } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       ScopedPyObjectPtr message(GetFieldValue(self, descriptor));
-      if (message == NULL) {
+      if (message == nullptr) {
         return -1;
       }
       CMessage* cmessage = reinterpret_cast<CMessage*>(message.get());
       if (PyDict_Check(value)) {
         // Make the message exist even if the dict is empty.
         AssureWritable(cmessage);
-        if (InitAttributes(cmessage, NULL, value) < 0) {
+        if (InitAttributes(cmessage, nullptr, value) < 0) {
           return -1;
         }
       } else {
         ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
-        if (merged == NULL) {
+        if (merged == nullptr) {
           return -1;
         }
       }
@@ -1191,7 +1193,7 @@
       ScopedPyObjectPtr new_val;
       if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
         new_val.reset(GetIntegerEnumValue(*descriptor, value));
-        if (new_val == NULL) {
+        if (new_val == nullptr) {
           return -1;
         }
         value = new_val.get();
@@ -1209,19 +1211,19 @@
 CMessage* NewEmptyMessage(CMessageClass* type) {
   CMessage* self = reinterpret_cast<CMessage*>(
       PyType_GenericAlloc(&type->super.ht_type, 0));
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
 
-  self->message = NULL;
-  self->parent = NULL;
-  self->parent_field_descriptor = NULL;
+  self->message = nullptr;
+  self->parent = nullptr;
+  self->parent_field_descriptor = nullptr;
   self->read_only = false;
 
-  self->composite_fields = NULL;
-  self->child_submessages = NULL;
+  self->composite_fields = nullptr;
+  self->child_submessages = nullptr;
 
-  self->unknown_field_set = NULL;
+  self->unknown_field_set = nullptr;
 
   return self;
 }
@@ -1313,30 +1315,27 @@
 
 
 PyObject* IsInitialized(CMessage* self, PyObject* args) {
-  PyObject* errors = NULL;
+  PyObject* errors = nullptr;
   if (!PyArg_ParseTuple(args, "|O", &errors)) {
-    return NULL;
+    return nullptr;
   }
   if (self->message->IsInitialized()) {
     Py_RETURN_TRUE;
   }
-  if (errors != NULL) {
+  if (errors != nullptr) {
     ScopedPyObjectPtr initialization_errors(
         FindInitializationErrors(self));
-    if (initialization_errors == NULL) {
-      return NULL;
+    if (initialization_errors == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr extend_name(PyUnicode_FromString("extend"));
-    if (extend_name == NULL) {
-      return NULL;
+    if (extend_name == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr result(PyObject_CallMethodObjArgs(
-        errors,
-        extend_name.get(),
-        initialization_errors.get(),
-        NULL));
-    if (result == NULL) {
-      return NULL;
+        errors, extend_name.get(), initialization_errors.get(), nullptr));
+    if (result == nullptr) {
+      return nullptr;
     }
   }
   Py_RETURN_FALSE;
@@ -1363,17 +1362,17 @@
   const Descriptor* descriptor = message->GetDescriptor();
   const FieldDescriptor* field_descriptor =
       descriptor->FindFieldByName(field_name);
-  if (field_descriptor != NULL) {
+  if (field_descriptor != nullptr) {
     return field_descriptor;
   }
   const OneofDescriptor* oneof_desc =
       descriptor->FindOneofByName(field_name);
-  if (oneof_desc != NULL) {
+  if (oneof_desc != nullptr) {
     *in_oneof = true;
     return message->GetReflection()->GetOneofFieldDescriptor(*message,
                                                              oneof_desc);
   }
-  return NULL;
+  return nullptr;
 }
 
 bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
@@ -1401,25 +1400,25 @@
   Py_ssize_t size;
   field_name = const_cast<char*>(PyUnicode_AsUTF8AndSize(arg, &size));
   if (!field_name) {
-    return NULL;
+    return nullptr;
   }
 
   Message* message = self->message;
   bool is_in_oneof;
   const FieldDescriptor* field_descriptor =
       FindFieldWithOneofs(message, StringParam(field_name, size), &is_in_oneof);
-  if (field_descriptor == NULL) {
+  if (field_descriptor == nullptr) {
     if (!is_in_oneof) {
       PyErr_Format(PyExc_ValueError, "Protocol message %s has no field %s.",
                    message->GetDescriptor()->name().c_str(), field_name);
-      return NULL;
+      return nullptr;
     } else {
       Py_RETURN_FALSE;
     }
   }
 
   if (!CheckHasPresence(field_descriptor, is_in_oneof)) {
-    return NULL;
+    return nullptr;
   }
 
   if (message->GetReflection()->HasField(*message, field_descriptor)) {
@@ -1431,8 +1430,8 @@
 
 PyObject* ClearExtension(CMessage* self, PyObject* extension) {
   const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
   if (ClearFieldByDescriptor(self, descriptor) < 0) {
     return nullptr;
@@ -1442,8 +1441,8 @@
 
 PyObject* HasExtension(CMessage* self, PyObject* extension) {
   const FieldDescriptor* descriptor = GetExtensionDescriptor(extension);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
   int has_field = HasFieldByDescriptor(self, descriptor);
   if (has_field < 0) {
@@ -1586,20 +1585,20 @@
   char* field_name;
   Py_ssize_t field_size;
   if (PyString_AsStringAndSize(arg, &field_name, &field_size) < 0) {
-    return NULL;
+    return nullptr;
   }
   AssureWritable(self);
   bool is_in_oneof;
   const FieldDescriptor* field_descriptor = FindFieldWithOneofs(
       self->message, StringParam(field_name, field_size), &is_in_oneof);
-  if (field_descriptor == NULL) {
+  if (field_descriptor == nullptr) {
     if (is_in_oneof) {
       // We gave the name of a oneof, and none of its fields are set.
       Py_RETURN_NONE;
     } else {
       PyErr_Format(PyExc_ValueError,
                    "Protocol message has no \"%s\" field.", field_name);
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -1626,7 +1625,7 @@
   }
   if (InternalReparentFields(self, messages_to_release, containers_to_release) <
       0) {
-    return NULL;
+    return nullptr;
   }
   if (self->unknown_field_set) {
     unknown_fields::Clear(
@@ -1640,7 +1639,7 @@
 // ---------------------------------------------------------------------
 
 static std::string GetMessageName(CMessage* self) {
-  if (self->parent_field_descriptor != NULL) {
+  if (self->parent_field_descriptor != nullptr) {
     return self->parent_field_descriptor->full_name();
   } else {
     return self->message->GetDescriptor()->full_name();
@@ -1651,33 +1650,33 @@
     CMessage* self, PyObject* args, PyObject* kwargs,
     bool require_initialized) {
   // Parse the "deterministic" kwarg; defaults to False.
-  static const char* kwlist[] = {"deterministic", 0};
+  static const char* kwlist[] = {"deterministic", nullptr};
   PyObject* deterministic_obj = Py_None;
   if (!PyArg_ParseTupleAndKeywords(
           args, kwargs, "|O", const_cast<char**>(kwlist), &deterministic_obj)) {
-    return NULL;
+    return nullptr;
   }
   // Preemptively convert to a bool first, so we don't need to back out of
   // allocating memory if this raises an exception.
   // NOTE: This is unused later if deterministic == Py_None, but that's fine.
   int deterministic = PyObject_IsTrue(deterministic_obj);
   if (deterministic < 0) {
-    return NULL;
+    return nullptr;
   }
 
   if (require_initialized && !self->message->IsInitialized()) {
     ScopedPyObjectPtr errors(FindInitializationErrors(self));
-    if (errors == NULL) {
-      return NULL;
+    if (errors == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr comma(PyUnicode_FromString(","));
-    if (comma == NULL) {
-      return NULL;
+    if (comma == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr joined(
         PyObject_CallMethod(comma.get(), "join", "O", errors.get()));
-    if (joined == NULL) {
-      return NULL;
+    if (joined == nullptr) {
+      return nullptr;
     }
 
     // TODO(haberman): this is a (hopefully temporary) hack.  The unit testing
@@ -1689,19 +1688,19 @@
     // again every time.
     ScopedPyObjectPtr message_module(PyImport_ImportModule(
         "google.protobuf.message"));
-    if (message_module.get() == NULL) {
-      return NULL;
+    if (message_module.get() == nullptr) {
+      return nullptr;
     }
 
     ScopedPyObjectPtr encode_error(
         PyObject_GetAttrString(message_module.get(), "EncodeError"));
-    if (encode_error.get() == NULL) {
-      return NULL;
+    if (encode_error.get() == nullptr) {
+      return nullptr;
     }
     PyErr_Format(encode_error.get(),
                  "Message %s is missing required fields: %s",
                  GetMessageName(self).c_str(), PyString_AsString(joined.get()));
-    return NULL;
+    return nullptr;
   }
 
   // Ok, arguments parsed and errors checked, now encode to a string
@@ -1718,9 +1717,9 @@
     return nullptr;
   }
 
-  PyObject* result = PyBytes_FromStringAndSize(NULL, size);
-  if (result == NULL) {
-    return NULL;
+  PyObject* result = PyBytes_FromStringAndSize(nullptr, size);
+  if (result == nullptr) {
+    return nullptr;
   }
   io::ArrayOutputStream out(PyBytes_AS_STRING(result), size);
   io::CodedOutputStream coded_out(&out);
@@ -1794,7 +1793,7 @@
   std::string output;
   if (!printer.PrintToString(*self->message, &output)) {
     PyErr_SetString(PyExc_ValueError, "Unable to convert message to str");
-    return NULL;
+    return nullptr;
   }
   return PyUnicode_FromString(output.c_str());
 }
@@ -1807,7 +1806,7 @@
                  "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  Py_TYPE(arg)->tp_name);
-    return NULL;
+    return nullptr;
   }
 
   other_message = reinterpret_cast<CMessage*>(arg);
@@ -1818,7 +1817,7 @@
                  "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  other_message->message->GetDescriptor()->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
   AssureWritable(self);
 
@@ -1826,7 +1825,7 @@
   // Child message might be lazily created before MergeFrom. Make sure they
   // are mutable at this point if child messages are really created.
   if (FixupMessageAfterMerge(self) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   Py_RETURN_NONE;
@@ -1840,7 +1839,7 @@
                  "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  Py_TYPE(arg)->tp_name);
-    return NULL;
+    return nullptr;
   }
 
   other_message = reinterpret_cast<CMessage*>(arg);
@@ -1856,7 +1855,7 @@
                  "expected %s got %s.",
                  self->message->GetDescriptor()->full_name().c_str(),
                  other_message->message->GetDescriptor()->full_name().c_str());
-    return NULL;
+    return nullptr;
   }
 
   AssureWritable(self);
@@ -1876,7 +1875,7 @@
   if (!arg || !PyBool_Check(arg)) {
     PyErr_SetString(PyExc_TypeError,
                     "Argument to SetAllowOversizeProtos must be boolean");
-    return NULL;
+    return nullptr;
   }
   allow_oversize_protos = PyObject_IsTrue(arg);
   if (allow_oversize_protos) {
@@ -1889,7 +1888,7 @@
 static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
   Py_buffer data;
   if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   AssureWritable(self);
@@ -1911,19 +1910,29 @@
   // Child message might be lazily created before MergeFrom. Make sure they
   // are mutable at this point if child messages are really created.
   if (FixupMessageAfterMerge(self) < 0) {
-    return NULL;
+    return nullptr;
   }
 
   // Python makes distinction in error message, between a general parse failure
   // and in-correct ending on a terminating tag. Hence we need to be a bit more
   // explicit in our correctness checks.
-  if (ptr == nullptr || ctx.BytesUntilLimit(ptr) < 0) {
-    // Parse error or the parser overshoot the limit.
+  if (ptr == nullptr) {
+    // Parse error.
     PyErr_Format(
         DecodeError_class, "Error parsing message with type '%s'",
         self->GetMessageClass()->message_descriptor->full_name().c_str());
+    return nullptr;
+  }
+  if (ctx.BytesUntilLimit(ptr) < 0) {
+    // The parser overshot the limit.
+    PyErr_Format(
+        DecodeError_class,
+        "Error parsing message as the message exceeded the protobuf limit "
+        "with type '%s'",
+        self->GetMessageClass()->message_descriptor->full_name().c_str());
     return NULL;
   }
+
   // ctx has an explicit limit set (length of string_view), so we have to
   // check we ended at that limit.
   if (!ctx.EndedAtLimit()) {
@@ -1936,8 +1945,8 @@
 }
 
 static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
-  if (ScopedPyObjectPtr(Clear(self)) == NULL) {
-    return NULL;
+  if (ScopedPyObjectPtr(Clear(self)) == nullptr) {
+    return nullptr;
   }
   return MergeFromString(self, arg);
 }
@@ -1949,25 +1958,25 @@
 PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle) {
   const FieldDescriptor* descriptor =
       GetExtensionDescriptor(extension_handle);
-  if (descriptor == NULL) {
-    return NULL;
+  if (descriptor == nullptr) {
+    return nullptr;
   }
   if (!PyObject_TypeCheck(cls, CMessageClass_Type)) {
     PyErr_Format(PyExc_TypeError, "Expected a message class, got %s",
                  cls->ob_type->tp_name);
-    return NULL;
+    return nullptr;
   }
   CMessageClass *message_class = reinterpret_cast<CMessageClass*>(cls);
-  if (message_class == NULL) {
-    return NULL;
+  if (message_class == nullptr) {
+    return nullptr;
   }
   // If the extension was already registered, check that it is the same.
   const FieldDescriptor* existing_extension =
       message_class->py_message_factory->pool->pool->FindExtensionByNumber(
           descriptor->containing_type(), descriptor->number());
-  if (existing_extension != NULL && existing_extension != descriptor) {
+  if (existing_extension != nullptr && existing_extension != descriptor) {
     PyErr_SetString(PyExc_ValueError, "Double registration of Extensions");
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -1980,20 +1989,19 @@
 static PyObject* WhichOneof(CMessage* self, PyObject* arg) {
   Py_ssize_t name_size;
   char *name_data;
-  if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0)
-    return NULL;
+  if (PyString_AsStringAndSize(arg, &name_data, &name_size) < 0) return nullptr;
   const OneofDescriptor* oneof_desc =
       self->message->GetDescriptor()->FindOneofByName(
           StringParam(name_data, name_size));
-  if (oneof_desc == NULL) {
+  if (oneof_desc == nullptr) {
     PyErr_Format(PyExc_ValueError,
                  "Protocol message has no oneof \"%s\" field.", name_data);
-    return NULL;
+    return nullptr;
   }
   const FieldDescriptor* field_in_oneof =
       self->message->GetReflection()->GetOneofFieldDescriptor(
           *self->message, oneof_desc);
-  if (field_in_oneof == NULL) {
+  if (field_in_oneof == nullptr) {
     Py_RETURN_NONE;
   } else {
     const std::string& name = field_in_oneof->name();
@@ -2009,8 +2017,8 @@
 
   // Normally, the list will be exactly the size of the fields.
   ScopedPyObjectPtr all_fields(PyList_New(fields.size()));
-  if (all_fields == NULL) {
-    return NULL;
+  if (all_fields == nullptr) {
+    return nullptr;
   }
 
   // When there are unknown extensions, the py list will *not* contain
@@ -2019,36 +2027,36 @@
   Py_ssize_t actual_size = 0;
   for (size_t i = 0; i < fields.size(); ++i) {
     ScopedPyObjectPtr t(PyTuple_New(2));
-    if (t == NULL) {
-      return NULL;
+    if (t == nullptr) {
+      return nullptr;
     }
 
     if (fields[i]->is_extension()) {
       ScopedPyObjectPtr extension_field(
           PyFieldDescriptor_FromDescriptor(fields[i]));
-      if (extension_field == NULL) {
-        return NULL;
+      if (extension_field == nullptr) {
+        return nullptr;
       }
       // With C++ descriptors, the field can always be retrieved, but for
       // unknown extensions which have not been imported in Python code, there
       // is no message class and we cannot retrieve the value.
       // TODO(amauryfa): consider building the class on the fly!
-      if (fields[i]->message_type() != NULL &&
-          message_factory::GetMessageClass(
-              GetFactoryForMessage(self),
-              fields[i]->message_type()) == NULL) {
+      if (fields[i]->message_type() != nullptr &&
+          message_factory::GetMessageClass(GetFactoryForMessage(self),
+                                           fields[i]->message_type()) ==
+              nullptr) {
         PyErr_Clear();
         continue;
       }
-      ScopedPyObjectPtr extensions(GetExtensionDict(self, NULL));
-      if (extensions == NULL) {
-        return NULL;
+      ScopedPyObjectPtr extensions(GetExtensionDict(self, nullptr));
+      if (extensions == nullptr) {
+        return nullptr;
       }
       // 'extension' reference later stolen by PyTuple_SET_ITEM.
       PyObject* extension = PyObject_GetItem(
           extensions.get(), extension_field.get());
-      if (extension == NULL) {
-        return NULL;
+      if (extension == nullptr) {
+        return nullptr;
       }
       PyTuple_SET_ITEM(t.get(), 0, extension_field.release());
       // Steals reference to 'extension'
@@ -2057,14 +2065,14 @@
       // Normal field
       ScopedPyObjectPtr field_descriptor(
           PyFieldDescriptor_FromDescriptor(fields[i]));
-      if (field_descriptor == NULL) {
-        return NULL;
+      if (field_descriptor == nullptr) {
+        return nullptr;
       }
 
       PyObject* field_value = GetFieldValue(self, fields[i]);
-      if (field_value == NULL) {
+      if (field_value == nullptr) {
         PyErr_SetString(PyExc_ValueError, fields[i]->name().c_str());
-        return NULL;
+        return nullptr;
       }
       PyTuple_SET_ITEM(t.get(), 0, field_descriptor.release());
       PyTuple_SET_ITEM(t.get(), 1, field_value);
@@ -2073,9 +2081,9 @@
     ++actual_size;
   }
   if (static_cast<size_t>(actual_size) != fields.size() &&
-      (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) <
+      (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), nullptr) <
        0)) {
-    return NULL;
+    return nullptr;
   }
   return all_fields.release();
 }
@@ -2092,16 +2100,16 @@
   message->FindInitializationErrors(&errors);
 
   PyObject* error_list = PyList_New(errors.size());
-  if (error_list == NULL) {
-    return NULL;
+  if (error_list == nullptr) {
+    return nullptr;
   }
   for (size_t i = 0; i < errors.size(); ++i) {
     const std::string& error = errors[i];
     PyObject* error_string =
         PyUnicode_FromStringAndSize(error.c_str(), error.length());
-    if (error_string == NULL) {
+    if (error_string == nullptr) {
       Py_DECREF(error_list);
-      return NULL;
+      return nullptr;
     }
     PyList_SET_ITEM(error_list, i, error_string);
   }
@@ -2147,10 +2155,10 @@
   const Reflection* reflection = message->GetReflection();
 
   if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
-    return NULL;
+    return nullptr;
   }
 
-  PyObject* result = NULL;
+  PyObject* result = nullptr;
   switch (field_descriptor->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32: {
       int32_t value = reflection->GetInt32(*message, field_descriptor);
@@ -2218,13 +2226,13 @@
       factory, field_descriptor->message_type());
   ScopedPyObjectPtr message_class_owner(
       reinterpret_cast<PyObject*>(message_class));
-  if (message_class == NULL) {
-    return NULL;
+  if (message_class == nullptr) {
+    return nullptr;
   }
 
   CMessage* cmsg = cmessage::NewEmptyMessage(message_class);
-  if (cmsg == NULL) {
-    return NULL;
+  if (cmsg == nullptr) {
+    return nullptr;
   }
 
   Py_INCREF(self);
@@ -2310,7 +2318,7 @@
         const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
         const EnumValueDescriptor* enum_value =
             enum_descriptor->FindValueByNumber(value);
-        if (enum_value != NULL) {
+        if (enum_value != nullptr) {
           reflection->SetEnum(message, field_descriptor, enum_value);
         } else {
           PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
@@ -2345,37 +2353,37 @@
 }
 
 PyObject* FromString(PyTypeObject* cls, PyObject* serialized) {
-  PyObject* py_cmsg = PyObject_CallObject(
-      reinterpret_cast<PyObject*>(cls), NULL);
-  if (py_cmsg == NULL) {
-    return NULL;
+  PyObject* py_cmsg =
+      PyObject_CallObject(reinterpret_cast<PyObject*>(cls), nullptr);
+  if (py_cmsg == nullptr) {
+    return nullptr;
   }
   CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
 
   ScopedPyObjectPtr py_length(MergeFromString(cmsg, serialized));
-  if (py_length == NULL) {
+  if (py_length == nullptr) {
     Py_DECREF(py_cmsg);
-    return NULL;
+    return nullptr;
   }
 
   return py_cmsg;
 }
 
 PyObject* DeepCopy(CMessage* self, PyObject* arg) {
-  PyObject* clone = PyObject_CallObject(
-      reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
-  if (clone == NULL) {
-    return NULL;
+  PyObject* clone =
+      PyObject_CallObject(reinterpret_cast<PyObject*>(Py_TYPE(self)), nullptr);
+  if (clone == nullptr) {
+    return nullptr;
   }
   if (!PyObject_TypeCheck(clone, CMessage_Type)) {
     Py_DECREF(clone);
-    return NULL;
+    return nullptr;
   }
-  if (ScopedPyObjectPtr(MergeFrom(
-          reinterpret_cast<CMessage*>(clone),
-          reinterpret_cast<PyObject*>(self))) == NULL) {
+  if (ScopedPyObjectPtr(MergeFrom(reinterpret_cast<CMessage*>(clone),
+                                  reinterpret_cast<PyObject*>(self))) ==
+      nullptr) {
     Py_DECREF(clone);
-    return NULL;
+    return nullptr;
   }
   return clone;
 }
@@ -2384,23 +2392,24 @@
   // Lazy import to prevent circular dependencies
   ScopedPyObjectPtr text_format(
       PyImport_ImportModule("google.protobuf.text_format"));
-  if (text_format == NULL) {
-    return NULL;
+  if (text_format == nullptr) {
+    return nullptr;
   }
   ScopedPyObjectPtr method_name(PyUnicode_FromString("MessageToString"));
-  if (method_name == NULL) {
-    return NULL;
+  if (method_name == nullptr) {
+    return nullptr;
   }
   Py_INCREF(Py_True);
   ScopedPyObjectPtr encoded(PyObject_CallMethodObjArgs(
-      text_format.get(), method_name.get(), self, Py_True, NULL));
+      text_format.get(), method_name.get(), self, Py_True, nullptr));
   Py_DECREF(Py_True);
-  if (encoded == NULL) {
-    return NULL;
+  if (encoded == nullptr) {
+    return nullptr;
   }
-  PyObject* decoded = PyUnicode_FromEncodedObject(encoded.get(), "utf-8", NULL);
-  if (decoded == NULL) {
-    return NULL;
+  PyObject* decoded =
+      PyUnicode_FromEncodedObject(encoded.get(), "utf-8", nullptr);
+  if (decoded == nullptr) {
+    return nullptr;
   }
   return decoded;
 }
@@ -2412,7 +2421,7 @@
     PyErr_SetString(PyExc_TypeError,
                     "Descriptors should not be created directly, "
                     "but only retrieved from their parent.");
-    return NULL;
+    return nullptr;
   }
   Py_RETURN_NONE;
 }
@@ -2423,20 +2432,20 @@
   const Descriptor* descriptor = GetMessageDescriptor(Py_TYPE(self));
   if (!descriptor->extension_range_count()) {
     PyErr_SetNone(PyExc_AttributeError);
-    return NULL;
+    return nullptr;
   }
   if (!self->composite_fields) {
     self->composite_fields = new CMessage::CompositeFieldsMap();
   }
   if (!self->composite_fields) {
-    return NULL;
+    return nullptr;
   }
   ExtensionDict* extension_dict = extension_dict::NewExtensionDict(self);
   return reinterpret_cast<PyObject*>(extension_dict);
 }
 
 static PyObject* UnknownFieldSet(CMessage* self) {
-  if (self->unknown_field_set == NULL) {
+  if (self->unknown_field_set == nullptr) {
     self->unknown_field_set = unknown_fields::NewPyUnknownFields(self);
   } else {
     Py_INCREF(self->unknown_field_set);
@@ -2455,75 +2464,70 @@
 }
 
 static PyGetSetDef Getters[] = {
-  {"Extensions", (getter)GetExtensionDict, NULL, "Extension dict"},
-  {"_extensions_by_name", (getter)GetExtensionsByName, NULL},
-  {"_extensions_by_number", (getter)GetExtensionsByNumber, NULL},
-  {NULL}
+    {"Extensions", (getter)GetExtensionDict, nullptr, "Extension dict"},
+    {"_extensions_by_name", (getter)GetExtensionsByName, nullptr},
+    {"_extensions_by_number", (getter)GetExtensionsByNumber, nullptr},
+    {nullptr},
 };
 
-
 static PyMethodDef Methods[] = {
-  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
-    "Makes a deep copy of the class." },
-  { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
-    "Outputs a unicode representation of the message." },
-  { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
-    "Returns the size of the message in bytes." },
-  { "Clear", (PyCFunction)Clear, METH_NOARGS,
-    "Clears the message." },
-  { "ClearExtension", (PyCFunction)ClearExtension, METH_O,
-    "Clears a message field." },
-  { "ClearField", (PyCFunction)ClearField, METH_O,
-    "Clears a message field." },
-  { "CopyFrom", (PyCFunction)CopyFrom, METH_O,
-    "Copies a protocol message into the current message." },
-  { "DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS,
-    "Discards the unknown fields." },
-  { "FindInitializationErrors", (PyCFunction)FindInitializationErrors,
-    METH_NOARGS,
-    "Finds unset required fields." },
-  { "FromString", (PyCFunction)FromString, METH_O | METH_CLASS,
-    "Creates new method instance from given serialized data." },
-  { "HasExtension", (PyCFunction)HasExtension, METH_O,
-    "Checks if a message field is set." },
-  { "HasField", (PyCFunction)HasField, METH_O,
-    "Checks if a message field is set." },
-  { "IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS,
-    "Checks if all required fields of a protocol message are set." },
-  { "ListFields", (PyCFunction)ListFields, METH_NOARGS,
-    "Lists all set fields of a message." },
-  { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
-    "Merges a protocol message into the current message." },
-  { "MergeFromString", (PyCFunction)MergeFromString, METH_O,
-    "Merges a serialized message into the current message." },
-  { "ParseFromString", (PyCFunction)ParseFromString, METH_O,
-    "Parses a serialized message into the current message." },
-  { "RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS,
-    "Registers an extension with the current message." },
-  { "SerializePartialToString", (PyCFunction)SerializePartialToString,
-    METH_VARARGS | METH_KEYWORDS,
-    "Serializes the message to a string, even if it isn't initialized." },
-  { "SerializeToString", (PyCFunction)SerializeToString,
-    METH_VARARGS | METH_KEYWORDS,
-    "Serializes the message to a string, only for initialized messages." },
-  { "SetInParent", (PyCFunction)SetInParent, METH_NOARGS,
-    "Sets the has bit of the given field in its parent message." },
-  { "UnknownFields", (PyCFunction)UnknownFieldSet, METH_NOARGS,
-    "Parse unknown field set"},
-  { "WhichOneof", (PyCFunction)WhichOneof, METH_O,
-    "Returns the name of the field set inside a oneof, "
-    "or None if no field is set." },
+    {"__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+     "Makes a deep copy of the class."},
+    {"__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
+     "Outputs a unicode representation of the message."},
+    {"ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
+     "Returns the size of the message in bytes."},
+    {"Clear", (PyCFunction)Clear, METH_NOARGS, "Clears the message."},
+    {"ClearExtension", (PyCFunction)ClearExtension, METH_O,
+     "Clears a message field."},
+    {"ClearField", (PyCFunction)ClearField, METH_O, "Clears a message field."},
+    {"CopyFrom", (PyCFunction)CopyFrom, METH_O,
+     "Copies a protocol message into the current message."},
+    {"DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS,
+     "Discards the unknown fields."},
+    {"FindInitializationErrors", (PyCFunction)FindInitializationErrors,
+     METH_NOARGS, "Finds unset required fields."},
+    {"FromString", (PyCFunction)FromString, METH_O | METH_CLASS,
+     "Creates new method instance from given serialized data."},
+    {"HasExtension", (PyCFunction)HasExtension, METH_O,
+     "Checks if a message field is set."},
+    {"HasField", (PyCFunction)HasField, METH_O,
+     "Checks if a message field is set."},
+    {"IsInitialized", (PyCFunction)IsInitialized, METH_VARARGS,
+     "Checks if all required fields of a protocol message are set."},
+    {"ListFields", (PyCFunction)ListFields, METH_NOARGS,
+     "Lists all set fields of a message."},
+    {"MergeFrom", (PyCFunction)MergeFrom, METH_O,
+     "Merges a protocol message into the current message."},
+    {"MergeFromString", (PyCFunction)MergeFromString, METH_O,
+     "Merges a serialized message into the current message."},
+    {"ParseFromString", (PyCFunction)ParseFromString, METH_O,
+     "Parses a serialized message into the current message."},
+    {"RegisterExtension", (PyCFunction)RegisterExtension, METH_O | METH_CLASS,
+     "Registers an extension with the current message."},
+    {"SerializePartialToString", (PyCFunction)SerializePartialToString,
+     METH_VARARGS | METH_KEYWORDS,
+     "Serializes the message to a string, even if it isn't initialized."},
+    {"SerializeToString", (PyCFunction)SerializeToString,
+     METH_VARARGS | METH_KEYWORDS,
+     "Serializes the message to a string, only for initialized messages."},
+    {"SetInParent", (PyCFunction)SetInParent, METH_NOARGS,
+     "Sets the has bit of the given field in its parent message."},
+    {"UnknownFields", (PyCFunction)UnknownFieldSet, METH_NOARGS,
+     "Parse unknown field set"},
+    {"WhichOneof", (PyCFunction)WhichOneof, METH_O,
+     "Returns the name of the field set inside a oneof, "
+     "or None if no field is set."},
 
-  // Static Methods.
-  { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile,
-    METH_NOARGS | METH_STATIC,
-    "Raises TypeError if the caller is not in a _pb2.py file."},
-  { NULL, NULL}
-};
+    // Static Methods.
+    {"_CheckCalledFromGeneratedFile",
+     (PyCFunction)_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC,
+     "Raises TypeError if the caller is not in a _pb2.py file."},
+    {nullptr, nullptr}};
 
 bool SetCompositeField(CMessage* self, const FieldDescriptor* field,
                        ContainerBase* value) {
-  if (self->composite_fields == NULL) {
+  if (self->composite_fields == nullptr) {
     self->composite_fields = new CMessage::CompositeFieldsMap();
   }
   (*self->composite_fields)[field] = value;
@@ -2531,7 +2535,7 @@
 }
 
 bool SetSubmessage(CMessage* self, CMessage* submessage) {
-  if (self->child_submessages == NULL) {
+  if (self->child_submessages == nullptr) {
     self->child_submessages = new CMessage::SubMessagesMap();
   }
   (*self->child_submessages)[submessage->message] = submessage;
@@ -2542,11 +2546,11 @@
   CMessage* self = reinterpret_cast<CMessage*>(pself);
   PyObject* result = PyObject_GenericGetAttr(
       reinterpret_cast<PyObject*>(self), name);
-  if (result != NULL) {
+  if (result != nullptr) {
     return result;
   }
   if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
-    return NULL;
+    return nullptr;
   }
 
   PyErr_Clear();
@@ -2571,7 +2575,7 @@
                  "descriptor to field '%s' doesn't apply to '%s' object",
                  field_descriptor->full_name().c_str(),
                  Py_TYPE(self)->tp_name);
-    return NULL;
+    return nullptr;
   }
 
   if (!field_descriptor->is_repeated() &&
@@ -2586,8 +2590,8 @@
     if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       CMessageClass* value_class = message_factory::GetMessageClass(
           GetFactoryForMessage(self), value_type->message_type());
-      if (value_class == NULL) {
-        return NULL;
+      if (value_class == nullptr) {
+        return nullptr;
       }
       py_container =
           NewMessageMapContainer(self, field_descriptor, value_class);
@@ -2598,8 +2602,8 @@
     if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       CMessageClass* message_class = message_factory::GetMessageClass(
           GetFactoryForMessage(self), field_descriptor->message_type());
-      if (message_class == NULL) {
-        return NULL;
+      if (message_class == nullptr) {
+        return nullptr;
       }
       py_container = repeated_composite_container::NewContainer(
           self, field_descriptor, message_class);
@@ -2614,12 +2618,12 @@
     PyErr_SetString(PyExc_SystemError, "Should never happen");
   }
 
-  if (py_container == NULL) {
-    return NULL;
+  if (py_container == nullptr) {
+    return nullptr;
   }
   if (!SetCompositeField(self, field_descriptor, py_container)) {
     Py_DECREF(py_container);
-    return NULL;
+    return nullptr;
   }
   return py_container->AsPyObject();
 }
@@ -2695,8 +2699,8 @@
   } else {
     cmsg = cmessage::NewEmptyMessage(message_class);
 
-    if (cmsg == NULL) {
-      return NULL;
+    if (cmsg == nullptr) {
+      return nullptr;
     }
     cmsg->message = sub_message;
     Py_INCREF(this);
@@ -2725,47 +2729,47 @@
   return released;
 }
 
-static CMessageClass _CMessage_Type = { { {
-  PyVarObject_HEAD_INIT(&_CMessageClass_Type, 0)
-  FULL_MODULE_NAME ".CMessage",        // tp_name
-  sizeof(CMessage),                    // tp_basicsize
-  0,                                   //  tp_itemsize
-  (destructor)cmessage::Dealloc,       //  tp_dealloc
-  0,                                   //  tp_print
-  0,                                   //  tp_getattr
-  0,                                   //  tp_setattr
-  0,                                   //  tp_compare
-  (reprfunc)cmessage::ToStr,           //  tp_repr
-  0,                                   //  tp_as_number
-  0,                                   //  tp_as_sequence
-  0,                                   //  tp_as_mapping
-  PyObject_HashNotImplemented,         //  tp_hash
-  0,                                   //  tp_call
-  (reprfunc)cmessage::ToStr,           //  tp_str
-  cmessage::GetAttr,                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-      | Py_TPFLAGS_HAVE_VERSION_TAG,   //  tp_flags
-  "A ProtocolMessage",                 //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  (richcmpfunc)cmessage::RichCompare,  //  tp_richcompare
-  offsetof(CMessage, weakreflist),     //  tp_weaklistoffset
-  0,                                   //  tp_iter
-  0,                                   //  tp_iternext
-  cmessage::Methods,                   //  tp_methods
-  0,                                   //  tp_members
-  cmessage::Getters,                   //  tp_getset
-  0,                                   //  tp_base
-  0,                                   //  tp_dict
-  0,                                   //  tp_descr_get
-  0,                                   //  tp_descr_set
-  0,                                   //  tp_dictoffset
-  (initproc)cmessage::Init,            //  tp_init
-  0,                                   //  tp_alloc
-  cmessage::New,                       //  tp_new
-} } };
+static CMessageClass _CMessage_Type = {{{
+    PyVarObject_HEAD_INIT(&_CMessageClass_Type, 0) FULL_MODULE_NAME
+    ".CMessage",                    // tp_name
+    sizeof(CMessage),               // tp_basicsize
+    0,                              //  tp_itemsize
+    (destructor)cmessage::Dealloc,  //  tp_dealloc
+    0,                              //  tp_print
+    nullptr,                        //  tp_getattr
+    nullptr,                        //  tp_setattr
+    nullptr,                        //  tp_compare
+    (reprfunc)cmessage::ToStr,      //  tp_repr
+    nullptr,                        //  tp_as_number
+    nullptr,                        //  tp_as_sequence
+    nullptr,                        //  tp_as_mapping
+    PyObject_HashNotImplemented,    //  tp_hash
+    nullptr,                        //  tp_call
+    (reprfunc)cmessage::ToStr,      //  tp_str
+    cmessage::GetAttr,              //  tp_getattro
+    nullptr,                        //  tp_setattro
+    nullptr,                        //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+        Py_TPFLAGS_HAVE_VERSION_TAG,     //  tp_flags
+    "A ProtocolMessage",                 //  tp_doc
+    nullptr,                             //  tp_traverse
+    nullptr,                             //  tp_clear
+    (richcmpfunc)cmessage::RichCompare,  //  tp_richcompare
+    offsetof(CMessage, weakreflist),     //  tp_weaklistoffset
+    nullptr,                             //  tp_iter
+    nullptr,                             //  tp_iternext
+    cmessage::Methods,                   //  tp_methods
+    nullptr,                             //  tp_members
+    cmessage::Getters,                   //  tp_getset
+    nullptr,                             //  tp_base
+    nullptr,                             //  tp_dict
+    nullptr,                             //  tp_descr_get
+    nullptr,                             //  tp_descr_set
+    0,                                   //  tp_dictoffset
+    (initproc)cmessage::Init,            //  tp_init
+    nullptr,                             //  tp_alloc
+    cmessage::New,                       //  tp_new
+}}};
 PyTypeObject* CMessage_Type = &_CMessage_Type.super.ht_type;
 
 // --- Exposing the C proto living inside Python proto to C code:
@@ -2775,18 +2779,18 @@
 
 static const Message* GetCProtoInsidePyProtoImpl(PyObject* msg) {
   const Message* message = PyMessage_GetMessagePointer(msg);
-  if (message == NULL) {
+  if (message == nullptr) {
     PyErr_Clear();
-    return NULL;
+    return nullptr;
   }
   return message;
 }
 
 static Message* MutableCProtoInsidePyProtoImpl(PyObject* msg) {
   Message* message = PyMessage_GetMutableMessagePointer(msg);
-  if (message == NULL) {
+  if (message == nullptr) {
     PyErr_Clear();
-    return NULL;
+    return nullptr;
   }
   return message;
 }
@@ -2794,7 +2798,7 @@
 const Message* PyMessage_GetMessagePointer(PyObject* msg) {
   if (!PyObject_TypeCheck(msg, CMessage_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a Message instance");
-    return NULL;
+    return nullptr;
   }
   CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
   return cmsg->message;
@@ -2803,7 +2807,7 @@
 Message* PyMessage_GetMutableMessagePointer(PyObject* msg) {
   if (!PyObject_TypeCheck(msg, CMessage_Type)) {
     PyErr_SetString(PyExc_TypeError, "Not a Message instance");
-    return NULL;
+    return nullptr;
   }
   CMessage* cmsg = reinterpret_cast<CMessage*>(msg);
 
@@ -2817,7 +2821,7 @@
     PyErr_SetString(PyExc_ValueError,
                     "Cannot reliably get a mutable pointer "
                     "to a message with extra references");
-    return NULL;
+    return nullptr;
   }
   cmessage::AssureWritable(cmsg);
   return cmsg->message;
@@ -2890,8 +2894,8 @@
   // also be freed and reset to NULL during finalization.
   kDESCRIPTOR = PyUnicode_FromString("DESCRIPTOR");
 
-  PyObject *dummy_obj = PySet_New(NULL);
-  kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL);
+  PyObject* dummy_obj = PySet_New(nullptr);
+  kEmptyWeakref = PyWeakref_NewRef(dummy_obj, nullptr);
   Py_DECREF(dummy_obj);
 }
 
@@ -2958,22 +2962,22 @@
 
     // Register them as MutableSequence.
     ScopedPyObjectPtr collections(PyImport_ImportModule("collections.abc"));
-    if (collections == NULL) {
+    if (collections == nullptr) {
       return false;
     }
     ScopedPyObjectPtr mutable_sequence(
         PyObject_GetAttrString(collections.get(), "MutableSequence"));
-    if (mutable_sequence == NULL) {
+    if (mutable_sequence == nullptr) {
       return false;
     }
     if (ScopedPyObjectPtr(
             PyObject_CallMethod(mutable_sequence.get(), "register", "O",
-                                &RepeatedScalarContainer_Type)) == NULL) {
+                                &RepeatedScalarContainer_Type)) == nullptr) {
       return false;
     }
     if (ScopedPyObjectPtr(
             PyObject_CallMethod(mutable_sequence.get(), "register", "O",
-                                &RepeatedCompositeContainer_Type)) == NULL) {
+                                &RepeatedCompositeContainer_Type)) == nullptr) {
       return false;
     }
   }
@@ -3042,7 +3046,7 @@
 
   PyObject* enum_type_wrapper = PyImport_ImportModule(
       "google.protobuf.internal.enum_type_wrapper");
-  if (enum_type_wrapper == NULL) {
+  if (enum_type_wrapper == nullptr) {
     return false;
   }
   EnumTypeWrapper_class =
@@ -3051,7 +3055,7 @@
 
   PyObject* message_module = PyImport_ImportModule(
       "google.protobuf.message");
-  if (message_module == NULL) {
+  if (message_module == nullptr) {
     return false;
   }
   EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
@@ -3060,7 +3064,7 @@
   Py_DECREF(message_module);
 
   PyObject* pickle_module = PyImport_ImportModule("pickle");
-  if (pickle_module == NULL) {
+  if (pickle_module == nullptr) {
     return false;
   }
   PickleError_class = PyObject_GetAttrString(pickle_module, "PickleError");
diff --git a/python/google/protobuf/pyext/message_factory.cc b/python/google/protobuf/pyext/message_factory.cc
index 5098379..6518c96 100644
--- a/python/google/protobuf/pyext/message_factory.cc
+++ b/python/google/protobuf/pyext/message_factory.cc
@@ -39,12 +39,13 @@
 #include <google/protobuf/pyext/message_factory.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define PyString_AsStringAndSize(ob, charpp, sizep)                           \
-  (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
-                               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
-                              ? -1                                            \
-                              : 0)                                            \
-                       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
+#define PyString_AsStringAndSize(ob, charpp, sizep)              \
+  (PyUnicode_Check(ob)                                           \
+       ? ((*(charpp) = const_cast<char*>(                        \
+               PyUnicode_AsUTF8AndSize(ob, (sizep)))) == nullptr \
+              ? -1                                               \
+              : 0)                                               \
+       : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
 
 namespace google {
 namespace protobuf {
@@ -55,8 +56,8 @@
 PyMessageFactory* NewMessageFactory(PyTypeObject* type, PyDescriptorPool* pool) {
   PyMessageFactory* factory = reinterpret_cast<PyMessageFactory*>(
       PyType_GenericAlloc(type, 0));
-  if (factory == NULL) {
-    return NULL;
+  if (factory == nullptr) {
+    return nullptr;
   }
 
   DynamicMessageFactory* message_factory = new DynamicMessageFactory();
@@ -73,25 +74,25 @@
 }
 
 PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
-  static const char* kwlist[] = {"pool", 0};
-  PyObject* pool = NULL;
+  static const char* kwlist[] = {"pool", nullptr};
+  PyObject* pool = nullptr;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
                                    const_cast<char**>(kwlist), &pool)) {
-    return NULL;
+    return nullptr;
   }
   ScopedPyObjectPtr owned_pool;
-  if (pool == NULL || pool == Py_None) {
+  if (pool == nullptr || pool == Py_None) {
     owned_pool.reset(PyObject_CallFunction(
-        reinterpret_cast<PyObject*>(&PyDescriptorPool_Type), NULL));
-    if (owned_pool == NULL) {
-      return NULL;
+        reinterpret_cast<PyObject*>(&PyDescriptorPool_Type), nullptr));
+    if (owned_pool == nullptr) {
+      return nullptr;
     }
     pool = owned_pool.get();
   } else {
     if (!PyObject_TypeCheck(pool, &PyDescriptorPool_Type)) {
       PyErr_Format(PyExc_TypeError, "Expected a DescriptorPool, got %s",
                    pool->ob_type->tp_name);
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -162,8 +163,8 @@
   }
   ScopedPyObjectPtr py_descriptor(
       PyMessageDescriptor_FromDescriptor(descriptor));
-  if (py_descriptor == NULL) {
-    return NULL;
+  if (py_descriptor == nullptr) {
+    return nullptr;
   }
   // Create a new message class.
   ScopedPyObjectPtr args(Py_BuildValue(
@@ -171,24 +172,24 @@
       "DESCRIPTOR", py_descriptor.get(),
       "__module__", Py_None,
       "message_factory", self));
-  if (args == NULL) {
-    return NULL;
+  if (args == nullptr) {
+    return nullptr;
   }
   ScopedPyObjectPtr message_class(PyObject_CallObject(
       reinterpret_cast<PyObject*>(CMessageClass_Type), args.get()));
-  if (message_class == NULL) {
-    return NULL;
+  if (message_class == nullptr) {
+    return nullptr;
   }
   // Create messages class for the messages used by the fields, and registers
   // all extensions for these messages during the recursion.
   for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
     const Descriptor* sub_descriptor =
         descriptor->field(field_idx)->message_type();
-    // It is NULL if the field type is not a message.
-    if (sub_descriptor != NULL) {
+    // It is null if the field type is not a message.
+    if (sub_descriptor != nullptr) {
       CMessageClass* result = GetOrCreateMessageClass(self, sub_descriptor);
-      if (result == NULL) {
-        return NULL;
+      if (result == nullptr) {
+        return nullptr;
       }
       Py_DECREF(result);
     }
@@ -200,17 +201,17 @@
     ScopedPyObjectPtr py_extended_class(
         GetOrCreateMessageClass(self, extension->containing_type())
             ->AsPyObject());
-    if (py_extended_class == NULL) {
-      return NULL;
+    if (py_extended_class == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr py_extension(PyFieldDescriptor_FromDescriptor(extension));
-    if (py_extension == NULL) {
-      return NULL;
+    if (py_extension == nullptr) {
+      return nullptr;
     }
     ScopedPyObjectPtr result(cmessage::RegisterExtension(
         py_extended_class.get(), py_extension.get()));
-    if (result == NULL) {
-      return NULL;
+    if (result == nullptr) {
+      return nullptr;
     }
   }
   return reinterpret_cast<CMessageClass*>(message_class.release());
@@ -224,14 +225,15 @@
   if (ret == self->classes_by_descriptor->end()) {
     PyErr_Format(PyExc_TypeError, "No message class registered for '%s'",
                  message_descriptor->full_name().c_str());
-    return NULL;
+    return nullptr;
   } else {
     return ret->second;
   }
 }
 
 static PyMethodDef Methods[] = {
-    {NULL}};
+    {nullptr},
+};
 
 static PyObject* GetPool(PyMessageFactory* self, void* closure) {
   Py_INCREF(self->pool);
@@ -239,8 +241,8 @@
 }
 
 static PyGetSetDef Getters[] = {
-    {"pool", (getter)GetPool, NULL, "DescriptorPool"},
-    {NULL}
+    {"pool", (getter)GetPool, nullptr, "DescriptorPool"},
+    {nullptr},
 };
 
 }  // namespace message_factory
@@ -252,37 +254,37 @@
     0,                         // tp_itemsize
     message_factory::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
+    nullptr,                   // tp_getattr
+    nullptr,                   // tp_setattr
+    nullptr,                   // tp_compare
+    nullptr,                   // tp_repr
+    nullptr,                   // tp_as_number
+    nullptr,                   // tp_as_sequence
+    nullptr,                   // tp_as_mapping
+    nullptr,                   // tp_hash
+    nullptr,                   // tp_call
+    nullptr,                   // tp_str
+    nullptr,                   // tp_getattro
+    nullptr,                   // tp_setattro
+    nullptr,                   // tp_as_buffer
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
     "A static Message Factory",                                     // tp_doc
     message_factory::GcTraverse,  // tp_traverse
     message_factory::GcClear,     // tp_clear
-    0,                            // tp_richcompare
+    nullptr,                      // tp_richcompare
     0,                            // tp_weaklistoffset
-    0,                            // tp_iter
-    0,                            // tp_iternext
+    nullptr,                      // tp_iter
+    nullptr,                      // tp_iternext
     message_factory::Methods,     // tp_methods
-    0,                            // tp_members
+    nullptr,                      // tp_members
     message_factory::Getters,     // tp_getset
-    0,                            // tp_base
-    0,                            // tp_dict
-    0,                            // tp_descr_get
-    0,                            // tp_descr_set
+    nullptr,                      // tp_base
+    nullptr,                      // tp_dict
+    nullptr,                      // tp_descr_get
+    nullptr,                      // tp_descr_set
     0,                            // tp_dictoffset
-    0,                            // tp_init
-    0,                            // tp_alloc
+    nullptr,                      // tp_init
+    nullptr,                      // tp_alloc
     message_factory::New,         // tp_new
     PyObject_GC_Del,              // tp_free
 };
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
index a0806a3..2d3c1d2 100644
--- a/python/google/protobuf/pyext/message_module.cc
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -94,28 +94,28 @@
      (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, METH_O,
      "Enable/disable oversize proto parsing."},
     // DO NOT USE: For migration and testing only.
-    {NULL, NULL}};
+    {nullptr, nullptr}};
 
 static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
                                      "_message",
                                      module_docstring,
                                      -1,
                                      ModuleMethods, /* m_methods */
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     NULL};
+                                     nullptr,
+                                     nullptr,
+                                     nullptr,
+                                     nullptr};
 
 PyMODINIT_FUNC PyInit__message() {
   PyObject* m;
   m = PyModule_Create(&_module);
-  if (m == NULL) {
-    return NULL;
+  if (m == nullptr) {
+    return nullptr;
   }
 
   if (!google::protobuf::python::InitProto2MessageModule(m)) {
     Py_DECREF(m);
-    return NULL;
+    return nullptr;
   }
 
   // Adds the C++ API
@@ -127,7 +127,7 @@
           })) {
     PyModule_AddObject(m, "proto_API", api);
   } else {
-    return NULL;
+    return nullptr;
   }
 
   return m;
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index 2e8ff4b..0b63f82 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -40,12 +40,12 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message_factory.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
-#include <google/protobuf/reflection.h>
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {
@@ -74,17 +74,15 @@
   if (cmessage::AssureWritable(self->parent) == -1) return nullptr;
   Message* message = self->parent->message;
 
-  Message* sub_message =
-      message->GetReflection()->AddMessage(
-          message,
-          self->parent_field_descriptor,
-          self->child_message_class->py_message_factory->message_factory);
+  Message* sub_message = message->GetReflection()->AddMessage(
+      message, self->parent_field_descriptor,
+      self->child_message_class->py_message_factory->message_factory);
   CMessage* cmsg = self->parent->BuildSubMessageFromPointer(
       self->parent_field_descriptor, sub_message, self->child_message_class);
 
   if (cmessage::InitAttributes(cmsg, args, kwargs) < 0) {
-    message->GetReflection()->RemoveLast(
-        message, self->parent_field_descriptor);
+    message->GetReflection()->RemoveLast(message,
+                                         self->parent_field_descriptor);
     Py_DECREF(cmsg);
     return nullptr;
   }
@@ -108,8 +106,7 @@
   if (py_cmsg == nullptr) return nullptr;
   CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
   if (ScopedPyObjectPtr(cmessage::MergeFrom(cmsg, value)) == nullptr) {
-    reflection->RemoveLast(
-        message, self->parent_field_descriptor);
+    reflection->RemoveLast(message, self->parent_field_descriptor);
     Py_DECREF(cmsg);
     return nullptr;
   }
@@ -152,7 +149,7 @@
   Py_ssize_t end_index = index;
   if (end_index < 0) end_index += length;
   if (end_index < 0) end_index = 0;
-  for (Py_ssize_t i = length; i > end_index; i --) {
+  for (Py_ssize_t i = length; i > end_index; i--) {
     reflection->SwapElements(message, field_descriptor, i, i - 1);
   }
 
@@ -268,8 +265,7 @@
   return Subscript(reinterpret_cast<RepeatedCompositeContainer*>(self), slice);
 }
 
-int AssignSubscript(RepeatedCompositeContainer* self,
-                    PyObject* slice,
+int AssignSubscript(RepeatedCompositeContainer* self, PyObject* slice,
                     PyObject* value) {
   if (value != nullptr) {
     PyErr_SetString(PyExc_TypeError, "does not support assignment");
@@ -368,27 +364,22 @@
   const FieldDescriptor* descriptor = self->parent_field_descriptor;
   const Py_ssize_t length = Length(reinterpret_cast<PyObject*>(self));
 
-  // We need to rearrange things to match python's sort order.  Because there
-  // was already an O(n*log(n)) step in python and a bunch of reflection, we
-  // expect an O(n**2) step in C++ won't hurt too much.
+  // We need to rearrange things to match python's sort order.
+  for (Py_ssize_t i = 0; i < length; ++i) {
+    reflection->UnsafeArenaReleaseLast(message, descriptor);
+  }
   for (Py_ssize_t i = 0; i < length; ++i) {
     Message* child_message =
         reinterpret_cast<CMessage*>(PyList_GET_ITEM(child_list, i))->message;
-    for (Py_ssize_t j = i; j < length; ++j) {
-      if (child_message ==
-          &reflection->GetRepeatedMessage(*message, descriptor, j)) {
-        reflection->SwapElements(message, descriptor, i, j);
-        break;
-      }
-    }
+    reflection->UnsafeArenaAddAllocatedMessage(message, descriptor,
+                                               child_message);
   }
 }
 
 // Returns 0 if successful; returns -1 and sets an exception if
 // unsuccessful.
-static int SortPythonMessages(RepeatedCompositeContainer* self,
-                               PyObject* args,
-                               PyObject* kwds) {
+static int SortPythonMessages(RepeatedCompositeContainer* self, PyObject* args,
+                              PyObject* kwds) {
   ScopedPyObjectPtr child_list(
       PySequence_List(reinterpret_cast<PyObject*>(self)));
   if (child_list == nullptr) {
@@ -486,9 +477,8 @@
 }
 
 // The private constructor of RepeatedCompositeContainer objects.
-RepeatedCompositeContainer *NewContainer(
-    CMessage* parent,
-    const FieldDescriptor* parent_field_descriptor,
+RepeatedCompositeContainer* NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor,
     CMessageClass* child_message_class) {
   if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
     return nullptr;
@@ -525,9 +515,9 @@
 };
 
 static PyMappingMethods MpMethods = {
-  Length,                 /* mp_length */
-  SubscriptMethod,        /* mp_subscript */
-  AssignSubscriptMethod,  /* mp_ass_subscript */
+    Length,                /* mp_length */
+    SubscriptMethod,       /* mp_subscript */
+    AssignSubscriptMethod, /* mp_ass_subscript */
 };
 
 static PyMethodDef Methods[] = {
@@ -555,14 +545,14 @@
 
 PyTypeObject RepeatedCompositeContainer_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
-    ".RepeatedCompositeContainer",              // tp_name
-    sizeof(RepeatedCompositeContainer),         // tp_basicsize
-    0,                                          //  tp_itemsize
-    repeated_composite_container::Dealloc,      //  tp_dealloc
+    ".RepeatedCompositeContainer",          // tp_name
+    sizeof(RepeatedCompositeContainer),     // tp_basicsize
+    0,                                      //  tp_itemsize
+    repeated_composite_container::Dealloc,  //  tp_dealloc
 #if PY_VERSION_HEX >= 0x03080000
-    0,                                          //  tp_vectorcall_offset
+    0,  //  tp_vectorcall_offset
 #else
-    nullptr,                                    //  tp_print
+    nullptr,  //  tp_print
 #endif
     nullptr,                                    //  tp_getattr
     nullptr,                                    //  tp_setattr
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index 4b6d12a..f4a8df2 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -274,6 +274,11 @@
   bool return_list = false;
   if (PyLong_Check(slice)) {
     from = to = PyLong_AsLong(slice);
+  } else if (PyIndex_Check(slice)) {
+    from = to = PyNumber_AsSsize_t(slice, PyExc_ValueError);
+    if (from == -1 && PyErr_Occurred()) {
+      return nullptr;
+    }
   } else if (PySlice_Check(slice)) {
     length = Len(pself);
     if (PySlice_GetIndicesEx(slice, length, &from, &to, &step, &slicelength) ==
diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
index 985df2c..f684152 100644
--- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -48,7 +48,7 @@
  public:
   // Takes the ownership of the specified object to ScopedPythonPtr.
   // The reference count of the specified py_object is not incremented.
-  explicit ScopedPythonPtr(PyObjectStruct* py_object = NULL)
+  explicit ScopedPythonPtr(PyObjectStruct* py_object = nullptr)
       : ptr_(py_object) {}
 
   // If a PyObject is owned, decrement its reference count.
@@ -70,7 +70,7 @@
   // The caller now owns the returned reference.
   PyObjectStruct* release() {
     PyObject* p = ptr_;
-    ptr_ = NULL;
+    ptr_ = nullptr;
     return p;
   }
 
diff --git a/python/google/protobuf/pyext/unknown_fields.cc b/python/google/protobuf/pyext/unknown_fields.cc
index 37e6eae..e632d77 100644
--- a/python/google/protobuf/pyext/unknown_fields.cc
+++ b/python/google/protobuf/pyext/unknown_fields.cc
@@ -50,7 +50,7 @@
 static Py_ssize_t Len(PyObject* pself) {
   PyUnknownFields* self =
       reinterpret_cast<PyUnknownFields*>(pself);
-  if (self->fields == NULL) {
+  if (self->fields == nullptr) {
     PyErr_Format(PyExc_ValueError,
                  "UnknownFields does not exist. "
                  "The parent message might be cleared.");
@@ -65,7 +65,7 @@
        it != self->sub_unknown_fields.end(); it++) {
     Clear(*it);
   }
-  self->fields = NULL;
+  self->fields = nullptr;
   self->sub_unknown_fields.clear();
 }
 
@@ -75,11 +75,11 @@
 static PyObject* Item(PyObject* pself, Py_ssize_t index) {
   PyUnknownFields* self =
       reinterpret_cast<PyUnknownFields*>(pself);
-  if (self->fields == NULL) {
+  if (self->fields == nullptr) {
     PyErr_Format(PyExc_ValueError,
                  "UnknownFields does not exist. "
                  "The parent message might be cleared.");
-    return NULL;
+    return nullptr;
   }
   Py_ssize_t total_size = self->fields->field_count();
   if (index < 0) {
@@ -89,7 +89,7 @@
     PyErr_Format(PyExc_IndexError,
                  "index (%zd) out of range",
                  index);
-    return NULL;
+    return nullptr;
   }
 
   return unknown_fields::NewPyUnknownFieldRef(self, index);
@@ -98,8 +98,8 @@
 PyObject* NewPyUnknownFields(CMessage* c_message) {
   PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
       PyType_GenericAlloc(&PyUnknownFields_Type, 0));
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   // Call "placement new" to initialize PyUnknownFields.
   new (self) PyUnknownFields;
@@ -117,8 +117,8 @@
                                Py_ssize_t index) {
   PyUnknownFieldRef* self = reinterpret_cast<PyUnknownFieldRef*>(
       PyType_GenericAlloc(&PyUnknownFieldRef_Type, 0));
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
 
   Py_INCREF(parent);
@@ -143,53 +143,53 @@
 }
 
 static PySequenceMethods SqMethods = {
-  Len,        /* sq_length */
-  0,          /* sq_concat */
-  0,          /* sq_repeat */
-  Item,       /* sq_item */
-  0,          /* sq_slice */
-  0,          /* sq_ass_item */
+    Len,     /* sq_length */
+    nullptr, /* sq_concat */
+    nullptr, /* sq_repeat */
+    Item,    /* sq_item */
+    nullptr, /* sq_slice */
+    nullptr, /* sq_ass_item */
 };
 
 }  // namespace unknown_fields
 
 PyTypeObject PyUnknownFields_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".PyUnknownFields",  // tp_name
-  sizeof(PyUnknownFields),             // tp_basicsize
-  0,                                   //  tp_itemsize
-  unknown_fields::Dealloc,             //  tp_dealloc
-  0,                                   //  tp_print
-  0,                                   //  tp_getattr
-  0,                                   //  tp_setattr
-  0,                                   //  tp_compare
-  0,                                   //  tp_repr
-  0,                                   //  tp_as_number
-  &unknown_fields::SqMethods,          //  tp_as_sequence
-  0,                                   //  tp_as_mapping
-  PyObject_HashNotImplemented,         //  tp_hash
-  0,                                   //  tp_call
-  0,                                   //  tp_str
-  0,                                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  //  tp_flags
-  "unknown field set",                 //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  0,                                   //  tp_richcompare
-  0,                                   //  tp_weaklistoffset
-  0,                                   //  tp_iter
-  0,                                   //  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
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownFields",           // tp_name
+    sizeof(PyUnknownFields),      // tp_basicsize
+    0,                            //  tp_itemsize
+    unknown_fields::Dealloc,      //  tp_dealloc
+    0,                            //  tp_print
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    nullptr,                      //  tp_repr
+    nullptr,                      //  tp_as_number
+    &unknown_fields::SqMethods,   //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    nullptr,                      //  tp_str
+    nullptr,                      //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           //  tp_flags
+    "unknown field set",          //  tp_doc
+    nullptr,                      //  tp_traverse
+    nullptr,                      //  tp_clear
+    nullptr,                      //  tp_richcompare
+    0,                            //  tp_weaklistoffset
+    nullptr,                      //  tp_iter
+    nullptr,                      //  tp_iternext
+    nullptr,                      //  tp_methods
+    nullptr,                      //  tp_members
+    nullptr,                      //  tp_getset
+    nullptr,                      //  tp_base
+    nullptr,                      //  tp_dict
+    nullptr,                      //  tp_descr_get
+    nullptr,                      //  tp_descr_set
+    0,                            //  tp_dictoffset
+    nullptr,                      //  tp_init
 };
 
 namespace unknown_field {
@@ -197,8 +197,8 @@
     PyUnknownFields* parent, const UnknownFieldSet& fields) {
   PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
       PyType_GenericAlloc(&PyUnknownFields_Type, 0));
-  if (self == NULL) {
-    return NULL;
+  if (self == nullptr) {
+    return nullptr;
   }
   // Call "placement new" to initialize PyUnknownFields.
   new (self) PyUnknownFields;
@@ -213,26 +213,26 @@
 
 const UnknownField* GetUnknownField(PyUnknownFieldRef* self) {
   const UnknownFieldSet* fields = self->parent->fields;
-  if (fields == NULL) {
+  if (fields == nullptr) {
     PyErr_Format(PyExc_ValueError,
                  "UnknownField does not exist. "
                  "The parent message might be cleared.");
-    return NULL;
+    return nullptr;
   }
   Py_ssize_t total_size = fields->field_count();
   if (self->index >= total_size) {
     PyErr_Format(PyExc_ValueError,
                  "UnknownField does not exist. "
                  "The parent message might be cleared.");
-    return NULL;
+    return nullptr;
   }
   return &fields->field(self->index);
 }
 
 static PyObject* GetFieldNumber(PyUnknownFieldRef* self, void *closure) {
   const UnknownField* unknown_field = GetUnknownField(self);
-  if (unknown_field == NULL) {
-    return NULL;
+  if (unknown_field == nullptr) {
+    return nullptr;
   }
   return PyLong_FromLong(unknown_field->number());
 }
@@ -240,8 +240,8 @@
 using internal::WireFormatLite;
 static PyObject* GetWireType(PyUnknownFieldRef* self, void *closure) {
   const UnknownField* unknown_field = GetUnknownField(self);
-  if (unknown_field == NULL) {
-    return NULL;
+  if (unknown_field == nullptr) {
+    return nullptr;
   }
 
   // Assign a default value to suppress may-uninitialized warnings (errors
@@ -269,10 +269,10 @@
 
 static PyObject* GetData(PyUnknownFieldRef* self, void *closure) {
   const UnknownField* field = GetUnknownField(self);
-  if (field == NULL) {
-    return NULL;
+  if (field == nullptr) {
+    return nullptr;
   }
-  PyObject* data = NULL;
+  PyObject* data = nullptr;
   switch (field->type()) {
     case UnknownField::TYPE_VARINT:
       data = PyLong_FromUnsignedLongLong(field->varint());
@@ -302,54 +302,53 @@
 }
 
 static PyGetSetDef Getters[] = {
-  {"field_number", (getter)GetFieldNumber, NULL},
-  {"wire_type", (getter)GetWireType, NULL},
-  {"data", (getter)GetData, NULL},
-  {NULL}
+    {"field_number", (getter)GetFieldNumber, nullptr},
+    {"wire_type", (getter)GetWireType, nullptr},
+    {"data", (getter)GetData, nullptr},
+    {nullptr},
 };
 
 }  // namespace unknown_field
 
 PyTypeObject PyUnknownFieldRef_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".PyUnknownFieldRef",  // tp_name
-  sizeof(PyUnknownFieldRef),           //  tp_basicsize
-  0,                                   //  tp_itemsize
-  unknown_field::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
-  PyObject_HashNotImplemented,         //  tp_hash
-  0,                                   //  tp_call
-  0,                                   //  tp_str
-  0,                                   //  tp_getattro
-  0,                                   //  tp_setattro
-  0,                                   //  tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  //  tp_flags
-  "unknown field",                     //  tp_doc
-  0,                                   //  tp_traverse
-  0,                                   //  tp_clear
-  0,                                   //  tp_richcompare
-  0,                                   //  tp_weaklistoffset
-  0,                                   //  tp_iter
-  0,                                   //  tp_iternext
-  0,                                   //  tp_methods
-  0,                                   //  tp_members
-  unknown_field::Getters,              //  tp_getset
-  0,                                   //  tp_base
-  0,                                   //  tp_dict
-  0,                                   //  tp_descr_get
-  0,                                   //  tp_descr_set
-  0,                                   //  tp_dictoffset
-  0,                                   //  tp_init
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".PyUnknownFieldRef",         // tp_name
+    sizeof(PyUnknownFieldRef),    //  tp_basicsize
+    0,                            //  tp_itemsize
+    unknown_field::Dealloc,       //  tp_dealloc
+    0,                            //  tp_print
+    nullptr,                      //  tp_getattr
+    nullptr,                      //  tp_setattr
+    nullptr,                      //  tp_compare
+    nullptr,                      //  tp_repr
+    nullptr,                      //  tp_as_number
+    nullptr,                      //  tp_as_sequence
+    nullptr,                      //  tp_as_mapping
+    PyObject_HashNotImplemented,  //  tp_hash
+    nullptr,                      //  tp_call
+    nullptr,                      //  tp_str
+    nullptr,                      //  tp_getattro
+    nullptr,                      //  tp_setattro
+    nullptr,                      //  tp_as_buffer
+    Py_TPFLAGS_DEFAULT,           //  tp_flags
+    "unknown field",              //  tp_doc
+    nullptr,                      //  tp_traverse
+    nullptr,                      //  tp_clear
+    nullptr,                      //  tp_richcompare
+    0,                            //  tp_weaklistoffset
+    nullptr,                      //  tp_iter
+    nullptr,                      //  tp_iternext
+    nullptr,                      //  tp_methods
+    nullptr,                      //  tp_members
+    unknown_field::Getters,       //  tp_getset
+    nullptr,                      //  tp_base
+    nullptr,                      //  tp_dict
+    nullptr,                      //  tp_descr_get
+    nullptr,                      //  tp_descr_set
+    0,                            //  tp_dictoffset
+    nullptr,                      //  tp_init
 };
 
-
 }  // namespace python
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/Makefile.am b/src/Makefile.am
index 225061a..d53cf57 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -71,6 +71,7 @@
   google/protobuf/arena.h                                        \
   google/protobuf/arena_impl.h                                   \
   google/protobuf/arenastring.h                                  \
+  google/protobuf/arenaz_sampler.h                               \
   google/protobuf/compiler/code_generator.h                      \
   google/protobuf/compiler/command_line_interface.h              \
   google/protobuf/compiler/cpp/cpp_file.h                        \
@@ -93,6 +94,7 @@
   google/protobuf/compiler/plugin.h                              \
   google/protobuf/compiler/plugin.pb.h                           \
   google/protobuf/compiler/python/python_generator.h             \
+  google/protobuf/compiler/python/python_pyi_generator.h         \
   google/protobuf/compiler/ruby/ruby_generator.h                 \
   google/protobuf/descriptor.h                                   \
   google/protobuf/descriptor.pb.h                                \
@@ -109,11 +111,8 @@
   google/protobuf/generated_enum_util.h                          \
   google/protobuf/generated_message_bases.h                      \
   google/protobuf/generated_message_reflection.h                 \
-  google/protobuf/generated_message_table_driven.h               \
-  google/protobuf/generated_message_table_driven_lite.h          \
   google/protobuf/generated_message_tctable_decl.h               \
   google/protobuf/generated_message_tctable_impl.h               \
-  google/protobuf/generated_message_tctable_impl.inc             \
   google/protobuf/generated_message_util.h                       \
   google/protobuf/has_bits.h                                     \
   google/protobuf/implicit_weak_message.h                        \
@@ -194,9 +193,9 @@
   google/protobuf/any_lite.cc                                  \
   google/protobuf/arena.cc                                     \
   google/protobuf/arenastring.cc                               \
+  google/protobuf/arenaz_sampler.cc                            \
   google/protobuf/extension_set.cc                             \
   google/protobuf/generated_enum_util.cc                       \
-  google/protobuf/generated_message_table_driven_lite.cc       \
   google/protobuf/generated_message_tctable_lite.cc            \
   google/protobuf/generated_message_util.cc                    \
   google/protobuf/implicit_weak_message.cc                     \
@@ -254,7 +253,6 @@
   google/protobuf/field_mask.pb.cc                             \
   google/protobuf/generated_message_bases.cc                   \
   google/protobuf/generated_message_reflection.cc              \
-  google/protobuf/generated_message_table_driven.cc            \
   google/protobuf/generated_message_tctable_full.cc            \
   google/protobuf/io/gzip_stream.cc                            \
   google/protobuf/io/printer.cc                                \
@@ -473,6 +471,9 @@
   google/protobuf/compiler/plugin.cc                           \
   google/protobuf/compiler/plugin.pb.cc                        \
   google/protobuf/compiler/python/python_generator.cc          \
+  google/protobuf/compiler/python/python_helpers.cc            \
+  google/protobuf/compiler/python/python_helpers.h             \
+  google/protobuf/compiler/python/python_pyi_generator.cc      \
   google/protobuf/compiler/ruby/ruby_generator.cc              \
   google/protobuf/compiler/scc.h                               \
   google/protobuf/compiler/subprocess.cc                       \
@@ -738,6 +739,7 @@
   google/protobuf/any_test.cc                                  \
   google/protobuf/arena_unittest.cc                            \
   google/protobuf/arenastring_unittest.cc                      \
+  google/protobuf/arenaz_sampler_test.cc                       \
   google/protobuf/compiler/annotation_test_util.cc             \
   google/protobuf/compiler/annotation_test_util.h              \
   google/protobuf/compiler/command_line_interface_unittest.cc  \
@@ -764,6 +766,7 @@
   google/protobuf/dynamic_message_unittest.cc                  \
   google/protobuf/extension_set_unittest.cc                    \
   google/protobuf/generated_message_reflection_unittest.cc     \
+  google/protobuf/generated_message_tctable_lite_test.cc       \
   google/protobuf/inlined_string_field_unittest.cc             \
   google/protobuf/io/coded_stream_unittest.cc                  \
   google/protobuf/io/io_win32_unittest.cc                      \
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index 73c002f..8d37008 100644
--- a/src/google/protobuf/any.cc
+++ b/src/google/protobuf/any.cc
@@ -35,6 +35,7 @@
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
index e8336fa..d688a0c 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -37,6 +37,7 @@
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/message_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index 52c6ccc..5539413 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -16,25 +16,33 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
+#if defined(__llvm__)
+  #pragma clang diagnostic push
+  #pragma clang diagnostic ignored "-Wuninitialized"
+#endif  // __llvm__
 PROTOBUF_NAMESPACE_OPEN
 constexpr Any::Any(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : type_url_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , value_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , _any_metadata_(&type_url_, &value_){}
 struct AnyDefaultTypeInternal {
   constexpr AnyDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~AnyDefaultTypeInternal() {}
   union {
     Any _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT AnyDefaultTypeInternal _Any_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 AnyDefaultTypeInternal _Any_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fany_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -46,12 +54,12 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, type_url_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, value_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Any)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Any_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Any_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -62,19 +70,21 @@
   "anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownT"
   "ypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fany_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
-  false, false, 212, descriptor_table_protodef_google_2fprotobuf_2fany_2eproto, "google/protobuf/any.proto", 
-  &descriptor_table_google_2fprotobuf_2fany_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fany_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fany_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+    false, false, 212, descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
+    "google/protobuf/any.proto",
+    &descriptor_table_google_2fprotobuf_2fany_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fany_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fany_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -83,14 +93,13 @@
     const ::PROTOBUF_NAMESPACE_ID::Message& message,
     const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
     const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field) {
-  return ::PROTOBUF_NAMESPACE_ID::internal::GetAnyFieldDescriptors(
+  return ::_pbi::GetAnyFieldDescriptors(
       message, type_url_field, value_field);
 }
 bool Any::ParseAnyTypeUrl(
     ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,
     std::string* full_type_name) {
-  return ::PROTOBUF_NAMESPACE_ID::internal::ParseAnyTypeUrl(type_url,
-                                             full_type_name);
+  return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);
 }
 
 class Any::_Internal {
@@ -102,16 +111,13 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   _any_metadata_(&type_url_, &value_) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Any)
 }
 Any::Any(const Any& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _any_metadata_(&type_url_, &value_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  type_url_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -119,7 +125,7 @@
     type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_type_url(), 
       GetArenaForAllocation());
   }
-  value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -131,11 +137,11 @@
 }
 
 inline void Any::SharedCtor() {
-type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+type_url_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -143,9 +149,11 @@
 
 Any::~Any() {
   // @@protoc_insertion_point(destructor:google.protobuf.Any)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Any::SharedDtor() {
@@ -154,12 +162,6 @@
   value_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void Any::ArenaDtor(void* object) {
-  Any* _this = reinterpret_cast< Any* >(object);
-  (void)_this;
-}
-void Any::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Any::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -175,19 +177,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Any::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Any::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string type_url = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_type_url();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Any.type_url"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Any.type_url"));
         } else
           goto handle_unusual;
         continue;
@@ -195,7 +197,7 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
         } else
           goto handle_unusual;
@@ -246,7 +248,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
@@ -335,7 +337,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Any::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fany_2eproto_getter, &descriptor_table_google_2fprotobuf_2fany_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
 }
@@ -343,10 +345,14 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Any* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Any >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Any*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Any >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Any >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
 
 // @@protoc_insertion_point(global_scope)
+#if defined(__llvm__)
+  #pragma clang diagnostic pop
+#endif  // __llvm__
 #include <google/protobuf/port_undef.inc>
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index ff7ef9c..46b2242 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fany_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto;
@@ -205,9 +196,6 @@
   protected:
   explicit Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -319,7 +307,7 @@
   type_url_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), type_url,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (type_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (type_url_.IsDefault()) {
     type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -370,7 +358,7 @@
   value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (value_.IsDefault()) {
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/any_lite.cc b/src/google/protobuf/any_lite.cc
index a98559d..d66a485 100644
--- a/src/google/protobuf/any_lite.cc
+++ b/src/google/protobuf/any_lite.cc
@@ -28,12 +28,11 @@
 // (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/any.h>
-
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 72cc72e..604a231 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -16,9 +16,13 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Api::Api(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : methods_()
   , options_()
   , mixins_()
@@ -29,15 +33,15 @@
 {}
 struct ApiDefaultTypeInternal {
   constexpr ApiDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ApiDefaultTypeInternal() {}
   union {
     Api _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ApiDefaultTypeInternal _Api_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ApiDefaultTypeInternal _Api_default_instance_;
 constexpr Method::Method(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : options_()
   , name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , request_type_url_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -48,30 +52,30 @@
 {}
 struct MethodDefaultTypeInternal {
   constexpr MethodDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~MethodDefaultTypeInternal() {}
   union {
     Method _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT MethodDefaultTypeInternal _Method_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDefaultTypeInternal _Method_default_instance_;
 constexpr Mixin::Mixin(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , root_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){}
 struct MixinDefaultTypeInternal {
   constexpr MixinDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~MixinDefaultTypeInternal() {}
   union {
     Mixin _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT MixinDefaultTypeInternal _Mixin_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MixinDefaultTypeInternal _Mixin_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fapi_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -109,16 +113,16 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, name_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Mixin, root_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Api)},
   { 13, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Method)},
   { 26, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Mixin)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Api_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Method_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Mixin_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Api_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Method_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Mixin_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -142,23 +146,25 @@
   "otobuf/types/known/apipb\242\002\003GPB\252\002\036Google."
   "Protobuf.WellKnownTypesb\006proto3"
   ;
-static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_google_2fprotobuf_2fapi_2eproto_deps[2] = {
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2fapi_2eproto_deps[2] = {
   &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
   &::descriptor_table_google_2fprotobuf_2ftype_2eproto,
 };
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fapi_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
-  false, false, 751, descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto, "google/protobuf/api.proto", 
-  &descriptor_table_google_2fprotobuf_2fapi_2eproto_once, descriptor_table_google_2fprotobuf_2fapi_2eproto_deps, 2, 3,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fapi_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fapi_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fapi_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+    false, false, 751, descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
+    "google/protobuf/api.proto",
+    &descriptor_table_google_2fprotobuf_2fapi_2eproto_once, descriptor_table_google_2fprotobuf_2fapi_2eproto_deps, 2, 3,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fapi_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fapi_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fapi_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fapi_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fapi_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fapi_2eproto(&descriptor_table_google_2fprotobuf_2fapi_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fapi_2eproto(&descriptor_table_google_2fprotobuf_2fapi_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -188,9 +194,6 @@
   options_(arena),
   mixins_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Api)
 }
 Api::Api(const Api& from)
@@ -199,7 +202,7 @@
       options_(from.options_),
       mixins_(from.mixins_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -207,7 +210,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  version_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  version_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -225,11 +228,11 @@
 }
 
 inline void Api::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-version_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+version_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -241,9 +244,11 @@
 
 Api::~Api() {
   // @@protoc_insertion_point(destructor:google.protobuf.Api)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Api::SharedDtor() {
@@ -253,12 +258,6 @@
   if (this != internal_default_instance()) delete source_context_;
 }
 
-void Api::ArenaDtor(void* object) {
-  Api* _this = reinterpret_cast< Api* >(object);
-  (void)_this;
-}
-void Api::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Api::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -282,19 +281,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Api::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Api.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.name"));
         } else
           goto handle_unusual;
         continue;
@@ -328,9 +327,9 @@
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_version();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Api.version"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Api.version"));
         } else
           goto handle_unusual;
         continue;
@@ -404,19 +403,19 @@
   }
 
   // repeated .google.protobuf.Method methods = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_methods_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_methods_size()); i < n; i++) {
+    const auto& repfield = this->_internal_methods(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_methods(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(3, this->_internal_options(i), target, stream);
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // string version = 4;
@@ -431,29 +430,28 @@
 
   // .google.protobuf.SourceContext source_context = 5;
   if (this->_internal_has_source_context()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        5, _Internal::source_context(this), target, stream);
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.Mixin mixins = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_mixins_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_mixins_size()); i < n; i++) {
+    const auto& repfield = this->_internal_mixins(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(6, this->_internal_mixins(i), target, stream);
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 7;
   if (this->_internal_syntax() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       7, this->_internal_syntax(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api)
@@ -513,7 +511,7 @@
   // .google.protobuf.Syntax syntax = 7;
   if (this->_internal_syntax() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -594,7 +592,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Api::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fapi_2eproto[0]);
 }
@@ -613,16 +611,13 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   options_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Method)
 }
 Method::Method(const Method& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       options_(from.options_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -630,7 +625,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  request_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  request_type_url_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -638,7 +633,7 @@
     request_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_request_type_url(), 
       GetArenaForAllocation());
   }
-  response_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  response_type_url_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -653,15 +648,15 @@
 }
 
 inline void Method::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-request_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+request_type_url_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-response_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+response_type_url_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -673,9 +668,11 @@
 
 Method::~Method() {
   // @@protoc_insertion_point(destructor:google.protobuf.Method)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Method::SharedDtor() {
@@ -685,12 +682,6 @@
   response_type_url_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void Method::ArenaDtor(void* object) {
-  Method* _this = reinterpret_cast< Method* >(object);
-  (void)_this;
-}
-void Method::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Method::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -711,19 +702,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Method::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Method::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.name"));
         } else
           goto handle_unusual;
         continue;
@@ -731,9 +722,9 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_request_type_url();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.request_type_url"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.request_type_url"));
         } else
           goto handle_unusual;
         continue;
@@ -749,9 +740,9 @@
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_response_type_url();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Method.response_type_url"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Method.response_type_url"));
         } else
           goto handle_unusual;
         continue;
@@ -837,7 +828,7 @@
   // bool request_streaming = 3;
   if (this->_internal_request_streaming() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->_internal_request_streaming(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_request_streaming(), target);
   }
 
   // string response_type_url = 4;
@@ -853,26 +844,26 @@
   // bool response_streaming = 5;
   if (this->_internal_response_streaming() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->_internal_response_streaming(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_response_streaming(), target);
   }
 
   // repeated .google.protobuf.Option options = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(6, this->_internal_options(i), target, stream);
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 7;
   if (this->_internal_syntax() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       7, this->_internal_syntax(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method)
@@ -928,7 +919,7 @@
   // .google.protobuf.Syntax syntax = 7;
   if (this->_internal_syntax() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -1016,7 +1007,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Method::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fapi_2eproto[1]);
 }
@@ -1031,15 +1022,12 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Mixin)
 }
 Mixin::Mixin(const Mixin& from)
   : ::PROTOBUF_NAMESPACE_ID::Message() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1047,7 +1035,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  root_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  root_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1059,11 +1047,11 @@
 }
 
 inline void Mixin::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-root_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+root_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1071,9 +1059,11 @@
 
 Mixin::~Mixin() {
   // @@protoc_insertion_point(destructor:google.protobuf.Mixin)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Mixin::SharedDtor() {
@@ -1082,12 +1072,6 @@
   root_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void Mixin::ArenaDtor(void* object) {
-  Mixin* _this = reinterpret_cast< Mixin* >(object);
-  (void)_this;
-}
-void Mixin::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Mixin::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1103,19 +1087,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Mixin::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Mixin::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Mixin.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.name"));
         } else
           goto handle_unusual;
         continue;
@@ -1123,9 +1107,9 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_root();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Mixin.root"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Mixin.root"));
         } else
           goto handle_unusual;
         continue;
@@ -1179,7 +1163,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin)
@@ -1268,7 +1252,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Mixin::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fapi_2eproto_getter, &descriptor_table_google_2fprotobuf_2fapi_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fapi_2eproto[2]);
 }
@@ -1276,13 +1260,16 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Api* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Api >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Api*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Api >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Api >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Method* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Method >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Method*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Method >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Method >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Mixin* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Mixin >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Mixin*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Mixin >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Mixin >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 093a02e..02fe43b 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -44,14 +43,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fapi_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[3]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto;
@@ -182,9 +173,6 @@
   protected:
   explicit Api(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -440,9 +428,6 @@
   protected:
   explicit Method(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -676,9 +661,6 @@
   protected:
   explicit Mixin(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -789,7 +771,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -917,7 +899,7 @@
   version_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), version,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (version_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (version_.IsDefault()) {
     version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1118,7 +1100,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1169,7 +1151,7 @@
   request_type_url_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), request_type_url,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (request_type_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (request_type_url_.IsDefault()) {
     request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1240,7 +1222,7 @@
   response_type_url_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), response_type_url,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (response_type_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (response_type_url_.IsDefault()) {
     response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1372,7 +1354,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1423,7 +1405,7 @@
   root_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), root,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (root_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (root_.IsDefault()) {
     root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 7624e0b..6ba508a 100644
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -38,12 +38,15 @@
 #include <typeinfo>
 
 #include <google/protobuf/arena_impl.h>
+#include <google/protobuf/arenaz_sampler.h>
+#include <google/protobuf/port.h>
 
 #include <google/protobuf/stubs/mutex.h>
 #ifdef ADDRESS_SANITIZER
 #include <sanitizer/asan_interface.h>
 #endif  // ADDRESS_SANITIZER
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -91,11 +94,7 @@
     if (dealloc_) {
       dealloc_(mem.ptr, mem.size);
     } else {
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
-      ::operator delete(mem.ptr, mem.size);
-#else
-      ::operator delete(mem.ptr);
-#endif
+      internal::SizedDelete(mem.ptr, mem.size);
     }
     *space_allocated_ += mem.size;
   }
@@ -105,18 +104,22 @@
   size_t* space_allocated_;
 };
 
-SerialArena::SerialArena(Block* b, void* owner) : space_allocated_(b->size) {
+SerialArena::SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats)
+    : space_allocated_(b->size) {
   owner_ = owner;
   head_ = b;
   ptr_ = b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize);
   limit_ = b->Pointer(b->size & static_cast<size_t>(-8));
+  arena_stats_ = stats;
 }
 
-SerialArena* SerialArena::New(Memory mem, void* owner) {
+SerialArena* SerialArena::New(Memory mem, void* owner,
+                              ThreadSafeArenaStats* stats) {
   GOOGLE_DCHECK_LE(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize, mem.size);
-
+  ThreadSafeArenaStats::RecordAllocateStats(
+      stats, /*requested=*/mem.size, /*allocated=*/mem.size, /*wasted=*/0);
   auto b = new (mem.ptr) Block{nullptr, mem.size};
-  return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, owner);
+  return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, owner, stats);
 }
 
 template <typename Deallocator>
@@ -151,7 +154,14 @@
   head_->start = reinterpret_cast<CleanupNode*>(limit_);
 
   // Record how much used in this block.
-  space_used_ += ptr_ - head_->Pointer(kBlockHeaderSize);
+  size_t used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  size_t wasted = head_->size - used;
+  space_used_ += used;
+
+  // TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
+  // win. In preliminary testing showed increased memory savings as expected,
+  // but with a CPU regression. The regression might have been an artifact of
+  // the microbenchmark.
 
   auto mem = AllocateMemory(policy, head_->size, n);
   // We don't want to emit an expensive RMW instruction that requires
@@ -159,6 +169,8 @@
   // regular add.
   auto relaxed = std::memory_order_relaxed;
   space_allocated_.store(space_allocated_.load(relaxed) + mem.size, relaxed);
+  ThreadSafeArenaStats::RecordAllocateStats(arena_stats_, /*requested=*/n,
+                                            /*allocated=*/mem.size, wasted);
   head_ = new (mem.ptr) Block{head_, mem.size};
   ptr_ = head_->Pointer(kBlockHeaderSize);
   limit_ = head_->Pointer(head_->size);
@@ -312,10 +324,12 @@
 #ifndef NDEBUG
   GOOGLE_CHECK_EQ(was_message_owned, IsMessageOwned());
 #endif  // NDEBUG
+  arena_stats_ = Sample();
 }
 
 void ThreadSafeArena::SetInitialBlock(void* mem, size_t size) {
-  SerialArena* serial = SerialArena::New({mem, size}, &thread_cache());
+  SerialArena* serial = SerialArena::New({mem, size}, &thread_cache(),
+                                         arena_stats_.MutableStats());
   serial->set_next(NULL);
   threads_.store(serial, std::memory_order_relaxed);
   CacheSerialArena(serial);
@@ -334,6 +348,10 @@
   ArenaMetricsCollector* collector = p ? p->metrics_collector : nullptr;
 
   if (alloc_policy_.is_user_owned_initial_block()) {
+#ifdef ADDRESS_SANITIZER
+    // Unpoison the initial block, now that it's going back to the user.
+    ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
+#endif  // ADDRESS_SANITIZER
     space_allocated += mem.size;
   } else {
     GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
@@ -360,6 +378,7 @@
   // Discard all blocks except the special block (if present).
   size_t space_allocated = 0;
   auto mem = Free(&space_allocated);
+  arena_stats_.RecordReset();
 
   AllocationPolicy* policy = alloc_policy_.get();
   if (policy) {
@@ -474,7 +493,8 @@
     // This thread doesn't have any SerialArena, which also means it doesn't
     // have any blocks yet.  So we'll allocate its first block now.
     serial = SerialArena::New(
-        AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), me);
+        AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), me,
+        arena_stats_.MutableStats());
 
     SerialArena* head = threads_.load(std::memory_order_relaxed);
     do {
@@ -500,6 +520,12 @@
 }
 
 PROTOBUF_FUNC_ALIGN(32)
+void* Arena::AllocateAlignedWithHookForArray(size_t n,
+                                             const std::type_info* type) {
+  return impl_.AllocateAligned<internal::AllocationClient::kArray>(n, type);
+}
+
+PROTOBUF_FUNC_ALIGN(32)
 std::pair<void*, internal::SerialArena::CleanupNode*>
 Arena::AllocateAlignedWithCleanup(size_t n, const std::type_info* type) {
   return impl_.AllocateAlignedWithCleanup(n, type);
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 785f273..1261dd8 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -52,6 +52,7 @@
 #include <google/protobuf/arena_impl.h>
 #include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -80,10 +81,11 @@
 
 namespace internal {
 
-struct ArenaStringPtr;  // defined in arenastring.h
-class InlinedStringField;  // defined in inlined_string_field.h
-class LazyField;        // defined in lazy_field.h
-class EpsCopyInputStream;  // defined in parse_context.h
+struct ArenaTestPeer;        // defined in arena_test_util.h
+class InternalMetadata;      // defined in metadata_lite.h
+class LazyField;             // defined in lazy_field.h
+class EpsCopyInputStream;    // defined in parse_context.h
+class RepeatedPtrFieldBase;  // defined in repeated_ptr_field.h
 
 template <typename Type>
 class GenericTypeHandler;  // defined in repeated_field.h
@@ -313,6 +315,20 @@
                              static_cast<Args&&>(args)...);
   }
 
+  // Allocates memory with the specific size and alignment.
+  void* AllocateAligned(size_t size, size_t align = 8) {
+    if (align <= 8) {
+      return AllocateAlignedNoHook(internal::AlignUpTo8(size));
+    } else {
+      // We are wasting space by over allocating align - 8 bytes. Compared
+      // to a dedicated function that takes current alignment in consideration.
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
+      // requires a dedicated function in the outline arena allocation
+      // functions. Possibly re-evaluate tradeoffs later.
+      return internal::AlignTo(AllocateAlignedNoHook(size + align - 8), align);
+    }
+  }
+
   // Create an array of object type T on the arena *without* invoking the
   // constructor of T. If `arena` is null, then the return value should be freed
   // with `delete[] x;` (or `::operator delete[](x);`).
@@ -529,6 +545,10 @@
     return impl_.IsMessageOwned();
   }
 
+  void ReturnArrayMemory(void* p, size_t size) {
+    impl_.ReturnArrayMemory(p, size);
+  }
+
   template <typename T, typename... Args>
   PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena,
                                                          Args&&... args) {
@@ -619,7 +639,7 @@
     // 8 AlignUpTo can be elided.
     const size_t n = sizeof(T) * num_elements;
     return static_cast<T*>(
-        AllocateAlignedWithHook(n, alignof(T), RTTI_TYPE_ID(T)));
+        AllocateAlignedWithHookForArray(n, alignof(T), RTTI_TYPE_ID(T)));
   }
 
   template <typename T, typename... Args>
@@ -762,17 +782,18 @@
     return nullptr;
   }
 
-  // For friends of arena.
-  void* AllocateAligned(size_t n, size_t align = 8) {
+  void* AllocateAlignedWithHookForArray(size_t n, size_t align,
+                                        const std::type_info* type) {
     if (align <= 8) {
-      return AllocateAlignedNoHook(internal::AlignUpTo8(n));
+      return AllocateAlignedWithHookForArray(internal::AlignUpTo8(n), type);
     } else {
       // We are wasting space by over allocating align - 8 bytes. Compared
       // to a dedicated function that takes current alignment in consideration.
       // Such a scheme would only waste (align - 8)/2 bytes on average, but
       // requires a dedicated function in the outline arena allocation
       // functions. Possibly re-evaluate tradeoffs later.
-      return internal::AlignTo(AllocateAlignedNoHook(n + align - 8), align);
+      return internal::AlignTo(
+          AllocateAlignedWithHookForArray(n + align - 8, type), align);
     }
   }
 
@@ -783,7 +804,7 @@
     } else {
       // We are wasting space by over allocating align - 8 bytes. Compared
       // to a dedicated function that takes current alignment in consideration.
-      // Such a schemee would only waste (align - 8)/2 bytes on average, but
+      // Such a scheme would only waste (align - 8)/2 bytes on average, but
       // requires a dedicated function in the outline arena allocation
       // functions. Possibly re-evaluate tradeoffs later.
       return internal::AlignTo(AllocateAlignedWithHook(n + align - 8, type),
@@ -793,18 +814,22 @@
 
   void* AllocateAlignedNoHook(size_t n);
   void* AllocateAlignedWithHook(size_t n, const std::type_info* type);
+  void* AllocateAlignedWithHookForArray(size_t n, const std::type_info* type);
   std::pair<void*, internal::SerialArena::CleanupNode*>
   AllocateAlignedWithCleanup(size_t n, const std::type_info* type);
 
   template <typename Type>
   friend class internal::GenericTypeHandler;
-  friend struct internal::ArenaStringPtr;  // For AllocateAligned.
-  friend class internal::InlinedStringField;  // For AllocateAligned.
+  friend class internal::InternalMetadata;  // For user_arena().
   friend class internal::LazyField;        // For CreateMaybeMessage.
   friend class internal::EpsCopyInputStream;  // For parser performance
   friend class MessageLite;
   template <typename Key, typename T>
   friend class Map;
+  template <typename>
+  friend class RepeatedField;                   // For ReturnArrayMemory
+  friend class internal::RepeatedPtrFieldBase;  // For ReturnArrayMemory
+  friend struct internal::ArenaTestPeer;
 };
 
 // Defined above for supporting environments without RTTI.
diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h
index 2ffac31..d02ad93 100644
--- a/src/google/protobuf/arena_impl.h
+++ b/src/google/protobuf/arena_impl.h
@@ -39,11 +39,15 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/port.h>
 
 #ifdef ADDRESS_SANITIZER
 #include <sanitizer/asan_interface.h>
 #endif  // ADDRESS_SANITIZER
 
+#include <google/protobuf/arenaz_sampler.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 
@@ -177,6 +181,8 @@
   uintptr_t policy_;
 };
 
+enum class AllocationClient { kDefault, kArray };
+
 // A simple arena allocator. Calls to allocate functions must be properly
 // serialized by the caller, hence this class cannot be used as a general
 // purpose allocator in a multi-threaded program. It serves as a building block
@@ -208,11 +214,47 @@
   }
   uint64_t SpaceUsed() const;
 
-  bool HasSpace(size_t n) { return n <= static_cast<size_t>(limit_ - ptr_); }
+  bool HasSpace(size_t n) const {
+    return n <= static_cast<size_t>(limit_ - ptr_);
+  }
 
+  // See comments on `cached_blocks_` member for details.
+  PROTOBUF_ALWAYS_INLINE void* TryAllocateFromCachedBlock(size_t size) {
+    if (PROTOBUF_PREDICT_FALSE(size < 16)) return nullptr;
+    // We round up to the next larger block in case the memory doesn't match
+    // the pattern we are looking for.
+    const size_t index = Bits::Log2FloorNonZero64(size - 1) - 3;
+
+    if (index >= cached_block_length_) return nullptr;
+    auto& cached_head = cached_blocks_[index];
+    if (cached_head == nullptr) return nullptr;
+
+    void* ret = cached_head;
+#ifdef ADDRESS_SANITIZER
+    ASAN_UNPOISON_MEMORY_REGION(ret, size);
+#endif  // ADDRESS_SANITIZER
+    cached_head = cached_head->next;
+    return ret;
+  }
+
+  // In kArray mode we look through cached blocks.
+  // We do not do this by default because most non-array allocations will not
+  // have the right size and will fail to find an appropriate cached block.
+  //
+  // TODO(sbenza): Evaluate if we should use cached blocks for message types of
+  // the right size. We can statically know if the allocation size can benefit
+  // from it.
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
   void* AllocateAligned(size_t n, const AllocationPolicy* policy) {
     GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
     GOOGLE_DCHECK_GE(limit_, ptr_);
+
+    if (alloc_client == AllocationClient::kArray) {
+      if (void* res = TryAllocateFromCachedBlock(n)) {
+        return res;
+      }
+    }
+
     if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
       return AllocateAlignedFallback(n, policy);
     }
@@ -229,6 +271,50 @@
     return ret;
   }
 
+  // See comments on `cached_blocks_` member for details.
+  void ReturnArrayMemory(void* p, size_t size) {
+    // We only need to check for 32-bit platforms.
+    // In 64-bit platforms the minimum allocation size from Repeated*Field will
+    // be 16 guaranteed.
+    if (sizeof(void*) < 8) {
+      if (PROTOBUF_PREDICT_FALSE(size < 16)) return;
+    } else {
+      GOOGLE_DCHECK(size >= 16);
+    }
+
+    // We round down to the next smaller block in case the memory doesn't match
+    // the pattern we are looking for. eg, someone might have called Reserve()
+    // on the repeated field.
+    const size_t index = Bits::Log2FloorNonZero64(size) - 4;
+
+    if (PROTOBUF_PREDICT_FALSE(index >= cached_block_length_)) {
+      // We can't put this object on the freelist so make this object the
+      // freelist. It is guaranteed it is larger than the one we have, and
+      // large enough to hold another allocation of `size`.
+      CachedBlock** new_list = static_cast<CachedBlock**>(p);
+      size_t new_size = size / sizeof(CachedBlock*);
+
+      std::copy(cached_blocks_, cached_blocks_ + cached_block_length_,
+                new_list);
+      std::fill(new_list + cached_block_length_, new_list + new_size, nullptr);
+      cached_blocks_ = new_list;
+      // Make the size fit in uint8_t. This is the power of two, so we don't
+      // need anything larger.
+      cached_block_length_ =
+          static_cast<uint8_t>(std::min(size_t{64}, new_size));
+
+      return;
+    }
+
+    auto& cached_head = cached_blocks_[index];
+    auto* new_node = static_cast<CachedBlock*>(p);
+    new_node->next = cached_head;
+    cached_head = new_node;
+#ifdef ADDRESS_SANITIZER
+    ASAN_POISON_MEMORY_REGION(p, size);
+#endif  // ADDRESS_SANITIZER
+  }
+
  public:
   // Allocate space if the current region provides enough space.
   bool MaybeAllocateAligned(size_t n, void** out) {
@@ -279,7 +365,8 @@
 
   // Creates a new SerialArena inside mem using the remaining memory as for
   // future allocations.
-  static SerialArena* New(SerialArena::Memory mem, void* owner);
+  static SerialArena* New(SerialArena::Memory mem, void* owner,
+                          ThreadSafeArenaStats* stats);
   // Free SerialArena returning the memory passed in to New
   template <typename Deallocator>
   Memory Free(Deallocator deallocator);
@@ -310,10 +397,28 @@
   // head_ (and head_->pos will always be non-canonical).  We keep these
   // here to reduce indirection.
   char* ptr_;
+  // Limiting address up to which memory can be allocated from the head block.
   char* limit_;
+  // For holding sampling information.  The pointer is owned by the
+  // ThreadSafeArena that holds this serial arena.
+  ThreadSafeArenaStats* arena_stats_;
+
+  // Repeated*Field and Arena play together to reduce memory consumption by
+  // reusing blocks. Currently, natural growth of the repeated field types makes
+  // them allocate blocks of size `8 + 2^N, N>=3`.
+  // When the repeated field grows returns the previous block and we put it in
+  // this free list.
+  // `cached_blocks_[i]` points to the free list for blocks of size `8+2^(i+3)`.
+  // The array of freelists is grown when needed in `ReturnArrayMemory()`.
+  struct CachedBlock {
+    // Simple linked list.
+    CachedBlock* next;
+  };
+  uint8_t cached_block_length_ = 0;
+  CachedBlock** cached_blocks_ = nullptr;
 
   // Constructor is private as only New() should be used.
-  inline SerialArena(Block* b, void* owner);
+  inline SerialArena(Block* b, void* owner, ThreadSafeArenaStats* stats);
   void* AllocateAlignedFallback(size_t n, const AllocationPolicy* policy);
   std::pair<void*, CleanupNode*> AllocateAlignedWithCleanupFallback(
       size_t n, const AllocationPolicy* policy);
@@ -368,16 +473,24 @@
   uint64_t SpaceAllocated() const;
   uint64_t SpaceUsed() const;
 
+  template <AllocationClient alloc_client = AllocationClient::kDefault>
   void* AllocateAligned(size_t n, const std::type_info* type) {
     SerialArena* arena;
     if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
                               GetSerialArenaFast(&arena))) {
-      return arena->AllocateAligned(n, AllocPolicy());
+      return arena->AllocateAligned<alloc_client>(n, AllocPolicy());
     } else {
       return AllocateAlignedFallback(n, type);
     }
   }
 
+  void ReturnArrayMemory(void* p, size_t size) {
+    SerialArena* arena;
+    if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+      arena->ReturnArrayMemory(p, size);
+    }
+  }
+
   // This function allocates n bytes if the common happy case is true and
   // returns true. Otherwise does nothing and returns false. This strange
   // semantics is necessary to allow callers to program functions that only
@@ -411,6 +524,8 @@
 
   TaggedAllocationPolicyPtr alloc_policy_;  // Tagged pointer to AllocPolicy.
 
+  static_assert(std::is_trivially_destructible<SerialArena>{},
+                "SerialArena needs to be trivially destructible.");
   // Pointer to a linked list of SerialArena.
   std::atomic<SerialArena*> threads_;
   std::atomic<SerialArena*> hint_;  // Fast thread-local block access
@@ -535,6 +650,8 @@
   static ThreadCache& thread_cache() { return thread_cache_; }
 #endif
 
+  ThreadSafeArenaStatsHandle arena_stats_;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeArena);
   // All protos have pointers back to the arena hence Arena must have
   // pointer stability.
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
index 33f5cf4..7286769 100644
--- a/src/google/protobuf/arena_test_util.h
+++ b/src/google/protobuf/arena_test_util.h
@@ -76,6 +76,12 @@
 
 namespace internal {
 
+struct ArenaTestPeer {
+  static void ReturnArrayMemory(Arena* arena, void* p, size_t size) {
+    arena->ReturnArrayMemory(p, size);
+  }
+};
+
 class NoHeapChecker {
  public:
   NoHeapChecker() { capture_alloc.Hook(); }
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 76d9126..0a38352 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -47,6 +47,9 @@
 #include <google/protobuf/unittest_arena.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/message.h>
@@ -54,14 +57,13 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <gtest/gtest.h>
-#include <google/protobuf/stubs/strutil.h>
 
 
 // Must be included last
 #include <google/protobuf/port_def.inc>
 
 using proto2_arena_unittest::ArenaMessage;
+using protobuf_unittest::ForeignMessage;
 using protobuf_unittest::TestAllExtensions;
 using protobuf_unittest::TestAllTypes;
 using protobuf_unittest::TestEmptyMessage;
@@ -542,6 +544,18 @@
   TestUtil::ExpectAllFieldsSet(*message2);
 }
 
+TEST(ArenaTest, GetOwningArena) {
+  Arena arena;
+  auto* m1 = Arena::CreateMessage<TestAllTypes>(&arena);
+  EXPECT_EQ(Arena::InternalHelper<TestAllTypes>::GetOwningArena(m1), &arena);
+  EXPECT_EQ(
+      &arena,
+      Arena::InternalHelper<RepeatedPtrField<ForeignMessage>>::GetOwningArena(
+          m1->mutable_repeated_foreign_message()));
+  EXPECT_EQ(&arena, Arena::InternalHelper<RepeatedField<int>>::GetOwningArena(
+                        m1->mutable_repeated_int32()));
+}
+
 TEST(ArenaTest, SwapBetweenArenasUsingReflection) {
   Arena arena1;
   TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1);
@@ -1465,6 +1479,71 @@
   }
 }
 
+TEST(ArenaTest, SpaceReuseForArraysSizeChecks) {
+  // Limit to 1<<20 to avoid using too much memory on the test.
+  for (int i = 0; i < 20; ++i) {
+    SCOPED_TRACE(i);
+    Arena arena;
+    std::vector<void*> pointers;
+
+    const size_t size = 16 << i;
+
+    for (int j = 0; j < 10; ++j) {
+      pointers.push_back(Arena::CreateArray<char>(&arena, size));
+    }
+
+    for (void* p : pointers) {
+      internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, size);
+    }
+
+    std::vector<void*> second_pointers;
+    for (int j = 9; j != 0; --j) {
+      second_pointers.push_back(Arena::CreateArray<char>(&arena, size));
+    }
+
+    // The arena will give us back the pointers we returned, except the first
+    // one. That one becomes part of the freelist data structure.
+    ASSERT_THAT(second_pointers,
+                testing::UnorderedElementsAreArray(
+                    std::vector<void*>(pointers.begin() + 1, pointers.end())));
+  }
+}
+
+TEST(ArenaTest, SpaceReusePoisonsAndUnpoisonsMemory) {
+#ifdef ADDRESS_SANITIZER
+  char buf[1024]{};
+  {
+    Arena arena(buf, sizeof(buf));
+    std::vector<void*> pointers;
+    for (int i = 0; i < 100; ++i) {
+      pointers.push_back(Arena::CreateArray<char>(&arena, 16));
+    }
+    for (void* p : pointers) {
+      internal::ArenaTestPeer::ReturnArrayMemory(&arena, p, 16);
+      // The first one is not poisoned because it becomes the freelist.
+      if (p != pointers[0]) EXPECT_TRUE(__asan_address_is_poisoned(p));
+    }
+
+    bool found_poison = false;
+    for (char& c : buf) {
+      if (__asan_address_is_poisoned(&c)) {
+        found_poison = true;
+        break;
+      }
+    }
+    EXPECT_TRUE(found_poison);
+  }
+
+  // Should not be poisoned after destruction.
+  for (char& c : buf) {
+    ASSERT_FALSE(__asan_address_is_poisoned(&c));
+  }
+
+#else   // ADDRESS_SANITIZER
+  GTEST_SKIP();
+#endif  // ADDRESS_SANITIZER
+}
+
 namespace {
 uint32_t hooks_num_init = 0;
 uint32_t hooks_num_allocations = 0;
diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc
index 169f527..c70abf7 100644
--- a/src/google/protobuf/arenastring.cc
+++ b/src/google/protobuf/arenastring.cc
@@ -30,13 +30,14 @@
 
 #include <google/protobuf/arenastring.h>
 
+#include <cstddef>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 // clang-format off
@@ -47,6 +48,27 @@
 namespace protobuf {
 namespace internal {
 
+namespace  {
+
+// Enforce that allocated data aligns to at least 8 bytes, and that
+// the alignment of the global const string value does as well.
+// The alignment guaranteed by `new std::string` depends on both:
+// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
+// - alignof(std::string)
+#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
+constexpr size_t kNewAlign = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
+constexpr size_t kNewAlign = alignof(::max_align_t);
+#else
+constexpr size_t kNewAlign = alignof(std::max_align_t);
+#endif
+constexpr size_t kStringAlign = alignof(std::string);
+
+static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 8, "");
+static_assert(alignof(ExplicitlyConstructedArenaString) >= 8, "");
+
+}  // namespace
+
 const std::string& LazyString::Init() const {
   static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
   mu.Lock();
@@ -61,38 +83,61 @@
   return *res;
 }
 
+namespace {
+
+
+// Creates a heap allocated std::string value.
+inline TaggedPtr<std::string> CreateString(ConstStringParam value) {
+  TaggedPtr<std::string> res;
+  res.SetAllocated(new std::string(value.data(), value.length()));
+  return res;
+}
+
+#if !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+// Creates an arena allocated std::string value.
+TaggedPtr<std::string> CreateArenaString(Arena& arena, ConstStringParam s) {
+  TaggedPtr<std::string> res;
+  res.SetMutableArena(Arena::Create<std::string>(&arena, s.data(), s.length()));
+  return res;
+}
+
+#endif  // !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
+
+}  // namespace
 
 std::string* ArenaStringPtr::SetAndReturnNewString() {
   std::string* new_string = new std::string();
-  tagged_ptr_.Set(new_string);
+  tagged_ptr_.SetAllocated(new_string);
   return new_string;
 }
 
-void ArenaStringPtr::DestroyNoArenaSlowPath() { delete UnsafeMutablePointer(); }
+void ArenaStringPtr::DestroyNoArenaSlowPath() {
+  GOOGLE_DCHECK(tagged_ptr_.IsAllocated());
+  delete UnsafeMutablePointer();
+}
 
-void ArenaStringPtr::Set(const std::string* default_value,
-                         ConstStringParam value, ::google::protobuf::Arena* arena) {
-  if (IsDefault(default_value)) {
-    tagged_ptr_.Set(Arena::Create<std::string>(arena, value));
+void ArenaStringPtr::Set(const std::string*, ConstStringParam value,
+                         ::google::protobuf::Arena* arena) {
+  if (IsDefault()) {
+    // If we're not on an arena, skip straight to a true string to avoid
+    // possible copy cost later.
+    tagged_ptr_ = arena != nullptr ? CreateArenaString(*arena, value)
+                                   : CreateString(value);
   } else {
     UnsafeMutablePointer()->assign(value.data(), value.length());
   }
 }
-
-void ArenaStringPtr::Set(const std::string* default_value, std::string&& value,
+void ArenaStringPtr::Set(const std::string*, std::string&& value,
                          ::google::protobuf::Arena* arena) {
-  if (IsDefault(default_value)) {
-    if (arena == nullptr) {
-      tagged_ptr_.Set(new std::string(std::move(value)));
-    } else {
-      tagged_ptr_.Set(Arena::Create<std::string>(arena, std::move(value)));
-    }
-  } else if (IsDonatedString()) {
+  if (IsDefault()) {
+    NewString(arena, std::move(value));
+  } else if (IsFixedSizeArena()) {
     std::string* current = tagged_ptr_.Get();
     auto* s = new (current) std::string(std::move(value));
     arena->OwnDestructor(s);
-    tagged_ptr_.Set(s);
-  } else /* !IsDonatedString() */ {
+    tagged_ptr_.SetMutableArena(s);
+  } else /* !IsFixedSizeArena() */ {
     *UnsafeMutablePointer() = std::move(value);
   }
 }
@@ -118,7 +163,7 @@
 }
 
 std::string* ArenaStringPtr::Mutable(EmptyDefault, ::google::protobuf::Arena* arena) {
-  if (!IsDonatedString() && !IsDefault(&GetEmptyStringAlreadyInited())) {
+  if (!IsFixedSizeArena() && !IsDefault()) {
     return UnsafeMutablePointer();
   } else {
     return MutableSlow(arena);
@@ -127,41 +172,34 @@
 
 std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
                                      ::google::protobuf::Arena* arena) {
-  if (!IsDonatedString() && !IsDefault(nullptr)) {
+  if (!IsFixedSizeArena() && !IsDefault()) {
     return UnsafeMutablePointer();
   } else {
     return MutableSlow(arena, default_value);
   }
 }
 
-std::string* ArenaStringPtr::MutableNoCopy(const std::string* default_value,
+std::string* ArenaStringPtr::MutableNoCopy(const std::string*,
                                            ::google::protobuf::Arena* arena) {
-  if (!IsDonatedString() && !IsDefault(default_value)) {
+  if (!IsFixedSizeArena() && !IsDefault()) {
     return UnsafeMutablePointer();
   } else {
-    GOOGLE_DCHECK(IsDefault(default_value));
+    GOOGLE_DCHECK(IsDefault());
     // Allocate empty. The contents are not relevant.
-    std::string* new_string = Arena::Create<std::string>(arena);
-    tagged_ptr_.Set(new_string);
-    return new_string;
+    return NewString(arena);
   }
 }
 
 template <typename... Lazy>
 std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
                                          const Lazy&... lazy_default) {
-  const std::string* const default_value =
-      sizeof...(Lazy) == 0 ? &GetEmptyStringAlreadyInited() : nullptr;
-  GOOGLE_DCHECK(IsDefault(default_value));
-  std::string* new_string =
-      Arena::Create<std::string>(arena, lazy_default.get()...);
-  tagged_ptr_.Set(new_string);
-  return new_string;
+  GOOGLE_DCHECK(IsDefault());
+  return NewString(arena, lazy_default.get()...);
 }
 
 std::string* ArenaStringPtr::Release(const std::string* default_value,
                                      ::google::protobuf::Arena* arena) {
-  if (IsDefault(default_value)) {
+  if (IsDefault()) {
     return nullptr;
   } else {
     return ReleaseNonDefault(default_value, arena);
@@ -170,9 +208,9 @@
 
 std::string* ArenaStringPtr::ReleaseNonDefault(const std::string* default_value,
                                                ::google::protobuf::Arena* arena) {
-  GOOGLE_DCHECK(!IsDefault(default_value));
+  GOOGLE_DCHECK(!IsDefault());
 
-  if (!IsDonatedString()) {
+  if (!IsFixedSizeArena()) {
     std::string* released;
     if (arena != nullptr) {
       released = new std::string;
@@ -180,12 +218,12 @@
     } else {
       released = UnsafeMutablePointer();
     }
-    tagged_ptr_.Set(const_cast<std::string*>(default_value));
+    tagged_ptr_.SetDefault(default_value);
     return released;
-  } else /* IsDonatedString() */ {
+  } else /* IsFixedSizeArena() */ {
     GOOGLE_DCHECK(arena != nullptr);
     std::string* released = new std::string(Get());
-    tagged_ptr_.Set(const_cast<std::string*>(default_value));
+    tagged_ptr_.SetDefault(default_value);
     return released;
   }
 }
@@ -193,33 +231,28 @@
 void ArenaStringPtr::SetAllocated(const std::string* default_value,
                                   std::string* value, ::google::protobuf::Arena* arena) {
   // Release what we have first.
-  if (arena == nullptr && !IsDefault(default_value)) {
+  if (arena == nullptr && !IsDefault()) {
     delete UnsafeMutablePointer();
   }
   if (value == nullptr) {
-    tagged_ptr_.Set(const_cast<std::string*>(default_value));
+    tagged_ptr_.SetDefault(default_value);
   } else {
-#ifdef NDEBUG
-    tagged_ptr_.Set(value);
-    if (arena != nullptr) {
-      arena->Own(value);
-    }
-#else
+#ifndef NDEBUG
     // On debug builds, copy the string so the address differs.  delete will
     // fail if value was a stack-allocated temporary/etc., which would have
     // failed when arena ran its cleanup list.
-    std::string* new_value = Arena::Create<std::string>(arena, *value);
+    std::string* new_value = new std::string(std::move(*value));
     delete value;
-    tagged_ptr_.Set(new_value);
-#endif
+    value = new_value;
+#endif  // !NDEBUG
+    InitAllocated(value, arena);
   }
 }
 
-void ArenaStringPtr::Destroy(const std::string* default_value,
-                             ::google::protobuf::Arena* arena) {
+void ArenaStringPtr::Destroy(const std::string*, ::google::protobuf::Arena* arena) {
   if (arena == nullptr) {
-    GOOGLE_DCHECK(!IsDonatedString());
-    if (!IsDefault(default_value)) {
+    GOOGLE_DCHECK(!IsFixedSizeArena());
+    if (!IsDefault()) {
       delete UnsafeMutablePointer();
     }
   }
@@ -234,12 +267,12 @@
 }
 
 void ArenaStringPtr::ClearToEmpty() {
-  if (IsDefault(&GetEmptyStringAlreadyInited())) {
+  if (IsDefault()) {
     // Already set to default -- do nothing.
   } else {
     // Unconditionally mask away the tag.
     //
-    // UpdateDonatedString uses assign when capacity is larger than the new
+    // UpdateArenaString uses assign when capacity is larger than the new
     // value, which is trivially true in the donated string case.
     // const_cast<std::string*>(PtrValue<std::string>())->clear();
     tagged_ptr_.Get()->clear();
@@ -249,19 +282,13 @@
 void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
                                     ::google::protobuf::Arena* arena) {
   (void)arena;
-  if (IsDefault(nullptr)) {
+  if (IsDefault()) {
     // Already set to default -- do nothing.
-  } else if (!IsDonatedString()) {
+  } else {
     UnsafeMutablePointer()->assign(default_value.get());
   }
 }
 
-inline void SetStrWithHeapBuffer(std::string* str, ArenaStringPtr* s) {
-  TaggedPtr<std::string> res;
-  res.Set(str);
-  s->UnsafeSetTaggedPointer(res);
-}
-
 const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
                                                 ArenaStringPtr* s,
                                                 Arena* arena) {
@@ -270,12 +297,9 @@
   int size = ReadSize(&ptr);
   if (!ptr) return nullptr;
 
-  auto* str = Arena::Create<std::string>(arena);
+  auto* str = s->NewString(arena);
   ptr = ReadString(ptr, size, str);
   GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-
-  SetStrWithHeapBuffer(str, s);
-
   return ptr;
 }
 
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index 38c3637..9d2eab0 100644
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -31,6 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
 #define GOOGLE_PROTOBUF_ARENASTRING_H__
 
+#include <algorithm>
 #include <string>
 #include <type_traits>
 #include <utility>
@@ -39,7 +40,9 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/explicitly_constructed.h>
 
+// must be last:
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -50,12 +53,14 @@
 namespace google {
 namespace protobuf {
 namespace internal {
-
-template <typename T>
-class ExplicitlyConstructed;
+class EpsCopyInputStream;
 
 class SwapFieldHelper;
 
+// Declared in message_lite.h
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
+    fixed_address_empty_string;
+
 // Lazy string instance to support string fields with non-empty default.
 // These are initialized on the first call to .get().
 class PROTOBUF_EXPORT LazyString {
@@ -92,25 +97,102 @@
 template <typename T>
 class TaggedPtr {
  public:
+  // Bit flags qualifying string properties. We can use up to 3 bits as
+  // ptr_ is guaranteed and enforced to be aligned on 8 byte boundaries.
+  enum Flags {
+    kArenaBit = 0x1,      // ptr is arena allocated
+    kAllocatedBit = 0x2,  // ptr is heap allocated
+    kMutableBit = 0x4,    // ptr contents are fully mutable
+    kMask = 0x7           // Bit mask
+  };
+
+  // Composed logical types
+  enum Type {
+    // Default strings are immutable and never owned.
+    kDefault = 0,
+
+    // Allocated strings are mutable and (as the name implies) owned.
+    // A heap allocated string must be deleted.
+    kAllocated = kAllocatedBit | kMutableBit,
+
+    // Mutable arena strings are strings where the string instance is owned
+    // by the arena, but the string contents itself are owned by the string
+    // instance. Mutable arena string instances need to be destroyed which is
+    // typically done through a cleanup action added to the arena owning it.
+    kMutableArena = kArenaBit | kMutableBit,
+
+    // Fixed size arena strings are strings where both the string instance and
+    // the string contents are fully owned by the arena. Fixed size arena
+    // strings are a platform and c++ library specific customization. Fixed
+    // size arena strings are immutable, with the exception of custom internal
+    // updates to the content that fit inside the existing capacity.
+    // Fixed size arena strings must never be deleted or destroyed.
+    kFixedSizeArena = kArenaBit,
+  };
+
   TaggedPtr() = default;
-  explicit constexpr TaggedPtr(const ExplicitlyConstructed<std::string>* ptr)
-      : ptr_(const_cast<ExplicitlyConstructed<std::string>*>(ptr)) {}
+  explicit constexpr TaggedPtr(ExplicitlyConstructedArenaString* ptr)
+      : ptr_(ptr) {}
 
-  void SetTagged(T* p) {
-    Set(p);
-    ptr_ = reinterpret_cast<void*>(as_int() | 1);
+  // Sets the value to `p`, tagging the value as being a 'default' value.
+  // See documentation for kDefault for more info.
+  inline const T* SetDefault(const T* p) {
+    return TagAs(kDefault, const_cast<T*>(p));
   }
-  void Set(T* p) { ptr_ = p; }
-  T* Get() const { return reinterpret_cast<T*>(as_int() & -2); }
-  bool IsTagged() const { return as_int() & 1; }
 
-  // Returned value is only safe to dereference if IsTagged() == false.
-  // It is safe to compare.
-  T* UnsafeGet() const { return static_cast<T*>(ptr_); }
+  // Sets the value to `p`, tagging the value as a heap allocated value.
+  // Allocated strings are mutable and (as the name implies) owned.
+  // `p` must not be null
+  inline T* SetAllocated(T* p) { return TagAs(kAllocated, p); }
 
-  bool IsNull() { return ptr_ == nullptr; }
+  // Sets the value to `p`, tagging the value as a fixed size arena string.
+  // See documentation for kFixedSizeArena for more info.
+  // `p` must not be null
+  inline T* SetFixedSizeArena(T* p) { return TagAs(kFixedSizeArena, p); }
+
+  // Sets the value to `p`, tagging the value as a mutable arena string.
+  // See documentation for kMutableArena for more info.
+  // `p` must not be null
+  inline T* SetMutableArena(T* p) { return TagAs(kMutableArena, p); }
+
+  // Returns true if the contents of the current string are fully mutable.
+  inline bool IsMutable() const { return as_int() & kMutableBit; }
+
+  // Returns true if the current string is an immutable default value.
+  inline bool IsDefault() const { return (as_int() & kMask) == kDefault; }
+
+  // Returns true if the current string is a heap allocated mutable value.
+  inline bool IsAllocated() const { return as_int() & kAllocatedBit; }
+
+  // Returns true if the current string is an arena allocated value.
+  // This means it's either a mutable or fixed size arena string.
+  inline bool IsArena() const { return as_int() & kArenaBit; }
+
+  // Returns true if the current string is a fixed size arena allocated value.
+  inline bool IsFixedSizeArena() const {
+    return (as_int() & kMask) == kFixedSizeArena;
+  }
+
+  // Returns the contained string pointer.
+  inline T* Get() const { return reinterpret_cast<T*>(as_int() & ~kMask); }
+
+  // Returns true if the contained pointer is null, indicating some error.
+  // The Null value is only used during parsing for temporary values.
+  // A persisted ArenaStringPtr value is never null.
+  inline bool IsNull() { return ptr_ == nullptr; }
 
  private:
+  static inline void assert_aligned(const void* p) {
+    GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(p) & kMask, 0UL);
+  }
+
+  inline T* TagAs(Type type, T* p) {
+    GOOGLE_DCHECK(type == kDefault || p != nullptr);
+    assert_aligned(p);
+    ptr_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) | type);
+    return p;
+  }
+
   uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
   void* ptr_;
 };
@@ -118,66 +200,29 @@
 static_assert(std::is_trivial<TaggedPtr<std::string>>::value,
               "TaggedPtr must be trivial");
 
-// This class encapsulates a pointer to a std::string with or without a donated
-// buffer, tagged by bottom bit. It is a high-level wrapper that almost directly
-// corresponds to the interface required by string fields in generated
-// code. It replaces the old std::string* pointer in such cases.
+// This class encapsulates a pointer to a std::string with or without arena
+// owned contents, tagged by the bottom bits of the string pointer. It is a
+// high-level wrapper that almost directly corresponds to the interface required
+// by string fields in generated code. It replaces the old std::string* pointer
+// in such cases.
 //
-// The object has different but similar code paths for when the default value is
-// the empty string and when it is a non-empty string.
-// The empty string is handled different throughout the library and there is a
-// single global instance of it we can share.
+// The string pointer is tagged to be either a default, externally owned value,
+// a mutable heap allocated value, or an arena allocated value. The object uses
+// a single global instance of an empty string that is used as the initial
+// default value. Fields that have empty default values directly use this global
+// default. Fields that have non empty default values are supported through
+// lazily initialized default values managed by the LazyString class.
 //
-// For fields with an empty string default value, there are three distinct
-// states:
-//
-// - Pointer set to 'String' tag (LSB is 0), equal to
-//   &GetEmptyStringAlreadyInited(): field is set to its default value. Points
-//   to a true std::string*, but we do not own that std::string* (it's a
-//   globally shared instance).
-//
-// - Pointer set to 'String' tag (LSB is 0), but not equal to the global empty
-//   string: field points to a true std::string* instance that we own. This
-//   instance is either on the heap or on the arena (i.e. registered on
-//   free()/destructor-call list) as appropriate.
-//
-// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
-//   instance with a buffer on the arena (arena is never nullptr in this case).
-//
-// For fields with a non-empty string default value, there are three distinct
-// states:
-//
-// - Pointer set to 'String' tag (LSB is 0), equal to `nullptr`:
-//   Field is in "default" mode and does not point to any actual instance.
-//   Methods that might need to create an instance of the object will pass a
-//   `const LazyString&` for it.
-//
-// - Pointer set to 'String' tag (LSB is 0), but not equal to `nullptr`:
-//   field points to a true std::string* instance that we own. This instance is
-//   either on the heap or on the arena (i.e. registered on
-//   free()/destructor-call list) as appropriate.
-//
-// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
-//   instance with a buffer on the arena (arena is never nullptr in this case).
-//
-// Generated code and reflection code both ensure that ptr_ is never null for
-// fields with an empty default.
+// Generated code and reflection code both ensure that ptr_ is never null.
 // Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
-// so the field is always manually initialized via method calls.
+// the field is always manually initialized via method calls.
 //
-// Side-note: why pass information about the default on every API call? Because
-// we don't want to hold it in a member variable, or else this would go into
-// every proto message instance. This would be a huge waste of space, since the
-// default instance pointer is typically a global (static class field). We want
-// the generated code to be as efficient as possible, and if we take
-// the default value information as a parameter that's in practice taken from a
-// static class field, and compare ptr_ to the default value, we end up with a
-// single "cmp %reg, GLOBAL" in the resulting machine code. (Note that this also
-// requires the String tag to be 0 so we can avoid the mask before comparing.)
+// See TaggedPtr for more information about the types of string values being
+// held, and the mutable and ownership invariants for each type.
 struct PROTOBUF_EXPORT ArenaStringPtr {
   ArenaStringPtr() = default;
   explicit constexpr ArenaStringPtr(
-      const ExplicitlyConstructed<std::string>* default_value)
+      ExplicitlyConstructedArenaString* default_value)
       : tagged_ptr_(default_value) {}
 
   // Some methods below are overloaded on a `default_value` and on tags.
@@ -282,11 +327,23 @@
   void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
 
   // Called from generated code / reflection runtime only. Resets value to point
-  // to a default string pointer, with the semantics that this
-  // ArenaStringPtr does not own the pointed-to memory. Disregards initial value
-  // of ptr_ (so this is the *ONLY* safe method to call after construction or
-  // when reinitializing after becoming the active field in a oneof union).
-  inline void UnsafeSetDefault(const std::string* default_value);
+  // to a default string pointer, with the semantics that this ArenaStringPtr
+  // does not own the pointed-to memory. Disregards initial value of ptr_ (so
+  // this is the *ONLY* safe method to call after construction or when
+  // reinitializing after becoming the active field in a oneof union).
+  // This function allows an explicit default value other than the default
+  // global empty string. This is used in unit tests and by fields with
+  // explicit non-empty default string values using null defaults.
+  inline void InitDefault();
+  inline void InitDefault(const std::string* str);
+
+  // Called from generated code / reflection runtime only. Resets the value of
+  // this instances to the heap allocated value in `str`. `str` must not be
+  // null. Invokes `arena->Own(str)` to transfer ownership into the arena if
+  // `arena` is not null, else, `str` will be owned by ArenaStringPtr. This
+  // function should only be used to initialize a ArenaStringPtr or on an
+  // instance known to not carry any heap allocated value.
+  inline void InitAllocated(std::string* str, Arena* arena);
 
   // Returns a mutable pointer, but doesn't initialize the string to the
   // default value.
@@ -311,18 +368,24 @@
   // tag tests.
   std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
 
-  inline bool IsDefault(const std::string* default_value) const {
-    // Relies on the fact that kPtrTagString == 0, so if IsString(), ptr_ is the
-    // actual std::string pointer (and if !IsString(), ptr_ will never be equal
-    // to any aligned |default_value| pointer). The key is that we want to avoid
-    // masking in the fastpath const-pointer Get() case for non-arena code.
-    return tagged_ptr_.UnsafeGet() == default_value;
-  }
+  // Returns true if this instances holds an immutable default value.
+  inline bool IsDefault() const { return tagged_ptr_.IsDefault(); }
 
  private:
+  template <typename... Args>
+  inline std::string* NewString(Arena* arena, Args&&... args) {
+    if (arena == nullptr) {
+      auto* s = new std::string(std::forward<Args>(args)...);
+      return tagged_ptr_.SetAllocated(s);
+    } else {
+      auto* s = Arena::Create<std::string>(arena, std::forward<Args>(args)...);
+      return tagged_ptr_.SetMutableArena(s);
+    }
+  }
+
   TaggedPtr<std::string> tagged_ptr_;
 
-  bool IsDonatedString() const { return false; }
+  bool IsFixedSizeArena() const { return false; }
 
   // Swaps tagged pointer without debug hardening. This is to allow python
   // protobuf to maintain pointer stability even in DEBUG builds.
@@ -332,6 +395,7 @@
   }
 
   friend class ::google::protobuf::internal::SwapFieldHelper;
+  friend class TcParser;
 
   // Slow paths.
 
@@ -346,32 +410,49 @@
   // Destroys the non-default string value out-of-line
   void DestroyNoArenaSlowPath();
 
+  friend class EpsCopyInputStream;
 };
 
-inline void ArenaStringPtr::UnsafeSetDefault(const std::string* value) {
-  tagged_ptr_.Set(const_cast<std::string*>(value));
+inline void ArenaStringPtr::InitDefault() {
+  tagged_ptr_ = TaggedPtr<std::string>(&fixed_address_empty_string);
+}
+
+inline void ArenaStringPtr::InitDefault(const std::string* str) {
+  tagged_ptr_.SetDefault(str);
+}
+
+inline void ArenaStringPtr::InitAllocated(std::string* str, Arena* arena) {
+  if (arena != nullptr) {
+    tagged_ptr_.SetMutableArena(str);
+    arena->Own(str);
+  } else {
+    tagged_ptr_.SetAllocated(str);
+  }
 }
 
 // Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
 inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap(  //
-    const std::string* default_value,                             //
+    const std::string*,                                           //
     ArenaStringPtr* rhs, Arena* rhs_arena,                        //
     ArenaStringPtr* lhs, Arena* lhs_arena) {
   // Silence unused variable warnings in release buildls.
-  (void)default_value;
   (void)rhs_arena;
   (void)lhs_arena;
   std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
 #ifdef PROTOBUF_FORCE_COPY_IN_SWAP
-  auto force_realloc = [default_value](ArenaStringPtr* p, Arena* arena) {
-    if (p->IsDefault(default_value)) return;
+  auto force_realloc = [](ArenaStringPtr* p, Arena* arena) {
+    if (p->IsDefault()) return;
     std::string* old_value = p->tagged_ptr_.Get();
     std::string* new_value =
-        p->IsDonatedString()
+        p->IsFixedSizeArena()
             ? Arena::Create<std::string>(arena, *old_value)
             : Arena::Create<std::string>(arena, std::move(*old_value));
-    if (arena == nullptr) delete old_value;
-    p->tagged_ptr_.Set(new_value);
+    if (arena == nullptr) {
+      delete old_value;
+      p->tagged_ptr_.SetAllocated(new_value);
+    } else {
+      p->tagged_ptr_.SetMutableArena(new_value);
+    }
   };
   // Because, at this point, tagged_ptr_ has been swapped, arena should also be
   // swapped.
@@ -386,28 +467,31 @@
 }
 
 inline std::string* ArenaStringPtr::MutableNoArenaNoDefault(
-    const std::string* default_value) {
+    const std::string* /* default_value */) {
   // VERY IMPORTANT for performance and code size: this will reduce to a member
   // variable load, a pointer check (against |default_value|, in practice a
   // static global) and a branch to the slowpath (which calls operator new and
   // the ctor). DO NOT add any tagged-pointer operations here.
-  if (IsDefault(default_value)) {
+  GOOGLE_DCHECK(!tagged_ptr_.IsArena());
+  if (IsDefault()) {
     return SetAndReturnNewString();
   } else {
     return UnsafeMutablePointer();
   }
 }
 
-inline void ArenaStringPtr::DestroyNoArena(const std::string* default_value) {
-  if (!IsDefault(default_value)) {
+inline void ArenaStringPtr::DestroyNoArena(
+    const std::string* /* default_value */) {
+  GOOGLE_DCHECK(!tagged_ptr_.IsArena());
+  if (!IsDefault()) {
     DestroyNoArenaSlowPath();
   }
 }
 
 inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
-  GOOGLE_DCHECK(!tagged_ptr_.IsTagged());
-  GOOGLE_DCHECK(tagged_ptr_.UnsafeGet() != nullptr);
-  return tagged_ptr_.UnsafeGet();
+  GOOGLE_DCHECK(tagged_ptr_.IsMutable());
+  GOOGLE_DCHECK(tagged_ptr_.Get() != nullptr);
+  return tagged_ptr_.Get();
 }
 
 
diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc
index db988af..bb48309 100644
--- a/src/google/protobuf/arenastring_unittest.cc
+++ b/src/google/protobuf/arenastring_unittest.cc
@@ -72,7 +72,7 @@
 TEST_P(SingleArena, GetSet) {
   auto arena = GetArena();
   ArenaStringPtr field;
-  field.UnsafeSetDefault(empty_default);
+  field.InitDefault(empty_default);
   EXPECT_EQ("", field.Get());
   field.Set(empty_default, "Test short", arena.get());
   EXPECT_EQ("Test short", field.Get());
@@ -86,7 +86,7 @@
   auto arena = GetArena();
   ArenaStringPtr field;
   const std::string* empty_default = &internal::GetEmptyString();
-  field.UnsafeSetDefault(empty_default);
+  field.InitDefault(empty_default);
 
   std::string* mut = field.Mutable(EmptyDefault{}, arena.get());
   EXPECT_EQ(mut, field.Mutable(EmptyDefault{}, arena.get()));
@@ -102,7 +102,7 @@
   auto arena = GetArena();
 
   ArenaStringPtr field;
-  field.UnsafeSetDefault(nullptr);
+  field.InitDefault(nullptr);
   std::string* mut = field.Mutable(nonempty_default, arena.get());
   EXPECT_EQ(mut, field.Mutable(nonempty_default, arena.get()));
   EXPECT_EQ(mut, &field.Get());
@@ -131,9 +131,9 @@
 TEST_P(DualArena, Swap) {
   auto lhs_arena = GetLhsArena();
   ArenaStringPtr lhs;
-  lhs.UnsafeSetDefault(empty_default);
+  lhs.InitDefault(empty_default);
   ArenaStringPtr rhs;
-  rhs.UnsafeSetDefault(empty_default);
+  rhs.InitDefault(empty_default);
 
   {
     auto rhs_arena = GetRhsArena();
diff --git a/src/google/protobuf/arenaz_sampler.cc b/src/google/protobuf/arenaz_sampler.cc
new file mode 100644
index 0000000..b0aed50
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler.cc
@@ -0,0 +1,177 @@
+// 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/arenaz_sampler.h>
+
+#include <atomic>
+#include <cstdint>
+#include <limits>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler() {
+  static auto* sampler = new ThreadSafeArenazSampler();
+  return *sampler;
+}
+
+void UnsampleSlow(ThreadSafeArenaStats* info) {
+  GlobalThreadSafeArenazSampler().Unregister(info);
+}
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+namespace {
+
+PROTOBUF_CONSTINIT std::atomic<bool> g_arenaz_enabled{true};
+PROTOBUF_CONSTINIT std::atomic<int32_t> g_arenaz_sample_parameter{1 << 20};
+PROTOBUF_THREAD_LOCAL absl::profiling_internal::ExponentialBiased
+    g_exponential_biased_generator;
+
+}  // namespace
+
+PROTOBUF_THREAD_LOCAL int64_t global_next_sample = 1LL << 20;
+
+ThreadSafeArenaStats::ThreadSafeArenaStats() { PrepareForSampling(); }
+ThreadSafeArenaStats::~ThreadSafeArenaStats() = default;
+
+void ThreadSafeArenaStats::PrepareForSampling() {
+  num_allocations.store(0, std::memory_order_relaxed);
+  num_resets.store(0, std::memory_order_relaxed);
+  bytes_requested.store(0, std::memory_order_relaxed);
+  bytes_allocated.store(0, std::memory_order_relaxed);
+  bytes_wasted.store(0, std::memory_order_relaxed);
+  max_bytes_allocated.store(0, std::memory_order_relaxed);
+  thread_ids.store(0, std::memory_order_relaxed);
+  // The inliner makes hardcoded skip_count difficult (especially when combined
+  // with LTO).  We use the ability to exclude stacks by regex when encoding
+  // instead.
+  depth = absl::GetStackTrace(stack, kMaxStackDepth, /* skip_count= */ 0);
+}
+
+void RecordResetSlow(ThreadSafeArenaStats* info) {
+  const size_t max_bytes =
+      info->max_bytes_allocated.load(std::memory_order_relaxed);
+  const size_t allocated_bytes =
+      info->bytes_allocated.load(std::memory_order_relaxed);
+  if (max_bytes < allocated_bytes) {
+    info->max_bytes_allocated.store(allocated_bytes);
+  }
+  info->bytes_requested.store(0, std::memory_order_relaxed);
+  info->bytes_allocated.store(0, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(0, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(0, std::memory_order_relaxed);
+  info->num_resets.fetch_add(1, std::memory_order_relaxed);
+}
+
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted) {
+  info->bytes_requested.fetch_add(requested, std::memory_order_relaxed);
+  info->bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
+  info->bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
+  info->num_allocations.fetch_add(1, std::memory_order_relaxed);
+  const uint64_t tid = (1ULL << (GetCachedTID() % 63));
+  const uint64_t thread_ids = info->thread_ids.load(std::memory_order_relaxed);
+  if (!(thread_ids & tid)) {
+    info->thread_ids.store(thread_ids | tid, std::memory_order_relaxed);
+  }
+}
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  bool first = *next_sample < 0;
+  *next_sample = g_exponential_biased_generator.GetStride(
+      g_arenaz_sample_parameter.load(std::memory_order_relaxed));
+  // Small values of interval are equivalent to just sampling next time.
+  ABSL_ASSERT(*next_sample >= 1);
+
+  // g_arenaz_enabled can be dynamically flipped, we need to set a threshold low
+  // enough that we will start sampling in a reasonable time, so we just use the
+  // default sampling rate.
+  if (!g_arenaz_enabled.load(std::memory_order_relaxed)) return nullptr;
+  // We will only be negative on our first count, so we should just retry in
+  // that case.
+  if (first) {
+    if (PROTOBUF_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+    return SampleSlow(next_sample);
+  }
+
+  return GlobalThreadSafeArenazSampler().Register();
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {
+  g_arenaz_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetThreadSafeArenazSampleParameter(int32_t rate) {
+  if (rate > 0) {
+    g_arenaz_sample_parameter.store(rate, std::memory_order_release);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz sample rate: %lld",
+                 static_cast<long long>(rate));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazMaxSamples(int32_t max) {
+  if (max > 0) {
+    GlobalThreadSafeArenazSampler().SetMaxSamples(max);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz max samples: %lld",
+                 static_cast<long long>(max));  // NOLINT(runtime/int)
+  }
+}
+
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {
+  if (next_sample >= 0) {
+    global_next_sample = next_sample;
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz next sample: %lld",
+                 static_cast<long long>(next_sample));  // NOLINT(runtime/int)
+  }
+}
+
+#else
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
+  *next_sample = std::numeric_limits<int64_t>::max();
+  return nullptr;
+}
+
+void SetThreadSafeArenazEnabled(bool enabled) {}
+void SetThreadSafeArenazSampleParameter(int32_t rate) {}
+void SetThreadSafeArenazMaxSamples(int32_t max) {}
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/arenaz_sampler.h b/src/google/protobuf/arenaz_sampler.h
new file mode 100644
index 0000000..b04b0cc
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler.h
@@ -0,0 +1,207 @@
+// 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_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+#define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+struct ThreadSafeArenaStats;
+void RecordResetSlow(ThreadSafeArenaStats* info);
+void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
+                        size_t allocated, size_t wasted);
+// Stores information about a sampled thread safe arena.  All mutations to this
+// *must* be made through `Record*` functions below.  All reads from this *must*
+// only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
+struct ThreadSafeArenaStats
+    : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
+  // Constructs the object but does not fill in any fields.
+  ThreadSafeArenaStats();
+  ~ThreadSafeArenaStats();
+
+  // Puts the object into a clean state, fills in the logically `const` members,
+  // blocking for any readers that are currently sampling the object.
+  void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+  // These fields are mutated by the various Record* APIs and need to be
+  // thread-safe.
+  std::atomic<int> num_allocations;
+  std::atomic<int> num_resets;
+  std::atomic<size_t> bytes_requested;
+  std::atomic<size_t> bytes_allocated;
+  std::atomic<size_t> bytes_wasted;
+  // Records the largest size an arena ever had.  Maintained across resets.
+  std::atomic<size_t> max_bytes_allocated;
+  // Bit i when set to 1 indicates that a thread with tid % 63 = i accessed the
+  // underlying arena.  The field is maintained across resets.
+  std::atomic<uint64_t> thread_ids;
+
+  // All of the fields below are set by `PrepareForSampling`, they must not
+  // be mutated in `Record*` functions.  They are logically `const` in that
+  // sense. These are guarded by init_mu, but that is not externalized to
+  // clients, who can only read them during
+  // `ThreadSafeArenazSampler::Iterate` which will hold the lock.
+  static constexpr int kMaxStackDepth = 64;
+  int32_t depth;
+  void* stack[kMaxStackDepth];
+  static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t requested,
+                                  size_t allocated, size_t wasted) {
+    if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
+    RecordAllocateSlow(info, requested, allocated, wasted);
+  }
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
+      : info_(info) {}
+
+  ~ThreadSafeArenaStatsHandle() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    UnsampleSlow(info_);
+  }
+
+  ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
+      : info_(absl::exchange(other.info_, nullptr)) {}
+
+  ThreadSafeArenaStatsHandle& operator=(
+      ThreadSafeArenaStatsHandle&& other) noexcept {
+    if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
+      UnsampleSlow(info_);
+    }
+    info_ = absl::exchange(other.info_, nullptr);
+    return *this;
+  }
+
+  void RecordReset() {
+    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordResetSlow(info_);
+  }
+
+  ThreadSafeArenaStats* MutableStats() { return info_; }
+
+  friend void swap(ThreadSafeArenaStatsHandle& lhs,
+                   ThreadSafeArenaStatsHandle& rhs) {
+    std::swap(lhs.info_, rhs.info_);
+  }
+
+  friend class ThreadSafeArenaStatsHandlePeer;
+
+ private:
+  ThreadSafeArenaStats* info_ = nullptr;
+};
+
+using ThreadSafeArenazSampler =
+    ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
+
+extern PROTOBUF_THREAD_LOCAL int64_t global_next_sample;
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  if (PROTOBUF_PREDICT_TRUE(--global_next_sample > 0)) {
+    return ThreadSafeArenaStatsHandle(nullptr);
+  }
+  return ThreadSafeArenaStatsHandle(SampleSlow(&global_next_sample));
+}
+
+#else
+struct ThreadSafeArenaStats {
+  static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
+                                  size_t /*allocated*/, size_t /*wasted*/) {}
+};
+
+ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(ThreadSafeArenaStats* info);
+
+class ThreadSafeArenaStatsHandle {
+ public:
+  explicit ThreadSafeArenaStatsHandle() = default;
+  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
+
+  void RecordReset() {}
+
+  ThreadSafeArenaStats* MutableStats() { return nullptr; }
+
+  friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
+
+ private:
+  friend class ThreadSafeArenaStatsHandlePeer;
+};
+
+class ThreadSafeArenazSampler {
+ public:
+  void Unregister(ThreadSafeArenaStats*) {}
+  void SetMaxSamples(int32_t) {}
+};
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline ThreadSafeArenaStatsHandle Sample() {
+  return ThreadSafeArenaStatsHandle(nullptr);
+}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+// Returns a global Sampler.
+ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
+
+// Enables or disables sampling for thread safe arenas.
+void SetThreadSafeArenazEnabled(bool enabled);
+
+// Sets the rate at which thread safe arena will be sampled.
+void SetThreadSafeArenazSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetThreadSafeArenazMaxSamples(int32_t max);
+
+// Sets the current value for when arenas should be next sampled.
+void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+#endif  // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__
diff --git a/src/google/protobuf/arenaz_sampler_test.cc b/src/google/protobuf/arenaz_sampler_test.cc
new file mode 100644
index 0000000..1bfec54
--- /dev/null
+++ b/src/google/protobuf/arenaz_sampler_test.cc
@@ -0,0 +1,382 @@
+// 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/arenaz_sampler.h>
+
+#include <memory>
+#include <random>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+class ThreadSafeArenaStatsHandlePeer {
+ public:
+  static bool IsSampled(const ThreadSafeArenaStatsHandle& h) {
+    return h.info_ != nullptr;
+  }
+
+  static ThreadSafeArenaStats* GetInfo(ThreadSafeArenaStatsHandle* h) {
+    return h->info_;
+  }
+};
+std::vector<size_t> GetBytesAllocated(ThreadSafeArenazSampler* s) {
+  std::vector<size_t> res;
+  s->Iterate([&](const ThreadSafeArenaStats& info) {
+    res.push_back(info.bytes_allocated.load(std::memory_order_acquire));
+  });
+  return res;
+}
+
+ThreadSafeArenaStats* Register(ThreadSafeArenazSampler* s, size_t size) {
+  auto* info = s->Register();
+  assert(info != nullptr);
+  info->bytes_allocated.store(size);
+  return info;
+}
+
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+namespace {
+
+#if defined(PROTOBUF_ARENAZ_SAMPLE)
+
+TEST(ThreadSafeArenaStatsTest, PrepareForSampling) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+
+  EXPECT_EQ(info.num_allocations.load(), 0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+
+  info.num_allocations.store(1, std::memory_order_relaxed);
+  info.num_resets.store(1, std::memory_order_relaxed);
+  info.bytes_requested.store(1, std::memory_order_relaxed);
+  info.bytes_allocated.store(1, std::memory_order_relaxed);
+  info.bytes_wasted.store(1, std::memory_order_relaxed);
+  info.max_bytes_allocated.store(1, std::memory_order_relaxed);
+
+  info.PrepareForSampling();
+  EXPECT_EQ(info.num_allocations.load(), 0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
+  EXPECT_EQ(info.num_allocations.load(), 1);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 100);
+  EXPECT_EQ(info.bytes_allocated.load(), 128);
+  EXPECT_EQ(info.bytes_wasted.load(), 0);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
+                     /*wasted=*/28);
+  EXPECT_EQ(info.num_allocations.load(), 2);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_requested.load(), 200);
+  EXPECT_EQ(info.bytes_allocated.load(), 384);
+  EXPECT_EQ(info.bytes_wasted.load(), 28);
+  EXPECT_EQ(info.max_bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenaStatsTest, RecordResetSlow) {
+  ThreadSafeArenaStats info;
+  MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+  RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
+  EXPECT_EQ(info.num_resets.load(), 0);
+  EXPECT_EQ(info.bytes_allocated.load(), 128);
+  RecordResetSlow(&info);
+  EXPECT_EQ(info.num_resets.load(), 1);
+  EXPECT_EQ(info.bytes_allocated.load(), 0);
+}
+
+TEST(ThreadSafeArenazSamplerTest, SmallSampleParameter) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(100);
+
+  for (int i = 0; i < 1000; ++i) {
+    int64_t next_sample = 0;
+    ThreadSafeArenaStats* sample = SampleSlow(&next_sample);
+    EXPECT_GT(next_sample, 0);
+    EXPECT_NE(sample, nullptr);
+    UnsampleSlow(sample);
+  }
+}
+
+TEST(ThreadSafeArenazSamplerTest, LargeSampleParameter) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(std::numeric_limits<int32_t>::max());
+
+  for (int i = 0; i < 1000; ++i) {
+    int64_t next_sample = 0;
+    ThreadSafeArenaStats* sample = SampleSlow(&next_sample);
+    EXPECT_GT(next_sample, 0);
+    EXPECT_NE(sample, nullptr);
+    UnsampleSlow(sample);
+  }
+}
+
+TEST(ThreadSafeArenazSamplerTest, Sample) {
+  SetThreadSafeArenazEnabled(true);
+  SetThreadSafeArenazSampleParameter(100);
+  SetThreadSafeArenazGlobalNextSample(0);
+  int64_t num_sampled = 0;
+  int64_t total = 0;
+  double sample_rate = 0.0;
+  for (int i = 0; i < 1000000; ++i) {
+    ThreadSafeArenaStatsHandle h = Sample();
+    ++total;
+    if (ThreadSafeArenaStatsHandlePeer::IsSampled(h)) {
+      ++num_sampled;
+    }
+    sample_rate = static_cast<double>(num_sampled) / total;
+    if (0.005 < sample_rate && sample_rate < 0.015) break;
+  }
+  EXPECT_NEAR(sample_rate, 0.01, 0.005);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Handle) {
+  auto& sampler = GlobalThreadSafeArenazSampler();
+  ThreadSafeArenaStatsHandle h(sampler.Register());
+  auto* info = ThreadSafeArenaStatsHandlePeer::GetInfo(&h);
+  info->bytes_allocated.store(0x12345678, std::memory_order_relaxed);
+
+  bool found = false;
+  sampler.Iterate([&](const ThreadSafeArenaStats& h) {
+    if (&h == info) {
+      EXPECT_EQ(h.bytes_allocated.load(), 0x12345678);
+      found = true;
+    }
+  });
+  EXPECT_TRUE(found);
+
+  h = ThreadSafeArenaStatsHandle();
+  found = false;
+  sampler.Iterate([&](const ThreadSafeArenaStats& h) {
+    if (&h == info) {
+      // this will only happen if some other thread has resurrected the info
+      // the old handle was using.
+      if (h.bytes_allocated.load() == 0x12345678) {
+        found = true;
+      }
+    }
+  });
+  EXPECT_FALSE(found);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Registration) {
+  ThreadSafeArenazSampler sampler;
+  auto* info1 = Register(&sampler, 1);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1));
+
+  auto* info2 = Register(&sampler, 2);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 2));
+  info1->bytes_allocated.store(3);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(3, 2));
+
+  sampler.Unregister(info1);
+  sampler.Unregister(info2);
+}
+
+TEST(ThreadSafeArenazSamplerTest, Unregistration) {
+  ThreadSafeArenazSampler sampler;
+  std::vector<ThreadSafeArenaStats*> infos;
+  for (size_t i = 0; i < 3; ++i) {
+    infos.push_back(Register(&sampler, i));
+  }
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 1, 2));
+
+  sampler.Unregister(infos[1]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2));
+
+  infos.push_back(Register(&sampler, 3));
+  infos.push_back(Register(&sampler, 4));
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2, 3, 4));
+  sampler.Unregister(infos[3]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(0, 2, 4));
+
+  sampler.Unregister(infos[0]);
+  sampler.Unregister(infos[2]);
+  sampler.Unregister(infos[4]);
+  EXPECT_THAT(GetBytesAllocated(&sampler), IsEmpty());
+}
+
+TEST(ThreadSafeArenazSamplerTest, MultiThreaded) {
+  ThreadSafeArenazSampler sampler;
+  absl::Notification stop;
+  ThreadPool pool(10);
+
+  for (int i = 0; i < 10; ++i) {
+    pool.Schedule([&sampler, &stop]() {
+      std::random_device rd;
+      std::mt19937 gen(rd());
+
+      std::vector<ThreadSafeArenaStats*> infoz;
+      while (!stop.HasBeenNotified()) {
+        if (infoz.empty()) {
+          infoz.push_back(sampler.Register());
+        }
+        switch (std::uniform_int_distribution<>(0, 1)(gen)) {
+          case 0: {
+            infoz.push_back(sampler.Register());
+            break;
+          }
+          case 1: {
+            size_t p =
+                std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
+            ThreadSafeArenaStats* info = infoz[p];
+            infoz[p] = infoz.back();
+            infoz.pop_back();
+            sampler.Unregister(info);
+            break;
+          }
+        }
+      }
+    });
+  }
+  // The threads will hammer away.  Give it a little bit of time for tsan to
+  // spot errors.
+  absl::SleepFor(absl::Seconds(3));
+  stop.Notify();
+}
+
+TEST(ThreadSafeArenazSamplerTest, Callback) {
+  ThreadSafeArenazSampler sampler;
+
+  auto* info1 = Register(&sampler, 1);
+  auto* info2 = Register(&sampler, 2);
+
+  static const ThreadSafeArenaStats* expected;
+
+  auto callback = [](const ThreadSafeArenaStats& info) {
+    // We can't use `info` outside of this callback because the object will be
+    // disposed as soon as we return from here.
+    EXPECT_EQ(&info, expected);
+  };
+
+  // Set the callback.
+  EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
+  expected = info1;
+  sampler.Unregister(info1);
+
+  // Unset the callback.
+  EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
+  expected = nullptr;  // no more calls.
+  sampler.Unregister(info2);
+}
+
+class ThreadSafeArenazSamplerTestThread : public Thread {
+ protected:
+  void Run() override {
+    google::protobuf::ArenaSafeUniquePtr<
+        protobuf_test_messages::proto2::TestAllTypesProto2>
+        message = google::protobuf::MakeArenaSafeUnique<
+            protobuf_test_messages::proto2::TestAllTypesProto2>(arena_);
+    GOOGLE_CHECK(message != nullptr);
+    // Signal that a message on the arena has been created.  This should create
+    // a SerialArena for this thread.
+    if (barrier_->Block()) {
+      delete barrier_;
+    }
+  }
+
+ public:
+  ThreadSafeArenazSamplerTestThread(const thread::Options& options,
+                                    StringPiece name,
+                                    google::protobuf::Arena* arena,
+                                    absl::Barrier* barrier)
+      : Thread(options, name), arena_(arena), barrier_(barrier) {}
+
+ private:
+  google::protobuf::Arena* arena_;
+  absl::Barrier* barrier_;
+};
+
+TEST(ThreadSafeArenazSamplerTest, MultiThread) {
+  SetThreadSafeArenazEnabled(true);
+  // Setting 1 as the parameter value means one in every two arenas would be
+  // sampled, on average.
+  SetThreadSafeArenazSampleParameter(1);
+  SetThreadSafeArenazGlobalNextSample(0);
+  auto& sampler = GlobalThreadSafeArenazSampler();
+  int count = 0;
+  for (int i = 0; i < 10; ++i) {
+    const int kNumThreads = 10;
+    absl::Barrier* barrier = new absl::Barrier(kNumThreads + 1);
+    google::protobuf::Arena arena;
+    thread::Options options;
+    options.set_joinable(true);
+    std::vector<std::unique_ptr<ThreadSafeArenazSamplerTestThread>> threads;
+    for (int i = 0; i < kNumThreads; i++) {
+      auto t = std::make_unique<ThreadSafeArenazSamplerTestThread>(
+          options, StrCat("thread", i), &arena, barrier);
+      t->Start();
+      threads.push_back(std::move(t));
+    }
+    // Wait till each thread has created a message on the arena.
+    if (barrier->Block()) {
+      delete barrier;
+    }
+    sampler.Iterate([&](const ThreadSafeArenaStats& h) { ++count; });
+    for (int i = 0; i < kNumThreads; i++) {
+      threads[i]->Join();
+    }
+  }
+  EXPECT_GT(count, 0);
+}
+#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
+
+}  // namespace
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/annotation_test_util.cc b/src/google/protobuf/compiler/annotation_test_util.cc
index 3c47aa4..f0815c5 100644
--- a/src/google/protobuf/compiler/annotation_test_util.cc
+++ b/src/google/protobuf/compiler/annotation_test_util.cc
@@ -58,9 +58,8 @@
   explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
       : file_(file) {}
 
-  virtual bool Generate(const FileDescriptor* file,
-                        const std::string& parameter, GeneratorContext* context,
-                        std::string* error) const {
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
     file->CopyTo(file_);
     return true;
   }
@@ -128,7 +127,7 @@
   std::vector<const GeneratedCodeInfo::Annotation*> annotations;
   FindAnnotationsOnPath(info, source_file, path, &annotations);
   if (annotations.empty()) {
-    return NULL;
+    return nullptr;
   }
   return annotations[0];
 }
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
index 4544f3e..dc9d450 100644
--- a/src/google/protobuf/compiler/code_generator.cc
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -76,13 +76,13 @@
 
 io::ZeroCopyOutputStream* GeneratorContext::OpenForAppend(
     const std::string& filename) {
-  return NULL;
+  return nullptr;
 }
 
 io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
     const std::string& filename, const std::string& insertion_point) {
   GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
-  return NULL;  // make compiler happy
+  return nullptr;  // make compiler happy
 }
 
 io::ZeroCopyOutputStream* GeneratorContext::OpenForInsertWithGeneratedCodeInfo(
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index 2cbda27..0a99fe1 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -43,6 +43,7 @@
 #include <vector>
 #include <google/protobuf/stubs/common.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 6cd17ea..62871ed 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -53,6 +53,7 @@
 #endif
 #include <ctype.h>
 #include <errno.h>
+
 #include <fstream>
 #include <iostream>
 
@@ -87,6 +88,7 @@
 #include <google/protobuf/stubs/stl_util.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -289,12 +291,12 @@
       public io::ErrorCollector,
       public DescriptorPool::ErrorCollector {
  public:
-  ErrorPrinter(ErrorFormat format, DiskSourceTree* tree = NULL)
+  ErrorPrinter(ErrorFormat format, DiskSourceTree* tree = nullptr)
       : format_(format),
         tree_(tree),
         found_errors_(false),
         found_warnings_(false) {}
-  ~ErrorPrinter() {}
+  ~ErrorPrinter() override {}
 
   // implements MultiFileErrorCollector ------------------------------
   void AddError(const std::string& filename, int line, int column,
@@ -341,8 +343,8 @@
                          std::ostream& out) {
     // Print full path when running under MSVS
     std::string dfile;
-    if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && tree_ != NULL &&
-        tree_->VirtualFileToDiskFile(filename, &dfile)) {
+    if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
+        tree_ != nullptr && tree_->VirtualFileToDiskFile(filename, &dfile)) {
       out << dfile;
     } else {
       out << filename;
@@ -434,7 +436,7 @@
                      const std::string& filename,
                      const std::string& insertion_point,
                      const google::protobuf::GeneratedCodeInfo& info);
-  virtual ~MemoryOutputStream();
+  ~MemoryOutputStream() override;
 
   // implements ZeroCopyOutputStream ---------------------------------
   bool Next(void** data, int* size) override {
@@ -1116,7 +1118,7 @@
       FileDescriptorProto file;
       file.set_name("empty_message.proto");
       file.add_message_type()->set_name("EmptyMessage");
-      GOOGLE_CHECK(pool.BuildFile(file) != NULL);
+      GOOGLE_CHECK(pool.BuildFile(file) != nullptr);
       codec_type_ = "EmptyMessage";
       if (!EncodeOrDecode(&pool)) {
         return 1;
@@ -1270,7 +1272,7 @@
     // Import the file.
     const FileDescriptor* parsed_file =
         descriptor_pool->FindFileByName(input_file);
-    if (parsed_file == NULL) {
+    if (parsed_file == nullptr) {
       result = false;
       break;
     }
@@ -1496,7 +1498,7 @@
     for (std::vector<OutputDirective>::const_iterator j =
              output_directives_.begin();
          j != output_directives_.end(); ++j) {
-      if (j->generator == NULL) {
+      if (j->generator == nullptr) {
         std::string plugin_name = PluginName(plugin_prefix_, j->name);
         if (plugin_name == i->first) {
           foundImplicitPlugin = true;
@@ -1606,7 +1608,7 @@
     // Two dashes:  Multi-character name, with '=' separating name and
     //   value.
     const char* equals_pos = strchr(arg, '=');
-    if (equals_pos != NULL) {
+    if (equals_pos != nullptr) {
       *name = std::string(arg, equals_pos - arg);
       *value = equals_pos + 1;
       parsed_value = true;
@@ -1948,11 +1950,11 @@
     // Some other flag.  Look it up in the generators list.
     const GeneratorInfo* generator_info =
         FindOrNull(generators_by_flag_name_, name);
-    if (generator_info == NULL &&
+    if (generator_info == nullptr &&
         (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
       // Check if it's a generator option flag.
       generator_info = FindOrNull(generators_by_option_name_, name);
-      if (generator_info != NULL) {
+      if (generator_info != nullptr) {
         std::string* parameters =
             &generator_parameters_[generator_info->flag_name];
         if (!parameters->empty()) {
@@ -1981,8 +1983,8 @@
 
       OutputDirective directive;
       directive.name = name;
-      if (generator_info == NULL) {
-        directive.generator = NULL;
+      if (generator_info == nullptr) {
+        directive.generator = nullptr;
       } else {
         directive.generator = generator_info->generator;
       }
@@ -2138,7 +2140,7 @@
     GeneratorContext* generator_context) {
   // Call the generator.
   std::string error;
-  if (output_directive.generator == NULL) {
+  if (output_directive.generator == nullptr) {
     // This is a plugin.
     GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") &&
           HasSuffixString(output_directive.name, "_out"))
@@ -2319,7 +2321,7 @@
       // before the new one is opened.
       current_output.reset();
       current_output.reset(generator_context->Open(output_file.name()));
-    } else if (current_output == NULL) {
+    } else if (current_output == nullptr) {
       *error = strings::Substitute(
           "$0: First file chunk returned by plugin did not specify a file "
           "name.",
@@ -2349,7 +2351,7 @@
 bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
   // Look up the type.
   const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
-  if (type == NULL) {
+  if (type == nullptr) {
     std::cerr << "Type not defined: " << codec_type_ << std::endl;
     return false;
   }
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 27178b1..e842550 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -49,6 +49,8 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 9cc8cf9..46c36b3 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -96,8 +96,8 @@
 
 class CommandLineInterfaceTest : public testing::Test {
  protected:
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   // Runs the CommandLineInterface with the given command line.  The
   // command is automatically split on spaces, and the string "$tmpdir"
@@ -256,14 +256,14 @@
 class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator {
  public:
   NullCodeGenerator() : called_(false) {}
-  ~NullCodeGenerator() {}
+  ~NullCodeGenerator() override {}
 
   mutable bool called_;
   mutable std::string parameter_;
 
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file, const std::string& parameter,
-                GeneratorContext* context, std::string* error) const {
+                GeneratorContext* context, std::string* error) const override {
     called_ = true;
     parameter_ = parameter;
     return true;
@@ -2518,12 +2518,12 @@
 
 class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     WriteUnittestProtoDescriptorSet();
     duped_stdin_ = dup(STDIN_FILENO);
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     dup2(duped_stdin_, STDIN_FILENO);
     close(duped_stdin_);
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index 60619f1..6ed3a07 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -69,13 +69,13 @@
 class MockErrorCollector : public MultiFileErrorCollector {
  public:
   MockErrorCollector() {}
-  ~MockErrorCollector() {}
+  ~MockErrorCollector() override {}
 
   std::string text_;
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const std::string& filename, int line, int column,
-                const std::string& message) {
+                const std::string& message) override {
     strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
                               message);
   }
@@ -113,7 +113,7 @@
 
   // implements GeneratorContext --------------------------------------
 
-  virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
+  io::ZeroCopyOutputStream* Open(const std::string& filename) override {
     auto& map_slot = files_[filename];
     map_slot.reset(new std::string);
     return new io::StringOutputStream(map_slot.get());
@@ -137,9 +137,9 @@
   // of the data to compare to.
   std::map<std::string, std::string> vpath_map;
   std::map<std::string, std::string> rpath_map;
-  rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto2"] =
+  rpath_map["third_party/protobuf/test_messages_proto2"] =
       "net/proto2/z_generated_example/test_messages_proto2";
-  rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto3"] =
+  rpath_map["third_party/protobuf/test_messages_proto3"] =
       "net/proto2/z_generated_example/test_messages_proto3";
   rpath_map["net/proto2/internal/proto2_weak"] =
       "net/proto2/z_generated_example/proto2_weak";
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 6ae5cf4..fb72b75 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -38,10 +38,10 @@
 #include <limits>
 #include <map>
 
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/compiler/cpp/cpp_names.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_names.h>
 
 namespace google {
 namespace protobuf {
@@ -88,7 +88,7 @@
   variables_["nested_name"] = descriptor_->name();
   variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
   variables_["prefix"] =
-      (descriptor_->containing_type() == NULL) ? "" : classname_ + "_";
+      (descriptor_->containing_type() == nullptr) ? "" : classname_ + "_";
 }
 
 EnumGenerator::~EnumGenerator() {}
@@ -405,7 +405,7 @@
         descriptor_->value_count());
   }
 
-  if (descriptor_->containing_type() != NULL) {
+  if (descriptor_->containing_type() != nullptr) {
     std::string parent = ClassName(descriptor_->containing_type(), false);
     // Before C++17, we must define the static constants which were
     // declared in the header, to give the linker a place to put them.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 3687f04..2a17ede 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -38,8 +38,9 @@
 #include <map>
 #include <set>
 #include <string>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
+
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 70311dd..b27ed1e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -33,10 +33,11 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 namespace google {
 namespace protobuf {
@@ -143,7 +144,7 @@
   Formatter format(printer, variables_);
   format(
       "target = stream->EnsureSpace(target);\n"
-      "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
+      "target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
       "  $number$, this->_internal_$name$(), target);\n");
 }
 
@@ -151,9 +152,7 @@
   Formatter format(printer, variables_);
   format(
       "total_size += $tag_size$ +\n"
-      "  "
-      "::$proto_ns$::internal::WireFormatLite::EnumSize(this->_internal_$name$("
-      "));\n");
+      "  ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n");
 }
 
 void EnumFieldGenerator::GenerateConstinitInitializer(
@@ -352,7 +351,7 @@
     format(
         "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
         "  target = stream->EnsureSpace(target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
+        "  target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
         "      $number$, this->_internal_$name$(i), target);\n"
         "}\n");
   }
@@ -368,7 +367,7 @@
   format.Indent();
   format(
       "for (unsigned int i = 0; i < count; i++) {\n"
-      "  data_size += ::$proto_ns$::internal::WireFormatLite::EnumSize(\n"
+      "  data_size += ::_pbi::WireFormatLite::EnumSize(\n"
       "    this->_internal_$name$(static_cast<int>(i)));\n"
       "}\n");
 
@@ -376,10 +375,9 @@
     format(
         "if (data_size > 0) {\n"
         "  total_size += $tag_size$ +\n"
-        "    ::$proto_ns$::internal::WireFormatLite::Int32Size(\n"
-        "        static_cast<$int32$>(data_size));\n"
+        "    ::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
         "}\n"
-        "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n"
+        "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
         "_$name$_cached_byte_size_.store(cached_size,\n"
         "                                std::memory_order_relaxed);\n"
         "total_size += data_size;\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index e65ec0f..2a4ca51 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 
 namespace google {
@@ -47,7 +48,7 @@
 class EnumFieldGenerator : public FieldGenerator {
  public:
   EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
-  ~EnumFieldGenerator();
+  ~EnumFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
@@ -71,7 +72,7 @@
  public:
   EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
                           const Options& options);
-  ~EnumOneofFieldGenerator();
+  ~EnumOneofFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@@ -87,7 +88,7 @@
  public:
   RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
                              const Options& options);
-  ~RepeatedEnumFieldGenerator();
+  ~RepeatedEnumFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 8604da5..d5d0520 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -33,11 +33,13 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
+
 #include <map>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/descriptor.pb.h>
+
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
@@ -91,6 +93,19 @@
   variables_["scope"] = scope;
   variables_["scoped_name"] = ExtensionName(descriptor_);
   variables_["number"] = StrCat(descriptor_->number());
+
+  bool add_verify_fn =
+      // Only verify msgs.
+      descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+      // Options say to verify.
+      ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
+      ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
+
+  variables_["verify_fn"] =
+      add_verify_fn
+          ? StrCat("&", FieldMessageTypeName(descriptor_, options_),
+                         "::InternalVerify")
+          : "nullptr";
 }
 
 ExtensionGenerator::~ExtensionGenerator() {}
@@ -164,23 +179,11 @@
   }
 
   format(
-      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY "
+      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
       "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
-      "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
-      "  $scoped_name$($constant_name$, $1$);\n",
+      "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$>\n"
+      "  $scoped_name$($constant_name$, $1$, $verify_fn$);\n",
       default_str);
-
-  // Register extension verify function if needed.
-  if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
-      ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
-      ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_)) {
-    format(
-        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY "
-        "::$proto_ns$::internal::RegisterExtensionVerify< $extendee$,\n"
-        "    $1$, $number$> $2$_$name$_register;\n",
-        ClassName(descriptor_->message_type(), true),
-        IsScoped() ? ClassName(descriptor_->extension_scope(), false) : "");
-  }
 }
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index a95dd33..143102d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -38,19 +38,19 @@
 #include <memory>
 #include <string>
 
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_map_field.h>
 #include <google/protobuf/compiler/cpp/cpp_message_field.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
 
 namespace google {
 namespace protobuf {
@@ -114,7 +114,7 @@
 
   if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) {
     return strings::Substitute(
-        "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member,
+        "$0.IsDefault() ? &$1.get() : $0.GetPointer()", field_member,
         MakeDefaultName(descriptor));
   }
 
@@ -153,9 +153,6 @@
   std::string field_member = (*variables)["field_member"];
   const google::protobuf::OneofDescriptor* oneof_member =
       descriptor->real_containing_oneof();
-  if (oneof_member) {
-    field_member = StrCat(oneof_member->name(), "_.", field_member);
-  }
   const std::string proto_ns = (*variables)["proto_ns"];
   const std::string substitute_template_prefix = "  _tracker_.$1<$0>(this, ";
   std::string prepared_template;
@@ -178,7 +175,7 @@
   } else if (descriptor->is_map()) {
     prepared_template = "nullptr";
   } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
-             !descriptor->options().lazy()) {
+             !IsExplicitLazy(descriptor)) {
     prepared_template = "nullptr";
   } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
     if (oneof_member) {
@@ -244,7 +241,7 @@
   (*variables)["number"] = StrCat(descriptor->number());
   (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
   (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
-  (*variables)["field_member"] = FieldName(descriptor) + "_";
+  (*variables)["field_member"] = FieldMemberName(descriptor);
 
   (*variables)["tag_size"] = StrCat(
       WireFormat::TagSize(descriptor->number(), descriptor->type()));
@@ -287,6 +284,9 @@
     GOOGLE_CHECK_EQ(inlined_string_index, -1);
     return;
   }
+  // The first bit is the tracking bit for on demand registering ArenaDtor.
+  GOOGLE_CHECK_GT(inlined_string_index, 0)
+      << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking";
   variables_["inlined_string_donated"] = StrCat(
       "(_inlined_string_donated_[", inlined_string_index / 32, "] & 0x",
       strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
@@ -303,8 +303,6 @@
     std::map<std::string, std::string>* variables) {
   const std::string prefix = descriptor->containing_oneof()->name() + "_.";
   (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
-  (*variables)["field_member"] =
-      StrCat(prefix, (*variables)["name"], "_");
 }
 
 FieldGenerator::~FieldGenerator() {}
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index e0eb679..165b6fa 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -40,9 +40,9 @@
 #include <memory>
 #include <string>
 
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
-#include <google/protobuf/descriptor.h>
 
 namespace google {
 namespace protobuf {
@@ -158,11 +158,10 @@
   // Generate a manual destructor invocation for use when the message is on an
   // arena. The code that this method generates will be executed inside a
   // shared-for-the-whole-message-class method registered with
-  // OwnDestructor(). The method should return |true| if it generated any code
-  // that requires a call; this allows the message generator to eliminate the
-  // OwnDestructor() registration if no fields require it.
-  virtual bool GenerateArenaDestructorCode(io::Printer* printer) const {
-    return false;
+  // OwnDestructor().
+  virtual void GenerateArenaDestructorCode(io::Printer* printer) const {
+    GOOGLE_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone)
+        << descriptor_->cpp_type_name();
   }
 
   // Generate initialization code for private members declared by
@@ -187,6 +186,10 @@
 
   virtual bool IsInlined() const { return false; }
 
+  virtual ArenaDtorNeeds NeedsArenaDestructor() const {
+    return ArenaDtorNeeds::kNone;
+  }
+
   void SetHasBitIndex(int32_t has_bit_index);
   void SetInlinedStringIndex(int32_t inlined_string_index);
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index c7816b5..dfce01a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -42,16 +42,16 @@
 #include <unordered_set>
 #include <vector>
 
+#include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
 #include <google/protobuf/compiler/cpp/cpp_service.h>
-#include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 
 // Must be last.
 #include <google/protobuf/port_def.inc>
@@ -87,6 +87,23 @@
   return sorted;
 }
 
+// TODO(b/203101078): remove pragmas that suppresses uninitialized warnings when
+// clang bug is fixed.
+inline void MuteWuninitialized(Formatter& format) {
+  format(
+      "#if defined(__llvm__)\n"
+      "  #pragma clang diagnostic push\n"
+      "  #pragma clang diagnostic ignored \"-Wuninitialized\"\n"
+      "#endif  // __llvm__\n");
+}
+
+inline void UnmuteWuninitialized(Formatter& format) {
+  format(
+      "#if defined(__llvm__)\n"
+      "  #pragma clang diagnostic pop\n"
+      "#endif  // __llvm__\n");
+}
+
 }  // namespace
 
 FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
@@ -335,7 +352,14 @@
              options_.runtime_include_base, path);
     }
   } else {
-    format("#include \"$1$\"", google3_name);
+    std::string path = google3_name;
+    // The bootstrapped proto generated code needs to use the
+    // third_party/protobuf header paths to avoid circular dependencies.
+    if (options_.bootstrap) {
+      path = StringReplace(google3_name, "net/proto2/public",
+                           "third_party/protobuf", false);
+    }
+    format("#include \"$1$\"", path);
   }
 
   if (do_export) {
@@ -428,12 +452,28 @@
 
   format("// @@protoc_insertion_point(includes)\n");
   IncludeFile("net/proto2/public/port_def.inc", printer);
+}
+
+void FileGenerator::GenerateSourcePrelude(io::Printer* printer) {
+  Formatter format(printer, variables_);
 
   // For MSVC builds, we use #pragma init_seg to move the initialization of our
   // libraries to happen before the user code.
   // This worksaround the fact that MSVC does not do constant initializers when
   // required by the standard.
   format("\nPROTOBUF_PRAGMA_INIT_SEG\n");
+
+  // Generate convenience aliases.
+  format(
+      "\n"
+      "namespace _pb = ::$1$;\n"
+      "namespace _pbi = _pb::internal;\n",
+      ProtobufNamespace(options_));
+  if (HasGeneratedMethods(file_, options_) &&
+      options_.tctable_mode != Options::kTCTableNever) {
+    format("namespace _fl = _pbi::field_layout;\n");
+  }
+  format("\n");
 }
 
 void FileGenerator::GenerateSourceDefaultInstance(int idx,
@@ -447,7 +487,7 @@
   format(
       "struct $1$ {\n"
       "  constexpr $1$()\n"
-      "    : _instance(::$proto_ns$::internal::ConstantInitialized{}) {}\n"
+      "      : _instance(::_pbi::ConstantInitialized{}) {}\n"
       "  ~$1$() {}\n"
       "  union {\n"
       "    $2$ _instance;\n"
@@ -459,7 +499,8 @@
   // enough. However, the empty destructor fails to be elided in some
   // configurations (like non-opt or with certain sanitizers). NO_DESTROY is
   // there just to improve performance and binary size in these builds.
-  format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT $1$ $2$;\n",
+  format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
+         "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
          DefaultInstanceType(generator->descriptor_, options_),
          DefaultInstanceName(generator->descriptor_, options_));
 
@@ -468,7 +509,7 @@
     if (IsStringInlined(field, options_)) {
       // Force the initialization of the inlined string in the default instance.
       format(
-          "PROTOBUF_ATTRIBUTE_INIT_PRIORITY std::true_type "
+          "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type "
           "$1$::_init_inline_$2$_ = "
           "($3$._instance.$2$_.Init(), std::true_type{});\n",
           ClassName(generator->descriptor_), FieldName(field),
@@ -477,10 +518,11 @@
   }
 
   if (options_.lite_implicit_weak_fields) {
-    format("$1$* $2$ = &$3$;\n",
-           DefaultInstanceType(generator->descriptor_, options_),
-           DefaultInstancePtr(generator->descriptor_, options_),
-           DefaultInstanceName(generator->descriptor_, options_));
+    format(
+        "PROTOBUF_CONSTINIT const void* $1$ =\n"
+        "    &$2$;\n",
+        DefaultInstancePtr(generator->descriptor_, options_),
+        DefaultInstanceName(generator->descriptor_, options_));
   }
 }
 
@@ -534,11 +576,10 @@
     for (auto instance : Sorted(refs.weak_default_instances)) {
       ns.ChangeTo(Namespace(instance, options_));
       if (options_.lite_implicit_weak_fields) {
-        format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_),
-               DefaultInstanceName(instance, options_));
-        format("__attribute__((weak)) $1$* $2$ = nullptr;\n",
-               DefaultInstanceType(instance, options_),
-               DefaultInstancePtr(instance, options_));
+        format(
+            "PROTOBUF_CONSTINIT __attribute__((weak)) const void* $1$ =\n"
+            "    &::_pbi::implicit_weak_message_default_instance;\n",
+            DefaultInstancePtr(instance, options_));
       } else {
         format("extern __attribute__((weak)) $1$ $2$;\n",
                DefaultInstanceType(instance, options_),
@@ -549,8 +590,7 @@
 
   for (auto file : Sorted(refs.weak_reflection_files)) {
     format(
-        "extern __attribute__((weak)) const "
-        "::$proto_ns$::internal::DescriptorTable $1$;\n",
+        "extern __attribute__((weak)) const ::_pbi::DescriptorTable $1$;\n",
         DescriptorTableName(file, options_));
   }
 }
@@ -558,6 +598,9 @@
 void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
   Formatter format(printer, variables_);
   GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
+
+  if (IsAnyMessage(file_, options_)) MuteWuninitialized(format);
 
   CrossFileReferences refs;
   ForEachField(message_generators_[idx]->descriptor_,
@@ -586,6 +629,8 @@
     message_generators_[idx]->GenerateSourceInProto2Namespace(printer);
   }
 
+  if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format);
+
   format(
       "\n"
       "// @@protoc_insertion_point(global_scope)\n");
@@ -594,6 +639,7 @@
 void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) {
   Formatter format(printer, variables_);
   GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
   NamespaceOpener ns(Namespace(file_, options_), format);
   extension_generators_[idx]->GenerateDefinition(printer);
 }
@@ -601,10 +647,9 @@
 void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
   Formatter format(printer, variables_);
   GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
 
   {
-    GenerateTables(printer);
-
     // Define the code to initialize reflection. This code uses a global
     // constructor to register reflection data with the runtime pre-main.
     if (HasDescriptorMethods(file_, options_)) {
@@ -623,10 +668,13 @@
 void FileGenerator::GenerateSource(io::Printer* printer) {
   Formatter format(printer, variables_);
   GenerateSourceIncludes(printer);
+  GenerateSourcePrelude(printer);
   CrossFileReferences refs;
   GetCrossFileReferencesForFile(file_, &refs);
   GenerateInternalForwardDeclarations(refs, printer);
 
+  if (IsAnyMessage(file_, options_)) MuteWuninitialized(format);
+
   {
     NamespaceOpener ns(Namespace(file_, options_), format);
 
@@ -637,8 +685,6 @@
   }
 
   {
-    GenerateTables(printer);
-
     if (HasDescriptorMethods(file_, options_)) {
       // Define the code to initialize reflection. This code uses a global
       // constructor to register reflection data with the runtime pre-main.
@@ -695,6 +741,8 @@
       "\n"
       "// @@protoc_insertion_point(global_scope)\n");
 
+  if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format);
+
   IncludeFile("net/proto2/public/port_undef.inc", printer);
 }
 
@@ -702,31 +750,30 @@
   Formatter format(printer, variables_);
 
   if (!message_generators_.empty()) {
-    format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n",
+    format("static ::_pb::Metadata $file_level_metadata$[$1$];\n",
            message_generators_.size());
   }
   if (!enum_generators_.empty()) {
     format(
-        "static "
-        "const ::$proto_ns$::EnumDescriptor* "
+        "static const ::_pb::EnumDescriptor* "
         "$file_level_enum_descriptors$[$1$];\n",
         enum_generators_.size());
   } else {
     format(
         "static "
-        "constexpr ::$proto_ns$::EnumDescriptor const** "
+        "constexpr ::_pb::EnumDescriptor const** "
         "$file_level_enum_descriptors$ = nullptr;\n");
   }
   if (HasGenericServices(file_, options_) && file_->service_count() > 0) {
     format(
         "static "
-        "const ::$proto_ns$::ServiceDescriptor* "
+        "const ::_pb::ServiceDescriptor* "
         "$file_level_service_descriptors$[$1$];\n",
         file_->service_count());
   } else {
     format(
         "static "
-        "constexpr ::$proto_ns$::ServiceDescriptor const** "
+        "constexpr ::_pb::ServiceDescriptor const** "
         "$file_level_service_descriptors$ = nullptr;\n");
   }
 
@@ -744,7 +791,7 @@
     format.Outdent();
     format(
         "};\n"
-        "static const ::$proto_ns$::internal::MigrationSchema schemas[] "
+        "static const ::_pbi::MigrationSchema schemas[] "
         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
     format.Indent();
     {
@@ -758,16 +805,13 @@
     format.Outdent();
     format(
         "};\n"
-        "\nstatic "
-        "::$proto_ns$::Message const * const file_default_instances[] = {\n");
+        "\nstatic const ::_pb::Message* const file_default_instances[] = {\n");
     format.Indent();
     for (int i = 0; i < message_generators_.size(); i++) {
       const Descriptor* descriptor = message_generators_[i]->descriptor_;
-      format(
-          "reinterpret_cast<const "
-          "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n",
-          Namespace(descriptor, options_),  // 1
-          ClassName(descriptor));           // 2
+      format("&$1$::_$2$_default_instance_._instance,\n",
+             Namespace(descriptor, options_),  // 1
+             ClassName(descriptor));           // 2
     }
     format.Outdent();
     format(
@@ -778,10 +822,8 @@
     format(
         // MSVC doesn't like empty arrays, so we add a dummy.
         "const $uint32$ $tablename$::offsets[1] = {};\n"
-        "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = "
-        "nullptr;"
-        "\n"
-        "static constexpr ::$proto_ns$::Message* const* "
+        "static constexpr ::_pbi::MigrationSchema* schemas = nullptr;\n"
+        "static constexpr ::_pb::Message* const* "
         "file_default_instances = nullptr;\n"
         "\n");
   }
@@ -836,7 +878,7 @@
   // Build array of DescriptorTable deps.
   if (num_deps > 0) {
     format(
-        "static const ::$proto_ns$::internal::DescriptorTable*const "
+        "static const ::_pbi::DescriptorTable* const "
         "$desc_table$_deps[$1$] = {\n",
         num_deps);
 
@@ -856,13 +898,14 @@
   // so disable for now.
   bool eager = false;
   format(
-      "static ::$proto_ns$::internal::once_flag $desc_table$_once;\n"
-      "const ::$proto_ns$::internal::DescriptorTable $desc_table$ = {\n"
-      "  false, $1$, $2$, $3$, \"$filename$\", \n"
-      "  &$desc_table$_once, $4$, $5$, $6$,\n"
-      "  schemas, file_default_instances, $tablename$::offsets,\n"
-      "  $7$, $file_level_enum_descriptors$, "
-      "$file_level_service_descriptors$,\n"
+      "static ::_pbi::once_flag $desc_table$_once;\n"
+      "const ::_pbi::DescriptorTable $desc_table$ = {\n"
+      "    false, $1$, $2$, $3$,\n"
+      "    \"$filename$\",\n"
+      "    &$desc_table$_once, $4$, $5$, $6$,\n"
+      "    schemas, file_default_instances, $tablename$::offsets,\n"
+      "    $7$, $file_level_enum_descriptors$,\n"
+      "    $file_level_service_descriptors$,\n"
       "};\n"
       // This function exists to be marked as weak.
       // It can significantly speed up compilation by breaking up LLVM's SCC in
@@ -875,7 +918,7 @@
       //   vtables -> GetMetadata
       // By adding a weak function here we break the connection from the
       // individual vtables back into the descriptor table.
-      "PROTOBUF_ATTRIBUTE_WEAK const ::$proto_ns$::internal::DescriptorTable* "
+      "PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* "
       "$desc_table$_getter() {\n"
       "  return &$desc_table$;\n"
       "}\n"
@@ -893,123 +936,12 @@
   if (file_->name() != "net/proto2/proto/descriptor.proto") {
     format(
         "// Force running AddDescriptors() at dynamic initialization time.\n"
-        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY "
-        "static ::$proto_ns$::internal::AddDescriptorsRunner "
-        "$1$(&$desc_table$);\n",
+        "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
+        "static ::_pbi::AddDescriptorsRunner $1$(&$desc_table$);\n",
         UniqueName("dynamic_init_dummy", file_, options_));
   }
 }
 
-void FileGenerator::GenerateTables(io::Printer* printer) {
-  Formatter format(printer, variables_);
-  if (options_.table_driven_parsing) {
-    // TODO(ckennelly): Gate this with the same options flag to enable
-    // table-driven parsing.
-    format(
-        "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n"
-        "    const $tablename$::entries[] "
-        "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
-    format.Indent();
-
-    std::vector<size_t> entries;
-    size_t count = 0;
-    for (int i = 0; i < message_generators_.size(); i++) {
-      size_t value = message_generators_[i]->GenerateParseOffsets(printer);
-      entries.push_back(value);
-      count += value;
-    }
-
-    // We need these arrays to exist, and MSVC does not like empty arrays.
-    if (count == 0) {
-      format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n");
-    }
-
-    format.Outdent();
-    format(
-        "};\n"
-        "\n"
-        "PROTOBUF_CONSTEXPR_VAR "
-        "::$proto_ns$::internal::AuxiliaryParseTableField\n"
-        "    const $tablename$::aux[] "
-        "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
-    format.Indent();
-
-    std::vector<size_t> aux_entries;
-    count = 0;
-    for (int i = 0; i < message_generators_.size(); i++) {
-      size_t value = message_generators_[i]->GenerateParseAuxTable(printer);
-      aux_entries.push_back(value);
-      count += value;
-    }
-
-    if (count == 0) {
-      format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n");
-    }
-
-    format.Outdent();
-    format(
-        "};\n"
-        "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n"
-        "    $tablename$::schema[] "
-        "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
-    format.Indent();
-
-    size_t offset = 0;
-    size_t aux_offset = 0;
-    for (int i = 0; i < message_generators_.size(); i++) {
-      message_generators_[i]->GenerateParseTable(printer, offset, aux_offset);
-      offset += entries[i];
-      aux_offset += aux_entries[i];
-    }
-
-    if (message_generators_.empty()) {
-      format("{ nullptr, nullptr, 0, -1, -1, false },\n");
-    }
-
-    format.Outdent();
-    format(
-        "};\n"
-        "\n");
-  }
-
-  if (!message_generators_.empty() && options_.table_driven_serialization) {
-    format(
-        "const ::$proto_ns$::internal::FieldMetadata "
-        "$tablename$::field_metadata[] "
-        "= {\n");
-    format.Indent();
-    std::vector<int> field_metadata_offsets;
-    int idx = 0;
-    for (int i = 0; i < message_generators_.size(); i++) {
-      field_metadata_offsets.push_back(idx);
-      idx += message_generators_[i]->GenerateFieldMetadata(printer);
-    }
-    field_metadata_offsets.push_back(idx);
-    format.Outdent();
-    format(
-        "};\n"
-        "const ::$proto_ns$::internal::SerializationTable "
-        "$tablename$::serialization_table[] = {\n");
-    format.Indent();
-    // We rely on the order we layout the tables to match the order we
-    // calculate them with FlattenMessagesInFile, so we check here that
-    // these match exactly.
-    std::vector<const Descriptor*> calculated_order =
-        FlattenMessagesInFile(file_);
-    GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size());
-    for (int i = 0; i < message_generators_.size(); i++) {
-      GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_);
-      format("{$1$, $tablename$::field_metadata + $2$},\n",
-             field_metadata_offsets[i + 1] - field_metadata_offsets[i],  // 1
-             field_metadata_offsets[i]);                                 // 2
-    }
-    format.Outdent();
-    format(
-        "};\n"
-        "\n");
-  }
-}
-
 class FileGenerator::ForwardDeclarations {
  public:
   void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; }
@@ -1185,7 +1117,6 @@
   if (HasSimpleBaseClasses(file_, options_)) {
     IncludeFile("net/proto2/public/generated_message_bases.h", printer);
   }
-  IncludeFile("net/proto2/public/generated_message_table_driven.h", printer);
   if (HasGeneratedMethods(file_, options_) &&
       options_.tctable_mode != Options::kTCTableNever) {
     IncludeFile("net/proto2/public/generated_message_tctable_decl.h", printer);
@@ -1297,20 +1228,8 @@
       "\n"
       "// Internal implementation detail -- do not use these members.\n"
       "struct $dllexport_decl $$tablename$ {\n"
-      // These tables describe how to serialize and parse messages. Used
-      // for table driven code.
-      "  static const ::$proto_ns$::internal::ParseTableField entries[]\n"
-      "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
-      "  static const ::$proto_ns$::internal::AuxiliaryParseTableField aux[]\n"
-      "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
-      "  static const ::$proto_ns$::internal::ParseTable schema[$1$]\n"
-      "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
-      "  static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n"
-      "  static const ::$proto_ns$::internal::SerializationTable "
-      "serialization_table[];\n"
       "  static const $uint32$ offsets[];\n"
-      "};\n",
-      std::max(size_t(1), message_generators_.size()));
+      "};\n");
   if (HasDescriptorMethods(file_, options_)) {
     format(
         "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable "
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index e881602..b69202f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -40,11 +40,12 @@
 #include <set>
 #include <string>
 #include <vector>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/compiler/scc.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 
 namespace google {
 namespace protobuf {
@@ -122,11 +123,11 @@
   void GenerateInternalForwardDeclarations(const CrossFileReferences& refs,
                                            io::Printer* printer);
   void GenerateSourceIncludes(io::Printer* printer);
+  void GenerateSourcePrelude(io::Printer* printer);
   void GenerateSourceDefaultInstance(int idx, io::Printer* printer);
 
   void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs,
                           io::Printer* printer);
-  void GenerateTables(io::Printer* printer);
   void GenerateReflectionInitializationCode(io::Printer* printer);
 
   // For other imports, generates their forward-declarations.
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 0851571..5abcd45 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -40,11 +40,11 @@
 #include <vector>
 
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/compiler/cpp/cpp_file.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream.h>
 
 namespace google {
 namespace protobuf {
@@ -109,7 +109,7 @@
       file_options.lite_implicit_weak_fields = true;
       if (!options[i].second.empty()) {
         file_options.num_cc_files =
-            strto32(options[i].second.c_str(), NULL, 10);
+            strto32(options[i].second.c_str(), nullptr, 10);
       }
     } else if (options[i].first == "annotate_accessor") {
       file_options.annotate_accessor = true;
@@ -127,14 +127,14 @@
               .insert(options[i].second.substr(pos, next_pos - pos));
         pos = next_pos + 1;
       } while (pos < options[i].second.size());
+    } else if (options[i].first == "verified_lazy_message_sets") {
+      file_options.unverified_lazy_message_sets = false;
+    } else if (options[i].first == "unverified_lazy_message_sets") {
+      file_options.unverified_lazy_message_sets = true;
     } else if (options[i].first == "eagerly_verified_lazy") {
       file_options.eagerly_verified_lazy = true;
     } else if (options[i].first == "force_eagerly_verified_lazy") {
       file_options.force_eagerly_verified_lazy = true;
-    } else if (options[i].first == "table_driven_parsing") {
-      file_options.table_driven_parsing = true;
-    } else if (options[i].first == "table_driven_serialization") {
-      file_options.table_driven_serialization = true;
     } else if (options[i].first == "experimental_tail_call_table_mode") {
       if (options[i].second == "never") {
         file_options.tctable_mode = Options::kTCTableNever;
@@ -183,7 +183,7 @@
     std::string info_path = basename + ".proto.h.meta";
     io::Printer printer(
         output.get(), '$',
-        file_options.annotate_headers ? &annotation_collector : NULL);
+        file_options.annotate_headers ? &annotation_collector : nullptr);
     file_generator.GenerateProtoHeader(
         &printer, file_options.annotate_headers ? info_path : "");
     if (file_options.annotate_headers) {
@@ -202,7 +202,7 @@
     std::string info_path = basename + ".pb.h.meta";
     io::Printer printer(
         output.get(), '$',
-        file_options.annotate_headers ? &annotation_collector : NULL);
+        file_options.annotate_headers ? &annotation_collector : nullptr);
     file_generator.GeneratePBHeader(
         &printer, file_options.annotate_headers ? info_path : "");
     if (file_options.annotate_headers) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
index 97e848d..1a374b9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -40,6 +40,7 @@
 #include <string>
 #include <google/protobuf/compiler/code_generator.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -54,7 +55,7 @@
 class PROTOC_EXPORT CppGenerator : public CodeGenerator {
  public:
   CppGenerator();
-  ~CppGenerator();
+  ~CppGenerator() override;
 
   enum class Runtime {
     kGoogle3,     // Use the internal google3 runtime.
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 9fe47bf..2eb91f3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -44,10 +44,10 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
-#include <google/protobuf/compiler/cpp/cpp_names.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_names.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -453,6 +453,14 @@
   return result;
 }
 
+std::string FieldMemberName(const FieldDescriptor* field) {
+  if (field->real_containing_oneof() == nullptr) {
+    return StrCat(FieldName(field), "_");
+  }
+  return StrCat(field->containing_oneof()->name(), "_.", FieldName(field),
+                      "_");
+}
+
 std::string OneofCaseConstantName(const FieldDescriptor* field) {
   GOOGLE_DCHECK(field->containing_oneof());
   std::string field_name = UnderscoresToCamelCase(field->name(), true);
@@ -1147,7 +1155,6 @@
   return UsingImplicitWeakFields(field->file(), options) &&
          field->type() == FieldDescriptor::TYPE_MESSAGE &&
          !field->is_required() && !field->is_map() && !field->is_extension() &&
-         !field->real_containing_oneof() &&
          !IsWellKnownMessage(field->message_type()->file()) &&
          field->message_type()->file()->name() !=
              "net/proto2/proto/descriptor.proto" &&
@@ -1264,7 +1271,7 @@
 
   std::unordered_map<std::string, std::string> bootstrap_mapping{
       {"net/proto2/proto/descriptor",
-       "net/proto2/internal/descriptor"},
+       "third_party/protobuf/descriptor"},
       {"net/proto2/compiler/proto/plugin",
        "net/proto2/compiler/proto/plugin"},
       {"net/proto2/compiler/proto/profile",
@@ -1297,7 +1304,7 @@
     *basename = bootstrap_basename;
     return false;
   } else {
-    std::string forward_to_basename = bootstrap_basename;
+    const std::string& forward_to_basename = bootstrap_basename;
 
     // Generate forwarding headers and empty .pb.cc.
     {
@@ -1486,8 +1493,9 @@
   return FileOptions::SPEED;
 }
 
-bool EnableMessageOwnedArena(const Descriptor* desc) {
+bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options) {
   (void)desc;
+  (void)options;
   return false;
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index bd4f48b..c021725 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -41,10 +41,10 @@
 #include <map>
 #include <string>
 
-#include <google/protobuf/compiler/cpp/cpp_options.h>
-#include <google/protobuf/compiler/cpp/cpp_names.h>
 #include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/cpp/cpp_names.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/descriptor.h>
@@ -59,6 +59,8 @@
 namespace compiler {
 namespace cpp {
 
+enum class ArenaDtorNeeds { kNone = 0, kOnDemand = 1, kRequired = 2 };
+
 inline std::string ProtobufNamespace(const Options& /* options */) {
   return "PROTOBUF_NAMESPACE_ID";
 }
@@ -186,6 +188,9 @@
 // anyway, so normally this just returns field->name().
 std::string FieldName(const FieldDescriptor* field);
 
+// Returns the (unqualified) private member name for this field in C++ code.
+std::string FieldMemberName(const FieldDescriptor* field);
+
 // Returns an estimate of the compiler's alignment for the field.  This
 // can't guarantee to be correct because the generated code could be compiled on
 // different systems with different alignment rules.  The estimates below assume
@@ -348,9 +353,17 @@
 bool IsLazy(const FieldDescriptor* field, const Options& options,
             MessageSCCAnalyzer* scc_analyzer);
 
+// Is this an explicit (non-profile driven) lazy field, as denoted by
+// lazy/unverified_lazy in the descriptor?
+inline bool IsExplicitLazy(const FieldDescriptor* field) {
+  return field->options().lazy() || field->options().unverified_lazy();
+}
+
 inline bool IsLazilyVerifiedLazy(const FieldDescriptor* field,
                                  const Options& options) {
-  return field->options().lazy() && !field->is_repeated() &&
+  // TODO(b/211906113): Make lazy() imply eagerly verified lazy.
+  return IsExplicitLazy(field) &&
+         !field->is_repeated() &&
          field->type() == FieldDescriptor::TYPE_MESSAGE &&
          GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME &&
          !options.opensource_runtime;
@@ -359,7 +372,8 @@
 inline bool IsEagerlyVerifiedLazy(const FieldDescriptor* field,
                                   const Options& options,
                                   MessageSCCAnalyzer* scc_analyzer) {
-  return IsLazy(field, options, scc_analyzer) && !field->options().lazy();
+  // TODO(b/211906113): Make lazy() imply eagerly verified lazy.
+  return IsLazy(field, options, scc_analyzer) && !IsExplicitLazy(field);
 }
 
 inline bool IsFieldUsed(const FieldDescriptor* /* field */,
@@ -955,7 +969,7 @@
 
 PROTOC_EXPORT std::string StripProto(const std::string& filename);
 
-bool EnableMessageOwnedArena(const Descriptor* desc);
+bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options);
 
 bool ShouldVerify(const Descriptor* descriptor, const Options& options,
                   MessageSCCAnalyzer* scc_analyzer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 96f512d..4c77658 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -30,10 +30,10 @@
 
 #include <google/protobuf/compiler/cpp/cpp_map_field.h>
 
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 
 namespace google {
@@ -53,10 +53,8 @@
   (*variables)["type"] = ClassName(descriptor->message_type(), false);
   (*variables)["full_name"] = descriptor->full_name();
 
-  const FieldDescriptor* key =
-      descriptor->message_type()->map_key();
-  const FieldDescriptor* val =
-      descriptor->message_type()->map_value();
+  const FieldDescriptor* key = descriptor->message_type()->map_key();
+  const FieldDescriptor* val = descriptor->message_type()->map_value();
   (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
   switch (val->cpp_type()) {
     case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -169,35 +167,27 @@
   GenerateMergingCode(printer);
 }
 
-static void GenerateSerializationLoop(const Formatter& format, bool string_key,
+static void GenerateSerializationLoop(Formatter& format, bool string_key,
                                       bool string_value,
                                       bool is_deterministic) {
-  std::string ptr;
   if (is_deterministic) {
-    format("for (size_type i = 0; i < n; i++) {\n");
-    ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]"
-                     : "items[static_cast<ptrdiff_t>(i)].second";
-  } else {
     format(
-        "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-        "    it = this->_internal_$name$().begin();\n"
-        "    it != this->_internal_$name$().end(); ++it) {\n");
-    ptr = "it";
+        "for (const auto& entry : "
+        "::_pbi::MapSorter$1$<MapType>(map_field)) {\n",
+        (string_key ? "Ptr" : "Flat"));
+  } else {
+    format("for (const auto& entry : map_field) {\n");
   }
-  format.Indent();
+  {
+    auto loop_scope = format.ScopedIndent();
+    format(
+        "target = WireHelper::InternalSerialize($number$, "
+        "entry.first, entry.second, target, stream);\n");
 
-  format(
-      "target = $map_classname$::Funcs::InternalSerialize($number$, "
-      "$1$->first, $1$->second, target, stream);\n",
-      ptr);
-
-  if (string_key || string_value) {
-    // ptr is either an actual pointer or an iterator, either way we can
-    // create a pointer by taking the address after de-referencing it.
-    format("Utf8Check::Check(&(*$1$));\n", ptr);
+    if (string_key || string_value) {
+      format("check_utf8(entry);\n");
+    }
   }
-
-  format.Outdent();
   format("}\n");
 }
 
@@ -206,77 +196,53 @@
   Formatter format(printer, variables_);
   format("if (!this->_internal_$name$().empty()) {\n");
   format.Indent();
-  const FieldDescriptor* key_field =
-      descriptor_->message_type()->map_key();
-  const FieldDescriptor* value_field =
-      descriptor_->message_type()->map_value();
+  const FieldDescriptor* key_field = descriptor_->message_type()->map_key();
+  const FieldDescriptor* value_field = descriptor_->message_type()->map_value();
   const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
   const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
 
   format(
-      "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
-      "    ConstPtr;\n");
-  if (string_key) {
-    format(
-        "typedef ConstPtr SortItem;\n"
-        "typedef ::$proto_ns$::internal::"
-        "CompareByDerefFirst<SortItem> Less;\n");
-  } else {
-    format(
-        "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > "
-        "SortItem;\n"
-        "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> "
-        "Less;\n");
-  }
+      "using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n"
+      "using WireHelper = $map_classname$::Funcs;\n"
+      "const auto& map_field = this->_internal_$name$();\n");
   bool utf8_check = string_key || string_value;
   if (utf8_check) {
-    format(
-        "struct Utf8Check {\n"
-        "  static void Check(ConstPtr p) {\n"
-        // p may be unused when GetUtf8CheckMode evaluates to kNone,
-        // thus disabling the validation.
-        "    (void)p;\n");
-    format.Indent();
-    format.Indent();
-    if (string_key) {
-      GenerateUtf8CheckCodeForString(
-          key_field, options_, false,
-          "p->first.data(), static_cast<int>(p->first.length()),\n", format);
+    format("auto check_utf8 = [](const MapType::value_type& entry) {\n");
+    {
+      auto check_scope = format.ScopedIndent();
+      // p may be unused when GetUtf8CheckMode evaluates to kNone,
+      // thus disabling the validation.
+      format("(void)entry;\n");
+      if (string_key) {
+        GenerateUtf8CheckCodeForString(
+            key_field, options_, false,
+            "entry.first.data(), static_cast<int>(entry.first.length()),\n",
+            format);
+      }
+      if (string_value) {
+        GenerateUtf8CheckCodeForString(
+            value_field, options_, false,
+            "entry.second.data(), static_cast<int>(entry.second.length()),\n",
+            format);
+      }
     }
-    if (string_value) {
-      GenerateUtf8CheckCodeForString(
-          value_field, options_, false,
-          "p->second.data(), static_cast<int>(p->second.length()),\n", format);
-    }
-    format.Outdent();
-    format.Outdent();
     format(
-        "  }\n"
         "};\n");
   }
 
   format(
       "\n"
-      "if (stream->IsSerializationDeterministic() &&\n"
-      "    this->_internal_$name$().size() > 1) {\n"
-      "  ::std::unique_ptr<SortItem[]> items(\n"
-      "      new SortItem[this->_internal_$name$().size()]);\n"
-      "  typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type "
-      "size_type;\n"
-      "  size_type n = 0;\n"
-      "  for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = this->_internal_$name$().begin();\n"
-      "      it != this->_internal_$name$().end(); ++it, ++n) {\n"
-      "    items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
-      "  }\n"
-      "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
-  format.Indent();
-  GenerateSerializationLoop(format, string_key, string_value, true);
-  format.Outdent();
+      "if (stream->IsSerializationDeterministic() && "
+      "map_field.size() > 1) {\n");
+  {
+    auto deterministic_scope = format.ScopedIndent();
+    GenerateSerializationLoop(format, string_key, string_value, true);
+  }
   format("} else {\n");
-  format.Indent();
-  GenerateSerializationLoop(format, string_key, string_value, false);
-  format.Outdent();
+  {
+    auto map_order_scope = format.ScopedIndent();
+    GenerateSerializationLoop(format, string_key, string_value, false);
+  }
   format("}\n");
   format.Outdent();
   format("}\n");
@@ -315,17 +281,28 @@
   }
 }
 
-bool MapFieldGenerator::GenerateArenaDestructorCode(
-    io::Printer* printer) const {
+void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
+
   Formatter format(printer, variables_);
-  if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    // _this is the object being destructed (we are inside a static method
-    // here).
-    format("_this->$name$_. ~MapField();\n");
-    return true;
-  } else {
-    return false;
+  format("$name$_.Destruct();\n");
+}
+
+void MapFieldGenerator::GenerateArenaDestructorCode(
+    io::Printer* printer) const {
+  if (NeedsArenaDestructor() == ArenaDtorNeeds::kNone) {
+    return;
   }
+
+  Formatter format(printer, variables_);
+  // _this is the object being destructed (we are inside a static method here).
+  format("_this->$name$_.Destruct();\n");
+}
+
+ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const {
+  return HasDescriptorMethods(descriptor_->file(), options_)
+             ? ArenaDtorNeeds::kRequired
+             : ArenaDtorNeeds::kNone;
 }
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index c01ae49..9e71267 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -62,7 +62,9 @@
   void GenerateByteSize(io::Printer* printer) const override;
   void GenerateIsInitialized(io::Printer* printer) const override;
   void GenerateConstinitInitializer(io::Printer* printer) const override;
-  bool GenerateArenaDestructorCode(io::Printer* printer) const override;
+  void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateArenaDestructorCode(io::Printer* printer) const override;
+  ArenaDtorNeeds NeedsArenaDestructor() const override;
 
  private:
   const bool has_required_fields_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 1385046..030fc4b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -44,6 +44,14 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map_entry_lite.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_extension.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
@@ -51,15 +59,6 @@
 #include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h>
 #include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/generated_message_table_driven.h>
-#include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/map_entry_lite.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/hash.h>
 
 
@@ -323,64 +322,6 @@
   return true;
 }
 
-bool TableDrivenParsingEnabled(const Descriptor* descriptor,
-                               const Options& options,
-                               MessageSCCAnalyzer* scc_analyzer) {
-  if (!options.table_driven_parsing) {
-    return false;
-  }
-
-  // Consider table-driven parsing.  We only do this if:
-  // - We have has_bits for fields.  This avoids a check on every field we set
-  //   when are present (the common case).
-  bool has_hasbit = false;
-  for (int i = 0; i < descriptor->field_count(); i++) {
-    if (HasHasbit(descriptor->field(i))) {
-      has_hasbit = true;
-      break;
-    }
-  }
-
-  if (!has_hasbit) return false;
-
-  const double table_sparseness = 0.5;
-  int max_field_number = 0;
-  for (auto field : FieldRange(descriptor)) {
-    if (max_field_number < field->number()) {
-      max_field_number = field->number();
-    }
-
-    // - There are no weak fields.
-    if (IsWeak(field, options)) {
-      return false;
-    }
-
-    // - There are no lazy fields (they require the non-lite library).
-    if (IsLazy(field, options, scc_analyzer)) {
-      return false;
-    }
-  }
-
-  // - There range of field numbers is "small"
-  if (max_field_number >= (2 << 14)) {
-    return false;
-  }
-
-  // - Field numbers are relatively dense within the actual number of fields.
-  //   We check for strictly greater than in the case where there are no fields
-  //   (only extensions) so max_field_number == descriptor->field_count() == 0.
-  if (max_field_number * table_sparseness > descriptor->field_count()) {
-    return false;
-  }
-
-  // - This is not a MapEntryMessage.
-  if (IsMapEntryMessage(descriptor)) {
-    return false;
-  }
-
-  return true;
-}
-
 bool IsCrossFileMapField(const FieldDescriptor* field) {
   if (!field->is_map()) {
     return false;
@@ -406,8 +347,8 @@
 
 bool HasSingularString(const Descriptor* desc, const Options& options) {
   for (const auto* field : FieldRange(desc)) {
-    if (IsString(field, options) && !IsStringInlined(field, options) &&
-        !field->is_repeated() && !field->real_containing_oneof()) {
+    if (IsString(field, options) && !field->is_repeated() &&
+        !field->real_containing_oneof()) {
       return true;
     }
   }
@@ -738,6 +679,9 @@
     if (IsStringInlined(field, options_)) {
       if (inlined_string_indices_.empty()) {
         inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit);
+        // The bitset[0] is for arena dtor tracking. Donating states start from
+        // bitset[1];
+        max_inlined_string_index_++;
       }
       inlined_string_indices_[field->index()] = max_inlined_string_index_++;
     }
@@ -758,8 +702,6 @@
     }
   }
 
-  table_driven_ =
-      TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_);
   parse_function_generator_.reset(new ParseFunctionGenerator(
       descriptor_, max_has_bit_index_, has_bit_indices_,
       inlined_string_indices_, options_, scc_analyzer_, variables_));
@@ -1432,7 +1374,9 @@
           ""
           "  ::$proto_ns$::Metadata GetMetadata() const final;\n");
     }
-    format("};\n");
+    format(
+        "  friend struct ::$tablename$;\n"
+        "};\n");
     return;
   }
 
@@ -1444,7 +1388,7 @@
   format(" public:\n");
   format.Indent();
 
-  if (EnableMessageOwnedArena(descriptor_)) {
+  if (EnableMessageOwnedArena(descriptor_, options_)) {
     format(
         "inline $classname$() : $classname$("
         "::$proto_ns$::Arena::InternalHelper<$classname$>::\n"
@@ -1484,14 +1428,6 @@
       "}\n"
       "\n");
 
-  if (options_.table_driven_serialization) {
-    format(
-        "private:\n"
-        "const void* InternalGetTable() const override;\n"
-        "public:\n"
-        "\n");
-  }
-
   if (PublicUnknownFieldsAccessors(descriptor_)) {
     format(
         "inline const $unknown_fields_type$& unknown_fields() const {\n"
@@ -1756,13 +1692,30 @@
       // we rely on.
       "protected:\n"
       "explicit $classname$(::$proto_ns$::Arena* arena,\n"
-      "                     bool is_message_owned = false);\n"
-      "private:\n");
+      "                     bool is_message_owned = false);\n");
 
-  if (!HasSimpleBaseClass(descriptor_, options_)) {
-    format(
-        "static void ArenaDtor(void* object);\n"
-        "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n");
+  switch (NeedsArenaDestructor()) {
+    case ArenaDtorNeeds::kOnDemand:
+      format(
+          "private:\n"
+          "static void ArenaDtor(void* object);\n"
+          "inline void OnDemandRegisterArenaDtor(::$proto_ns$::Arena* arena) "
+          "override {\n"
+          "  if (arena == nullptr || (_inlined_string_donated_[0] & 0x1u) == "
+          "0) {\n"
+          "   return;\n"
+          "  }\n"
+          "  _inlined_string_donated_[0] &= 0xFFFFFFFEu;\n"
+          "  arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+          "}\n");
+      break;
+    case ArenaDtorNeeds::kRequired:
+      format(
+          "private:\n"
+          "static void ArenaDtor(void* object);\n");
+      break;
+    case ArenaDtorNeeds::kNone:
+      break;
   }
 
   format(
@@ -1866,7 +1819,7 @@
   // Prepare decls for _cached_size_ and _has_bits_.  Their position in the
   // output will be determined later.
 
-  bool need_to_emit_cached_size = true;
+  bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_);
   const std::string cached_size_decl =
       "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n";
 
@@ -1917,8 +1870,10 @@
     // _cached_size_ together with _has_bits_ improves cache locality despite
     // potential alignment padding.
     format(has_bits_decl.c_str());
-    format(cached_size_decl.c_str());
-    need_to_emit_cached_size = false;
+    if (need_to_emit_cached_size) {
+      format(cached_size_decl.c_str());
+      need_to_emit_cached_size = false;
+    }
   }
 
   // Field members:
@@ -2007,67 +1962,6 @@
   }
 }
 
-bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset,
-                                          size_t aux_offset) {
-  Formatter format(printer, variables_);
-
-  if (!table_driven_) {
-    format("{ nullptr, nullptr, 0, -1, -1, -1, -1, nullptr, false },\n");
-    return false;
-  }
-
-  int max_field_number = 0;
-  for (auto field : FieldRange(descriptor_)) {
-    if (max_field_number < field->number()) {
-      max_field_number = field->number();
-    }
-  }
-
-  format("{\n");
-  format.Indent();
-
-  format(
-      "$tablename$::entries + $1$,\n"
-      "$tablename$::aux + $2$,\n"
-      "$3$,\n",
-      offset, aux_offset, max_field_number);
-
-  if (has_bit_indices_.empty()) {
-    // If no fields have hasbits, then _has_bits_ does not exist.
-    format("-1,\n");
-  } else {
-    format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n");
-  }
-
-  if (descriptor_->real_oneof_decl_count() > 0) {
-    format("PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_),\n");
-  } else {
-    format("-1,  // no _oneof_case_\n");
-  }
-
-  if (descriptor_->extension_range_count() > 0) {
-    format("PROTOBUF_FIELD_OFFSET($classtype$, _extensions_),\n");
-  } else {
-    format("-1,  // no _extensions_\n");
-  }
-
-  // TODO(ckennelly): Consolidate this with the calculation for
-  // AuxiliaryParseTableField.
-  format(
-      "PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n"
-      "&$package_ns$::_$classname$_default_instance_,\n");
-
-  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
-    format("true,\n");
-  } else {
-    format("false,\n");
-  }
-
-  format.Outdent();
-  format("},\n");
-  return true;
-}
-
 void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
                                       int has_offset) {
   Formatter format(printer, variables_);
@@ -2087,218 +1981,6 @@
          inlined_string_indices_offset);
 }
 
-namespace {
-
-// We need to calculate for each field what function the table driven code
-// should use to serialize it. This returns the index in a lookup table.
-uint32_t CalcFieldNum(const FieldGenerator& generator,
-                      const FieldDescriptor* field, const Options& options) {
-  bool is_a_map = IsMapEntryMessage(field->containing_type());
-  int type = field->type();
-  if (type == FieldDescriptor::TYPE_STRING ||
-      type == FieldDescriptor::TYPE_BYTES) {
-    // string field
-    if (generator.IsInlined()) {
-      type = internal::FieldMetadata::kInlinedType;
-    } else if (IsCord(field, options)) {
-      type = internal::FieldMetadata::kCordType;
-    } else if (IsStringPiece(field, options)) {
-      type = internal::FieldMetadata::kStringPieceType;
-    }
-  }
-
-  if (field->real_containing_oneof()) {
-    return internal::FieldMetadata::CalculateType(
-        type, internal::FieldMetadata::kOneOf);
-  } else if (field->is_packed()) {
-    return internal::FieldMetadata::CalculateType(
-        type, internal::FieldMetadata::kPacked);
-  } else if (field->is_repeated()) {
-    return internal::FieldMetadata::CalculateType(
-        type, internal::FieldMetadata::kRepeated);
-  } else if (HasHasbit(field) || field->real_containing_oneof() || is_a_map) {
-    return internal::FieldMetadata::CalculateType(
-        type, internal::FieldMetadata::kPresence);
-  } else {
-    return internal::FieldMetadata::CalculateType(
-        type, internal::FieldMetadata::kNoPresence);
-  }
-}
-
-int FindMessageIndexInFile(const Descriptor* descriptor) {
-  std::vector<const Descriptor*> flatten =
-      FlattenMessagesInFile(descriptor->file());
-  return std::find(flatten.begin(), flatten.end(), descriptor) -
-         flatten.begin();
-}
-
-}  // namespace
-
-int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) {
-  Formatter format(printer, variables_);
-  if (!options_.table_driven_serialization) {
-    return 0;
-  }
-
-  std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_);
-  if (IsMapEntryMessage(descriptor_)) {
-    for (int i = 0; i < 2; i++) {
-      const FieldDescriptor* field = sorted[i];
-      const FieldGenerator& generator = field_generators_.get(field);
-
-      uint32_t tag = internal::WireFormatLite::MakeTag(
-          field->number(), WireFormat::WireTypeForFieldType(field->type()));
-
-      std::map<std::string, std::string> vars;
-      vars["classtype"] = QualifiedClassName(descriptor_, options_);
-      vars["field_name"] = FieldName(field);
-      vars["tag"] = StrCat(tag);
-      vars["hasbit"] = StrCat(i);
-      vars["type"] = StrCat(CalcFieldNum(generator, field, options_));
-      vars["ptr"] = "nullptr";
-      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-        GOOGLE_CHECK(!IsMapEntryMessage(field->message_type()));
-        vars["ptr"] =
-            "::" + UniqueName("TableStruct", field->message_type(), options_) +
-            "::serialization_table + " +
-            StrCat(FindMessageIndexInFile(field->message_type()));
-      }
-      Formatter::SaveState saver(&format);
-      format.AddMap(vars);
-      format(
-          "{PROTOBUF_FIELD_OFFSET("
-          "::$proto_ns$::internal::MapEntryHelper<$classtype$::"
-          "SuperType>, $field_name$_), $tag$,"
-          "PROTOBUF_FIELD_OFFSET("
-          "::$proto_ns$::internal::MapEntryHelper<$classtype$::"
-          "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, "
-          "$ptr$},\n");
-    }
-    return 2;
-  }
-  format(
-      "{PROTOBUF_FIELD_OFFSET($classtype$, _cached_size_),"
-      " 0, 0, 0, nullptr},\n");
-  std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
-  sorted_extensions.reserve(descriptor_->extension_range_count());
-  for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
-    sorted_extensions.push_back(descriptor_->extension_range(i));
-  }
-  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
-            ExtensionRangeSorter());
-  for (int i = 0, extension_idx = 0; /* no range */; i++) {
-    for (; extension_idx < sorted_extensions.size() &&
-           (i == sorted.size() ||
-            sorted_extensions[extension_idx]->start < sorted[i]->number());
-         extension_idx++) {
-      const Descriptor::ExtensionRange* range =
-          sorted_extensions[extension_idx];
-      format(
-          "{PROTOBUF_FIELD_OFFSET($classtype$, _extensions_), "
-          "$1$, $2$, ::$proto_ns$::internal::FieldMetadata::kSpecial, "
-          "reinterpret_cast<const "
-          "void*>(::$proto_ns$::internal::ExtensionSerializer)},\n",
-          range->start, range->end);
-    }
-    if (i == sorted.size()) break;
-    const FieldDescriptor* field = sorted[i];
-
-    uint32_t tag = internal::WireFormatLite::MakeTag(
-        field->number(), WireFormat::WireTypeForFieldType(field->type()));
-    if (field->is_packed()) {
-      tag = internal::WireFormatLite::MakeTag(
-          field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
-    }
-
-    std::string classfieldname = FieldName(field);
-    if (field->real_containing_oneof()) {
-      classfieldname = field->containing_oneof()->name();
-    }
-    format.Set("field_name", classfieldname);
-    std::string ptr = "nullptr";
-    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      if (IsMapEntryMessage(field->message_type())) {
-        format(
-            "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$, $2$, "
-            "::$proto_ns$::internal::FieldMetadata::kSpecial, "
-            "reinterpret_cast<const void*>(static_cast< "
-            "::$proto_ns$::internal::SpecialSerializer>("
-            "::$proto_ns$::internal::MapFieldSerializer< "
-            "::$proto_ns$::internal::MapEntryToMapField<"
-            "$3$>::MapFieldType, "
-            "$tablename$::serialization_table>))},\n",
-            tag, FindMessageIndexInFile(field->message_type()),
-            QualifiedClassName(field->message_type(), options_));
-        continue;
-      } else if (!field->message_type()->options().message_set_wire_format()) {
-        // message_set doesn't have the usual table and we need to
-        // dispatch to generated serializer, hence ptr stays zero.
-        ptr =
-            "::" + UniqueName("TableStruct", field->message_type(), options_) +
-            "::serialization_table + " +
-            StrCat(FindMessageIndexInFile(field->message_type()));
-      }
-    }
-
-    const FieldGenerator& generator = field_generators_.get(field);
-    int type = CalcFieldNum(generator, field, options_);
-
-    if (IsLazy(field, options_, scc_analyzer_)) {
-      type = internal::FieldMetadata::kSpecial;
-      ptr = "reinterpret_cast<const void*>(::" + variables_["proto_ns"] +
-            "::internal::LazyFieldSerializer";
-      if (field->real_containing_oneof()) {
-        ptr += "OneOf";
-      } else if (!HasHasbit(field)) {
-        ptr += "NoPresence";
-      }
-      ptr += ")";
-    }
-
-    if (field->options().weak()) {
-      // TODO(gerbens) merge weak fields into ranges
-      format(
-          "{PROTOBUF_FIELD_OFFSET("
-          "$classtype$, _weak_field_map_), $1$, $1$, "
-          "::$proto_ns$::internal::FieldMetadata::kSpecial, "
-          "reinterpret_cast<const "
-          "void*>(::$proto_ns$::internal::WeakFieldSerializer)},\n",
-          tag);
-    } else if (field->real_containing_oneof()) {
-      format.Set("oneofoffset",
-                 sizeof(uint32_t) * field->containing_oneof()->index());
-      format(
-          "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$,"
-          " PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_) + "
-          "$oneofoffset$, $2$, $3$},\n",
-          tag, type, ptr);
-    } else if (HasHasbit(field)) {
-      format.Set("hasbitsoffset", has_bit_indices_[field->index()]);
-      format(
-          "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), "
-          "$1$, PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_) * 8 + "
-          "$hasbitsoffset$, $2$, $3$},\n",
-          tag, type, ptr);
-    } else {
-      format(
-          "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), "
-          "$1$, ~0u, $2$, $3$},\n",
-          tag, type, ptr);
-    }
-  }
-  int num_field_metadata = 1 + sorted.size() + sorted_extensions.size();
-  num_field_metadata++;
-  std::string serializer = UseUnknownFieldSet(descriptor_->file(), options_)
-                               ? "UnknownFieldSetSerializer"
-                               : "UnknownFieldSerializerLite";
-  format(
-      "{PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_), 0, ~0u, "
-      "::$proto_ns$::internal::FieldMetadata::kSpecial, reinterpret_cast<const "
-      "void*>(::$proto_ns$::internal::$1$)},\n",
-      serializer);
-  return num_field_metadata;
-}
-
 void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
   Formatter format(printer, variables_);
   if (IsMapEntryMessage(descriptor_)) {
@@ -2314,7 +1996,7 @@
         format(
             "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
             "$annotate_reflection$"
-            "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+            "  return ::_pbi::AssignDescriptors(\n"
             "      &$desc_table$_getter, &$desc_table$_once,\n"
             "      $file_level_metadata$[$1$]);\n"
             "}\n",
@@ -2322,7 +2004,7 @@
       } else {
         format(
             "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-            "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+            "  return ::_pbi::AssignDescriptors(\n"
             "      &$desc_table$_getter, &$desc_table$_once,\n"
             "      $file_level_metadata$[$1$]);\n"
             "}\n",
@@ -2339,7 +2021,7 @@
           "    const ::$proto_ns$::Message& message,\n"
           "    const ::$proto_ns$::FieldDescriptor** type_url_field,\n"
           "    const ::$proto_ns$::FieldDescriptor** value_field) {\n"
-          "  return ::$proto_ns$::internal::GetAnyFieldDescriptors(\n"
+          "  return ::_pbi::GetAnyFieldDescriptors(\n"
           "      message, type_url_field, value_field);\n"
           "}\n");
     }
@@ -2347,8 +2029,7 @@
         "bool $classname$::ParseAnyTypeUrl(\n"
         "    ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n"
         "    std::string* full_type_name) {\n"
-        "  return ::$proto_ns$::internal::ParseAnyTypeUrl(type_url,\n"
-        "                                             full_type_name);\n"
+        "  return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);\n"
         "}\n"
         "\n");
   }
@@ -2455,20 +2136,12 @@
   GenerateSwap(printer);
   format("\n");
 
-  if (options_.table_driven_serialization) {
-    format(
-        "const void* $classname$::InternalGetTable() const {\n"
-        "  return ::$tablename$::serialization_table + $1$;\n"
-        "}\n"
-        "\n",
-        index_in_file_messages_);
-  }
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
     if (!descriptor_->options().map_entry()) {
       format(
           "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
           "$annotate_reflection$"
-          "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+          "  return ::_pbi::AssignDescriptors(\n"
           "      &$desc_table$_getter, &$desc_table$_once,\n"
           "      $file_level_metadata$[$1$]);\n"
           "}\n",
@@ -2476,7 +2149,7 @@
     } else {
       format(
           "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-          "  return ::$proto_ns$::internal::AssignDescriptors(\n"
+          "  return ::_pbi::AssignDescriptors(\n"
           "      &$desc_table$_getter, &$desc_table$_once,\n"
           "      $file_level_metadata$[$1$]);\n"
           "}\n",
@@ -2500,202 +2173,6 @@
   }
 }
 
-size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
-  Formatter format(printer, variables_);
-
-  if (!table_driven_) {
-    return 0;
-  }
-
-  // Field "0" is special:  We use it in our switch statement of processing
-  // types to handle the successful end tag case.
-  format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n");
-  int last_field_number = 1;
-
-  std::vector<const FieldDescriptor*> ordered_fields =
-      SortFieldsByNumber(descriptor_);
-
-  for (auto field : ordered_fields) {
-    Formatter::SaveState saver(&format);
-    GOOGLE_CHECK_GE(field->number(), last_field_number);
-
-    for (; last_field_number < field->number(); last_field_number++) {
-      format(
-          "{ 0, 0, ::$proto_ns$::internal::kInvalidMask,\n"
-          "  ::$proto_ns$::internal::kInvalidMask, 0, 0 },\n");
-    }
-    last_field_number++;
-
-    unsigned char normal_wiretype, packed_wiretype, processing_type;
-    normal_wiretype = WireFormat::WireTypeForFieldType(field->type());
-
-    if (field->is_packable()) {
-      packed_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
-    } else {
-      packed_wiretype = internal::kNotPackedMask;
-    }
-
-    processing_type = static_cast<unsigned>(field->type());
-    const FieldGenerator& generator = field_generators_.get(field);
-    if (field->type() == FieldDescriptor::TYPE_STRING) {
-      switch (EffectiveStringCType(field, options_)) {
-        case FieldOptions::STRING:
-          if (generator.IsInlined()) {
-            processing_type = internal::TYPE_STRING_INLINED;
-          }
-          break;
-        case FieldOptions::CORD:
-          processing_type = internal::TYPE_STRING_CORD;
-          break;
-        case FieldOptions::STRING_PIECE:
-          processing_type = internal::TYPE_STRING_STRING_PIECE;
-          break;
-      }
-    } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
-      switch (EffectiveStringCType(field, options_)) {
-        case FieldOptions::STRING:
-          if (generator.IsInlined()) {
-            processing_type = internal::TYPE_BYTES_INLINED;
-          }
-          break;
-        case FieldOptions::CORD:
-          processing_type = internal::TYPE_BYTES_CORD;
-          break;
-        case FieldOptions::STRING_PIECE:
-          processing_type = internal::TYPE_BYTES_STRING_PIECE;
-          break;
-      }
-    }
-
-    processing_type |= static_cast<unsigned>(
-        field->is_repeated() ? internal::kRepeatedMask : 0);
-    processing_type |= static_cast<unsigned>(
-        field->real_containing_oneof() ? internal::kOneofMask : 0);
-
-    if (field->is_map()) {
-      processing_type = internal::TYPE_MAP;
-    }
-
-    const unsigned char tag_size =
-        WireFormat::TagSize(field->number(), field->type());
-
-    std::map<std::string, std::string> vars;
-    if (field->real_containing_oneof()) {
-      vars["name"] = field->containing_oneof()->name();
-      vars["presence"] = StrCat(field->containing_oneof()->index());
-    } else {
-      vars["name"] = FieldName(field);
-      vars["presence"] = StrCat(has_bit_indices_[field->index()]);
-    }
-    vars["nwtype"] = StrCat(normal_wiretype);
-    vars["pwtype"] = StrCat(packed_wiretype);
-    vars["ptype"] = StrCat(processing_type);
-    vars["tag_size"] = StrCat(tag_size);
-
-    format.AddMap(vars);
-
-    format(
-        "{\n"
-        "  PROTOBUF_FIELD_OFFSET($classtype$, $name$_),\n"
-        "  static_cast<$uint32$>($presence$),\n"
-        "  $nwtype$, $pwtype$, $ptype$, $tag_size$\n"
-        "},\n");
-  }
-
-  return last_field_number;
-}
-
-size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) {
-  Formatter format(printer, variables_);
-
-  if (!table_driven_) {
-    return 0;
-  }
-
-  std::vector<const FieldDescriptor*> ordered_fields =
-      SortFieldsByNumber(descriptor_);
-
-  format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n");
-  int last_field_number = 1;
-  for (auto field : ordered_fields) {
-    Formatter::SaveState saver(&format);
-
-    GOOGLE_CHECK_GE(field->number(), last_field_number);
-    for (; last_field_number < field->number(); last_field_number++) {
-      format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n");
-    }
-
-    std::map<std::string, std::string> vars;
-    SetCommonFieldVariables(field, &vars, options_);
-    format.AddMap(vars);
-
-    switch (field->cpp_type()) {
-      case FieldDescriptor::CPPTYPE_ENUM:
-        if (HasPreservingUnknownEnumSemantics(field)) {
-          format(
-              "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{"
-              "nullptr}},\n");
-        } else {
-          format(
-              "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{"
-              "$1$_IsValid}},\n",
-              ClassName(field->enum_type(), true));
-        }
-        last_field_number++;
-        break;
-      case FieldDescriptor::CPPTYPE_MESSAGE: {
-        if (field->is_map()) {
-          format(
-              "{::$proto_ns$::internal::AuxiliaryParseTableField::map_"
-              "aux{&::$proto_ns$::internal::ParseMap<$1$>}},\n",
-              QualifiedClassName(field->message_type(), options_));
-          last_field_number++;
-          break;
-        }
-        format.Set("field_classname", ClassName(field->message_type(), false));
-        format.Set("default_instance", QualifiedDefaultInstanceName(
-                                           field->message_type(), options_));
-
-        format(
-            "{::$proto_ns$::internal::AuxiliaryParseTableField::message_aux{\n"
-            "  &$default_instance$}},\n");
-        last_field_number++;
-        break;
-      }
-      case FieldDescriptor::CPPTYPE_STRING: {
-        std::string default_val;
-        switch (EffectiveStringCType(field, options_)) {
-          case FieldOptions::STRING:
-            default_val = field->default_value_string().empty()
-                              ? "&::" + variables_["proto_ns"] +
-                                    "::internal::fixed_address_empty_string"
-                              : "&" +
-                                    QualifiedClassName(descriptor_, options_) +
-                                    "::" + MakeDefaultName(field);
-            break;
-          case FieldOptions::CORD:
-          case FieldOptions::STRING_PIECE:
-            default_val =
-                "\"" + CEscape(field->default_value_string()) + "\"";
-            break;
-        }
-        format(
-            "{::$proto_ns$::internal::AuxiliaryParseTableField::string_aux{\n"
-            "  $1$,\n"
-            "  \"$2$\"\n"
-            "}},\n",
-            default_val, field->full_name());
-        last_field_number++;
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  return last_field_number;
-}
-
 std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
     io::Printer* printer) {
   Formatter format(printer, variables_);
@@ -2740,7 +2217,7 @@
     if (field->options().weak() || field->real_containing_oneof()) {
       // Mark the field to prevent unintentional access through reflection.
       // Don't use the top bit because that is for unused fields.
-      format("::$proto_ns$::internal::kInvalidFieldOffsetTag");
+      format("::_pbi::kInvalidFieldOffsetTag");
     } else {
       format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field));
     }
@@ -2787,11 +2264,12 @@
   }
   if (!inlined_string_indices_.empty()) {
     entries += inlined_string_indices_.size();
-    for (int inlined_string_indice : inlined_string_indices_) {
-      const std::string index = inlined_string_indice >= 0
-                                    ? StrCat(inlined_string_indice)
-                                    : "~0u";
-      format("$1$,\n", index);
+    for (int inlined_string_index : inlined_string_indices_) {
+      const std::string index =
+          inlined_string_index >= 0
+              ? StrCat(inlined_string_index, ",  // inlined_string_index")
+              : "~0u,";
+      format("$1$\n", index);
     }
   }
 
@@ -2845,8 +2323,20 @@
       "\n");
 }
 
+ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const {
+  if (HasSimpleBaseClass(descriptor_, options_)) return ArenaDtorNeeds::kNone;
+  ArenaDtorNeeds needs = ArenaDtorNeeds::kNone;
+  for (const auto* field : FieldRange(descriptor_)) {
+    if (IsFieldStripped(field, options_)) continue;
+    needs =
+        std::max(needs, field_generators_.get(field).NeedsArenaDestructor());
+  }
+  return needs;
+}
+
 void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) {
-  if (HasSimpleBaseClass(descriptor_, options_)) return;
+  GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone);
+
   Formatter format(printer, variables_);
 
   // Generate the ArenaDtor() method. Track whether any fields actually produced
@@ -2858,48 +2348,25 @@
   // since that simplifies Arena's destructor list (ordinary function pointers
   // rather than member function pointers). _this is the object being
   // destructed.
-  format(
-      "$classname$* _this = reinterpret_cast< $classname$* >(object);\n"
-      // avoid an "unused variable" warning in case no fields have dtor code.
-      "(void)_this;\n");
+  format("$classname$* _this = reinterpret_cast< $classname$* >(object);\n");
 
-  bool need_registration = false;
   // Process non-oneof fields first.
   for (auto field : optimized_order_) {
-    if (field_generators_.get(field).GenerateArenaDestructorCode(printer)) {
-      need_registration = true;
-    }
+    if (IsFieldStripped(field, options_)) continue;
+    const FieldGenerator& fg = field_generators_.get(field);
+    fg.GenerateArenaDestructorCode(printer);
   }
 
   // Process oneof fields.
-  //
-  // Note:  As of 10/5/2016, GenerateArenaDestructorCode does not emit anything
-  // and returns false for oneof fields.
   for (auto oneof : OneOfRange(descriptor_)) {
     for (auto field : FieldRange(oneof)) {
-      if (!IsFieldStripped(field, options_) &&
-          field_generators_.get(field).GenerateArenaDestructorCode(printer)) {
-        need_registration = true;
-      }
+      if (IsFieldStripped(field, options_)) continue;
+      field_generators_.get(field).GenerateArenaDestructorCode(printer);
     }
   }
 
   format.Outdent();
   format("}\n");
-
-  if (need_registration) {
-    format(
-        "inline void $classname$::RegisterArenaDtor(::$proto_ns$::Arena* "
-        "arena) {\n"
-        "  if (arena != nullptr) {\n"
-        "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
-        "  }\n"
-        "}\n");
-  } else {
-    format(
-        "void $classname$::RegisterArenaDtor(::$proto_ns$::Arena*) {\n"
-        "}\n");
-  }
 }
 
 void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) {
@@ -2907,7 +2374,7 @@
 
   format(
       "constexpr $classname$::$classname$(\n"
-      "  ::$proto_ns$::internal::ConstantInitialized)");
+      "    ::_pbi::ConstantInitialized)");
   format.Indent();
   const char* field_sep = ":";
   const auto put_sep = [&] {
@@ -3049,19 +2516,37 @@
 
   if (!inlined_string_indices_.empty()) {
     // Donate inline string fields.
-    format("  if (arena != nullptr) {\n");
-    for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) {
-      format("    _inlined_string_donated_[$1$] = ~0u;\n", i);
+    format.Indent();
+    // The last bit is the tracking bit for registering ArenaDtor. The bit is 1
+    // means ArenaDtor is not registered on construction, and on demand register
+    // is needed.
+    format("if (arena != nullptr) {\n");
+    if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) {
+      format(
+          "  if (!is_message_owned) {\n"
+          "    _inlined_string_donated_[0] = ~0u;\n"
+          "  } else {\n"
+          // We should not register ArenaDtor for MOA.
+          "    _inlined_string_donated_[0] = 0xFFFFFFFEu;\n"
+          "  }\n");
+    } else {
+      format("  _inlined_string_donated_[0] = 0xFFFFFFFEu;\n");
     }
-    format("  }\n");
+    for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) {
+      format("  _inlined_string_donated_[$1$] = ~0u;\n", i);
+    }
+    format("}\n");
+    format.Outdent();
   }
 
   if (!HasSimpleBaseClass(descriptor_, options_)) {
-    format(
-        "  SharedCtor();\n"
-        "  if (!is_message_owned) {\n"
-        "    RegisterArenaDtor(arena);\n"
-        "  }\n");
+    format("  SharedCtor();\n");
+    if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) {
+      format(
+          "  if (arena != nullptr && !is_message_owned) {\n"
+          "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+          "  }\n");
+    }
   }
   format(
       "  // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
@@ -3172,10 +2657,19 @@
   if (!HasSimpleBaseClass(descriptor_, options_)) {
     format(
         "$classname$::~$classname$() {\n"
-        "  // @@protoc_insertion_point(destructor:$full_name$)\n"
-        "  if (GetArenaForAllocation() != nullptr) return;\n"
+        "  // @@protoc_insertion_point(destructor:$full_name$)\n");
+    format(
+        "  if (auto *arena = "
+        "_internal_metadata_.DeleteReturnArena<$unknown_fields_type$>()) {\n"
+        "  (void)arena;\n");
+    if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) {
+      format("    ArenaDtor(this);\n");
+    }
+    format(
+        "    return;\n"
+        "  }\n");
+    format(
         "  SharedDtor();\n"
-        "  _internal_metadata_.Delete<$unknown_fields_type$>();\n"
         "}\n"
         "\n");
   } else {
@@ -3190,7 +2684,9 @@
   GenerateSharedDestructorCode(printer);
 
   // Generate the arena-specific destructor code.
-  GenerateArenaDestructorCode(printer);
+  if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) {
+    GenerateArenaDestructorCode(printer);
+  }
 
   if (!HasSimpleBaseClass(descriptor_, options_)) {
     // Generate SetCachedSize.
@@ -3205,8 +2701,8 @@
   Formatter format(printer, variables_);
   format(
       "template<> "
-      "PROTOBUF_NOINLINE "
-      "$classtype$* Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n"
+      "PROTOBUF_NOINLINE $classtype$*\n"
+      "Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n"
       "  return Arena::CreateMessageInternal< $classtype$ >(arena);\n"
       "}\n");
 }
@@ -3508,6 +3004,15 @@
     if (num_weak_fields_) {
       format("_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n");
     }
+
+    if (!inlined_string_indices_.empty()) {
+      for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) {
+        format(
+            "swap(_inlined_string_donated_[$1$], "
+            "other->_inlined_string_donated_[$1$]);\n",
+            i);
+      }
+    }
   } else {
     format("GetReflection()->Swap(this, other);");
   }
@@ -3549,7 +3054,7 @@
       format(
           "void $classname$::CheckTypeAndMergeFrom(\n"
           "    const ::$proto_ns$::MessageLite& from) {\n"
-          "  MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n"
+          "  MergeFrom(*::_pbi::DownCast<const $classname$*>(\n"
           "      &from));\n"
           "}\n");
     }
@@ -3882,7 +3387,7 @@
     SetUnknownFieldsVariable(descriptor_, options_, &vars);
     format.AddMap(vars);
     format(
-        "  target = ::$proto_ns$::internal::"
+        "  target = ::_pbi::"
         "InternalSerializeUnknownMessageSetItemsToArray(\n"
         "               $unknown_fields$, target, stream);\n");
     format(
@@ -4077,7 +3582,7 @@
             ExtensionRangeSorter());
   if (num_weak_fields_) {
     format(
-        "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer("
+        "::_pbi::WeakFieldMap::FieldWriter field_writer("
         "_weak_field_map_);\n");
   }
 
@@ -4126,7 +3631,7 @@
   if (UseUnknownFieldSet(descriptor_->file(), options_)) {
     format(
         "target = "
-        "::$proto_ns$::internal::WireFormat::"
+        "::_pbi::WireFormat::"
         "InternalSerializeUnknownFieldsToArray(\n"
         "    $unknown_fields$, target, stream);\n");
   } else {
@@ -4167,7 +3672,7 @@
 
   if (num_weak_fields_) {
     format(
-        "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer("
+        "::_pbi::WeakFieldMap::FieldWriter field_writer("
         "_weak_field_map_);\n");
   }
 
@@ -4218,7 +3723,7 @@
   if (UseUnknownFieldSet(descriptor_->file(), options_)) {
     format(
         "target = "
-        "::$proto_ns$::internal::WireFormat::"
+        "::_pbi::WireFormat::"
         "InternalSerializeUnknownFieldsToArray(\n"
         "    $unknown_fields$, target, stream);\n");
   } else {
@@ -4261,11 +3766,11 @@
         "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n"
         "  size_t total_size = _extensions_.MessageSetByteSize();\n"
         "  if ($have_unknown_fields$) {\n"
-        "    total_size += ::$proto_ns$::internal::\n"
+        "    total_size += ::_pbi::\n"
         "        ComputeUnknownMessageSetItemsSize($unknown_fields$);\n"
         "  }\n"
         "  int cached_size = "
-        "::$proto_ns$::internal::ToCachedSize(total_size);\n"
+        "::_pbi::ToCachedSize(total_size);\n"
         "  SetCachedSize(cached_size);\n"
         "  return total_size;\n"
         "}\n");
@@ -4496,7 +4001,7 @@
     // where even relaxed memory order might have perf impact to replace it with
     // ordinary loads and stores.
     format(
-        "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n"
+        "int cached_size = ::_pbi::ToCachedSize(total_size);\n"
         "SetCachedSize(cached_size);\n"
         "return total_size;\n");
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 64af2bf..a076563 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -96,22 +96,10 @@
   void GenerateFieldAccessorDeclarations(io::Printer* printer);
   void GenerateFieldAccessorDefinitions(io::Printer* printer);
 
-  // Generate the table-driven parsing array.  Returns the number of entries
-  // generated.
-  size_t GenerateParseOffsets(io::Printer* printer);
-  size_t GenerateParseAuxTable(io::Printer* printer);
-  // Generates a ParseTable entry.  Returns whether the proto uses
-  // table-driven parsing.
-  bool GenerateParseTable(io::Printer* printer, size_t offset,
-                          size_t aux_offset);
-
   // Generate the field offsets array.  Returns the a pair of the total number
   // of entries generated and the index of the first has_bit entry.
   std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
   void GenerateSchema(io::Printer* printer, int offset, int has_offset);
-  // For each field generates a table entry describing the field for the
-  // table driven serializer.
-  int GenerateFieldMetadata(io::Printer* printer);
 
   // Generate constructors and destructor.
   void GenerateStructors(io::Printer* printer);
@@ -177,6 +165,18 @@
                                std::vector<bool> already_processed,
                                bool copy_constructor) const;
 
+  // Returns the level that this message needs ArenaDtor. If the message has
+  // a field that is not arena-exclusive, it needs an ArenaDtor
+  // (go/proto-destructor).
+  //
+  // - Returning kNone means we don't need to generate ArenaDtor.
+  // - Returning kOnDemand means we need to generate ArenaDtor, but don't need
+  //   to register ArenaDtor at construction. Such as when the message's
+  //   ArenaDtor code is only for destructing inlined string.
+  // - Returning kRequired means we meed to generate ArenaDtor and register it
+  //   at construction.
+  ArenaDtorNeeds NeedsArenaDestructor() const;
+
   size_t HasBitsSize() const;
   size_t InlinedStringDonatedSize() const;
   int HasBitIndex(const FieldDescriptor* a) const;
@@ -209,8 +209,6 @@
   std::vector<const ExtensionGenerator*> extension_generators_;
   int num_required_fields_;
   int num_weak_fields_;
-  // table_driven_ indicates the generated message uses table-driven parsing.
-  bool table_driven_;
 
   std::unique_ptr<MessageLayoutHelper> message_layout_helper_;
   std::unique_ptr<ParseFunctionGenerator> parse_function_generator_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 6199903..845dc05 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -33,8 +33,9 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_message_field.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 #include <google/protobuf/stubs/strutil.h>
 
@@ -60,11 +61,16 @@
   SetCommonFieldVariables(descriptor, variables, options);
   (*variables)["type"] = FieldMessageTypeName(descriptor, options);
   (*variables)["casted_member"] = ReinterpretCast(
-      (*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak);
+      (*variables)["type"] + "*", (*variables)["field_member"], implicit_weak);
+  (*variables)["casted_member_const"] =
+      ReinterpretCast("const " + (*variables)["type"] + "&",
+                      "*" + (*variables)["field_member"], implicit_weak);
   (*variables)["type_default_instance"] =
       QualifiedDefaultInstanceName(descriptor->message_type(), options);
-  (*variables)["type_default_instance_ptr"] =
-      QualifiedDefaultInstancePtr(descriptor->message_type(), options);
+  (*variables)["type_default_instance_ptr"] = ReinterpretCast(
+      "const ::PROTOBUF_NAMESPACE_ID::MessageLite*",
+      QualifiedDefaultInstancePtr(descriptor->message_type(), options),
+      implicit_weak);
   (*variables)["type_reference_function"] =
       implicit_weak ? ("  ::" + (*variables)["proto_ns"] +
                        "::internal::StrongReference(reinterpret_cast<const " +
@@ -322,14 +328,10 @@
     format(
         "const ::$proto_ns$::MessageLite& $classname$::_Internal::$name$(\n"
         "    const $classname$* msg) {\n"
-        "  if (msg->$name$_ != nullptr) {\n"
-        "    return *msg->$name$_;\n"
-        "  } else if ($type_default_instance_ptr$ != nullptr) {\n"
-        "    return *reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n"
-        "        $type_default_instance_ptr$);\n"
+        "  if (msg->$field_member$ != nullptr) {\n"
+        "    return *msg->$field_member$;\n"
         "  } else {\n"
-        "    return "
-        "*::$proto_ns$::internal::ImplicitWeakMessage::default_instance();\n"
+        "    return *$type_default_instance_ptr$;\n"
         "  }\n"
         "}\n");
     format(
@@ -338,20 +340,19 @@
     if (HasHasbit(descriptor_)) {
       format("  msg->$set_hasbit$\n");
     }
+    if (descriptor_->real_containing_oneof() == nullptr) {
+      format("  if (msg->$field_member$ == nullptr) {\n");
+    } else {
+      format(
+          "  if (!msg->_internal_has_$name$()) {\n"
+          "    msg->clear_$oneof_name$();\n"
+          "    msg->set_has_$name$();\n");
+    }
     format(
-        "  if (msg->$name$_ == nullptr) {\n"
-        "    if ($type_default_instance_ptr$ == nullptr) {\n"
-        "      msg->$name$_ = ::$proto_ns$::Arena::CreateMessage<\n"
-        "          ::$proto_ns$::internal::ImplicitWeakMessage>(\n"
-        "              msg->GetArenaForAllocation());\n"
-        "    } else {\n"
-        "      msg->$name$_ = \n"
-        "          reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n"
-        "              $type_default_instance_ptr$)->New(\n"
-        "                  msg->GetArenaForAllocation());\n"
-        "    }\n"
+        "    msg->$field_member$ = $type_default_instance_ptr$->New(\n"
+        "        msg->GetArenaForAllocation());\n"
         "  }\n"
-        "  return msg->$name$_;\n"
+        "  return msg->$field_member$;\n"
         "}\n");
   } else {
     // This inline accessor directly returns member field and is used in
@@ -371,7 +372,7 @@
   Formatter format(printer, variables_);
   if (!HasHasbit(descriptor_)) {
     // If we don't have has-bits, message presence is indicated only by ptr !=
-    // NULL. Thus on clear, we need to delete the object.
+    // nullptr. Thus on clear, we need to delete the object.
     format(
         "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n"
         "  delete $name$_;\n"
@@ -389,7 +390,7 @@
   Formatter format(printer, variables_);
   if (!HasHasbit(descriptor_)) {
     // If we don't have has-bits, message presence is indicated only by ptr !=
-    // NULL. Thus on clear, we need to delete the object.
+    // nullptr. Thus on clear, we need to delete the object.
     format(
         "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n"
         "  delete $name$_;\n"
@@ -465,11 +466,18 @@
   GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
 
   Formatter format(printer, variables_);
-  format(
-      "target = stream->EnsureSpace(target);\n"
-      "target = ::$proto_ns$::internal::WireFormatLite::\n"
-      "  InternalWrite$declared_type$(\n"
-      "    $number$, _Internal::$name$(this), target, stream);\n");
+  if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+    format(
+        "target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "  InternalWrite$declared_type$($number$, _Internal::$name$(this),\n"
+        "    _Internal::$name$(this).GetCachedSize(), target, stream);\n");
+  } else {
+    format(
+        "target = stream->EnsureSpace(target);\n"
+        "target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "  InternalWrite$declared_type$(\n"
+        "    $number$, _Internal::$name$(this), target, stream);\n");
+  }
 }
 
 void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const {
@@ -554,9 +562,10 @@
       "inline $type$* $classname$::$release_name$() {\n"
       "$annotate_release$"
       "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+      "$type_reference_function$"
       "  if (_internal_has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
-      "      $type$* temp = $field_member$;\n"
+      "    $type$* temp = $casted_member$;\n"
       "    if (GetArenaForAllocation() != nullptr) {\n"
       "      temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
       "    }\n"
@@ -569,8 +578,9 @@
 
   format(
       "inline const $type$& $classname$::_internal_$name$() const {\n"
+      "$type_reference_function$"
       "  return _internal_has_$name$()\n"
-      "      ? *$field_member$\n"
+      "      ? $casted_member_const$\n"
       "      : reinterpret_cast< $type$&>($type_default_instance$);\n"
       "}\n"
       "inline const $type$& $classname$::$name$() const {\n"
@@ -582,9 +592,10 @@
       "$annotate_release$"
       "  // @@protoc_insertion_point(field_unsafe_arena_release"
       ":$full_name$)\n"
+      "$type_reference_function$"
       "  if (_internal_has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
-      "    $type$* temp = $field_member$;\n"
+      "    $type$* temp = $casted_member$;\n"
       "    $field_member$ = nullptr;\n"
       "    return temp;\n"
       "  } else {\n"
@@ -598,21 +609,38 @@
       // new value.
       "  clear_$oneof_name$();\n"
       "  if ($name$) {\n"
-      "    set_has_$name$();\n"
-      "    $field_member$ = $name$;\n"
+      "    set_has_$name$();\n");
+  if (implicit_weak_field_) {
+    format(
+        "    $field_member$ = "
+        "reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n");
+  } else {
+    format("    $field_member$ = $name$;\n");
+  }
+  format(
       "  }\n"
       "$annotate_set$"
       "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
       "$full_name$)\n"
       "}\n"
       "inline $type$* $classname$::_internal_mutable_$name$() {\n"
+      "$type_reference_function$"
       "  if (!_internal_has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
-      "    set_has_$name$();\n"
-      "    $field_member$ = CreateMaybeMessage< $type$ "
-      ">(GetArenaForAllocation());\n"
+      "    set_has_$name$();\n");
+  if (implicit_weak_field_) {
+    format(
+        "    $field_member$ = "
+        "reinterpret_cast<::$proto_ns$::MessageLite*>(CreateMaybeMessage< "
+        "$type$ >(GetArenaForAllocation()));\n");
+  } else {
+    format(
+        "    $field_member$ = CreateMaybeMessage< $type$ "
+        ">(GetArenaForAllocation());\n");
+  }
+  format(
       "  }\n"
-      "  return $field_member$;\n"
+      "  return $casted_member$;\n"
       "}\n"
       "inline $type$* $classname$::mutable_$name$() {\n"
       "  $type$* _msg = _internal_mutable_$name$();\n"
@@ -830,22 +858,40 @@
   if (implicit_weak_field_) {
     format(
         "for (auto it = this->$name$_.pointer_begin(),\n"
-        "          end = this->$name$_.pointer_end(); it < end; ++it) {\n"
-        "  target = stream->EnsureSpace(target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "    InternalWrite$declared_type$($number$, **it, target, stream);\n"
-        "}\n");
+        "          end = this->$name$_.pointer_end(); it < end; ++it) {\n");
+    if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+      format(
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, "
+          "**it, (**it).GetCachedSize(), target, stream);\n");
+    } else {
+      format(
+          "  target = stream->EnsureSpace(target);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, **it, target, "
+          "stream);\n");
+    }
+    format("}\n");
   } else {
     format(
-        "for (unsigned int i = 0,\n"
-        "    n = static_cast<unsigned int>(this->_internal_$name$_size()); i < "
-        "n; i++) "
-        "{\n"
-        "  target = stream->EnsureSpace(target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "    InternalWrite$declared_type$($number$, "
-        "this->_internal_$name$(i), target, stream);\n"
-        "}\n");
+        "for (unsigned i = 0,\n"
+        "    n = static_cast<unsigned>(this->_internal_$name$_size());"
+        " i < n; i++) {\n");
+    if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
+      format(
+          "  const auto& repfield = this->_internal_$name$(i);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "      InternalWrite$declared_type$($number$, "
+          "repfield, repfield.GetCachedSize(), target, stream);\n"
+          "}\n");
+    } else {
+      format(
+          "  target = stream->EnsureSpace(target);\n"
+          "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+          "    InternalWrite$declared_type$($number$, "
+          "this->_internal_$name$(i), target, stream);\n"
+          "}\n");
+    }
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 2beac62..528b419 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h
index 9d8063d..8086005 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h
@@ -35,8 +35,8 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
 
-#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_names.h b/src/google/protobuf/compiler/cpp/cpp_names.h
index 6bcbff0..b27b596 100644
--- a/src/google/protobuf/compiler/cpp/cpp_names.h
+++ b/src/google/protobuf/compiler/cpp/cpp_names.h
@@ -33,6 +33,7 @@
 
 #include <string>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index d0f16d0..aaecda5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -57,34 +57,38 @@
 
 // Generator options (see generator.cc for a description of each):
 struct Options {
+  const AccessInfoMap* access_info_map = nullptr;
   std::string dllexport_decl;
-  bool safe_boundary_check = false;
-  bool proto_h = false;
-  bool transitive_pb_h = true;
-  bool annotate_headers = false;
-  EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement;
-  bool table_driven_parsing = false;
-  bool table_driven_serialization = false;
-  bool lite_implicit_weak_fields = false;
-  bool bootstrap = false;
-  bool opensource_runtime = false;
-  bool annotate_accessor = false;
-  bool unused_field_stripping = false;
-  bool profile_driven_inline_string = true;
-  bool force_inline_string = false;
   std::string runtime_include_base;
-  int num_cc_files = 0;
   std::string annotation_pragma_name;
   std::string annotation_guard_name;
-  const AccessInfoMap* access_info_map = nullptr;
+  FieldListenerOptions field_listener_options;
+  EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement;
   enum {
     kTCTableNever,
     kTCTableGuarded,
     kTCTableAlways
   } tctable_mode = kTCTableNever;
-  FieldListenerOptions field_listener_options;
-  bool eagerly_verified_lazy = false;
+  int num_cc_files = 0;
+  bool safe_boundary_check = false;
+  bool proto_h = false;
+  bool transitive_pb_h = true;
+  bool annotate_headers = false;
+  bool lite_implicit_weak_fields = false;
+  bool bootstrap = false;
+  bool opensource_runtime = false;
+  bool annotate_accessor = false;
+  bool unused_field_stripping = false;
+  bool unverified_lazy_message_sets = true;
+  bool eagerly_verified_lazy = true;
+  bool profile_driven_inline_string = true;
+#ifdef PROTOBUF_STABLE_EXPERIMENTS
+  bool force_eagerly_verified_lazy = true;
+  bool force_inline_string = true;
+#else   // PROTOBUF_STABLE_EXPERIMENTS
   bool force_eagerly_verified_lazy = false;
+  bool force_inline_string = false;
+#endif  // !PROTOBUF_STABLE_EXPERIMENTS
 };
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
index 0b660c7..f48ba71 100644
--- a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc
@@ -47,7 +47,7 @@
   FieldGroup() : preferred_location_(0) {}
 
   // A group with a single field.
-  FieldGroup(float preferred_location, const FieldDescriptor* field)
+  FieldGroup(double preferred_location, const FieldDescriptor* field)
       : preferred_location_(preferred_location), fields_(1, field) {}
 
   // Append the fields in 'other' to this group.
@@ -63,7 +63,7 @@
     fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
   }
 
-  void SetPreferredLocation(float location) { preferred_location_ = location; }
+  void SetPreferredLocation(double location) { preferred_location_ = location; }
   const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
 
   // FieldGroup objects sort by their preferred location.
@@ -77,7 +77,7 @@
   // field in this group in the original ordering of fields.  This is very
   // approximate, but should put this group close to where its member fields
   // originally went.
-  float preferred_location_;
+  double preferred_location_;
   std::vector<const FieldDescriptor*> fields_;
   // We rely on the default copy constructor and operator= so this type can be
   // used in a vector.
@@ -203,7 +203,7 @@
           field_group.SetPreferredLocation(-1);
         } else {
           // Move incomplete 4-byte block to the end.
-          field_group.SetPreferredLocation(fields->size() + 1);
+          field_group.SetPreferredLocation(double{FieldDescriptor::kMaxNumber});
         }
       }
       aligned_to_8[f].push_back(field_group);
diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
index 027bf82..a0bd937 100644
--- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
@@ -33,9 +33,10 @@
 #include <algorithm>
 #include <limits>
 #include <string>
+#include <utility>
 
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/wire_format.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 namespace google {
 namespace protobuf {
@@ -43,7 +44,6 @@
 namespace cpp {
 
 namespace {
-using google::protobuf::internal::TcFieldData;
 using google::protobuf::internal::WireFormat;
 using google::protobuf::internal::WireFormatLite;
 
@@ -73,167 +73,314 @@
   return 2;
 }
 
-const char* CodedTagType(int tag_size) {
-  return tag_size == 1 ? "uint8_t" : "uint16_t";
-}
+std::string FieldParseFunctionName(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options);
 
-const char* TagType(const FieldDescriptor* field) {
-  return CodedTagType(TagSize(field->number()));
-}
-
-std::string TcParserName(const Options& options) {
-  return StrCat("::", ProtobufNamespace(options),
-                      "::internal::TcParser::");
-}
-
-std::string MessageTcParseFunctionName(const FieldDescriptor* field,
-                                       const Options& options) {
-  if (field->message_type()->field_count() == 0 ||
-      !HasGeneratedMethods(field->message_type()->file(), options)) {
-    // For files with `option optimize_for = CODE_SIZE`, or which derive from
-    // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because
-    // there is no generated tailcall function. For tailcall parsing, this is
-    // done by helpers in TcParser.
-    return StrCat(TcParserName(options),
-                        (field->is_repeated() ? "Repeated" : "Singular"),
-                        "ParseMessage<",
-                        QualifiedClassName(field->message_type()),  //
-                        ", ", TagType(field), ">");
+bool IsFieldEligibleForFastParsing(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  const auto* field = entry.field;
+  // Map, oneof, weak, and lazy fields are not handled on the fast path.
+  if (field->is_map() || field->real_containing_oneof() ||
+      field->options().weak() ||
+      IsImplicitWeakField(field, options, scc_analyzer) ||
+      IsLazy(field, options, scc_analyzer)) {
+    return false;
   }
-  // This matches macros in generated_message_tctable_impl.h:
-  return StrCat("PROTOBUF_TC_PARSE_",
-                      (field->is_repeated() ? "REPEATED" : "SINGULAR"),
-                      TagSize(field->number()), "(",
-                      QualifiedClassName(field->message_type()), ")");
+  switch (field->type()) {
+    // Strings, enums, and groups are not handled on the fast path.
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_GROUP:
+      return false;
+
+    case FieldDescriptor::TYPE_ENUM:
+      // If enum values are not validated at parse time, then this field can be
+      // handled on the fast path like an int32.
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        break;
+      }
+      if (field->is_repeated() && field->is_packed()) {
+        return false;
+      }
+      break;
+
+      // Some bytes fields can be handled on fast path.
+    case FieldDescriptor::TYPE_BYTES:
+      if (field->options().ctype() != FieldOptions::STRING ||
+          !field->default_value_string().empty() ||
+          IsStringInlined(field, options)) {
+        return false;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  if (HasHasbit(field)) {
+    // The tailcall parser can only update the first 32 hasbits. Fields with
+    // has-bits beyond the first 32 are handled by mini parsing/fallback.
+    GOOGLE_CHECK_GE(entry.hasbit_idx, 0) << field->DebugString();
+    if (entry.hasbit_idx >= 32) return false;
+  }
+
+  // If the field needs auxiliary data, then the aux index is needed. This
+  // must fit in a uint8_t.
+  if (entry.aux_idx > std::numeric_limits<uint8_t>::max()) {
+    return false;
+  }
+
+  // The largest tag that can be read by the tailcall parser is two bytes
+  // when varint-coded. This allows 14 bits for the numeric tag value:
+  //   byte 0   byte 1
+  //   1nnnnttt 0nnnnnnn
+  //    ^^^^^^^  ^^^^^^^
+  if (field->number() >= 1 << 11) return false;
+
+  return true;
 }
 
-std::string FieldParseFunctionName(const FieldDescriptor* field,
-                                   const Options& options);
+std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize(
+    const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries,
+    int table_size_log2, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  std::vector<TailCallTableInfo::FastFieldInfo> result(1 << table_size_log2);
+  const uint32_t idx_mask = result.size() - 1;
 
-}  // namespace
-
-TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
-                                     const Options& options,
-                                     const std::vector<int>& has_bit_indices,
-                                     MessageSCCAnalyzer* scc_analyzer) {
-  std::vector<const FieldDescriptor*> ordered_fields =
-      GetOrderedFields(descriptor, options);
-
-  // The table size is rounded up to the nearest power of 2, clamping at 2^5.
-  // Note that this is a naive approach: a better approach should only consider
-  // table-eligible fields. We may also want to push rarely-encountered fields
-  // into the fallback, to make the table smaller.
-  table_size_log2 = ordered_fields.size() >= 16  ? 5
-                    : ordered_fields.size() >= 8 ? 4
-                    : ordered_fields.size() >= 4 ? 3
-                    : ordered_fields.size() >= 2 ? 2
-                                                 : 1;
-  const unsigned table_size = 1 << table_size_log2;
-
-  // Construct info for each possible entry. Fields that do not use table-driven
-  // parsing will still have an entry that nominates the fallback function.
-  fast_path_fields.resize(table_size);
-
-  for (const auto* field : ordered_fields) {
-    // Eagerly assume slow path. If we can handle this field on the fast path,
-    // we will pop its entry from `fallback_fields`.
-    fallback_fields.push_back(field);
-
-    // Anything difficult slow path:
-    if (field->is_map()) continue;
-    if (field->real_containing_oneof()) continue;
-    if (field->options().weak()) continue;
-    if (IsImplicitWeakField(field, options, scc_analyzer)) continue;
-    if (IsLazy(field, options, scc_analyzer)) continue;
-
-    // The largest tag that can be read by the tailcall parser is two bytes
-    // when varint-coded. This allows 14 bits for the numeric tag value:
-    //   byte 0   byte 1
-    //   1nnnnttt 0nnnnnnn
-    //    ^^^^^^^  ^^^^^^^
-    uint32_t tag = WireFormat::MakeTag(field);
-    if (tag >= 1 << 14) {
+  for (const auto& entry : field_entries) {
+    if (!IsFieldEligibleForFastParsing(entry, options, scc_analyzer)) {
       continue;
-    } else if (tag >= 1 << 7) {
-      tag = ((tag << 1) & 0x7F00) | 0x80 | (tag & 0x7F);
     }
+
+    const auto* field = entry.field;
+    uint32_t tag = WireFormat::MakeTag(field);
+
+    // Construct the varint-coded tag. If it is more than 7 bits, we need to
+    // shift the high bits and add a continue bit.
+    if (uint32_t hibits = tag & 0xFFFFFF80) {
+      tag = tag + hibits + 128;  // tag = lobits + 2*hibits + 128
+    }
+
     // The field index is determined by the low bits of the field number, where
     // the table size determines the width of the mask. The largest table
     // supported is 32 entries. The parse loop uses these bits directly, so that
     // the dispatch does not require arithmetic:
-    //   byte 0   byte 1
-    //   1nnnnttt 0nnnnnnn
-    //   ^^^^^
+    //        byte 0   byte 1
+    //   tag: 1nnnnttt 0nnnnnnn
+    //        ^^^^^
+    //         idx (table_size_log2=5)
     // This means that any field number that does not fit in the lower 4 bits
-    // will always have the top bit of its table index asserted:
-    uint32_t idx = (tag >> 3) & (table_size - 1);
-    // If this entry in the table is already used, then this field will be
-    // handled by the generated fallback function.
-    if (!fast_path_fields[idx].func_name.empty()) continue;
+    // will always have the top bit of its table index asserted.
+    const uint32_t fast_idx = (tag >> 3) & idx_mask;
 
-    // Determine the hasbit mask for this field, if needed. (Note that fields
-    // without hasbits use different parse functions.)
-    int hasbit_idx;
-    if (HasHasbit(field)) {
-      hasbit_idx = has_bit_indices[field->index()];
-      GOOGLE_CHECK_NE(-1, hasbit_idx) << field->DebugString();
-      // The tailcall parser can only update the first 32 hasbits. If this
-      // field's has-bit is beyond that, then it will need to be handled by the
-      // fallback parse function.
-      if (hasbit_idx >= 32) continue;
-    } else {
-      // The tailcall parser only ever syncs 32 has-bits, so if there is no
-      // presence, set a bit that will not be used.
-      hasbit_idx = 63;
+    TailCallTableInfo::FastFieldInfo& info = result[fast_idx];
+    if (info.field != nullptr) {
+      // This field entry is already filled.
+      continue;
     }
 
-    // Determine the name of the fastpath parse function to use for this field.
-    std::string name;
+    // Fill in this field's entry:
+    GOOGLE_CHECK(info.func_name.empty()) << info.func_name;
+    info.func_name = FieldParseFunctionName(entry, options);
+    info.field = field;
+    info.coded_tag = tag;
+    // If this field does not have presence, then it can set an out-of-bounds
+    // bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32).
+    info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63;
+    info.aux_idx = static_cast<uint8_t>(entry.aux_idx);
+  }
+  return result;
+}
 
+// Filter out fields that will be handled by mini parsing.
+std::vector<const FieldDescriptor*> FilterMiniParsedFields(
+    const std::vector<const FieldDescriptor*>& fields, const Options& options,
+    MessageSCCAnalyzer* scc_analyzer) {
+  std::vector<const FieldDescriptor*> generated_fallback_fields;
+
+  for (const auto* field : fields) {
+    bool handled = false;
     switch (field->type()) {
-      case FieldDescriptor::TYPE_MESSAGE:
-        name = MessageTcParseFunctionName(field, options);
-        break;
-
-      case FieldDescriptor::TYPE_FIXED64:
-      case FieldDescriptor::TYPE_FIXED32:
-      case FieldDescriptor::TYPE_SFIXED64:
-      case FieldDescriptor::TYPE_SFIXED32:
       case FieldDescriptor::TYPE_DOUBLE:
       case FieldDescriptor::TYPE_FLOAT:
-      case FieldDescriptor::TYPE_INT64:
+      case FieldDescriptor::TYPE_FIXED32:
+      case FieldDescriptor::TYPE_SFIXED32:
+      case FieldDescriptor::TYPE_FIXED64:
+      case FieldDescriptor::TYPE_SFIXED64:
+      case FieldDescriptor::TYPE_BOOL:
+      case FieldDescriptor::TYPE_UINT32:
+      case FieldDescriptor::TYPE_SINT32:
       case FieldDescriptor::TYPE_INT32:
       case FieldDescriptor::TYPE_UINT64:
-      case FieldDescriptor::TYPE_UINT32:
       case FieldDescriptor::TYPE_SINT64:
-      case FieldDescriptor::TYPE_SINT32:
-      case FieldDescriptor::TYPE_BOOL:
-        name = FieldParseFunctionName(field, options);
+      case FieldDescriptor::TYPE_INT64:
+        // These are handled by MiniParse, so we don't need any generated
+        // fallback code.
+        handled = true;
         break;
 
+      case FieldDescriptor::TYPE_ENUM:
+        if (field->is_repeated() &&
+            !HasPreservingUnknownEnumSemantics(field)) {
+          // TODO(b/206890171): handle packed repeated closed enums
+          // Non-packed repeated can be handled using tables, but we still
+          // need to generate fallback code for all repeated enums in order to
+          // handle packed encoding. This is because of the lite/full split
+          // when handling invalid enum values in a packed field.
+          handled = false;
+        } else {
+          handled = true;
+        }
+        break;
+
+        // TODO(b/209516305): add TYPE_STRING once field names are available.
       case FieldDescriptor::TYPE_BYTES:
-        if (field->options().ctype() == FieldOptions::STRING &&
-            field->default_value_string().empty() &&
-            !IsStringInlined(field, options)) {
-          name = FieldParseFunctionName(field, options);
+        if (IsStringInlined(field, options)) {
+          // TODO(b/198211897): support InilnedStringField.
+          handled = false;
+        } else {
+          handled = true;
+        }
+        break;
+
+      case FieldDescriptor::TYPE_MESSAGE:
+        // TODO(b/210762816): support remaining field types.
+        if (field->is_map() || IsWeak(field, options) ||
+            IsImplicitWeakField(field, options, scc_analyzer) ||
+            IsLazy(field, options, scc_analyzer)) {
+          handled = false;
+        } else {
+          handled = true;
         }
         break;
 
       default:
+        handled = false;
         break;
     }
-
-    if (name.empty()) {
-      continue;
-    }
-    // This field made it into the fast path, so remove it from the fallback
-    // fields and fill in the table entry.
-    fallback_fields.pop_back();
-    fast_path_fields[idx].func_name = name;
-    fast_path_fields[idx].bits = TcFieldData(tag, hasbit_idx, 0);
-    fast_path_fields[idx].field = field;
+    if (!handled) generated_fallback_fields.push_back(field);
   }
 
+  return generated_fallback_fields;
+}
+
+}  // namespace
+
+TailCallTableInfo::TailCallTableInfo(
+    const Descriptor* descriptor, const Options& options,
+    const std::vector<const FieldDescriptor*>& ordered_fields,
+    const std::vector<int>& has_bit_indices, MessageSCCAnalyzer* scc_analyzer) {
+  int oneof_count = descriptor->real_oneof_decl_count();
+  // If this message has any oneof fields, store the case offset in the first
+  // auxiliary entry.
+  if (oneof_count > 0) {
+    GOOGLE_LOG_IF(DFATAL, ordered_fields.empty())
+        << "Invalid message: " << descriptor->full_name() << " has "
+        << oneof_count << " oneof declarations, but no fields";
+    aux_entries.push_back(StrCat(
+        "_fl::Offset{offsetof(", ClassName(descriptor), ", _oneof_case_)}"));
+  }
+  // Fill in mini table entries.
+  for (const FieldDescriptor* field : ordered_fields) {
+    field_entries.push_back(
+        {field, (HasHasbit(field) ? has_bit_indices[field->index()] : -1)});
+    auto& entry = field_entries.back();
+
+    if (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+        field->type() == FieldDescriptor::TYPE_GROUP) {
+      // Message-typed fields have a FieldAux with the default instance pointer.
+      if (field->is_map()) {
+        // TODO(b/205904770): generate aux entries for maps
+      } else if (IsWeak(field, options)) {
+        // Don't generate anything for weak fields. They are handled by the
+        // generated fallback.
+      } else if (IsImplicitWeakField(field, options, scc_analyzer)) {
+        // Implicit weak fields don't need to store a default instance pointer.
+      } else if (IsLazy(field, options, scc_analyzer)) {
+        // Lazy fields are handled by the generated fallback function.
+      } else {
+        field_entries.back().aux_idx = aux_entries.size();
+        const Descriptor* field_type = field->message_type();
+        aux_entries.push_back(StrCat(
+            "reinterpret_cast<const ", QualifiedClassName(field_type, options),
+            "*>(&", QualifiedDefaultInstanceName(field_type, options), ")"));
+      }
+    } else if (field->type() == FieldDescriptor::TYPE_ENUM &&
+               !HasPreservingUnknownEnumSemantics(field)) {
+      // Enum fields which preserve unknown values (proto3 behavior) are
+      // effectively int32 fields with respect to parsing -- i.e., the value
+      // does not need to be validated at parse time.
+      //
+      // Enum fields which do not preserve unknown values (proto2 behavior) use
+      // a FieldAux to store validation information. If the enum values are
+      // sequential (and within a range we can represent), then the FieldAux
+      // entry represents the range using the minimum value (which must fit in
+      // an int16_t) and count (a uint16_t). Otherwise, the entry holds a
+      // pointer to the generated Name_IsValid function.
+
+      entry.aux_idx = aux_entries.size();
+      const EnumDescriptor* enum_type = field->enum_type();
+      GOOGLE_CHECK_GT(enum_type->value_count(), 0) << enum_type->DebugString();
+
+      // Check if the enum values are a single, contiguous range.
+      std::vector<int> enum_values;
+      for (int i = 0, N = enum_type->value_count(); i < N; ++i) {
+        enum_values.push_back(enum_type->value(i)->number());
+      }
+      auto values_begin = enum_values.begin();
+      auto values_end = enum_values.end();
+      std::sort(values_begin, values_end);
+      enum_values.erase(std::unique(values_begin, values_end), values_end);
+
+      if (enum_values.back() - enum_values[0] == enum_values.size() - 1 &&
+          enum_values[0] >= std::numeric_limits<int16_t>::min() &&
+          enum_values[0] <= std::numeric_limits<int16_t>::max() &&
+          enum_values.size() <= std::numeric_limits<uint16_t>::max()) {
+        entry.is_enum_range = true;
+        aux_entries.push_back(
+            StrCat(enum_values[0], ", ", enum_values.size()));
+      } else {
+        entry.is_enum_range = false;
+        aux_entries.push_back(
+            StrCat(QualifiedClassName(enum_type, options), "_IsValid"));
+      }
+    }
+  }
+
+  // Choose the smallest fast table that covers the maximum number of fields.
+  table_size_log2 = 0;  // fallback value
+  int num_fast_fields = -1;
+  for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) {
+    size_t try_size = 1 << try_size_log2;
+    auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2,
+                                               options, scc_analyzer);
+    GOOGLE_CHECK_EQ(split_fields.size(), try_size);
+    int try_num_fast_fields = 0;
+    for (const auto& info : split_fields) {
+      if (info.field != nullptr) ++try_num_fast_fields;
+    }
+    // Use this size if (and only if) it covers more fields.
+    if (try_num_fast_fields > num_fast_fields) {
+      fast_path_fields = std::move(split_fields);
+      table_size_log2 = try_size_log2;
+      num_fast_fields = try_num_fast_fields;
+    }
+    // The largest table we allow has the same number of entries as the message
+    // has fields, rounded up to the next power of 2 (e.g., a message with 5
+    // fields can have a fast table of size 8). A larger table *might* cover
+    // more fields in certain cases, but a larger table in that case would have
+    // mostly empty entries; so, we cap the size to avoid pathologically sparse
+    // tables.
+    if (try_size > ordered_fields.size()) {
+      break;
+    }
+  }
+
+  // Filter out fields that are handled by MiniParse. We don't need to generate
+  // a fallback for these, which saves code size.
+  fallback_fields = FilterMiniParsedFields(ordered_fields, options,
+                                           scc_analyzer);
+
   // If there are no fallback fields, and at most one extension range, the
   // parser can use a generic fallback function. Otherwise, a message-specific
   // fallback routine is needed.
@@ -252,10 +399,11 @@
       options_(options),
       variables_(vars),
       inlined_string_indices_(inlined_string_indices),
+      ordered_fields_(GetOrderedFields(descriptor_, options_)),
       num_hasbits_(max_has_bit_index) {
   if (should_generate_tctable()) {
-    tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_,
-                                               has_bit_indices, scc_analyzer));
+    tc_table_info_.reset(new TailCallTableInfo(
+        descriptor_, options_, ordered_fields_, has_bit_indices, scc_analyzer));
   }
   SetCommonVars(options_, &variables_);
   SetUnknownFieldsVariable(descriptor_, options_, &variables_);
@@ -265,45 +413,18 @@
 void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) {
   Formatter format(printer, variables_);
   if (should_generate_tctable()) {
-    auto declare_function = [&format](const char* name,
-                                      const std::string& guard) {
-      if (!guard.empty()) {
-        format.Outdent();
-        format("#if $1$\n", guard);
-        format.Indent();
-      }
-      format("static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n", name);
-      if (!guard.empty()) {
-        format.Outdent();
-        format("#endif  // $1$\n", guard);
-        format.Indent();
-      }
-    };
+    format.Outdent();
     if (should_generate_guarded_tctable()) {
-      format.Outdent();
       format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
-      format.Indent();
     }
-    format("// The Tct_* functions are internal to the protobuf runtime:\n");
-    // These guards are defined in port_def.inc:
-    declare_function("Tct_ParseS1", "PROTOBUF_TC_STATIC_PARSE_SINGULAR1");
-    declare_function("Tct_ParseS2", "PROTOBUF_TC_STATIC_PARSE_SINGULAR2");
-    declare_function("Tct_ParseR1", "PROTOBUF_TC_STATIC_PARSE_REPEATED1");
-    declare_function("Tct_ParseR2", "PROTOBUF_TC_STATIC_PARSE_REPEATED2");
-    if (tc_table_info_->use_generated_fallback) {
-      format.Outdent();
-      format(
-          " private:\n"
-          "  ");
-      declare_function("Tct_ParseFallback", "");
-      format(" public:\n");
-      format.Indent();
-    }
+    format(
+        " private:\n"
+        "  static const char* Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL);\n"
+        " public:\n");
     if (should_generate_guarded_tctable()) {
-      format.Outdent();
       format("#endif\n");
-      format.Indent();
     }
+    format.Indent();
   }
   format(
       "const char* _InternalParse(const char* ptr, "
@@ -318,8 +439,14 @@
     need_parse_function = false;
     format(
         "const char* $classname$::_InternalParse(const char* ptr,\n"
-        "                  ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "$annotate_deserialize$"
+        "                  ::_pbi::ParseContext* ctx) {\n"
+        "$annotate_deserialize$");
+    if (!options_.unverified_lazy_message_sets &&
+        ShouldVerify(descriptor_, options_, scc_analyzer_)) {
+      format(
+          "  ctx->set_lazy_eager_verify_func(&$classname$::InternalVerify);\n");
+    }
+    format(
         "  return _extensions_.ParseMessageSet(ptr, \n"
         "      internal_default_instance(), &_internal_metadata_, ctx);\n"
         "}\n");
@@ -339,7 +466,6 @@
   if (tc_table_info_->use_generated_fallback) {
     GenerateTailcallFallbackFunction(format);
   }
-  GenerateTailcallFieldParseFunctions(format);
   if (should_generate_guarded_tctable()) {
     if (need_parse_function) {
       format("\n#else  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
@@ -362,10 +488,10 @@
   // Generate an `_InternalParse` that starts the tail-calling loop.
   format(
       "const char* $classname$::_InternalParse(\n"
-      "    const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
+      "    const char* ptr, ::_pbi::ParseContext* ctx) {\n"
       "$annotate_deserialize$"
-      "  ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n"
-      "      this, ptr, ctx, &_table_.header);\n");
+      "  ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, "
+      "&_table_.header);\n");
   format(
       "  return ptr;\n"
       "}\n\n");
@@ -384,6 +510,7 @@
     // Sync hasbits
     format("typed_msg->_has_bits_[0] = hasbits;\n");
   }
+  format("uint32_t tag = data.tag();\n");
 
   format.Set("msg", "typed_msg->");
   format.Set("this", "typed_msg");
@@ -401,63 +528,6 @@
       "}\n");
 }
 
-void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions(
-    Formatter& format) {
-  GOOGLE_CHECK(should_generate_tctable());
-  // There are four cases where a tailcall target are needed for messages:
-  //   {singular, repeated} x {1, 2}-byte tag
-  struct {
-    const char* type;
-    int size;
-  } const kTagLayouts[] = {
-      {"uint8_t", 1},
-      {"uint16_t", 2},
-  };
-  // Singular:
-  for (const auto& layout : kTagLayouts) {
-    // Guard macros are defined in port_def.inc.
-    format(
-        "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n"
-        "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n"
-        "  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n"
-        "    PROTOBUF_MUSTTAIL "
-        "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
-        "  ptr += $1$;\n"
-        "  hasbits |= (uint64_t{1} << data.hasbit_idx());\n"
-        "  ::$proto_ns$::internal::TcParser::SyncHasbits"
-        "(msg, hasbits, table);\n"
-        "  auto& field = ::$proto_ns$::internal::TcParser::"
-        "RefAt<$classtype$*>(msg, data.offset());\n"
-        "  if (field == nullptr)\n"
-        "    field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n"
-        "  return ctx->ParseMessage(field, ptr);\n"
-        "}\n"
-        "#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n",
-        layout.size, layout.type);
-  }
-  // Repeated:
-  for (const auto& layout : kTagLayouts) {
-    // Guard macros are defined in port_def.inc.
-    format(
-        "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n"
-        "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n"
-        "  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n"
-        "    PROTOBUF_MUSTTAIL "
-        "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
-        "  }\n"
-        "  ptr += $1$;\n"
-        "  auto& field = ::$proto_ns$::internal::TcParser::RefAt<"
-        "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n"
-        "  ::$proto_ns$::internal::TcParser::SyncHasbits"
-        "(msg, hasbits, table);\n"
-        "  ptr = ctx->ParseMessage(field.Add(), ptr);\n"
-        "  return ptr;\n"
-        "}\n"
-        "#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n",
-        layout.size, layout.type);
-  }
-}
-
 void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
   if (!should_generate_tctable()) {
     return;
@@ -469,9 +539,10 @@
     format.Indent();
   }
   format(
-      "static const ::$proto_ns$::internal::TcParseTable<$1$>\n"
-      "    _table_;\n",
-      tc_table_info_->table_size_log2);
+      "static const ::$proto_ns$::internal::TcParseTable<$1$, $2$, $3$, $4$> "
+      "_table_;\n",
+      tc_table_info_->table_size_log2, ordered_fields_.size(),
+      tc_table_info_->aux_entries.size(), CalculateFieldNamesSize());
   if (should_generate_guarded_tctable()) {
     format.Outdent();
     format("#endif  // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
@@ -496,7 +567,7 @@
 void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) {
   format(
       "const char* $classname$::_InternalParse(const char* ptr, "
-      "::$proto_ns$::internal::ParseContext* ctx) {\n"
+      "::_pbi::ParseContext* ctx) {\n"
       "$annotate_deserialize$"
       "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n");
   format.Indent();
@@ -518,8 +589,10 @@
   format("while (!ctx->Done(&ptr)) {\n");
   format.Indent();
 
-  GenerateParseIterationBody(format, descriptor_,
-                             GetOrderedFields(descriptor_, options_));
+  format(
+      "uint32_t tag;\n"
+      "ptr = ::_pbi::ReadTag(ptr, &tag);\n");
+  GenerateParseIterationBody(format, descriptor_, ordered_fields_);
 
   format.Outdent();
   format("}  // while\n");
@@ -544,7 +617,7 @@
   if (tc_table_info_->use_generated_fallback) {
     fallback = ClassName(descriptor_) + "::Tct_ParseFallback";
   } else {
-    fallback = TcParserName(options_) + "GenericFallback";
+    fallback = "::_pbi::TcParser::GenericFallback";
     if (GetOptimizeFor(descriptor_->file(), options_) ==
         FileOptions::LITE_RUNTIME) {
       fallback += "Lite";
@@ -559,9 +632,11 @@
   // the table is sufficient we can use a generic routine, that just handles
   // unknown fields and potentially an extension range.
   format(
-      "const ::$proto_ns$::internal::TcParseTable<$1$>\n"
-      "    $classname$::_table_ = {\n",
-      tc_table_info_->table_size_log2);
+      "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\n"
+      "const ::_pbi::TcParseTable<$1$, $2$, $3$, $4$> $classname$::_table_ = "
+      "{\n",
+      tc_table_info_->table_size_log2, ordered_fields_.size(),
+      tc_table_info_->aux_entries.size(), CalculateFieldNamesSize());
   {
     auto table_scope = format.ScopedIndent();
     format("{\n");
@@ -581,44 +656,336 @@
       } else {
         format("0, 0, 0,  // no _extensions_\n");
       }
+      format("$1$, $2$,  // max_field_number, fast_idx_mask\n",
+             (ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()),
+             (((1 << tc_table_info_->table_size_log2) - 1) << 3));
+
+      // Determine the sequential fields that can be looked up by index:
+      uint16_t num_sequential_fields = 0;
+      uint16_t sequential_fields_start = 0;
+      if (!ordered_fields_.empty() &&
+          ordered_fields_.front()->number() <=
+              std::numeric_limits<uint16_t>::max()) {
+        sequential_fields_start = ordered_fields_[0]->number();
+        const FieldDescriptor* previous_field = ordered_fields_[0];
+        const int N = std::min(ordered_fields_.size(),
+                               size_t{std::numeric_limits<uint8_t>::max()} + 1);
+        for (int i = 1; i < N; ++i) {
+          const FieldDescriptor* current_field = ordered_fields_[i];
+          if (current_field->number() > previous_field->number() + 1) {
+            break;
+          }
+          ++num_sequential_fields;
+          previous_field = current_field;
+        }
+      }
+      format("$1$, $2$,  // num_sequential_fields, sequential_fields_start\n",
+             num_sequential_fields, sequential_fields_start);
+
       format(
-          "$1$, 0, $2$,  // fast_idx_mask, reserved, num_fields\n"
-          "&$3$._instance,\n"
-          "$4$  // fallback\n",
-          (((1 << tc_table_info_->table_size_log2) - 1) << 3),
-          descriptor_->field_count(),
+          "$1$,  // num_field_entries\n"
+          "$2$,  // num_aux_entries\n",
+          ordered_fields_.size(), tc_table_info_->aux_entries.size());
+      if (tc_table_info_->aux_entries.empty()) {
+        format(
+            "offsetof(decltype(_table_), field_names),  // no aux_entries\n");
+      } else {
+        format("offsetof(decltype(_table_), aux_entries),\n");
+      }
+      format(
+          "&$1$._instance,\n"
+          "$2$,  // fallback\n"
+          "",
           DefaultInstanceName(descriptor_, options_), fallback);
     }
-    format("}, {\n");
+    format("}, {{\n");
     {
+      // fast_entries[]
       auto fast_scope = format.ScopedIndent();
-      GenerateFastFieldEntries(format, fallback);
+      GenerateFastFieldEntries(format);
     }
-    format("},\n");  // entries[]
+    if (ordered_fields_.empty()) {
+      GOOGLE_LOG_IF(DFATAL, !tc_table_info_->aux_entries.empty())
+          << "Invalid message: " << descriptor_->full_name() << " has "
+          << tc_table_info_->aux_entries.size()
+          << " auxiliary field entries, but no fields";
+      format("}},\n"
+             "// no field_numbers, field_entries, or aux_entries\n"
+             "{{\n");
+    } else {
+      format("}}, {{\n");
+      {
+        // field_numbers[]
+        auto field_number_scope = format.ScopedIndent();
+        for (int i = 0, N = ordered_fields_.size(); i < N; ++i) {
+          const FieldDescriptor* field = ordered_fields_[i];
+          if (i > 0) {
+            if (i % 10 == 0) {
+              format(",\n");
+            } else {
+              format(", ");
+            }
+          }
+          format("$1$", field->number());
+        }
+        format("\n");
+      }
+      format("}}, {{\n");
+      {
+        // field_entries[]
+        auto field_scope = format.ScopedIndent();
+        GenerateFieldEntries(format);
+      }
+      if (tc_table_info_->aux_entries.empty()) {
+        format(
+            "}},\n"
+            "// no aux_entries\n"
+            "{{\n");
+      } else {
+        format("}}, {{\n");
+        {
+          // aux_entries[]
+          auto aux_scope = format.ScopedIndent();
+          for (const std::string& aux_entry : tc_table_info_->aux_entries) {
+            format("{$1$},\n", aux_entry);
+          }
+        }
+        format("}}, {{\n");
+      }
+    }  // ordered_fields_.empty()
+    {
+      // field_names[]
+      auto field_scope = format.ScopedIndent();
+      GenerateFieldNames(format);
+    }
+    format("}},\n");
   }
   format("};\n\n");  // _table_
 }
 
-void ParseFunctionGenerator::GenerateFastFieldEntries(
-    Formatter& format, const std::string& fallback) {
+void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) {
   for (const auto& info : tc_table_info_->fast_path_fields) {
     if (info.field != nullptr) {
       PrintFieldComment(format, info.field);
     }
-    format("{$1$, ", info.func_name.empty() ? fallback : info.func_name);
-    if (info.bits.data) {
-      GOOGLE_DCHECK_NE(nullptr, info.field);
-      format(
-          "{$1$, $2$, "
-          "static_cast<uint16_t>(PROTOBUF_FIELD_OFFSET($classname$, $3$_))}",
-          info.bits.coded_tag(), info.bits.hasbit_idx(), FieldName(info.field));
+    if (info.func_name.empty()) {
+      format("{::_pbi::TcParser::MiniParse, {}},\n");
     } else {
-      format("{}");
+      format(
+          "{$1$,\n"
+          " {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$, $5$_)}},\n",
+          info.func_name, info.coded_tag, info.hasbit_idx, info.aux_idx,
+          FieldName(info.field));
+    }
+  }
+}
+
+static void FormatFieldKind(Formatter& format,
+                            const TailCallTableInfo::FieldEntryInfo& entry,
+                            const Options& options,
+                            MessageSCCAnalyzer* scc_analyzer) {
+  const FieldDescriptor* field = entry.field;
+  // Spell the field kind in proto language declaration order, starting with
+  // cardinality:
+  format("(::_fl::kFc");
+  if (HasHasbit(field)) {
+    format("Optional");
+  } else if (field->is_repeated()) {
+    format("Repeated");
+  } else if (field->real_containing_oneof()) {
+    format("Oneof");
+  } else {
+    format("Singular");
+  }
+
+  // The rest of the type uses convenience aliases:
+  format(" | ::_fl::k");
+  if (field->is_repeated() && field->is_packed()) {
+    format("Packed");
+  }
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_DOUBLE:
+      format("Double");
+      break;
+    case FieldDescriptor::TYPE_FLOAT:
+      format("Float");
+      break;
+    case FieldDescriptor::TYPE_FIXED32:
+      format("Fixed32");
+      break;
+    case FieldDescriptor::TYPE_SFIXED32:
+      format("SFixed32");
+      break;
+    case FieldDescriptor::TYPE_FIXED64:
+      format("Fixed64");
+      break;
+    case FieldDescriptor::TYPE_SFIXED64:
+      format("SFixed64");
+      break;
+    case FieldDescriptor::TYPE_BOOL:
+      format("Bool");
+      break;
+    case FieldDescriptor::TYPE_ENUM:
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        // No validation is required.
+        format("OpenEnum");
+      } else if (entry.is_enum_range) {
+        // Validation is done by range check (start/length in FieldAux).
+        format("EnumRange");
+      } else {
+        // Validation uses the generated _IsValid function.
+        format("Enum");
+      }
+      break;
+    case FieldDescriptor::TYPE_UINT32:
+      format("UInt32");
+      break;
+    case FieldDescriptor::TYPE_SINT32:
+      format("SInt32");
+      break;
+    case FieldDescriptor::TYPE_INT32:
+      format("Int32");
+      break;
+    case FieldDescriptor::TYPE_UINT64:
+      format("UInt64");
+      break;
+    case FieldDescriptor::TYPE_SINT64:
+      format("SInt64");
+      break;
+    case FieldDescriptor::TYPE_INT64:
+      format("Int64");
+      break;
+
+    case FieldDescriptor::TYPE_BYTES:
+      format("Bytes");
+      break;
+    case FieldDescriptor::TYPE_STRING: {
+      auto mode = GetUtf8CheckMode(field, options);
+      switch (mode) {
+        case Utf8CheckMode::kStrict:
+          format("Utf8String");
+          break;
+        case Utf8CheckMode::kVerify:
+          format("RawString");
+          break;
+        case Utf8CheckMode::kNone:
+          // Treat LITE_RUNTIME strings as bytes.
+          format("Bytes");
+          break;
+        default:
+          GOOGLE_LOG(FATAL) << "Invalid Utf8CheckMode (" << static_cast<int>(mode)
+                     << ") for " << field->DebugString();
+      }
+      break;
+    }
+
+    case FieldDescriptor::TYPE_GROUP:
+      format("Message | ::_fl::kRepGroup");
+      break;
+    case FieldDescriptor::TYPE_MESSAGE:
+      if (field->is_map()) {
+        format("Map");
+      } else {
+        format("Message");
+        if (IsLazy(field, options, scc_analyzer)) {
+          format(" | ::_fl::kRepLazy");
+        } else if (IsImplicitWeakField(field, options, scc_analyzer)) {
+          format(" | ::_fl::kRepIWeak");
+        }
+      }
+      break;
+  }
+
+  // Fill in extra information about string and bytes field representations.
+  if (field->type() == FieldDescriptor::TYPE_BYTES ||
+      field->type() == FieldDescriptor::TYPE_STRING) {
+    if (field->is_repeated()) {
+      format(" | ::_fl::kRepSString");
+    } else {
+      format(" | ::_fl::kRepAString");
+    }
+  }
+
+  format(")");
+}
+
+void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) {
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    PrintFieldComment(format, field);
+    format("{");
+    if (IsWeak(field, options_)) {
+      // Weak fields are handled by the generated fallback function.
+      // (These are handled by legacy Google-internal logic.)
+      format("/* weak */ 0, 0, 0, 0");
+    } else {
+      const OneofDescriptor* oneof = field->real_containing_oneof();
+      format("PROTOBUF_FIELD_OFFSET($classname$, $1$), $2$, $3$,\n ",
+             FieldMemberName(field),
+             (oneof ? oneof->index() : entry.hasbit_idx), entry.aux_idx);
+      FormatFieldKind(format, entry, options_, scc_analyzer_);
     }
     format("},\n");
   }
 }
 
+static constexpr int kMaxNameLength = 255;
+
+int ParseFunctionGenerator::CalculateFieldNamesSize() const {
+  // The full name of the message appears first.
+  int size = std::min(static_cast<int>(descriptor_->full_name().size()),
+                      kMaxNameLength);
+  int lengths_size = 1;
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    GOOGLE_CHECK_LE(field->name().size(), kMaxNameLength);
+    size += field->name().size();
+    lengths_size += 1;
+  }
+  // align to an 8-byte boundary
+  lengths_size = (lengths_size + 7) & -8;
+  return size + lengths_size + 1;
+}
+
+static void FormatOctal(Formatter& format, int size) {
+  int octal_size = ((size >> 6) & 3) * 100 +  //
+                   ((size >> 3) & 7) * 10 +   //
+                   ((size >> 0) & 7);
+  format("\\$1$", octal_size);
+}
+
+void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) {
+  // First, we output the size of each string, as an unsigned byte. The first
+  // string is the message name.
+  int count = 1;
+  format("\"");
+  FormatOctal(format,
+              std::min(static_cast<int>(descriptor_->full_name().size()), 255));
+  for (const auto& entry : tc_table_info_->field_entries) {
+    FormatOctal(format, entry.field->name().size());
+    ++count;
+  }
+  while (count & 7) {  // align to an 8-byte boundary
+    format("\\0");
+    ++count;
+  }
+  format("\"\n");
+  // The message name is stored at the beginning of the string
+  std::string message_name = descriptor_->full_name();
+  if (message_name.size() > kMaxNameLength) {
+    static constexpr int kNameHalfLength = (kMaxNameLength - 3) / 2;
+    message_name = StrCat(
+        message_name.substr(0, kNameHalfLength), "...",
+        message_name.substr(message_name.size() - kNameHalfLength));
+  }
+  format("\"$1$\"\n", message_name);
+  // Then we output the actual field names
+  for (const auto& entry : tc_table_info_->field_entries) {
+    const FieldDescriptor* field = entry.field;
+    format("\"$1$\"\n", field->name());
+  }
+}
+
 void ParseFunctionGenerator::GenerateArenaString(Formatter& format,
                                                  const FieldDescriptor* field) {
   if (HasHasbit(field)) {
@@ -636,11 +1003,12 @@
   if (IsStringInlined(field, options_)) {
     GOOGLE_DCHECK(!inlined_string_indices_.empty());
     int inlined_string_index = inlined_string_indices_[field->index()];
-    GOOGLE_DCHECK_GE(inlined_string_index, 0);
+    GOOGLE_DCHECK_GT(inlined_string_index, 0);
     format(
         ", $msg$_internal_$name$_donated()"
         ", &$msg$_inlined_string_donated_[$1$]"
-        ", ~0x$2$u",
+        ", ~0x$2$u"
+        ", $this$",
         inlined_string_index / 32,
         strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8));
   } else {
@@ -649,7 +1017,7 @@
   format(
       ");\n"
       "} else {\n"
-      "  ptr = ::$proto_ns$::internal::InlineGreedyStringParser("
+      "  ptr = ::_pbi::InlineGreedyStringParser("
       "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n"
       "}\n"
       "const std::string* str = &$msg$$name$_.Get(); (void)str;\n",
@@ -685,11 +1053,14 @@
     }
     format(
         "auto str = $msg$$1$$2$_$name$();\n"
-        "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n",
+        "ptr = ::_pbi::Inline$3$(str, ptr, ctx);\n",
         HasInternalAccessors(ctype) ? "_internal_" : "",
         field->is_repeated() && !field->is_packable() ? "add" : "mutable",
         parser_name);
   }
+  // It is intentionally placed before VerifyUTF8 because it doesn't make sense
+  // to verify UTF8 when we already know parsing failed.
+  format("CHK_(ptr);\n");
   if (!check_utf8) return;  // return if this is a bytes field
   auto level = GetUtf8CheckMode(field, options_);
   switch (level) {
@@ -707,7 +1078,7 @@
   if (HasDescriptorMethods(field->file(), options_)) {
     field_name = StrCat("\"", field->full_name(), "\"");
   }
-  format("::$proto_ns$::internal::VerifyUTF8(str, $1$)", field_name);
+  format("::_pbi::VerifyUTF8(str, $1$)", field_name);
   switch (level) {
     case Utf8CheckMode::kNone:
       return;
@@ -740,6 +1111,7 @@
           "$msg$_internal_mutable_$name$(), ptr, ctx);\n",
           DeclaredTypeMethodName(field->type()));
     }
+    format("CHK_(ptr);\n");
   } else {
     auto field_type = field->type();
     switch (field_type) {
@@ -751,8 +1123,7 @@
         break;
       case FieldDescriptor::TYPE_MESSAGE: {
         if (field->is_map()) {
-          const FieldDescriptor* val =
-              field->message_type()->map_value();
+          const FieldDescriptor* val = field->message_type()->map_value();
           GOOGLE_CHECK(val);
           if (val->type() == FieldDescriptor::TYPE_ENUM &&
               !HasPreservingUnknownEnumSemantics(field)) {
@@ -768,6 +1139,16 @@
             format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
           }
         } else if (IsLazy(field, options_, scc_analyzer_)) {
+          bool eager_verify =
+              IsEagerlyVerifiedLazy(field, options_, scc_analyzer_);
+          if (ShouldVerify(descriptor_, options_, scc_analyzer_)) {
+            format(
+                "ctx->set_lazy_eager_verify_func($1$);\n",
+                eager_verify
+                    ? StrCat("&", ClassName(field->message_type(), true),
+                                   "::InternalVerify")
+                    : "nullptr");
+          }
           if (field->real_containing_oneof()) {
             format(
                 "if (!$msg$_internal_has_$name$()) {\n"
@@ -790,9 +1171,16 @@
               "::$proto_ns$::internal::LazyFieldParseHelper<\n"
               "  ::$proto_ns$::internal::LazyField> parse_helper(\n"
               "    $1$::default_instance(),\n"
-              "    $msg$GetArenaForAllocation(), lazy_field);\n"
+              "    $msg$GetArenaForAllocation(),\n"
+              "    ::google::protobuf::internal::LazyVerifyOption::$2$,\n"
+              "    lazy_field);\n"
               "ptr = ctx->ParseMessage(&parse_helper, ptr);\n",
-              FieldMessageTypeName(field, options_));
+              FieldMessageTypeName(field, options_),
+              eager_verify ? "kEager" : "kLazy");
+          if (ShouldVerify(descriptor_, options_, scc_analyzer_) &&
+              eager_verify) {
+            format("ctx->set_lazy_eager_verify_func(nullptr);\n");
+          }
         } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
           if (!field->is_repeated()) {
             format(
@@ -819,6 +1207,7 @@
               "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
               "ptr);\n");
         }
+        format("CHK_(ptr);\n");
         break;
       }
       default:
@@ -925,7 +1314,6 @@
     }
     case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
       GenerateLengthDelim(format, field);
-      format("CHK_(ptr);\n");
       break;
     }
     case WireFormatLite::WIRETYPE_START_GROUP: {
@@ -983,13 +1371,9 @@
 // parse the next tag in the stream.
 void ParseFunctionGenerator::GenerateParseIterationBody(
     Formatter& format, const Descriptor* descriptor,
-    const std::vector<const FieldDescriptor*>& ordered_fields) {
-  format(
-      "$uint32$ tag;\n"
-      "ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n");
-
-  if (!ordered_fields.empty()) {
-    GenerateFieldSwitch(format, ordered_fields);
+    const std::vector<const FieldDescriptor*>& fields) {
+  if (!fields.empty()) {
+    GenerateFieldSwitch(format, fields);
     // Each field `case` only considers field number. Field numbers that are
     // not defined in the message, or tags with an incompatible wire type, are
     // considered "unusual" cases. They will be handled by the logic below.
@@ -1045,12 +1429,11 @@
 }
 
 void ParseFunctionGenerator::GenerateFieldSwitch(
-    Formatter& format,
-    const std::vector<const FieldDescriptor*>& ordered_fields) {
+    Formatter& format, const std::vector<const FieldDescriptor*>& fields) {
   format("switch (tag >> 3) {\n");
   format.Indent();
 
-  for (const auto* field : ordered_fields) {
+  for (const auto* field : fields) {
     PrintFieldComment(format, field);
     format("case $1$:\n", field->number());
     format.Indent();
@@ -1104,64 +1487,68 @@
 
 namespace {
 
-std::string FieldParseFunctionName(const FieldDescriptor* field,
-                                   const Options& options) {
-  ParseCardinality card =  //
-      field->is_packed()               ? ParseCardinality::kPacked
-      : field->is_repeated()           ? ParseCardinality::kRepeated
-      : field->real_containing_oneof() ? ParseCardinality::kOneof
-                                       : ParseCardinality::kSingular;
+std::string FieldParseFunctionName(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options) {
+  const FieldDescriptor* field = entry.field;
+  std::string name = "::_pbi::TcParser::Fast";
 
-  TypeFormat type_format;
   switch (field->type()) {
-    case FieldDescriptor::TYPE_FIXED64:
-    case FieldDescriptor::TYPE_SFIXED64:
-    case FieldDescriptor::TYPE_DOUBLE:
-      type_format = TypeFormat::kFixed64;
-      break;
-
     case FieldDescriptor::TYPE_FIXED32:
     case FieldDescriptor::TYPE_SFIXED32:
     case FieldDescriptor::TYPE_FLOAT:
-      type_format = TypeFormat::kFixed32;
+      name.append("F32");
       break;
 
-    case FieldDescriptor::TYPE_INT64:
-    case FieldDescriptor::TYPE_UINT64:
-      type_format = TypeFormat::kVar64;
-      break;
-
-    case FieldDescriptor::TYPE_INT32:
-    case FieldDescriptor::TYPE_UINT32:
-      type_format = TypeFormat::kVar32;
-      break;
-
-    case FieldDescriptor::TYPE_SINT64:
-      type_format = TypeFormat::kSInt64;
-      break;
-
-    case FieldDescriptor::TYPE_SINT32:
-      type_format = TypeFormat::kSInt32;
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+    case FieldDescriptor::TYPE_DOUBLE:
+      name.append("F64");
       break;
 
     case FieldDescriptor::TYPE_BOOL:
-      type_format = TypeFormat::kBool;
+      name.append("V8");
+      break;
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+      name.append("V32");
+      break;
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+      name.append("V64");
+      break;
+
+    case FieldDescriptor::TYPE_ENUM:
+      if (HasPreservingUnknownEnumSemantics(field)) {
+        name.append("V32");
+        break;
+      }
+      if (field->is_repeated() && field->is_packed()) {
+        GOOGLE_LOG(DFATAL) << "Enum validation not handled: " << field->DebugString();
+        return "";
+      }
+      name.append(entry.is_enum_range ? "Er" : "Ev");
+      break;
+
+    case FieldDescriptor::TYPE_SINT32:
+      name.append("Z32");
+      break;
+    case FieldDescriptor::TYPE_SINT64:
+      name.append("Z64");
       break;
 
     case FieldDescriptor::TYPE_BYTES:
-      type_format = TypeFormat::kBytes;
+      name.append("B");
       break;
-
     case FieldDescriptor::TYPE_STRING:
       switch (GetUtf8CheckMode(field, options)) {
         case Utf8CheckMode::kNone:
-          type_format = TypeFormat::kBytes;
-          break;
-        case Utf8CheckMode::kStrict:
-          type_format = TypeFormat::kString;
+          name.append("B");
           break;
         case Utf8CheckMode::kVerify:
-          type_format = TypeFormat::kStringValidateOnly;
+          name.append("S");
+          break;
+        case Utf8CheckMode::kStrict:
+          name.append("U");
           break;
         default:
           GOOGLE_LOG(DFATAL) << "Mode not handled: "
@@ -1170,133 +1557,32 @@
       }
       break;
 
+    case FieldDescriptor::TYPE_MESSAGE:
+      name.append("M");
+      break;
+
     default:
       GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString();
       return "";
   }
 
-  return "::" + ProtobufNamespace(options) + "::internal::TcParser::" +
-         GetTailCallFieldHandlerName(card, type_format,
-                                     TagSize(field->number()), options);
+  // The field implementation functions are prefixed by cardinality:
+  //   `S` for optional or implicit fields.
+  //   `R` for non-packed repeated.
+  //   `P` for packed repeated.
+  name.append(field->is_packed()               ? "P"
+              : field->is_repeated()           ? "R"
+              : field->real_containing_oneof() ? "O"
+                                               : "S");
+
+  // Append the tag length. Fast parsing only handles 1- or 2-byte tags.
+  name.append(TagSize(field->number()) == 1 ? "1" : "2");
+
+  return name;
 }
 
 }  // namespace
 
-std::string GetTailCallFieldHandlerName(ParseCardinality card,
-                                        TypeFormat type_format,
-                                        int tag_length_bytes,
-                                        const Options& options) {
-  std::string name;
-
-  // The field implementation functions are prefixed by cardinality:
-  //   `Singular` for optional or implicit fields.
-  //   `Repeated` for non-packed repeated.
-  //   `Packed` for packed repeated.
-  switch (card) {
-    case ParseCardinality::kSingular:
-      name.append("Singular");
-      break;
-    case ParseCardinality::kOneof:
-      name.append("Oneof");
-      break;
-    case ParseCardinality::kRepeated:
-      name.append("Repeated");
-      break;
-    case ParseCardinality::kPacked:
-      name.append("Packed");
-      break;
-  }
-
-  // Next in the function name is the TypeFormat-specific name.
-  switch (type_format) {
-    case TypeFormat::kFixed64:
-    case TypeFormat::kFixed32:
-      name.append("Fixed");
-      break;
-
-    case TypeFormat::kVar64:
-    case TypeFormat::kVar32:
-    case TypeFormat::kSInt64:
-    case TypeFormat::kSInt32:
-    case TypeFormat::kBool:
-      name.append("Varint");
-      break;
-
-    case TypeFormat::kBytes:
-    case TypeFormat::kString:
-    case TypeFormat::kStringValidateOnly:
-      name.append("String");
-      break;
-
-    default:
-      break;
-  }
-
-  name.append("<");
-
-  // Determine the numeric layout type for the parser to use, independent of
-  // the specific parsing logic used.
-  switch (type_format) {
-    case TypeFormat::kVar64:
-    case TypeFormat::kFixed64:
-      name.append("uint64_t, ");
-      break;
-
-    case TypeFormat::kSInt64:
-      name.append("int64_t, ");
-      break;
-
-    case TypeFormat::kVar32:
-    case TypeFormat::kFixed32:
-      name.append("uint32_t, ");
-      break;
-
-    case TypeFormat::kSInt32:
-      name.append("int32_t, ");
-      break;
-
-    case TypeFormat::kBool:
-      name.append("bool, ");
-      break;
-
-    default:
-      break;
-  }
-
-  name.append(CodedTagType(tag_length_bytes));
-
-  switch (type_format) {
-    case TypeFormat::kVar64:
-    case TypeFormat::kVar32:
-    case TypeFormat::kBool:
-      StrAppend(&name, ", ", TcParserName(options), "kNoConversion");
-      break;
-
-    case TypeFormat::kSInt64:
-    case TypeFormat::kSInt32:
-      StrAppend(&name, ", ", TcParserName(options), "kZigZag");
-      break;
-
-    case TypeFormat::kBytes:
-      StrAppend(&name, ", ", TcParserName(options), "kNoUtf8");
-      break;
-
-    case TypeFormat::kString:
-      StrAppend(&name, ", ", TcParserName(options), "kUtf8");
-      break;
-
-    case TypeFormat::kStringValidateOnly:
-      StrAppend(&name, ", ", TcParserName(options), "kUtf8ValidateOnly");
-      break;
-
-    default:
-      break;
-  }
-
-  name.append(">");
-  return name;
-}
-
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
index b921067..a1621fd 100644
--- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
@@ -35,12 +35,11 @@
 #include <string>
 #include <vector>
 
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/generated_message_tctable_decl.h>
 #include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 
 namespace google {
 namespace protobuf {
@@ -50,18 +49,34 @@
 // Helper class for generating tailcall parsing functions.
 struct TailCallTableInfo {
   TailCallTableInfo(const Descriptor* descriptor, const Options& options,
+                    const std::vector<const FieldDescriptor*>& ordered_fields,
                     const std::vector<int>& has_bit_indices,
                     MessageSCCAnalyzer* scc_analyzer);
-  // Information to generate field entries.
-  struct FieldInfo {
-    const FieldDescriptor* field;
-    google::protobuf::internal::TcFieldData bits;
-    std::string func_name;
-  };
+
   // Fields parsed by the table fast-path.
-  std::vector<FieldInfo> fast_path_fields;
-  // Fields parsed by slow-path fallback.
+  struct FastFieldInfo {
+    std::string func_name;
+    const FieldDescriptor* field;
+    uint16_t coded_tag;
+    uint8_t hasbit_idx;
+    uint8_t aux_idx;
+  };
+  std::vector<FastFieldInfo> fast_path_fields;
+
+  // Fields parsed by mini parsing routines.
+  struct FieldEntryInfo {
+    const FieldDescriptor* field;
+    int hasbit_idx;
+    uint16_t aux_idx;
+    // True for enums entirely covered by the start/length fields of FieldAux:
+    bool is_enum_range;
+  };
+  std::vector<FieldEntryInfo> field_entries;
+  std::vector<std::string> aux_entries;
+
+  // Fields parsed by generated fallback function.
   std::vector<const FieldDescriptor*> fallback_fields;
+
   // Table size.
   int table_size_log2;
   // Mask for has-bits of required fields.
@@ -110,15 +125,15 @@
   // Generates a fallback function for tailcall table-based parsing.
   void GenerateTailcallFallbackFunction(Formatter& format);
 
-  // Generates functions for parsing this message as a field.
-  void GenerateTailcallFieldParseFunctions(Formatter& format);
-
   // Generates a looping `_InternalParse` function.
   void GenerateLoopingParseFunction(Formatter& format);
 
   // Generates the tail-call table definition.
   void GenerateTailCallTable(Formatter& format);
-  void GenerateFastFieldEntries(Formatter& format, const std::string& fallback);
+  void GenerateFastFieldEntries(Formatter& format);
+  void GenerateFieldEntries(Formatter& format);
+  int CalculateFieldNamesSize() const;
+  void GenerateFieldNames(Formatter& format);
 
   // Generates parsing code for an `ArenaString` field.
   void GenerateArenaString(Formatter& format, const FieldDescriptor* field);
@@ -139,12 +154,11 @@
   // Generates code to parse the next field from the input stream.
   void GenerateParseIterationBody(
       Formatter& format, const Descriptor* descriptor,
-      const std::vector<const FieldDescriptor*>& ordered_fields);
+      const std::vector<const FieldDescriptor*>& fields);
 
-  // Generates a `switch` statement to parse each of `ordered_fields`.
-  void GenerateFieldSwitch(
-      Formatter& format,
-      const std::vector<const FieldDescriptor*>& ordered_fields);
+  // Generates a `switch` statement to parse each of `fields`.
+  void GenerateFieldSwitch(Formatter& format,
+                           const std::vector<const FieldDescriptor*>& fields);
 
   const Descriptor* descriptor_;
   MessageSCCAnalyzer* scc_analyzer_;
@@ -152,45 +166,10 @@
   std::map<std::string, std::string> variables_;
   std::unique_ptr<TailCallTableInfo> tc_table_info_;
   std::vector<int> inlined_string_indices_;
+  const std::vector<const FieldDescriptor*> ordered_fields_;
   int num_hasbits_;
 };
 
-enum class ParseCardinality {
-  kSingular,
-  kOneof,
-  kRepeated,
-  kPacked,
-};
-
-// TypeFormat defines parsing types, which encapsulates the expected wire
-// format, conversion or validation, and the in-memory layout.
-enum class TypeFormat {
-  // Fixed types:
-  kFixed64,  // fixed64, sfixed64, double
-  kFixed32,  // fixed32, sfixed32, float
-
-  // Varint types:
-  kVar64,   // int64, uint64
-  kVar32,   // int32, uint32
-  kSInt64,  // sint64
-  kSInt32,  // sint32
-  kBool,    // bool
-
-  // Length-delimited types:
-  kBytes,               // bytes
-  kString,              // string (proto3/UTF-8 strict)
-  kStringValidateOnly,  // string (proto2/UTF-8 validate only)
-};
-
-// Returns the name of a field parser function.
-//
-// These are out-of-line functions generated by
-// parse_function_inc_generator_main.
-std::string GetTailCallFieldHandlerName(ParseCardinality card,
-                                        TypeFormat type_format,
-                                        int tag_length_bytes,
-                                        const Options& options);
-
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 373f38d..5bc419d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -54,11 +54,10 @@
 class TestGenerator : public CodeGenerator {
  public:
   TestGenerator() {}
-  ~TestGenerator() {}
+  ~TestGenerator() override {}
 
-  virtual bool Generate(const FileDescriptor* file,
-                        const std::string& parameter, GeneratorContext* context,
-                        std::string* error) const {
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
     TryInsert("test.pb.h", "includes", context);
     TryInsert("test.pb.h", "namespace_scope", context);
     TryInsert("test.pb.h", "global_scope", context);
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index ffccf08..e09f93e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -34,10 +34,10 @@
 
 #include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
 
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 namespace google {
 namespace protobuf {
@@ -201,7 +201,7 @@
   format(
       "target = stream->EnsureSpace(target);\n"
       "target = "
-      "::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray("
+      "::_pbi::WireFormatLite::Write$declared_type$ToArray("
       "$number$, this->_internal_$name$(), target);\n");
 }
 
@@ -214,12 +214,12 @@
       // Adding one is very common and it turns out it can be done for
       // free inside of WireFormatLite, so we can save an instruction here.
       format(
-          "total_size += ::$proto_ns$::internal::WireFormatLite::"
+          "total_size += ::_pbi::WireFormatLite::"
           "$declared_type$SizePlusOne(this->_internal_$name$());\n");
     } else {
       format(
           "total_size += $tag_size$ +\n"
-          "  ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+          "  ::_pbi::WireFormatLite::$declared_type$Size(\n"
           "    this->_internal_$name$());\n");
     }
   } else {
@@ -440,7 +440,7 @@
     format(
         "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
         "  target = stream->EnsureSpace(target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::"
+        "  target = ::_pbi::WireFormatLite::"
         "Write$declared_type$ToArray($number$, this->_internal_$name$(i), "
         "target);\n"
         "}\n");
@@ -455,7 +455,7 @@
   int fixed_size = FixedSize(descriptor_->type());
   if (fixed_size == -1) {
     format(
-        "size_t data_size = ::$proto_ns$::internal::WireFormatLite::\n"
+        "size_t data_size = ::_pbi::WireFormatLite::\n"
         "  $declared_type$Size(this->$name$_);\n");
   } else {
     format(
@@ -468,12 +468,11 @@
     format(
         "if (data_size > 0) {\n"
         "  total_size += $tag_size$ +\n"
-        "    ::$proto_ns$::internal::WireFormatLite::Int32Size(\n"
-        "        static_cast<$int32$>(data_size));\n"
+        "    ::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
         "}\n");
     if (FixedSize(descriptor_->type()) == -1) {
       format(
-          "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n"
+          "int cached_size = ::_pbi::ToCachedSize(data_size);\n"
           "_$name$_cached_byte_size_.store(cached_size,\n"
           "                                std::memory_order_relaxed);\n");
     }
@@ -482,7 +481,7 @@
     format(
         "total_size += $tag_size$ *\n"
         "              "
-        "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
+        "::_pbi::FromIntSize(this->_internal_$name$_size());\n"
         "total_size += data_size;\n");
   }
   format.Outdent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index ff7c208..0cdc12c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 
 namespace google {
@@ -48,7 +49,7 @@
  public:
   PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
                           const Options& options);
-  ~PrimitiveFieldGenerator();
+  ~PrimitiveFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
@@ -72,7 +73,7 @@
  public:
   PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
                                const Options& options);
-  ~PrimitiveOneofFieldGenerator();
+  ~PrimitiveOneofFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@@ -88,7 +89,7 @@
  public:
   RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
                                   const Options& options);
-  ~RepeatedPrimitiveFieldGenerator();
+  ~RepeatedPrimitiveFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc
index 6b1ca83..c630e7f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_service.cc
@@ -33,9 +33,10 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_service.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h
index 63c7ca4..8b210af 100644
--- a/src/google/protobuf/compiler/cpp/cpp_service.h
+++ b/src/google/protobuf/compiler/cpp/cpp_service.h
@@ -37,8 +37,9 @@
 
 #include <map>
 #include <string>
-#include <google/protobuf/compiler/cpp/cpp_options.h>
+
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/cpp/cpp_options.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 607e815..529cb86 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -33,10 +33,11 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_string_field.h>
-#include <google/protobuf/compiler/cpp/cpp_helpers.h>
-#include <google/protobuf/descriptor.pb.h>
+
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
 
 
 namespace google {
@@ -50,36 +51,36 @@
                         std::map<std::string, std::string>* variables,
                         const Options& options) {
   SetCommonFieldVariables(descriptor, variables, options);
+
+  const std::string kNS = "::" + (*variables)["proto_ns"] + "::internal::";
+  const std::string kArenaStringPtr = kNS + "ArenaStringPtr";
+  const std::string kEmptyDefault = kArenaStringPtr + "::EmptyDefault{}";
+  const std::string kNonEmptyDefault = kArenaStringPtr + "::NonEmptyDefault{}";
+
   (*variables)["default"] = DefaultValue(options, descriptor);
   (*variables)["default_length"] =
       StrCat(descriptor->default_value_string().length());
   std::string default_variable_string = MakeDefaultName(descriptor);
   (*variables)["default_variable_name"] = default_variable_string;
 
-  if (!descriptor->default_value_string().empty()) {
+  if (descriptor->default_value_string().empty()) {
+    (*variables)["init_value"] = "";
+    (*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()";
+    (*variables)["default_value"] = "&" + (*variables)["default_string"];
+    (*variables)["default_value_tag"] = kEmptyDefault;
+    (*variables)["default_variable_or_tag"] = kEmptyDefault;
+  } else {
     (*variables)["lazy_variable"] =
         QualifiedClassName(descriptor->containing_type(), options) +
         "::" + default_variable_string;
+
+    (*variables)["init_value"] = "nullptr";
+    (*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()";
+    (*variables)["default_value"] = "nullptr";
+    (*variables)["default_value_tag"] = kNonEmptyDefault;
+    (*variables)["default_variable_or_tag"] = (*variables)["lazy_variable"];
   }
 
-  (*variables)["default_string"] =
-      descriptor->default_value_string().empty()
-          ? "::" + (*variables)["proto_ns"] +
-                "::internal::GetEmptyStringAlreadyInited()"
-          : (*variables)["lazy_variable"] + ".get()";
-  (*variables)["init_value"] =
-      descriptor->default_value_string().empty()
-          ? "&::" + (*variables)["proto_ns"] +
-                "::internal::GetEmptyStringAlreadyInited()"
-          : "nullptr";
-  (*variables)["default_value_tag"] =
-      "::" + (*variables)["proto_ns"] + "::internal::ArenaStringPtr::" +
-      (descriptor->default_value_string().empty() ? "Empty" : "NonEmpty") +
-      "Default{}";
-  (*variables)["default_variable_or_tag"] =
-      (*variables)[descriptor->default_value_string().empty()
-                       ? "default_value_tag"
-                       : "lazy_variable"];
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
   (*variables)["setter"] =
@@ -116,9 +117,14 @@
   if (!inlined_) {
     format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
   } else {
+    // Skips the automatic destruction; rather calls it explicitly if
+    // allocating arena is null. This is required to support message-owned
+    // arena (go/path-to-arenas) where a root proto is destroyed but
+    // InlinedStringField may have arena-allocated memory.
+    //
     // `_init_inline_xxx` is used for initializing default instances.
     format(
-        "::$proto_ns$::internal::InlinedStringField $name$_;\n"
+        "union { ::$proto_ns$::internal::InlinedStringField $name$_; };\n"
         "static std::true_type _init_inline_$name$_;\n");
   }
 }
@@ -204,7 +210,7 @@
       "  // @@protoc_insertion_point(field_get:$full_name$)\n");
   if (!descriptor_->default_value_string().empty()) {
     format(
-        "  if ($name$_.IsDefault(nullptr)) return "
+        "  if ($name$_.IsDefault()) return "
         "$default_variable_name$.get();\n");
   }
   format(
@@ -229,7 +235,7 @@
         " $set_hasbit$\n"
         " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0),"
         " args..., GetArenaForAllocation(), _internal_$name$_donated(), "
-        "&$donating_states_word$, $mask_for_undonate$);\n"
+        "&$donating_states_word$, $mask_for_undonate$, this);\n"
         "$annotate_set$"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
@@ -259,7 +265,7 @@
     format(
         "  $name$_.Set(nullptr, value, GetArenaForAllocation(),\n"
         "    _internal_$name$_donated(), &$donating_states_word$, "
-        "$mask_for_undonate$);\n"
+        "$mask_for_undonate$, this);\n"
         "}\n");
   }
   format(
@@ -274,7 +280,7 @@
     format(
         "  return $name$_.Mutable($default_variable_or_tag$, "
         "GetArenaForAllocation(), _internal_$name$_donated(), "
-        "&$donating_states_word$, $mask_for_undonate$);\n"
+        "&$donating_states_word$, $mask_for_undonate$, this);\n"
         "}\n");
   }
   format(
@@ -290,13 +296,13 @@
         "  $clear_hasbit$\n");
     if (!inlined_) {
       format(
-          "  auto* p = $name$_.ReleaseNonDefault($init_value$, "
+          "  auto* p = $name$_.ReleaseNonDefault($default_value$, "
           "GetArenaForAllocation());\n");
       if (descriptor_->default_value_string().empty()) {
         format(
             "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
-            "  if ($name$_.IsDefault($init_value$)) {\n"
-            "    $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n"
+            "  if ($name$_.IsDefault()) {\n"
+            "    $name$_.Set($default_value$, \"\", GetArenaForAllocation());\n"
             "  }\n"
             "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
       }
@@ -308,7 +314,7 @@
     }
   } else {
     format(
-        "  return $name$_.Release($init_value$, GetArenaForAllocation());\n");
+        "  return $name$_.Release($default_value$, GetArenaForAllocation());\n");
   }
 
   format(
@@ -321,13 +327,13 @@
       "  }\n");
   if (!inlined_) {
     format(
-        "  $name$_.SetAllocated($init_value$, $name$,\n"
+        "  $name$_.SetAllocated($default_value$, $name$,\n"
         "      GetArenaForAllocation());\n");
     if (descriptor_->default_value_string().empty()) {
       format(
           "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
-          "  if ($name$_.IsDefault($init_value$)) {\n"
-          "    $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n"
+          "  if ($name$_.IsDefault()) {\n"
+          "    $name$_.Set($default_value$, \"\", GetArenaForAllocation());\n"
           "  }\n"
           "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
     }
@@ -336,7 +342,7 @@
     format(
         "    $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
         "_internal_$name$_donated(), &$donating_states_word$, "
-        "$mask_for_undonate$);\n");
+        "$mask_for_undonate$, this);\n");
   }
   format(
       "$annotate_set$"
@@ -388,7 +394,7 @@
     //
     // For non-inlined strings, we distinguish from non-default by comparing
     // instances, rather than contents.
-    format("$DCHK$(!$name$_.IsDefault(nullptr));\n");
+    format("$DCHK$(!$name$_.IsDefault());\n");
   }
 
   if (descriptor_->default_value_string().empty()) {
@@ -416,34 +422,32 @@
   if (!inlined_) {
     format(
         "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
-        "    $init_value$,\n"
+        "    $default_value$,\n"
         "    &$name$_, lhs_arena,\n"
         "    &other->$name$_, rhs_arena\n"
         ");\n");
   } else {
-    // At this point, it's guaranteed that the two fields being swapped are on
-    // the same arena.
     format(
-        "$name$_.Swap(&other->$name$_, nullptr, GetArenaForAllocation(), "
-        "_internal_$name$_donated(), other->_internal_$name$_donated(), "
-        "&$donating_states_word$, &(other->$donating_states_word$), "
-        "$mask_for_undonate$);\n");
+        "::$proto_ns$::internal::InlinedStringField::InternalSwap(\n"
+        "  &$name$_, lhs_arena, "
+        "(_inlined_string_donated_[0] & 0x1u) == 0, this,\n"
+        "  &other->$name$_, rhs_arena, "
+        "(other->_inlined_string_donated_[0] & 0x1u) == 0, other);\n");
   }
 }
 
 void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
   if (inlined_ && descriptor_->default_value_string().empty()) {
-    // Automatic initialization will construct the string.
     return;
   }
   GOOGLE_DCHECK(!inlined_);
-  format("$name$_.UnsafeSetDefault($init_value$);\n");
+  format("$name$_.InitDefault($init_value$);\n");
   if (IsString(descriptor_, options_) &&
       descriptor_->default_value_string().empty()) {
     format(
         "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
-        "  $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n"
+        "  $name$_.Set($default_value$, \"\", GetArenaForAllocation());\n"
         "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
   }
 }
@@ -452,6 +456,9 @@
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   GenerateConstructorCode(printer);
+  if (inlined_) {
+    format("new (&$name$_) ::$proto_ns$::internal::InlinedStringField();\n");
+  }
 
   if (HasHasbit(descriptor_)) {
     format("if (from._internal_has_$name$()) {\n");
@@ -469,7 +476,7 @@
     format(
         "$name$_.Set(nullptr, from._internal_$name$(),\n"
         "  GetArenaForAllocation(), _internal_$name$_donated(), "
-        "&$donating_states_word$, $mask_for_undonate$);\n");
+        "&$donating_states_word$, $mask_for_undonate$, this);\n");
   }
 
   format.Outdent();
@@ -478,12 +485,30 @@
 
 void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
   Formatter format(printer, variables_);
-  if (inlined_) {
-    // The destructor is automatically invoked.
+  if (!inlined_) {
+    format("$name$_.DestroyNoArena($default_value$);\n");
     return;
   }
+  // Explicitly calls ~InlinedStringField as its automatic call is disabled.
+  // Destructor has been implicitly skipped as a union, and even the
+  // message-owned arena is enabled, arena could still be missing for
+  // Arena::CreateMessage(nullptr).
+  format("$name$_.~InlinedStringField();\n");
+}
 
-  format("$name$_.DestroyNoArena($init_value$);\n");
+ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const {
+  return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone;
+}
+
+void StringFieldGenerator::GenerateArenaDestructorCode(
+    io::Printer* printer) const {
+  if (!inlined_) return;
+  Formatter format(printer, variables_);
+  // _this is the object being destructed (we are inside a static method here).
+  format(
+      "if (!_this->_internal_$name$_donated()) {\n"
+      "  _this->$name$_.~InlinedStringField();\n"
+      "}\n");
 }
 
 void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
@@ -550,7 +575,7 @@
       "  if (!_internal_has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
-      "    $field_member$.UnsafeSetDefault($init_value$);\n"
+      "    $field_member$.InitDefault($init_value$);\n"
       "  }\n"
       "  $field_member$.$setter$($default_value_tag$,"
       " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n"
@@ -574,7 +599,7 @@
       "  if (!_internal_has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
-      "    $field_member$.UnsafeSetDefault($init_value$);\n"
+      "    $field_member$.InitDefault($init_value$);\n"
       "  }\n"
       "  $field_member$.Set($default_value_tag$, value, "
       "GetArenaForAllocation());\n"
@@ -584,7 +609,7 @@
       "  if (!_internal_has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
-      "    $field_member$.UnsafeSetDefault($init_value$);\n"
+      "    $field_member$.InitDefault($init_value$);\n"
       "  }\n"
       "  return $field_member$.Mutable(\n"
       "      $default_variable_or_tag$, GetArenaForAllocation());\n"
@@ -594,7 +619,7 @@
       "  // @@protoc_insertion_point(field_release:$full_name$)\n"
       "  if (_internal_has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
-      "    return $field_member$.ReleaseNonDefault($init_value$, "
+      "    return $field_member$.ReleaseNonDefault($default_value$, "
       "GetArenaForAllocation());\n"
       "  } else {\n"
       "    return nullptr;\n"
@@ -606,11 +631,7 @@
       "  }\n"
       "  if ($name$ != nullptr) {\n"
       "    set_has_$name$();\n"
-      "    $field_member$.UnsafeSetDefault($name$);\n"
-      "    ::$proto_ns$::Arena* arena = GetArenaForAllocation();\n"
-      "    if (arena != nullptr) {\n"
-      "      arena->Own($name$);\n"
-      "    }\n"
+      "    $field_member$.InitAllocated($name$, GetArenaForAllocation());\n"
       "  }\n"
       "$annotate_set$"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 3f05443..436643c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 
 namespace google {
@@ -48,7 +49,7 @@
  public:
   StringFieldGenerator(const FieldDescriptor* descriptor,
                        const Options& options);
-  ~StringFieldGenerator();
+  ~StringFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
@@ -64,11 +65,13 @@
   void GenerateConstructorCode(io::Printer* printer) const override;
   void GenerateCopyConstructorCode(io::Printer* printer) const override;
   void GenerateDestructorCode(io::Printer* printer) const override;
+  void GenerateArenaDestructorCode(io::Printer* printer) const override;
   void GenerateSerializeWithCachedSizesToArray(
       io::Printer* printer) const override;
   void GenerateByteSize(io::Printer* printer) const override;
   void GenerateConstinitInitializer(io::Printer* printer) const override;
   bool IsInlined() const override { return inlined_; }
+  ArenaDtorNeeds NeedsArenaDestructor() const override;
 
  private:
   bool inlined_;
@@ -79,7 +82,7 @@
  public:
   StringOneofFieldGenerator(const FieldDescriptor* descriptor,
                             const Options& options);
-  ~StringOneofFieldGenerator();
+  ~StringOneofFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@@ -99,7 +102,7 @@
  public:
   RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
                                const Options& options);
-  ~RepeatedStringFieldGenerator();
+  ~RepeatedStringFieldGenerator() override;
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
index 782d226..cfaa8df 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.inc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
@@ -95,7 +95,7 @@
 class MockErrorCollector : public MultiFileErrorCollector {
  public:
   MockErrorCollector() {}
-  ~MockErrorCollector() {}
+  ~MockErrorCollector() override {}
 
   std::string text_;
 
@@ -126,7 +126,7 @@
   const FileDescriptor* parsed_descriptor =
       importer.Import(TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH));
   EXPECT_EQ("", error_collector.text_);
-  ASSERT_TRUE(parsed_descriptor != NULL);
+  ASSERT_TRUE(parsed_descriptor != nullptr);
 
   // Test that descriptors are generated correctly by converting them to
   // FileDescriptorProtos and comparing.
@@ -147,7 +147,7 @@
   const Descriptor* generated_descriptor =
     ::protobuf_unittest::TestEnormousDescriptor::descriptor();
 
-  EXPECT_TRUE(generated_descriptor != NULL);
+  EXPECT_TRUE(generated_descriptor != nullptr);
 }
 #endif
 
@@ -249,11 +249,11 @@
 }
 
 TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseString) {
-  // Check that release_foo() starts out NULL, and gives us a value
+  // Check that release_foo() starts out nullptr, and gives us a value
   // that we can delete after it's been set.
   UNITTEST::TestAllTypes message;
 
-  EXPECT_EQ(NULL, message.release_default_string());
+  EXPECT_EQ(nullptr, message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
   EXPECT_EQ("hello", message.default_string());
 
@@ -261,30 +261,30 @@
   EXPECT_TRUE(message.has_default_string());
   std::unique_ptr<std::string> str(message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
-  ASSERT_TRUE(str != NULL);
+  ASSERT_TRUE(str != nullptr);
   EXPECT_EQ("blah", *str);
 
-  EXPECT_EQ(NULL, message.release_default_string());
+  EXPECT_EQ(nullptr, message.release_default_string());
   EXPECT_FALSE(message.has_default_string());
   EXPECT_EQ("hello", message.default_string());
 }
 
 TEST(GENERATED_MESSAGE_TEST_NAME, ReleaseMessage) {
-  // Check that release_foo() starts out NULL, and gives us a value
+  // Check that release_foo() starts out nullptr, and gives us a value
   // that we can delete after it's been set.
   UNITTEST::TestAllTypes message;
 
-  EXPECT_EQ(NULL, message.release_optional_nested_message());
+  EXPECT_EQ(nullptr, message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
 
   message.mutable_optional_nested_message()->set_bb(1);
   std::unique_ptr<UNITTEST::TestAllTypes::NestedMessage> nest(
       message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
-  ASSERT_TRUE(nest != NULL);
+  ASSERT_TRUE(nest != nullptr);
   EXPECT_EQ(1, nest->bb());
 
-  EXPECT_EQ(NULL, message.release_optional_nested_message());
+  EXPECT_EQ(nullptr, message.release_optional_nested_message());
   EXPECT_FALSE(message.has_optional_nested_message());
 }
 
@@ -297,7 +297,7 @@
   message.set_optional_string(kHello);
   EXPECT_TRUE(message.has_optional_string());
 
-  message.set_allocated_optional_string(NULL);
+  message.set_allocated_optional_string(nullptr);
   EXPECT_FALSE(message.has_optional_string());
   EXPECT_EQ("", message.optional_string());
 
@@ -315,7 +315,7 @@
   message.mutable_optional_nested_message()->set_bb(1);
   EXPECT_TRUE(message.has_optional_nested_message());
 
-  message.set_allocated_optional_nested_message(NULL);
+  message.set_allocated_optional_nested_message(nullptr);
   EXPECT_FALSE(message.has_optional_nested_message());
   EXPECT_EQ(&UNITTEST::TestAllTypes::NestedMessage::default_instance(),
             &message.optional_nested_message());
@@ -323,7 +323,7 @@
   message.mutable_optional_nested_message()->set_bb(1);
   UNITTEST::TestAllTypes::NestedMessage* nest =
       message.release_optional_nested_message();
-  ASSERT_TRUE(nest != NULL);
+  ASSERT_TRUE(nest != nullptr);
   EXPECT_FALSE(message.has_optional_nested_message());
 
   message.set_allocated_optional_nested_message(nest);
@@ -531,6 +531,7 @@
   // None set.
   {
     UNITTEST::TestAllTypes message1;
+    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
     UNITTEST::TestAllTypes message2(message1);
 
     EXPECT_FALSE(message1.has_optional_string());
@@ -879,77 +880,81 @@
 }
 
 TEST(GENERATED_MESSAGE_TEST_NAME, TestSpaceUsed) {
-  UNITTEST::TestAllTypes message1;
+  // Allocate explicitly on the heap to prevent arena creation.
+  std::unique_ptr<UNITTEST::TestAllTypes> message1(
+    Arena::CreateMessage<UNITTEST::TestAllTypes>(nullptr));
   // sizeof provides a lower bound on SpaceUsedLong().
-  EXPECT_LE(sizeof(UNITTEST::TestAllTypes), message1.SpaceUsedLong());
-  const size_t empty_message_size = message1.SpaceUsedLong();
+  EXPECT_LE(sizeof(UNITTEST::TestAllTypes), message1->SpaceUsedLong());
+  const size_t empty_message_size = message1->SpaceUsedLong();
 
   // Setting primitive types shouldn't affect the space used.
-  message1.set_optional_int32(123);
-  message1.set_optional_int64(12345);
-  message1.set_optional_uint32(123);
-  message1.set_optional_uint64(12345);
-  EXPECT_EQ(empty_message_size, message1.SpaceUsedLong());
+  message1->set_optional_int32(123);
+  message1->set_optional_int64(12345);
+  message1->set_optional_uint32(123);
+  message1->set_optional_uint64(12345);
+  EXPECT_EQ(empty_message_size, message1->SpaceUsedLong());
 
   // On some STL implementations, setting the string to a small value should
   // only increase SpaceUsedLong() by the size of a string object, though this
   // is not true everywhere.
-  message1.set_optional_string("abc");
-  EXPECT_LE(empty_message_size + message1.optional_string().size(),
-            message1.SpaceUsedLong());
+  message1->set_optional_string("abc");
+  EXPECT_LE(empty_message_size + message1->optional_string().size(),
+            message1->SpaceUsedLong());
 
   // Setting a string to a value larger than the string object itself should
   // increase SpaceUsedLong(), because it cannot store the value internally.
-  message1.set_optional_string(std::string(sizeof(std::string) + 1, 'x'));
-  int min_expected_increase = message1.optional_string().capacity();
+  message1->set_optional_string(std::string(sizeof(std::string) + 1, 'x'));
+  int min_expected_increase = message1->optional_string().capacity();
   EXPECT_LE(empty_message_size + min_expected_increase,
-            message1.SpaceUsedLong());
+            message1->SpaceUsedLong());
 
-  size_t previous_size = message1.SpaceUsedLong();
+  size_t previous_size = message1->SpaceUsedLong();
   // Adding an optional message should increase the size by the size of the
   // nested message type. NestedMessage is simple enough (1 int field) that it
   // is equal to sizeof(NestedMessage)
-  message1.mutable_optional_nested_message();
+  message1->mutable_optional_nested_message();
   ASSERT_EQ(sizeof(UNITTEST::TestAllTypes::NestedMessage),
-            message1.optional_nested_message().SpaceUsedLong());
+            message1->optional_nested_message().SpaceUsedLong());
   EXPECT_EQ(previous_size +
             sizeof(UNITTEST::TestAllTypes::NestedMessage),
-            message1.SpaceUsedLong());
+            message1->SpaceUsedLong());
 }
 
 TEST(GENERATED_MESSAGE_TEST_NAME, TestOneofSpaceUsed) {
-  UNITTEST::TestOneof2 message1;
-  EXPECT_LE(sizeof(UNITTEST::TestOneof2), message1.SpaceUsedLong());
+  // Allocate explicitly on the heap to prevent arena creation.
+  std::unique_ptr<UNITTEST::TestOneof2> message1(
+    Arena::CreateMessage<UNITTEST::TestOneof2>(nullptr));
+  EXPECT_LE(sizeof(UNITTEST::TestOneof2), message1->SpaceUsedLong());
 
-  const size_t empty_message_size = message1.SpaceUsedLong();
+  const size_t empty_message_size = message1->SpaceUsedLong();
   // Setting primitive types shouldn't affect the space used.
-  message1.set_foo_int(123);
-  message1.set_bar_int(12345);
-  EXPECT_EQ(empty_message_size, message1.SpaceUsedLong());
+  message1->set_foo_int(123);
+  message1->set_bar_int(12345);
+  EXPECT_EQ(empty_message_size, message1->SpaceUsedLong());
 
   // Setting a string in oneof to a small value should only increase
   // SpaceUsedLong() by the size of a string object.
-  message1.set_foo_string("abc");
-  EXPECT_LE(empty_message_size + sizeof(std::string), message1.SpaceUsedLong());
+  message1->set_foo_string("abc");
+  EXPECT_LE(empty_message_size + sizeof(std::string), message1->SpaceUsedLong());
 
   // Setting a string in oneof to a value larger than the string object itself
   // should increase SpaceUsedLong(), because it cannot store the value
   // internally.
-  message1.set_foo_string(std::string(sizeof(std::string) + 1, 'x'));
+  message1->set_foo_string(std::string(sizeof(std::string) + 1, 'x'));
   int min_expected_increase =
-      message1.foo_string().capacity() + sizeof(std::string);
+      message1->foo_string().capacity() + sizeof(std::string);
   EXPECT_LE(empty_message_size + min_expected_increase,
-            message1.SpaceUsedLong());
+            message1->SpaceUsedLong());
 
   // Setting a message in oneof should delete the other fields and increase the
   // size by the size of the nested message type. NestedMessage is simple enough
   // that it is equal to sizeof(NestedMessage). It may be backed by LazyField,
   // increasing space used by LazyField and backing Cord.
-  message1.mutable_foo_message();
+  message1->mutable_foo_message();
   ASSERT_EQ(sizeof(UNITTEST::TestOneof2::NestedMessage),
-            message1.foo_message().SpaceUsedLong());
+            message1->foo_message().SpaceUsedLong());
   EXPECT_LE(empty_message_size + sizeof(UNITTEST::TestOneof2::NestedMessage),
-            message1.SpaceUsedLong());
+            message1->SpaceUsedLong());
 }
 
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
@@ -1065,14 +1070,13 @@
   EXPECT_EQ(12589235, UNITTEST::TestSparseEnum_ARRAYSIZE);
 
   // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE.
-  void* null_pointer = 0;  // NULL may be integer-type, not pointer-type.
-  EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MIN);
-  EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_MAX);
-  EXPECT_NE(null_pointer, &UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE);
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_MIN);
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_MAX);
+  EXPECT_NE(nullptr, &UNITTEST::TestAllTypes::NestedEnum_ARRAYSIZE);
 
-  EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MIN);
-  EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_MAX);
-  EXPECT_NE(null_pointer, &UNITTEST::ForeignEnum_ARRAYSIZE);
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_MIN);
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_MAX);
+  EXPECT_NE(nullptr, &UNITTEST::ForeignEnum_ARRAYSIZE);
 
   // Make sure we can use _MIN and _MAX as switch cases.
   switch (UNITTEST::SPARSE_A) {
@@ -1146,14 +1150,14 @@
   class MockTestService : public UNITTEST::TestService {
    public:
     MockTestService()
-      : called_(false),
-        method_(""),
-        controller_(NULL),
-        request_(NULL),
-        response_(NULL),
-        done_(NULL) {}
+        : called_(false),
+          method_(""),
+          controller_(nullptr),
+          request_(nullptr),
+          response_(nullptr),
+          done_(nullptr) {}
 
-    ~MockTestService() {}
+    ~MockTestService() override {}
 
     void Reset() { called_ = false; }
 
@@ -1194,16 +1198,16 @@
   class MockRpcChannel : public RpcChannel {
    public:
     MockRpcChannel()
-      : called_(false),
-        method_(NULL),
-        controller_(NULL),
-        request_(NULL),
-        response_(NULL),
-        done_(NULL),
-        destroyed_(NULL) {}
+        : called_(false),
+          method_(nullptr),
+          controller_(nullptr),
+          request_(nullptr),
+          response_(nullptr),
+          done_(nullptr),
+          destroyed_(nullptr) {}
 
-    ~MockRpcChannel() {
-      if (destroyed_ != NULL) *destroyed_ = true;
+    ~MockRpcChannel() override {
+      if (destroyed_ != nullptr) *destroyed_ = true;
     }
 
     void Reset() { called_ = false; }
@@ -1269,8 +1273,8 @@
       done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {}
 
   void SetUp() override {
-    ASSERT_TRUE(foo_ != NULL);
-    ASSERT_TRUE(bar_ != NULL);
+    ASSERT_TRUE(foo_ != nullptr);
+    ASSERT_TRUE(bar_ != nullptr);
   }
 
   const ServiceDescriptor* descriptor_;
@@ -1585,21 +1589,21 @@
 }
 
 TEST_F(OneofTest, ReleaseString) {
-  // Check that release_foo() starts out NULL, and gives us a value
+  // Check that release_foo() starts out nullptr, and gives us a value
   // that we can delete after it's been set.
   UNITTEST::TestOneof2 message;
 
-  EXPECT_EQ(NULL, message.release_foo_string());
+  EXPECT_EQ(nullptr, message.release_foo_string());
   EXPECT_FALSE(message.has_foo_string());
 
   message.set_foo_string("blah");
   EXPECT_TRUE(message.has_foo_string());
   std::unique_ptr<std::string> str(message.release_foo_string());
   EXPECT_FALSE(message.has_foo_string());
-  ASSERT_TRUE(str != NULL);
+  ASSERT_TRUE(str != nullptr);
   EXPECT_EQ("blah", *str);
 
-  EXPECT_EQ(NULL, message.release_foo_string());
+  EXPECT_EQ(nullptr, message.release_foo_string());
   EXPECT_FALSE(message.has_foo_string());
 }
 
@@ -1612,7 +1616,7 @@
   message.set_foo_string(kHello);
   EXPECT_TRUE(message.has_foo_string());
 
-  message.set_allocated_foo_string(NULL);
+  message.set_allocated_foo_string(nullptr);
   EXPECT_FALSE(message.has_foo_string());
   EXPECT_EQ("", message.foo_string());
 
@@ -1632,7 +1636,7 @@
   message->set_foo_string(kHello);
   EXPECT_TRUE(message->has_foo_string());
 
-  message->set_allocated_foo_string(NULL);
+  message->set_allocated_foo_string(nullptr);
   EXPECT_FALSE(message->has_foo_string());
   EXPECT_EQ("", message->foo_string());
 
@@ -1659,11 +1663,11 @@
 }
 
 TEST_F(OneofTest, ReleaseMessage) {
-  // Check that release_foo() starts out NULL, and gives us a value
+  // Check that release_foo() starts out nullptr, and gives us a value
   // that we can delete after it's been set.
   UNITTEST::TestOneof2 message;
 
-  EXPECT_EQ(NULL, message.release_foo_message());
+  EXPECT_EQ(nullptr, message.release_foo_message());
   EXPECT_FALSE(message.has_foo_message());
 
   message.mutable_foo_message()->set_qux_int(1);
@@ -1671,10 +1675,10 @@
   std::unique_ptr<UNITTEST::TestOneof2_NestedMessage> mes(
       message.release_foo_message());
   EXPECT_FALSE(message.has_foo_message());
-  ASSERT_TRUE(mes != NULL);
+  ASSERT_TRUE(mes != nullptr);
   EXPECT_EQ(1, mes->qux_int());
 
-  EXPECT_EQ(NULL, message.release_foo_message());
+  EXPECT_EQ(nullptr, message.release_foo_message());
   EXPECT_FALSE(message.has_foo_message());
 }
 
@@ -1687,14 +1691,14 @@
   message.mutable_foo_message()->set_qux_int(1);
   EXPECT_TRUE(message.has_foo_message());
 
-  message.set_allocated_foo_message(NULL);
+  message.set_allocated_foo_message(nullptr);
   EXPECT_FALSE(message.has_foo_message());
   EXPECT_EQ(&message.foo_message(),
             &UNITTEST::TestOneof2_NestedMessage::default_instance());
 
   message.mutable_foo_message()->set_qux_int(1);
   UNITTEST::TestOneof2_NestedMessage* mes = message.release_foo_message();
-  ASSERT_TRUE(mes != NULL);
+  ASSERT_TRUE(mes != nullptr);
   EXPECT_FALSE(message.has_foo_message());
 
   message.set_allocated_foo_message(mes);
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index b5cac8f4..c48a971 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -76,12 +76,12 @@
 
     std::string output_base = TestTempDir() + "/" + StripProto(filename);
 
-    if (pb_cc != NULL) {
+    if (pb_cc != nullptr) {
       GOOGLE_CHECK_OK(
           File::GetContents(output_base + ".pb.cc", pb_cc, true));
     }
 
-    if (pb_h != NULL && pb_h_info != NULL) {
+    if (pb_h != nullptr && pb_h_info != nullptr) {
       GOOGLE_CHECK_OK(
           File::GetContents(output_base + ".pb.h", pb_h, true));
       if (!atu::DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
@@ -89,7 +89,7 @@
       }
     }
 
-    if (proto_h != NULL && proto_h_info != NULL) {
+    if (proto_h != nullptr && proto_h_info != nullptr) {
       GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
                                  true));
       if (!atu::DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
@@ -112,15 +112,15 @@
   GeneratedCodeInfo info;
   std::string pb_h;
   atu::AddFile("test.proto", kSmallTestFile);
-  EXPECT_TRUE(
-      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
   EXPECT_EQ("Enum", file.enum_type(0).name());
   std::vector<int> enum_path;
   enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
   enum_path.push_back(0);
   const GeneratedCodeInfo::Annotation* enum_annotation =
       atu::FindAnnotationOnPath(info, "test.proto", enum_path);
-  EXPECT_TRUE(NULL != enum_annotation);
+  EXPECT_TRUE(nullptr != enum_annotation);
   EXPECT_TRUE(atu::AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
 }
 
@@ -129,8 +129,8 @@
   GeneratedCodeInfo info;
   std::string pb_h;
   atu::AddFile("test.proto", kSmallTestFile);
-  EXPECT_TRUE(
-      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
   EXPECT_TRUE(pb_h.find("#ifdef guard_name") != std::string::npos);
   EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
               std::string::npos);
@@ -141,15 +141,15 @@
   GeneratedCodeInfo info;
   std::string pb_h;
   atu::AddFile("test.proto", kSmallTestFile);
-  EXPECT_TRUE(
-      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+                              nullptr, nullptr));
   EXPECT_EQ("Message", file.message_type(0).name());
   std::vector<int> message_path;
   message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
   message_path.push_back(0);
   const GeneratedCodeInfo::Annotation* message_annotation =
       atu::FindAnnotationOnPath(info, "test.proto", message_path);
-  EXPECT_TRUE(NULL != message_annotation);
+  EXPECT_TRUE(nullptr != message_annotation);
   EXPECT_TRUE(
       atu::AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
 }
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 3bcb0c9..137baae 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -93,13 +93,13 @@
       : filename_(filename),
         multi_file_error_collector_(multi_file_error_collector),
         had_errors_(false) {}
-  ~SingleFileErrorCollector() {}
+  ~SingleFileErrorCollector() override {}
 
   bool had_errors() { return had_errors_; }
 
   // implements ErrorCollector ---------------------------------------
   void AddError(int line, int column, const std::string& message) override {
-    if (multi_file_error_collector_ != NULL) {
+    if (multi_file_error_collector_ != nullptr) {
       multi_file_error_collector_->AddError(filename_, line, column, message);
     }
     had_errors_ = true;
@@ -134,12 +134,12 @@
 bool SourceTreeDescriptorDatabase::FindFileByName(const std::string& filename,
                                                   FileDescriptorProto* output) {
   std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
-  if (input == NULL) {
+  if (input == nullptr) {
     if (fallback_database_ != nullptr &&
         fallback_database_->FindFileByName(filename, output)) {
       return true;
     }
-    if (error_collector_ != NULL) {
+    if (error_collector_ != nullptr) {
       error_collector_->AddError(filename, -1, 0,
                                  source_tree_->GetLastErrorMessage());
     }
@@ -151,7 +151,7 @@
   io::Tokenizer tokenizer(input.get(), &file_error_collector);
 
   Parser parser;
-  if (error_collector_ != NULL) {
+  if (error_collector_ != nullptr) {
     parser.RecordErrorsTo(&file_error_collector);
   }
   if (using_validation_error_collector_) {
@@ -187,7 +187,7 @@
     const std::string& filename, const std::string& element_name,
     const Message* descriptor, ErrorLocation location,
     const std::string& message) {
-  if (owner_->error_collector_ == NULL) return;
+  if (owner_->error_collector_ == nullptr) return;
 
   int line, column;
   if (location == DescriptorPool::ErrorCollector::IMPORT) {
@@ -203,7 +203,7 @@
     const std::string& filename, const std::string& element_name,
     const Message* descriptor, ErrorLocation location,
     const std::string& message) {
-  if (owner_->error_collector_ == NULL) return;
+  if (owner_->error_collector_ == nullptr) return;
 
   int line, column;
   if (location == DescriptorPool::ErrorCollector::IMPORT) {
@@ -429,7 +429,7 @@
   // of verifying that we are not canonicalizing away any non-existent
   // directories.
   std::unique_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
-  if (stream == NULL) {
+  if (stream == nullptr) {
     return CANNOT_OPEN;
   }
 
@@ -440,11 +440,11 @@
                                            std::string* disk_file) {
   std::unique_ptr<io::ZeroCopyInputStream> stream(
       OpenVirtualFile(virtual_file, disk_file));
-  return stream != NULL;
+  return stream != nullptr;
 }
 
 io::ZeroCopyInputStream* DiskSourceTree::Open(const std::string& filename) {
-  return OpenVirtualFile(filename, NULL);
+  return OpenVirtualFile(filename, nullptr);
 }
 
 std::string DiskSourceTree::GetLastErrorMessage() {
@@ -461,7 +461,7 @@
     last_error_message_ =
         "Backslashes, consecutive slashes, \".\", or \"..\" "
         "are not allowed in the virtual path";
-    return NULL;
+    return nullptr;
   }
 
   for (const auto& mapping : mappings_) {
@@ -469,8 +469,8 @@
     if (ApplyMapping(virtual_file, mapping.virtual_path, mapping.disk_path,
                      &temp_disk_file)) {
       io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
-      if (stream != NULL) {
-        if (disk_file != NULL) {
+      if (stream != nullptr) {
+        if (disk_file != nullptr) {
           *disk_file = temp_disk_file;
         }
         return stream;
@@ -480,12 +480,12 @@
         // The file exists but is not readable.
         last_error_message_ =
             "Read access is denied for file: " + temp_disk_file;
-        return NULL;
+        return nullptr;
       }
     }
   }
   last_error_message_ = "File not found.";
-  return NULL;
+  return nullptr;
 }
 
 io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
@@ -503,7 +503,7 @@
 #else
   if (ret == 0 && S_ISDIR(sb.st_mode)) {
     last_error_message_ = "Input file is a directory.";
-    return NULL;
+    return nullptr;
   }
 #endif
   int file_descriptor;
@@ -515,7 +515,7 @@
     result->SetCloseOnDelete(true);
     return result;
   } else {
-    return NULL;
+    return nullptr;
   }
 }
 
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index 08a49c5..2ed3b3a 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -45,6 +45,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor_database.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -85,7 +86,7 @@
   // the specified source_tree.
   SourceTreeDescriptorDatabase(SourceTree* source_tree,
                                DescriptorDatabase* fallback_database);
-  ~SourceTreeDescriptorDatabase();
+  ~SourceTreeDescriptorDatabase() override;
 
   // Instructs the SourceTreeDescriptorDatabase to report any parse errors
   // to the given MultiFileErrorCollector.  This should be called before
@@ -124,7 +125,7 @@
       : public DescriptorPool::ErrorCollector {
    public:
     ValidationErrorCollector(SourceTreeDescriptorDatabase* owner);
-    ~ValidationErrorCollector();
+    ~ValidationErrorCollector() override;
 
     // implements ErrorCollector ---------------------------------------
     void AddError(const std::string& filename, const std::string& element_name,
@@ -241,7 +242,7 @@
 class PROTOBUF_EXPORT DiskSourceTree : public SourceTree {
  public:
   DiskSourceTree();
-  ~DiskSourceTree();
+  ~DiskSourceTree() override;
 
   // Map a path on disk to a location in the SourceTree.  The path may be
   // either a file or a directory.  If it is a directory, the entire tree
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index daa197f..d2810ad 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -66,20 +66,20 @@
 class MockErrorCollector : public MultiFileErrorCollector {
  public:
   MockErrorCollector() {}
-  ~MockErrorCollector() {}
+  ~MockErrorCollector() override {}
 
   std::string text_;
   std::string warning_text_;
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const std::string& filename, int line, int column,
-                const std::string& message) {
+                const std::string& message) override {
     strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
                               message);
   }
 
   void AddWarning(const std::string& filename, int line, int column,
-                  const std::string& message) {
+                  const std::string& message) override {
     strings::SubstituteAndAppend(&warning_text_, "$0:$1:$2: $3\n", filename, line,
                               column, message);
   }
@@ -91,23 +91,23 @@
 class MockSourceTree : public SourceTree {
  public:
   MockSourceTree() {}
-  ~MockSourceTree() {}
+  ~MockSourceTree() override {}
 
   void AddFile(const std::string& name, const char* contents) {
     files_[name] = contents;
   }
 
   // implements SourceTree -------------------------------------------
-  io::ZeroCopyInputStream* Open(const std::string& filename) {
+  io::ZeroCopyInputStream* Open(const std::string& filename) override {
     const char* contents = FindPtrOrNull(files_, filename);
-    if (contents == NULL) {
-      return NULL;
+    if (contents == nullptr) {
+      return nullptr;
     } else {
       return new io::ArrayInputStream(contents, strlen(contents));
     }
   }
 
-  std::string GetLastErrorMessage() { return "File not found."; }
+  std::string GetLastErrorMessage() override { return "File not found."; }
 
  private:
   std::unordered_map<std::string, const char*> files_;
@@ -139,7 +139,7 @@
 
   const FileDescriptor* file = importer_.Import("foo.proto");
   EXPECT_EQ("", error_collector_.text_);
-  ASSERT_TRUE(file != NULL);
+  ASSERT_TRUE(file != nullptr);
 
   ASSERT_EQ(1, file->message_type_count());
   EXPECT_EQ("Foo", file->message_type(0)->name());
@@ -168,8 +168,8 @@
   const FileDescriptor* foo = importer_.Import("foo.proto");
   const FileDescriptor* bar = importer_.Import("bar.proto");
   EXPECT_EQ("", error_collector_.text_);
-  ASSERT_TRUE(foo != NULL);
-  ASSERT_TRUE(bar != NULL);
+  ASSERT_TRUE(foo != nullptr);
+  ASSERT_TRUE(bar != nullptr);
 
   // Check that foo's dependency is the same object as bar.
   ASSERT_EQ(1, foo->dependency_count());
@@ -187,7 +187,7 @@
 
 TEST_F(ImporterTest, FileNotFound) {
   // Error:  Parsing a file that doesn't exist.
-  EXPECT_TRUE(importer_.Import("foo.proto") == NULL);
+  EXPECT_TRUE(importer_.Import("foo.proto") == nullptr);
   EXPECT_EQ("foo.proto:-1:0: File not found.\n", error_collector_.text_);
 }
 
@@ -197,7 +197,7 @@
           "syntax = \"proto2\";\n"
           "import \"bar.proto\";\n");
 
-  EXPECT_TRUE(importer_.Import("foo.proto") == NULL);
+  EXPECT_TRUE(importer_.Import("foo.proto") == nullptr);
   EXPECT_EQ(
       "bar.proto:-1:0: File not found.\n"
       "foo.proto:1:0: Import \"bar.proto\" was not found or had errors.\n",
@@ -214,7 +214,7 @@
           "syntax = \"proto2\";\n"
           "import \"recursive1.proto\";\n");
 
-  EXPECT_TRUE(importer_.Import("recursive1.proto") == NULL);
+  EXPECT_TRUE(importer_.Import("recursive1.proto") == nullptr);
   EXPECT_EQ(
       "recursive1.proto:2:0: File recursively imports itself: "
       "recursive1.proto "
@@ -262,7 +262,7 @@
 
 class DiskSourceTreeTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_1");
     dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2");
 
@@ -274,7 +274,7 @@
     }
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     for (int i = 0; i < dirnames_.size(); i++) {
       if (FileExists(dirnames_[i])) {
         File::DeleteRecursively(dirnames_[i], NULL, NULL);
@@ -294,7 +294,7 @@
                           const char* expected_contents) {
     std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
 
-    ASSERT_FALSE(input == NULL);
+    ASSERT_FALSE(input == nullptr);
 
     // Read all the data from the file.
     std::string file_contents;
@@ -310,7 +310,7 @@
   void ExpectCannotOpenFile(const std::string& filename,
                             const std::string& error_message) {
     std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename));
-    EXPECT_TRUE(input == NULL);
+    EXPECT_TRUE(input == nullptr);
     EXPECT_EQ(error_message, source_tree_.GetLastErrorMessage());
   }
 
@@ -537,8 +537,8 @@
   EXPECT_EQ("not touched", not_touched);
 
   // Accept NULL as output parameter.
-  EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL));
-  EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL));
+  EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", nullptr));
+  EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", nullptr));
 }
 
 }  // namespace
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index fea870f..19cb631 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -30,11 +30,11 @@
 
 #include <google/protobuf/compiler/java/java_context.h>
 
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_field.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc
index 80b7902..d0e0184 100644
--- a/src/google/protobuf/compiler/java/java_doc_comment.cc
+++ b/src/google/protobuf/compiler/java/java_doc_comment.cc
@@ -36,9 +36,9 @@
 
 #include <vector>
 
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
@@ -199,7 +199,16 @@
     return;
   }
 
-  printer->Print(" * @deprecated\n");
+  std::string startLine = "0";
+  SourceLocation location;
+  if (field->GetSourceLocation(&location)) {
+    startLine = std::to_string(location.start_line);
+  }
+
+  printer->Print(" * @deprecated $name$ is deprecated.\n", "name",
+                 field->full_name());
+  printer->Print(" *     See $file$;l=$line$\n", "file", field->file()->name(),
+                 "line", startLine);
 }
 
 void WriteFieldAccessorDocComment(io::Printer* printer,
diff --git a/src/google/protobuf/compiler/java/java_doc_comment.h b/src/google/protobuf/compiler/java/java_doc_comment.h
index b7de877..7f68778 100644
--- a/src/google/protobuf/compiler/java/java_doc_comment.h
+++ b/src/google/protobuf/compiler/java/java_doc_comment.h
@@ -37,6 +37,7 @@
 
 #include <google/protobuf/descriptor.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 51032c2..0d9a71b 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -32,17 +32,18 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/compiler/java/java_enum.h>
+
 #include <map>
 #include <string>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
-#include <google/protobuf/compiler/java/java_enum.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 0dad42a..0e6fb44 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -40,13 +40,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 82dbd9e..abdc188 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
@@ -99,7 +100,7 @@
   ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor,
                                    int messageBitIndex, int builderBitIndex,
                                    Context* context);
-  ~ImmutableEnumOneofFieldGenerator();
+  ~ImmutableEnumOneofFieldGenerator() override;
 
   void GenerateMembers(io::Printer* printer) const override;
   void GenerateBuilderMembers(io::Printer* printer) const override;
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 ca3a2e8..27b62ac 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -40,13 +40,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index aa64c97..5d7955c 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -32,17 +32,18 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/compiler/java/java_enum_lite.h>
+
 #include <map>
 #include <string>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
-#include <google/protobuf/compiler/java/java_enum_lite.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index db210fb..6ebca41 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -34,12 +34,12 @@
 
 #include <google/protobuf/compiler/java/java_extension.h>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
index f928a78..318cfa4 100644
--- a/src/google/protobuf/compiler/java/java_extension.h
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -92,7 +92,7 @@
  public:
   explicit ImmutableExtensionGenerator(const FieldDescriptor* descriptor,
                                        Context* context);
-  virtual ~ImmutableExtensionGenerator();
+  ~ImmutableExtensionGenerator() override;
 
   void Generate(io::Printer* printer) override;
   int GenerateNonNestedInitializationCode(io::Printer* printer) override;
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc
index 71bf4e2..d84ee27 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.cc
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
@@ -30,12 +30,12 @@
 
 #include <google/protobuf/compiler/java/java_extension_lite.h>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h
index 7696156..54dc437 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.h
+++ b/src/google/protobuf/compiler/java/java_extension_lite.h
@@ -49,7 +49,7 @@
  public:
   explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor,
                                            Context* context);
-  virtual ~ImmutableExtensionLiteGenerator();
+  ~ImmutableExtensionLiteGenerator() override;
 
   void Generate(io::Printer* printer) override;
 
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index 8916d13..cd08d60 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -38,6 +38,9 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
 #include <google/protobuf/compiler/java/java_enum_field_lite.h>
@@ -50,9 +53,6 @@
 #include <google/protobuf/compiler/java/java_primitive_field_lite.h>
 #include <google/protobuf/compiler/java/java_string_field.h>
 #include <google/protobuf/compiler/java/java_string_field_lite.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 9dbf818..7dbf64d 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -37,6 +37,11 @@
 #include <memory>
 #include <set>
 
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/stubs/strutil.h>
 #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>
@@ -47,12 +52,7 @@
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/compiler/java/java_service.h>
 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
-#include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 71ee3e8..79ee630 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -38,6 +38,7 @@
 #include <memory>
 #include <string>
 #include <vector>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_options.h>
 
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index 29ae2cf..2ee0874 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -37,6 +37,8 @@
 
 #include <memory>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/compiler/java/java_file.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
@@ -44,8 +46,6 @@
 #include <google/protobuf/compiler/java/java_options.h>
 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
 #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>
 
diff --git a/src/google/protobuf/compiler/java/java_generator.h b/src/google/protobuf/compiler/java/java_generator.h
index 6315e7c..bbc7170 100644
--- a/src/google/protobuf/compiler/java/java_generator.h
+++ b/src/google/protobuf/compiler/java/java_generator.h
@@ -40,6 +40,7 @@
 #include <string>
 #include <google/protobuf/compiler/code_generator.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -54,7 +55,7 @@
 class PROTOC_EXPORT JavaGenerator : public CodeGenerator {
  public:
   JavaGenerator();
-  ~JavaGenerator();
+  ~JavaGenerator() override;
 
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file, const std::string& parameter,
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.h b/src/google/protobuf/compiler/java/java_generator_factory.h
index 831d9dd..807bca3 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.h
+++ b/src/google/protobuf/compiler/java/java_generator_factory.h
@@ -78,7 +78,7 @@
 class ImmutableGeneratorFactory : public GeneratorFactory {
  public:
   ImmutableGeneratorFactory(Context* context);
-  virtual ~ImmutableGeneratorFactory();
+  ~ImmutableGeneratorFactory() override;
 
   MessageGenerator* NewMessageGenerator(
       const Descriptor* descriptor) const override;
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 681d597..8653605 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -41,12 +41,12 @@
 #include <vector>
 
 #include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/compiler/java/java_names.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_names.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/hash.h>  // for hash<T *>
 
 namespace google {
@@ -1060,8 +1060,7 @@
 
   if (field->is_map()) {
     if (!SupportUnknownEnumValue(field)) {
-      const FieldDescriptor* value =
-          field->message_type()->map_value();
+      const FieldDescriptor* value = field->message_type()->map_value();
       if (GetJavaType(value) == JAVATYPE_ENUM) {
         extra_bits |= kMapWithProto2EnumValue;
       }
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 28cac6a..dd947bc 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -38,10 +38,10 @@
 #include <cstdint>
 #include <string>
 
-#include <google/protobuf/compiler/java/java_context.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
@@ -151,6 +151,21 @@
 // fields.
 std::string GetOneofStoredType(const FieldDescriptor* field);
 
+// We use either the proto1 enums if the enum is generated, otherwise fall back
+// to use integers.
+enum class Proto1EnumRepresentation {
+  kEnum,
+  kInteger,
+};
+
+// Returns which representation we should use.
+inline Proto1EnumRepresentation GetProto1EnumRepresentation(
+    const EnumDescriptor* descriptor) {
+  if (descriptor->containing_type() != nullptr) {
+    return Proto1EnumRepresentation::kEnum;
+  }
+  return Proto1EnumRepresentation::kInteger;
+}
 
 // Whether we should generate multiple java files for messages.
 inline bool MultipleJavaFiles(const FileDescriptor* descriptor,
diff --git a/src/google/protobuf/compiler/java/java_kotlin_generator.cc b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
index 8d262a0..aa54bb2 100644
--- a/src/google/protobuf/compiler/java/java_kotlin_generator.cc
+++ b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
@@ -30,11 +30,11 @@
 
 #include <google/protobuf/compiler/java/java_kotlin_generator.h>
 
+#include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/java/java_file.h>
+#include <google/protobuf/compiler/java/java_generator.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_options.h>
-#include <google/protobuf/compiler/java/java_generator.h>
-#include <google/protobuf/compiler/code_generator.h>
 
 namespace google {
 namespace protobuf {
@@ -63,11 +63,13 @@
     if (option.first == "output_list_file") {
       file_options.output_list_file = option.second;
     } else if (option.first == "immutable") {
+      // Note: the option is considered always set regardless of the input.
       file_options.generate_immutable_code = true;
     } else if (option.first == "mutable") {
       *error = "Mutable not supported by Kotlin generator";
       return false;
     } else if (option.first == "shared") {
+      // Note: the option is considered always set regardless of the input.
       file_options.generate_shared_code = true;
     } else if (option.first == "lite") {
       file_options.enforce_lite = true;
@@ -81,23 +83,17 @@
     }
   }
 
-  // By default we generate immutable code and shared code for immutable API.
-  if (!file_options.generate_immutable_code &&
-      !file_options.generate_shared_code) {
-    file_options.generate_immutable_code = true;
-    file_options.generate_shared_code = true;
-  }
+  // We only support generation of immutable code so we do it.
+  file_options.generate_immutable_code = true;
+  file_options.generate_shared_code = true;
 
   std::vector<std::string> all_files;
   std::vector<std::string> all_annotations;
 
-  std::unique_ptr<FileGenerator> file_generator;
-  if (file_options.generate_immutable_code) {
-    file_generator.reset(
+  std::unique_ptr<FileGenerator> file_generator(
         new FileGenerator(file, file_options, /* immutable_api = */ true));
-  }
 
-  if (!file_generator->Validate(error)) {
+  if (!file_generator || !file_generator->Validate(error)) {
     return false;
   }
 
diff --git a/src/google/protobuf/compiler/java/java_kotlin_generator.h b/src/google/protobuf/compiler/java/java_kotlin_generator.h
index 66e32b9..ccd9688 100644
--- a/src/google/protobuf/compiler/java/java_kotlin_generator.h
+++ b/src/google/protobuf/compiler/java/java_kotlin_generator.h
@@ -36,6 +36,8 @@
 #include <string>
 
 #include <google/protobuf/compiler/code_generator.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 74d43bb..606d26e 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -30,11 +30,11 @@
 
 #include <google/protobuf/compiler/java/java_map_field.h>
 
+#include <google/protobuf/io/printer.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
 
 namespace google {
 namespace protobuf {
@@ -99,6 +99,8 @@
   const JavaType keyJavaType = GetJavaType(key);
   const JavaType valueJavaType = GetJavaType(value);
 
+  std::string pass_through_nullness = "/* nullable */\n";
+
   (*variables)["key_type"] = TypeName(key, name_resolver, false);
   std::string boxed_key_type = TypeName(key, name_resolver, true);
   (*variables)["boxed_key_type"] = boxed_key_type;
@@ -129,6 +131,9 @@
 
     (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
 
+    (*variables)["value_enum_type_pass_through_nullness"] =
+        pass_through_nullness + (*variables)["value_enum_type"];
+
     if (SupportUnknownEnumValue(descriptor->file())) {
       // Map unknown values to a special UNRECOGNIZED value if supported.
       (*variables)["unrecognized_value"] =
@@ -140,6 +145,11 @@
     }
   } else {
     (*variables)["value_type"] = TypeName(value, name_resolver, false);
+
+    (*variables)["value_type_pass_through_nullness"] =
+        (IsReferenceType(valueJavaType) ? pass_through_nullness : "") +
+        (*variables)["value_type"];
+
     (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
     (*variables)["value_wire_type"] = WireType(value);
     (*variables)["value_default_value"] =
@@ -218,11 +228,12 @@
         "${$get$capitalized_name$Map$}$();\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
-        "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n"
-        "    $key_type$ key,\n"
-        "    $value_enum_type$ defaultValue);\n");
+    printer->Print(variables_,
+                   "$deprecation$$value_enum_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_enum_type_pass_through_nullness$ "
+                   "        defaultValue);\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
@@ -276,9 +287,10 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
                    "$deprecation$\n"
-                   "$value_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+                   "$value_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
                    "    $key_type$ key,\n"
-                   "    $value_type$ defaultValue);\n");
+                   "    $value_type_pass_through_nullness$ defaultValue);\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -538,9 +550,10 @@
         variables_,
         "@java.lang.Override\n"
         "$deprecation$\n"
-        "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "public $value_enum_type_pass_through_nullness$ "
+        "${$get$capitalized_name$OrDefault$}$(\n"
         "    $key_type$ key,\n"
-        "    $value_enum_type$ defaultValue) {\n"
+        "    $value_enum_type_pass_through_nullness$ defaultValue) {\n"
         "  $key_null_check$\n"
         "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
         "      internalGet$capitalized_name$().getMap();\n"
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 dac3ae9..f624522 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -32,11 +32,11 @@
 
 #include <cstdint>
 
+#include <google/protobuf/io/printer.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
 
 namespace google {
 namespace protobuf {
@@ -101,6 +101,8 @@
   const JavaType keyJavaType = GetJavaType(key);
   const JavaType valueJavaType = GetJavaType(value);
 
+  std::string pass_through_nullness = "/* nullable */\n";
+
   (*variables)["key_type"] = TypeName(key, name_resolver, false);
   (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
   (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
@@ -128,6 +130,9 @@
 
     (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
 
+    (*variables)["value_enum_type_pass_through_nullness"] =
+        pass_through_nullness + (*variables)["value_enum_type"];
+
     if (SupportUnknownEnumValue(descriptor->file())) {
       // Map unknown values to a special UNRECOGNIZED value if supported.
       (*variables)["unrecognized_value"] =
@@ -139,6 +144,11 @@
     }
   } else {
     (*variables)["value_type"] = TypeName(value, name_resolver, false);
+
+    (*variables)["value_type_pass_through_nullness"] =
+        (IsReferenceType(valueJavaType) ? pass_through_nullness : "") +
+        (*variables)["value_type"];
+
     (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
     (*variables)["value_wire_type"] = WireType(value);
     (*variables)["value_default_value"] =
@@ -203,11 +213,12 @@
         "${$get$capitalized_name$Map$}$();\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
-        "$deprecation$$value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n"
-        "    $key_type$ key,\n"
-        "    $value_enum_type$ defaultValue);\n");
+    printer->Print(variables_,
+                   "$deprecation$$value_enum_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
+                   "    $key_type$ key,\n"
+                   "    $value_enum_type_pass_through_nullness$ "
+                   "        defaultValue);\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
@@ -261,9 +272,10 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
                    "$deprecation$\n"
-                   "$value_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+                   "$value_type_pass_through_nullness$ "
+                   "${$get$capitalized_name$OrDefault$}$(\n"
                    "    $key_type$ key,\n"
-                   "    $value_type$ defaultValue);\n");
+                   "    $value_type_pass_through_nullness$ defaultValue);\n");
     printer->Annotate("{", "}", descriptor_);
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -606,9 +618,10 @@
         variables_,
         "@java.lang.Override\n"
         "$deprecation$\n"
-        "public $value_enum_type$ ${$get$capitalized_name$OrDefault$}$(\n"
+        "public $value_enum_type_pass_through_nullness$ "
+        "${$get$capitalized_name$OrDefault$}$(\n"
         "    $key_type$ key,\n"
-        "    $value_enum_type$ defaultValue) {\n"
+        "    $value_enum_type_pass_through_nullness$ defaultValue) {\n"
         "  $key_null_check$\n"
         "  java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
         "      instance.get$capitalized_name$Map();\n"
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 8fdd115..7fbad3f 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -40,6 +40,11 @@
 #include <memory>
 #include <vector>
 
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_enum.h>
@@ -50,11 +55,6 @@
 #include <google/protobuf/compiler/java/java_message_builder_lite.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
@@ -1273,6 +1273,9 @@
   printer->Print(
       "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
       "  throw e.setUnfinishedMessage(this);\n"
+      "} catch (com.google.protobuf.UninitializedMessageException e) {\n"
+      "  throw "
+      "e.asInvalidProtocolBufferException().setUnfinishedMessage(this);\n"
       "} catch (java.io.IOException e) {\n"
       "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
       "      e).setUnfinishedMessage(this);\n"
@@ -1455,7 +1458,7 @@
 void ImmutableMessageGenerator::GenerateKotlinMembers(
     io::Printer* printer) const {
   printer->Print(
-      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n"
       "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
       "kotlin.Unit): "
       "$message$ "
@@ -1486,7 +1489,7 @@
       "kotlin.Unit): "
       "$message$ =\n"
       "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
-      "}._build()\n",
+      "}._build()\n\n",
       "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
       name_resolver_->GetKotlinExtensionsClassName(descriptor_));
 
@@ -1495,6 +1498,25 @@
     ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
         .GenerateTopLevelKotlinMembers(printer);
   }
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->has_optional_keyword() &&
+        GetJavaType(field) == JAVATYPE_MESSAGE) {
+      printer->Print(
+          "val $full_classname$OrBuilder.$camelcase_name$OrNull: $full_name$?\n"
+          "  get() = if (has$name$()) get$name$() else null\n\n",
+          "full_classname", name_resolver_->GetClassName(descriptor_, true),
+          "camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
+          "full_name",
+          name_resolver_->GetImmutableClassName(field->message_type()), "name",
+          context_->GetFieldGeneratorInfo(field)->capitalized_name);
+    }
+  }
 }
 
 void ImmutableMessageGenerator::GenerateKotlinExtensions(
@@ -1632,7 +1654,8 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public operator fun <E> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.set(index: Int, value: "
       "E) {\n"
       "  _builder.setExtension(this.extension, index, value)\n"
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index cafc91e..cc24d73 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
@@ -100,7 +101,7 @@
 class ImmutableMessageGenerator : public MessageGenerator {
  public:
   ImmutableMessageGenerator(const Descriptor* descriptor, Context* context);
-  virtual ~ImmutableMessageGenerator();
+  ~ImmutableMessageGenerator() override;
 
   void Generate(io::Printer* printer) override;
   void GenerateInterface(io::Printer* printer) override;
@@ -136,6 +137,7 @@
   void GenerateParsingConstructor(io::Printer* printer);
   void GenerateMutableCopy(io::Printer* printer);
   void GenerateKotlinExtensions(io::Printer* printer) const;
+  void GenerateKotlinOrNull(io::Printer* printer) const;
   void GenerateAnyMethods(io::Printer* printer);
 
   Context* context_;
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index b44015c..4d46669 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -39,6 +39,11 @@
 #include <memory>
 #include <vector>
 
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_enum.h>
@@ -47,11 +52,6 @@
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h
index fcd73b3..619bf9e 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.h
+++ b/src/google/protobuf/compiler/java/java_message_builder.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
index 7b69a9a..b8136e3 100644
--- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -39,6 +39,11 @@
 #include <memory>
 #include <vector>
 
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_enum.h>
@@ -47,11 +52,6 @@
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.h b/src/google/protobuf/compiler/java/java_message_builder_lite.h
index 3402adf..03ecbf8 100644
--- a/src/google/protobuf/compiler/java/java_message_builder_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 8aae961..1705c32 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -32,17 +32,18 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/compiler/java/java_message_field.h>
+
 #include <map>
 #include <string>
 
-#include <google/protobuf/compiler/java/java_context.h>
-#include <google/protobuf/compiler/java/java_doc_comment.h>
-#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/compiler/java/java_message_field.h>
-#include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
 
 namespace google {
 namespace protobuf {
@@ -438,6 +439,16 @@
       "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
       "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
       "}\n");
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageFieldGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  if (descriptor_->has_optional_keyword()) {
+    printer->Print(variables_,
+                   "public val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n"
+                   "  get() = $kt_dsl_builder$.$name$OrNull\n");
+  }
 }
 
 void ImmutableMessageFieldGenerator::GenerateFieldBuilderInitializationCode(
@@ -698,8 +709,9 @@
 
       "if ($has_oneof_case_message$) {\n"
       "  $name$Builder_.mergeFrom(value);\n"
-      "}\n"
-      "$name$Builder_.setMessage(value);\n",
+      "} else {\n"
+      "  $name$Builder_.setMessage(value);\n"
+      "}\n",
 
       "$set_oneof_case_message$;\n"
       "return this;\n");
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 8588100..be1fb20 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
@@ -61,7 +62,7 @@
                                           int messageBitIndex,
                                           int builderBitIndex,
                                           Context* context);
-  ~ImmutableMessageFieldGenerator();
+  ~ImmutableMessageFieldGenerator() override;
 
   // implements ImmutableFieldGenerator
   // ---------------------------------------
@@ -102,6 +103,7 @@
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldGenerator);
+  void GenerateKotlinOrNull(io::Printer* printer) const;
 };
 
 class ImmutableMessageOneofFieldGenerator
@@ -110,7 +112,7 @@
   ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
                                       int messageBitIndex, int builderBitIndex,
                                       Context* context);
-  ~ImmutableMessageOneofFieldGenerator();
+  ~ImmutableMessageOneofFieldGenerator() override;
 
   void GenerateMembers(io::Printer* printer) const override;
   void GenerateBuilderMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
index 1c4d016..658d105 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -38,13 +38,13 @@
 #include <map>
 #include <string>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
@@ -308,6 +308,15 @@
       "public fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
       "  return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
       "}\n");
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageFieldLiteGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  if (descriptor_->has_optional_keyword()) {
+    printer->Print(variables_,
+                   "public val $classname$Kt.Dsl.$name$OrNull: $kt_type$?\n"
+                   "  get() = $kt_dsl_builder$.$name$OrNull\n");
+  }
 }
 
 void ImmutableMessageFieldLiteGenerator::GenerateFieldInfo(
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
index 8f81f60..313a409 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -62,7 +62,7 @@
   explicit ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
                                               int messageBitIndex,
                                               Context* context);
-  ~ImmutableMessageFieldLiteGenerator();
+  ~ImmutableMessageFieldLiteGenerator() override;
 
   // implements ImmutableFieldLiteGenerator
   // ------------------------------------
@@ -85,6 +85,7 @@
 
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator);
+  void GenerateKotlinOrNull(io::Printer* printer) const;
 };
 
 class ImmutableMessageOneofFieldLiteGenerator
@@ -93,7 +94,7 @@
   ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
                                           int messageBitIndex,
                                           Context* context);
-  ~ImmutableMessageOneofFieldLiteGenerator();
+  ~ImmutableMessageOneofFieldLiteGenerator() override;
 
   void GenerateMembers(io::Printer* printer) const override;
   void GenerateBuilderMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index c2c2788..5be4b6b 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -40,6 +40,11 @@
 #include <memory>
 #include <vector>
 
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_enum_lite.h>
@@ -50,11 +55,6 @@
 #include <google/protobuf/compiler/java/java_message_builder_lite.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/stubs/substitute.h>
 
 namespace google {
 namespace protobuf {
@@ -779,7 +779,7 @@
 void ImmutableMessageLiteGenerator::GenerateKotlinMembers(
     io::Printer* printer) const {
   printer->Print(
-      "@kotlin.jvm.JvmSynthetic\n"
+      "@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n"
       "public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
       "kotlin.Unit): "
       "$message$ =\n"
@@ -808,7 +808,7 @@
       "kotlin.Unit): "
       "$message$ =\n"
       "  $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
-      "}._build()\n",
+      "}._build()\n\n",
       "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
       name_resolver_->GetKotlinExtensionsClassName(descriptor_));
 
@@ -817,6 +817,27 @@
     ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
         .GenerateTopLevelKotlinMembers(printer);
   }
+
+  GenerateKotlinOrNull(printer);
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinOrNull(io::Printer* printer) const {
+  // Generate getFieldOrNull getters for all optional message fields.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->has_optional_keyword() &&
+        GetJavaType(field) == JAVATYPE_MESSAGE) {
+      printer->Print(
+          "val $full_classname$OrBuilder.$camelcase_name$OrNull: "
+          "$full_name$?\n"
+          "  get() = if (has$name$()) get$name$() else null\n\n",
+          "full_classname", name_resolver_->GetClassName(descriptor_, true),
+          "camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
+          "full_name",
+          name_resolver_->GetImmutableClassName(field->message_type()), "name",
+          context_->GetFieldGeneratorInfo(field)->capitalized_name);
+    }
+  }
 }
 
 void ImmutableMessageLiteGenerator::GenerateKotlinExtensions(
@@ -954,7 +975,8 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public operator fun <E> "
+      "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.set(index: Int, value: "
       "E) {\n"
       "  _builder.setExtension(this.extension, index, value)\n"
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index adb0df7..c0afbc9 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 #include <google/protobuf/compiler/java/java_message.h>
 
@@ -48,7 +49,7 @@
 class ImmutableMessageLiteGenerator : public MessageGenerator {
  public:
   ImmutableMessageLiteGenerator(const Descriptor* descriptor, Context* context);
-  virtual ~ImmutableMessageLiteGenerator();
+  ~ImmutableMessageLiteGenerator() override;
 
   void Generate(io::Printer* printer) override;
   void GenerateInterface(io::Printer* printer) override;
@@ -70,6 +71,7 @@
   void GenerateConstructor(io::Printer* printer);
   void GenerateDynamicMethodNewBuildMessageInfo(io::Printer* printer);
   void GenerateKotlinExtensions(io::Printer* printer) const;
+  void GenerateKotlinOrNull(io::Printer* printer) const;
 
   Context* context_;
   ClassNameResolver* name_resolver_;
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index 39bf3e2..08c009b 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -33,10 +33,10 @@
 #include <map>
 #include <string>
 
-#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/compiler/java/java_names.h>
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_names.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index a688d49..eddf23b 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -123,7 +123,6 @@
   std::string GetDowngradedFileClassName(const FileDescriptor* file);
   std::string GetDowngradedClassName(const Descriptor* descriptor);
 
- private:
   // Get the full name of a Java class by prepending the Java package name
   // or outer class name.
   std::string GetClassFullName(const std::string& name_without_package,
@@ -132,6 +131,8 @@
   std::string GetClassFullName(const std::string& name_without_package,
                                const FileDescriptor* file, bool immutable,
                                bool is_own_file, bool kotlin);
+
+ private:
   // Get the Java Class style full name of a message.
   std::string GetJavaClassFullName(const std::string& name_without_package,
                                    const FileDescriptor* file, bool immutable);
diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
index 3bdd53b..56b5fc7 100644
--- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
@@ -54,11 +54,10 @@
 class TestGenerator : public CodeGenerator {
  public:
   TestGenerator() {}
-  ~TestGenerator() {}
+  ~TestGenerator() override {}
 
-  virtual bool Generate(const FileDescriptor* file,
-                        const std::string& parameter, GeneratorContext* context,
-                        std::string* error) const {
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
     std::string filename = "Test.java";
     TryInsert(filename, "outer_class_scope", context);
     TryInsert(filename, "class_scope:foo.Bar", context);
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index f67f6d3..3a338ee 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -40,13 +40,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index 1f0eb8c..2eb1b23 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -37,6 +37,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
@@ -101,7 +102,7 @@
   ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
                                         int messageBitIndex,
                                         int builderBitIndex, Context* context);
-  ~ImmutablePrimitiveOneofFieldGenerator();
+  ~ImmutablePrimitiveOneofFieldGenerator() override;
 
   void GenerateMembers(io::Printer* printer) const override;
   void GenerateBuilderMembers(io::Printer* printer) const override;
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 5441d01..2da5f0d 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -40,13 +40,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
@@ -161,7 +161,6 @@
     (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
   } else {
     (*variables)["set_has_field_bit_message"] = "";
-    (*variables)["set_has_field_bit_message"] = "";
     (*variables)["clear_has_field_bit_message"] = "";
 
     switch (descriptor->type()) {
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
index dfafae3..d277436 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -93,7 +93,7 @@
   ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
                                             int messageBitIndex,
                                             Context* context);
-  ~ImmutablePrimitiveOneofFieldLiteGenerator();
+  ~ImmutablePrimitiveOneofFieldLiteGenerator() override;
 
   void GenerateMembers(io::Printer* printer) const override;
   void GenerateBuilderMembers(io::Printer* printer) const override;
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index e30d155..68b915b 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -34,12 +34,12 @@
 
 #include <google/protobuf/compiler/java/java_service.h>
 
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
index 81db519..9cb9021 100644
--- a/src/google/protobuf/compiler/java/java_service.h
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -78,7 +78,7 @@
  public:
   ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
                             Context* context);
-  virtual ~ImmutableServiceGenerator();
+  ~ImmutableServiceGenerator() override;
 
   void Generate(io::Printer* printer) override;
 
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 45943d7..e527234 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -34,15 +34,15 @@
 
 #include <memory>
 
-#include <google/protobuf/compiler/java/java_helpers.h>
-#include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/compiler/java/java_names.h>
 #include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_names.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 1a0959e..f08e89a 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -41,13 +41,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index efab5fe..3112887 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -38,6 +38,7 @@
 
 #include <map>
 #include <string>
+
 #include <google/protobuf/compiler/java/java_field.h>
 
 namespace google {
@@ -61,7 +62,7 @@
   explicit ImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
                                          int messageBitIndex,
                                          int builderBitIndex, Context* context);
-  ~ImmutableStringFieldGenerator();
+  ~ImmutableStringFieldGenerator() override;
 
   // implements ImmutableFieldGenerator
   // ---------------------------------------
@@ -101,7 +102,7 @@
   ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor,
                                      int messageBitIndex, int builderBitIndex,
                                      Context* context);
-  ~ImmutableStringOneofFieldGenerator();
+  ~ImmutableStringOneofFieldGenerator() override;
 
  private:
   void GenerateMembers(io::Printer* printer) const override;
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 1833903..d010634 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -41,13 +41,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index d2dac2f..2cee9da 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -3625,23 +3625,19 @@
     if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
       printer->Print("var proto = {};\n\n");
     } else {
-      // To get the global object we call a function with .call(null), this will set "this" inside the
-      // function to the global object.
-      // This does not work if we are running in strict mode ("use strict"),
-      // so we fallback to the following things (in order from first to last):
+      // To get the global object we call a function with .call(null), this will
+      // set "this" inside the function to the global object. This does not work
+      // if we are running in strict mode ("use strict"), so we fallback to the
+      // following things (in order from first to last):
       // - window: defined in browsers
       // - global: defined in most server side environments like NodeJS
       // - self: defined inside Web Workers (WorkerGlobalScope)
-      // - Function('return this')(): this will work on most platforms, but it may be blocked by things like CSP.
+      // - Function('return this')(): this will work on most platforms, but it
+      // may be blocked by things like CSP.
       //   Function('') is almost the same as eval('')
       printer->Print(
-          "var global = (function() {\n"
-          "  if (this) { return this; }\n"
-          "  if (typeof window !== 'undefined') { return window; }\n"
-          "  if (typeof global !== 'undefined') { return global; }\n"
-          "  if (typeof self !== 'undefined') { return self; }\n"
-          "  return Function('return this')();\n"
-          "}.call(null));\n\n");
+          "var global = (function() { return this || window || global || self "
+          "|| Function('return this')(); }).call(null);\n\n");
     }
 
     for (int i = 0; i < file->dependency_count(); i++) {
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 7cb7a63..08d77a6 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -34,11 +34,13 @@
 #include <google/protobuf/compiler/js/js_generator.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/compiler/python/python_generator.h>
+#include <google/protobuf/compiler/python/python_pyi_generator.h>
 #include <google/protobuf/compiler/csharp/csharp_generator.h>
 #include <google/protobuf/compiler/objectivec/objectivec_generator.h>
 #include <google/protobuf/compiler/php/php_generator.h>
 #include <google/protobuf/compiler/ruby/ruby_generator.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -75,6 +77,10 @@
   python::Generator py_generator;
   cli.RegisterGenerator("--python_out", "--python_opt", &py_generator,
                         "Generate Python source file.");
+  // Python pyi
+  python::PyiGenerator pyi_generator;
+  cli.RegisterGenerator("--pyi_out", &pyi_generator,
+                        "Generate python pyi stub.");
 
   // PHP
   php::Generator php_generator;
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 1fce106..53f6118 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -315,7 +315,7 @@
     io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
         &annotations);
     io::Printer printer(output.get(), '$',
-                        annotate ? &annotation_collector : NULL);
+                        annotate ? &annotation_collector : nullptr);
     printer.PrintRaw(GetOutputFileContent(name_, parameter, file, context));
     std::string annotate_suffix = "_annotation";
     if (annotate) {
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 6e10105..45d735a 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -78,7 +78,7 @@
 class MockCodeGenerator : public CodeGenerator {
  public:
   MockCodeGenerator(const std::string& name);
-  virtual ~MockCodeGenerator();
+  ~MockCodeGenerator() override;
 
   // Expect (via gTest) that a MockCodeGenerator with the given name was called
   // with the given parameters by inspecting the output location.
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 49ddfce..860d4a6 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -46,11 +46,11 @@
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/hash.h>
 
@@ -180,9 +180,9 @@
 // ===================================================================
 
 Parser::Parser()
-    : input_(NULL),
-      error_collector_(NULL),
-      source_location_table_(NULL),
+    : input_(nullptr),
+      error_collector_(nullptr),
+      source_location_table_(nullptr),
       had_errors_(false),
       require_syntax_identifier_(false),
       stop_after_syntax_identifier_(false) {
@@ -347,7 +347,7 @@
     // from last time.
     leading.swap(upcoming_doc_comments_);
 
-    if (location != NULL) {
+    if (location != nullptr) {
       upcoming_detached_comments_.swap(detached);
       location->AttachComments(&leading, &trailing, &detached);
     } else if (strcmp(text, "}") == 0) {
@@ -380,7 +380,7 @@
 // -------------------------------------------------------------------
 
 void Parser::AddError(int line, int column, const std::string& error) {
-  if (error_collector_ != NULL) {
+  if (error_collector_ != nullptr) {
     error_collector_->AddError(line, column, error);
   }
   had_errors_ = true;
@@ -473,7 +473,7 @@
 void Parser::LocationRecorder::RecordLegacyLocation(
     const Message* descriptor,
     DescriptorPool::ErrorCollector::ErrorLocation location) {
-  if (parser_->source_location_table_ != NULL) {
+  if (parser_->source_location_table_ != nullptr) {
     parser_->source_location_table_->Add(
         descriptor, location, location_->span(0), location_->span(1));
   }
@@ -516,7 +516,7 @@
     if (AtEnd()) {
       return;
     } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
-      if (TryConsumeEndOfDeclaration(";", NULL)) {
+      if (TryConsumeEndOfDeclaration(";", nullptr)) {
         return;
       } else if (TryConsume("{")) {
         SkipRestOfBlock();
@@ -534,7 +534,7 @@
     if (AtEnd()) {
       return;
     } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
-      if (TryConsumeEndOfDeclaration("}", NULL)) {
+      if (TryConsumeEndOfDeclaration("}", nullptr)) {
         return;
       } else if (TryConsume("{")) {
         SkipRestOfBlock();
@@ -628,7 +628,7 @@
 
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
     // Advance to first token.
-    input_->NextWithComments(NULL, &upcoming_detached_comments_,
+    input_->NextWithComments(nullptr, &upcoming_detached_comments_,
                              &upcoming_doc_comments_);
   }
 
@@ -644,7 +644,7 @@
         return false;
       }
       // Store the syntax into the file.
-      if (file != NULL) file->set_syntax(syntax_identifier_);
+      if (file != nullptr) file->set_syntax(syntax_identifier_);
     } else if (!stop_after_syntax_identifier_) {
       GOOGLE_LOG(WARNING) << "No syntax specified for the proto file: " << file->name()
                    << ". Please use 'syntax = \"proto2\";' "
@@ -664,16 +664,16 @@
 
         if (LookingAt("}")) {
           AddError("Unmatched \"}\".");
-          input_->NextWithComments(NULL, &upcoming_detached_comments_,
+          input_->NextWithComments(nullptr, &upcoming_detached_comments_,
                                    &upcoming_doc_comments_);
         }
       }
     }
   }
 
-  input_ = NULL;
-  source_code_info_ = NULL;
-  assert(file != NULL);
+  input_ = nullptr;
+  source_code_info_ = nullptr;
+  assert(file != nullptr);
   source_code_info.Swap(file->mutable_source_code_info());
   return !had_errors_;
 }
@@ -706,7 +706,7 @@
 
 bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
                                     const LocationRecorder& root_location) {
-  if (TryConsumeEndOfDeclaration(";", NULL)) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("message")) {
@@ -862,7 +862,7 @@
                                const FileDescriptorProto* containing_file) {
   DO(ConsumeEndOfDeclaration("{", &message_location));
 
-  while (!TryConsumeEndOfDeclaration("}", NULL)) {
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
     if (AtEnd()) {
       AddError("Reached end of input in message definition (missing '}').");
       return false;
@@ -887,7 +887,7 @@
 bool Parser::ParseMessageStatement(DescriptorProto* message,
                                    const LocationRecorder& message_location,
                                    const FileDescriptorProto* containing_file) {
-  if (TryConsumeEndOfDeclaration(";", NULL)) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("message")) {
@@ -1458,7 +1458,7 @@
   // Create an entry in the uninterpreted_option field.
   const FieldDescriptor* uninterpreted_option_field =
       options->GetDescriptor()->FindFieldByName("uninterpreted_option");
-  GOOGLE_CHECK(uninterpreted_option_field != NULL)
+  GOOGLE_CHECK(uninterpreted_option_field != nullptr)
       << "No field named \"uninterpreted_option\" in the Options proto.";
 
   const Reflection* reflection = options->GetReflection();
@@ -1906,7 +1906,7 @@
       // other statements.
       SkipStatement();
     }
-  } while (!TryConsumeEndOfDeclaration("}", NULL));
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
 
   return true;
 }
@@ -1970,7 +1970,7 @@
       // other statements.
       SkipStatement();
     }
-  } while (!TryConsumeEndOfDeclaration("}", NULL));
+  } while (!TryConsumeEndOfDeclaration("}", nullptr));
 
   return true;
 }
@@ -2003,7 +2003,7 @@
                             const FileDescriptorProto* containing_file) {
   DO(ConsumeEndOfDeclaration("{", &enum_location));
 
-  while (!TryConsumeEndOfDeclaration("}", NULL)) {
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
     if (AtEnd()) {
       AddError("Reached end of input in enum definition (missing '}').");
       return false;
@@ -2022,7 +2022,7 @@
 bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
                                 const LocationRecorder& enum_location,
                                 const FileDescriptorProto* containing_file) {
-  if (TryConsumeEndOfDeclaration(";", NULL)) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("option")) {
@@ -2120,7 +2120,7 @@
                                const FileDescriptorProto* containing_file) {
   DO(ConsumeEndOfDeclaration("{", &service_location));
 
-  while (!TryConsumeEndOfDeclaration("}", NULL)) {
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
     if (AtEnd()) {
       AddError("Reached end of input in service definition (missing '}').");
       return false;
@@ -2139,7 +2139,7 @@
 bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
                                    const LocationRecorder& service_location,
                                    const FileDescriptorProto* containing_file) {
-  if (TryConsumeEndOfDeclaration(";", NULL)) {
+  if (TryConsumeEndOfDeclaration(";", nullptr)) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("option")) {
@@ -2177,7 +2177,6 @@
                                     DescriptorPool::ErrorCollector::OTHER);
       method->set_client_streaming(true);
       DO(Consume("stream"));
-
     }
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kInputTypeFieldNumber);
@@ -2198,7 +2197,6 @@
                                     DescriptorPool::ErrorCollector::OTHER);
       DO(Consume("stream"));
       method->set_server_streaming(true);
-
     }
     LocationRecorder location(method_location,
                               MethodDescriptorProto::kOutputTypeFieldNumber);
@@ -2226,13 +2224,13 @@
                                 Message* mutable_options) {
   // Options!
   ConsumeEndOfDeclaration("{", &parent_location);
-  while (!TryConsumeEndOfDeclaration("}", NULL)) {
+  while (!TryConsumeEndOfDeclaration("}", nullptr)) {
     if (AtEnd()) {
       AddError("Reached end of input in method options (missing '}').");
       return false;
     }
 
-    if (TryConsumeEndOfDeclaration(";", NULL)) {
+    if (TryConsumeEndOfDeclaration(";", nullptr)) {
       // empty statement; ignore
     } else {
       LocationRecorder location(parent_location, optionsFieldNumber);
@@ -2396,7 +2394,7 @@
     int* column) const {
   const std::pair<int, int>* result =
       FindOrNull(location_map_, std::make_pair(descriptor, location));
-  if (result == NULL) {
+  if (result == nullptr) {
     *line = -1;
     *column = 0;
     return false;
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index b5a5df8..f95c419 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -42,10 +42,10 @@
 #include <string>
 #include <utility>
 
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/repeated_field.h>
+#include <google/protobuf/descriptor.pb.h>
 
 // Must be included last.
 #include <google/protobuf/port_def.inc>
@@ -281,9 +281,6 @@
                         std::vector<std::string>* detached_comments) const;
 
    private:
-    // Indexes of parent and current location in the parent
-    // SourceCodeInfo.location repeated field. For top-level elements,
-    // parent_index_ is -1.
     Parser* parser_;
     SourceCodeInfo* source_code_info_;
     SourceCodeInfo::Location* location_;
@@ -434,7 +431,6 @@
                           const LocationRecorder& method_location,
                           const FileDescriptorProto* containing_file);
 
-
   // Parse options of a single method or stream.
   bool ParseMethodOptions(const LocationRecorder& parent_location,
                           const FileDescriptorProto* containing_file,
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 6973bc9..8ddc312 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -83,7 +83,7 @@
                                io::ErrorCollector* wrapped_collector)
       : source_locations_(source_locations),
         wrapped_collector_(wrapped_collector) {}
-  ~MockValidationErrorCollector() {}
+  ~MockValidationErrorCollector() override {}
 
   // implements ErrorCollector ---------------------------------------
   void AddError(const std::string& filename, const std::string& element_name,
@@ -173,7 +173,7 @@
     MockValidationErrorCollector validation_error_collector(source_locations,
                                                             &error_collector_);
     EXPECT_TRUE(pool_.BuildFileCollectingErrors(
-                    file, &validation_error_collector) == NULL);
+                    file, &validation_error_collector) == nullptr);
     EXPECT_EQ(expected_errors, error_collector_.text_);
   }
 
@@ -194,7 +194,7 @@
       "syntax = \"foobar\";\n"
       "this line will not be parsed\n");
   parser_->SetStopAfterSyntaxIdentifier(true);
-  EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
+  EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
   EXPECT_EQ("", error_collector_.text_);
   EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
 }
@@ -204,7 +204,7 @@
       "// blah\n"
       "this line will not be parsed\n");
   parser_->SetStopAfterSyntaxIdentifier(true);
-  EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
+  EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
   EXPECT_EQ("", error_collector_.text_);
   EXPECT_EQ("", parser_->GetSyntaxIdentifier());
 }
@@ -214,7 +214,7 @@
       "// blah\n"
       "syntax = error;\n");
   parser_->SetStopAfterSyntaxIdentifier(true);
-  EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
+  EXPECT_FALSE(parser_->Parse(input_.get(), nullptr));
   EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
 }
 
@@ -1792,7 +1792,7 @@
   FileDescriptorProto other_file;
   other_file.set_name("bar.proto");
   other_file.add_message_type()->set_name("foo");
-  EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
 
   // Now try to define it as a package.
   ExpectHasValidationErrors(
@@ -2071,7 +2071,7 @@
   other_file.set_name("base.proto");
   other_file.set_package("base");
   other_file.add_message_type()->set_name("bar");
-  EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
 
   // Define "foo.base" and try "base.bar".
   // "base.bar" is resolved to "foo.base.bar" which is not defined.
@@ -2092,7 +2092,7 @@
   // Build descriptor message in test pool
   FileDescriptorProto descriptor_proto;
   DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
-  ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != NULL);
+  ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != nullptr);
 
   // base2.proto:
   //   package baz
@@ -2121,7 +2121,7 @@
   extension->set_type_name("Bar");
   extension->set_extendee("google.protobuf.FileOptions");
 
-  EXPECT_TRUE(pool_.BuildFile(other_file) != NULL);
+  EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
 
   // qux.proto:
   //   package qux.baz
@@ -2228,17 +2228,17 @@
       protobuf_unittest_import::PublicImportMessage::descriptor()->file();
   FileDescriptorProto public_import_proto;
   public_import->CopyTo(&public_import_proto);
-  ASSERT_TRUE(pool_.BuildFile(public_import_proto) != NULL);
+  ASSERT_TRUE(pool_.BuildFile(public_import_proto) != nullptr);
   const FileDescriptor* import =
       protobuf_unittest_import::ImportMessage::descriptor()->file();
   FileDescriptorProto import_proto;
   import->CopyTo(&import_proto);
-  ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+  ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
   const FileDescriptor* actual = pool_.BuildFile(parsed);
   parsed.Clear();
-  ASSERT_TRUE(actual != NULL) << "Failed to validate:\n" << debug_string;
+  ASSERT_TRUE(actual != nullptr) << "Failed to validate:\n" << debug_string;
   actual->CopyTo(&parsed);
-  ASSERT_TRUE(actual != NULL);
+  ASSERT_TRUE(actual != nullptr);
 
   // The messages might be in different orders, making them hard to compare.
   // So, sort the messages in the descriptor protos (including nested messages,
@@ -2276,14 +2276,14 @@
   const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
   FileDescriptorProto import_proto;
   import->CopyTo(&import_proto);
-  ASSERT_TRUE(pool_.BuildFile(import_proto) != NULL);
+  ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
 
   FileDescriptorProto any_import;
   google::protobuf::Any::descriptor()->file()->CopyTo(&any_import);
   ASSERT_TRUE(pool_.BuildFile(any_import) != nullptr);
 
   const FileDescriptor* actual = pool_.BuildFile(parsed);
-  ASSERT_TRUE(actual != NULL);
+  ASSERT_TRUE(actual != nullptr);
   parsed.Clear();
   actual->CopyTo(&parsed);
 
@@ -2365,7 +2365,7 @@
   MockValidationErrorCollector collector(source_locations, &error_collector_);
   const FileDescriptor* descriptor =
       pool_.BuildFileCollectingErrors(parsed_desc, &collector);
-  ASSERT_TRUE(descriptor != NULL);
+  ASSERT_TRUE(descriptor != nullptr);
 
   // 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
@@ -2429,7 +2429,7 @@
   EXPECT_TRUE(parser_->Parse(input_.get(), &original));
   original.set_name("foo.proto");
   const FileDescriptor* file = pool_.BuildFile(original);
-  ASSERT_TRUE(file != NULL);
+  ASSERT_TRUE(file != nullptr);
 
   // Make sure the debug string uses map syntax and does not have the auto
   // generated entry.
@@ -2472,7 +2472,7 @@
   if (path_begin == path_end) {
     // Path refers to this whole message.
     *output_message = &root;
-    *output_field = NULL;
+    *output_field = nullptr;
     *output_index = -1;
     return true;
   }
@@ -2482,7 +2482,7 @@
 
   const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
 
-  if (field == NULL) {
+  if (field == nullptr) {
     ADD_FAILURE() << descriptor->name()
                   << " has no field number: " << *path_begin;
     return false;
@@ -2573,8 +2573,8 @@
     const SourceCodeInfo& source_info = file_.source_code_info();
     for (int i = 0; i < source_info.location_size(); i++) {
       const SourceCodeInfo::Location& location = source_info.location(i);
-      const Message* descriptor_proto = NULL;
-      const FieldDescriptor* field = NULL;
+      const Message* descriptor_proto = nullptr;
+      const FieldDescriptor* field = nullptr;
       int index = 0;
       if (!FollowPath(file_, location.path().begin(), location.path().end(),
                       &descriptor_proto, &field, &index)) {
@@ -2601,8 +2601,8 @@
 
   bool HasSpan(char start_marker, char end_marker,
                const Message& descriptor_proto) {
-    return HasSpanWithComment(start_marker, end_marker, descriptor_proto, NULL,
-                              -1, NULL, NULL, NULL);
+    return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
+                              nullptr, -1, nullptr, nullptr, nullptr);
   }
 
   bool HasSpanWithComment(char start_marker, char end_marker,
@@ -2610,8 +2610,8 @@
                           const char* expected_leading_comments,
                           const char* expected_trailing_comments,
                           const char* expected_leading_detached_comments) {
-    return HasSpanWithComment(start_marker, end_marker, descriptor_proto, NULL,
-                              -1, expected_leading_comments,
+    return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
+                              nullptr, -1, expected_leading_comments,
                               expected_trailing_comments,
                               expected_leading_detached_comments);
   }
@@ -2625,7 +2625,7 @@
                const Message& descriptor_proto, const std::string& field_name,
                int index) {
     return HasSpan(start_marker, end_marker, descriptor_proto, field_name,
-                   index, NULL, NULL, NULL);
+                   index, nullptr, nullptr, nullptr);
   }
 
   bool HasSpan(char start_marker, char end_marker,
@@ -2635,7 +2635,7 @@
                const char* expected_leading_detached_comments) {
     const FieldDescriptor* field =
         descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
-    if (field == NULL) {
+    if (field == nullptr) {
       ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
                     << " has no such field: " << field_name;
       return false;
@@ -2648,8 +2648,8 @@
   }
 
   bool HasSpan(const Message& descriptor_proto) {
-    return HasSpanWithComment('\0', '\0', descriptor_proto, NULL, -1, NULL,
-                              NULL, NULL);
+    return HasSpanWithComment('\0', '\0', descriptor_proto, nullptr, -1,
+                              nullptr, nullptr, nullptr);
   }
 
   bool HasSpan(const Message& descriptor_proto, const std::string& field_name) {
@@ -2686,21 +2686,21 @@
 
       for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
         if (CompareSpans(expected_span, iter->second->span())) {
-          if (expected_leading_comments == NULL) {
+          if (expected_leading_comments == nullptr) {
             EXPECT_FALSE(iter->second->has_leading_comments());
           } else {
             EXPECT_TRUE(iter->second->has_leading_comments());
             EXPECT_EQ(expected_leading_comments,
                       iter->second->leading_comments());
           }
-          if (expected_trailing_comments == NULL) {
+          if (expected_trailing_comments == nullptr) {
             EXPECT_FALSE(iter->second->has_trailing_comments());
           } else {
             EXPECT_TRUE(iter->second->has_trailing_comments());
             EXPECT_EQ(expected_trailing_comments,
                       iter->second->trailing_comments());
           }
-          if (expected_leading_detached_comments == NULL) {
+          if (expected_leading_detached_comments == nullptr) {
             EXPECT_EQ(0, iter->second->leading_detached_comments_size());
           } else {
             EXPECT_EQ(
@@ -3496,7 +3496,7 @@
   const FieldDescriptorProto& bar = foo.field(0);
 
   EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n",
-                                 " Foo trailing\n line 2\n", NULL));
+                                 " Foo trailing\n line 2\n", nullptr));
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
                                  " bar trailing\n", " detached\n"));
 
@@ -3572,7 +3572,7 @@
   const FieldDescriptorProto& bar = foo.field(0);
 
   EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
-                                 " bar trailing\n", NULL));
+                                 " bar trailing\n", nullptr));
 
   // Ignore these.
   EXPECT_TRUE(HasSpan(file_));
@@ -3655,7 +3655,7 @@
   const FieldDescriptorProto& bar_int = foo.field(0);
 
   EXPECT_TRUE(HasSpanWithComment('a', 'f', foo, " Foo leading\n",
-                                 " Foo trailing\n", NULL));
+                                 " Foo trailing\n", nullptr));
   EXPECT_TRUE(HasSpanWithComment('b', 'e', bar, " bar leading\n line 2 ",
                                  " bar trailing\n line 2 ",
                                  " detached before oneof\n"));
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 7809968..25ca5f0 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -68,7 +68,7 @@
       : compiler_version_(compiler_version),
         response_(response),
         parsed_files_(parsed_files) {}
-  virtual ~GeneratorResponseContext() {}
+  ~GeneratorResponseContext() override {}
 
   // implements GeneratorContext --------------------------------------
 
@@ -117,7 +117,7 @@
   DescriptorPool pool;
   for (int i = 0; i < request.proto_file_size(); i++) {
     const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
-    if (file == NULL) {
+    if (file == nullptr) {
       // BuildFile() already wrote an error message.
       return false;
     }
@@ -126,7 +126,7 @@
   std::vector<const FileDescriptor*> parsed_files;
   for (int i = 0; i < request.file_to_generate_size(); i++) {
     parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
-    if (parsed_files.back() == NULL) {
+    if (parsed_files.back() == nullptr) {
       *error_msg =
           "protoc asked plugin to generate a file but "
           "did not provide a descriptor for the file: " +
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 7d1bf45..611713e 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -64,6 +64,7 @@
 
 #include <string>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index e423e85..f6be664 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -16,72 +16,76 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 namespace compiler {
 constexpr Version::Version(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : suffix_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , major_(0)
   , minor_(0)
   , patch_(0){}
 struct VersionDefaultTypeInternal {
   constexpr VersionDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~VersionDefaultTypeInternal() {}
   union {
     Version _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT VersionDefaultTypeInternal _Version_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 VersionDefaultTypeInternal _Version_default_instance_;
 constexpr CodeGeneratorRequest::CodeGeneratorRequest(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : file_to_generate_()
   , proto_file_()
   , parameter_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , compiler_version_(nullptr){}
 struct CodeGeneratorRequestDefaultTypeInternal {
   constexpr CodeGeneratorRequestDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~CodeGeneratorRequestDefaultTypeInternal() {}
   union {
     CodeGeneratorRequest _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorRequestDefaultTypeInternal _CodeGeneratorRequest_default_instance_;
 constexpr CodeGeneratorResponse_File::CodeGeneratorResponse_File(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , insertion_point_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , content_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , generated_code_info_(nullptr){}
 struct CodeGeneratorResponse_FileDefaultTypeInternal {
   constexpr CodeGeneratorResponse_FileDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~CodeGeneratorResponse_FileDefaultTypeInternal() {}
   union {
     CodeGeneratorResponse_File _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorResponse_FileDefaultTypeInternal _CodeGeneratorResponse_File_default_instance_;
 constexpr CodeGeneratorResponse::CodeGeneratorResponse(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : file_()
   , error_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , supported_features_(uint64_t{0u}){}
 struct CodeGeneratorResponseDefaultTypeInternal {
   constexpr CodeGeneratorResponseDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~CodeGeneratorResponseDefaultTypeInternal() {}
   union {
     CodeGeneratorResponse _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 CodeGeneratorResponseDefaultTypeInternal _CodeGeneratorResponse_default_instance_;
 }  // namespace compiler
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
-static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::compiler::Version, _has_bits_),
@@ -139,18 +143,18 @@
   1,
   ~0u,
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, 10, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::Version)},
   { 14, 24, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest)},
   { 28, 38, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File)},
   { 42, 51, -1, sizeof(::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorRequest_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_File_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::compiler::_Version_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorRequest_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_File_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::compiler::_CodeGeneratorResponse_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -175,22 +179,24 @@
   "uginProtosZ)google.golang.org/protobuf/t"
   "ypes/pluginpb"
   ;
-static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps[1] = {
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps[1] = {
   &::descriptor_table_google_2fprotobuf_2fdescriptor_2eproto,
 };
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
-  false, false, 773, descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto, "google/protobuf/compiler/plugin.proto", 
-  &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps, 1, 4,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+    false, false, 773, descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+    "google/protobuf/compiler/plugin.proto",
+    &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once, descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_deps, 1, 4,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fcompiler_2fplugin_2eproto(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fcompiler_2fplugin_2eproto(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 namespace compiler {
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor() {
@@ -238,16 +244,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.Version)
 }
 Version::Version(const Version& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  suffix_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -262,7 +265,7 @@
 }
 
 inline void Version::SharedCtor() {
-suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+suffix_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -274,9 +277,11 @@
 
 Version::~Version() {
   // @@protoc_insertion_point(destructor:google.protobuf.compiler.Version)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Version::SharedDtor() {
@@ -284,12 +289,6 @@
   suffix_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void Version::ArenaDtor(void* object) {
-  Version* _this = reinterpret_cast< Version* >(object);
-  (void)_this;
-}
-void Version::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Version::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -313,12 +312,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Version::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Version::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional int32 major = 1;
       case 1:
@@ -351,11 +350,11 @@
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_suffix();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.Version.suffix");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.Version.suffix");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -393,19 +392,19 @@
   // optional int32 major = 1;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_major(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_major(), target);
   }
 
   // optional int32 minor = 2;
   if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_minor(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_minor(), target);
   }
 
   // optional int32 patch = 3;
   if (cached_has_bits & 0x00000008u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_patch(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_patch(), target);
   }
 
   // optional string suffix = 4;
@@ -419,7 +418,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.Version)
@@ -445,17 +444,17 @@
 
     // optional int32 major = 1;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_major());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_major());
     }
 
     // optional int32 minor = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_minor());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_minor());
     }
 
     // optional int32 patch = 3;
     if (cached_has_bits & 0x00000008u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_patch());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_patch());
     }
 
   }
@@ -531,7 +530,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Version::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]);
 }
@@ -563,9 +562,6 @@
   file_to_generate_(arena),
   proto_file_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorRequest)
 }
 CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
@@ -574,7 +570,7 @@
       file_to_generate_(from.file_to_generate_),
       proto_file_(from.proto_file_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  parameter_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -591,7 +587,7 @@
 }
 
 inline void CodeGeneratorRequest::SharedCtor() {
-parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+parameter_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -600,9 +596,11 @@
 
 CodeGeneratorRequest::~CodeGeneratorRequest() {
   // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorRequest)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void CodeGeneratorRequest::SharedDtor() {
@@ -611,12 +609,6 @@
   if (this != internal_default_instance()) delete compiler_version_;
 }
 
-void CodeGeneratorRequest::ArenaDtor(void* object) {
-  CodeGeneratorRequest* _this = reinterpret_cast< CodeGeneratorRequest* >(object);
-  (void)_this;
-}
-void CodeGeneratorRequest::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void CodeGeneratorRequest::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -643,12 +635,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated string file_to_generate = 1;
       case 1:
@@ -657,11 +649,11 @@
           do {
             ptr += 1;
             auto str = _internal_add_file_to_generate();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            #ifndef NDEBUG
-            ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
-            #endif  // !NDEBUG
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
+            #endif  // !NDEBUG
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
         } else
@@ -671,11 +663,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_parameter();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -753,22 +745,21 @@
 
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        3, _Internal::compiler_version(this), target, stream);
+      InternalWriteMessage(3, _Internal::compiler_version(this),
+        _Internal::compiler_version(this).GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_proto_file_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_proto_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_proto_file(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(15, this->_internal_proto_file(i), target, stream);
+        InternalWriteMessage(15, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorRequest)
@@ -881,7 +872,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorRequest::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]);
 }
@@ -918,16 +909,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
 }
 CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -935,7 +923,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  insertion_point_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -943,7 +931,7 @@
     insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_insertion_point(), 
       GetArenaForAllocation());
   }
-  content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  content_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -960,15 +948,15 @@
 }
 
 inline void CodeGeneratorResponse_File::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+insertion_point_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+content_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -977,9 +965,11 @@
 
 CodeGeneratorResponse_File::~CodeGeneratorResponse_File() {
   // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse.File)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void CodeGeneratorResponse_File::SharedDtor() {
@@ -990,12 +980,6 @@
   if (this != internal_default_instance()) delete generated_code_info_;
 }
 
-void CodeGeneratorResponse_File::ArenaDtor(void* object) {
-  CodeGeneratorResponse_File* _this = reinterpret_cast< CodeGeneratorResponse_File* >(object);
-  (void)_this;
-}
-void CodeGeneratorResponse_File::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void CodeGeneratorResponse_File::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1026,22 +1010,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1049,11 +1033,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_insertion_point();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1061,11 +1045,11 @@
       case 15:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 122)) {
           auto str = _internal_mutable_content();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1140,14 +1124,13 @@
 
   // optional .google.protobuf.GeneratedCodeInfo generated_code_info = 16;
   if (cached_has_bits & 0x00000008u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        16, _Internal::generated_code_info(this), target, stream);
+      InternalWriteMessage(16, _Internal::generated_code_info(this),
+        _Internal::generated_code_info(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse.File)
@@ -1269,7 +1252,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse_File::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]);
 }
@@ -1292,9 +1275,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   file_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.compiler.CodeGeneratorResponse)
 }
 CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
@@ -1302,7 +1282,7 @@
       _has_bits_(from._has_bits_),
       file_(from.file_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  error_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1315,7 +1295,7 @@
 }
 
 inline void CodeGeneratorResponse::SharedCtor() {
-error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+error_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1324,9 +1304,11 @@
 
 CodeGeneratorResponse::~CodeGeneratorResponse() {
   // @@protoc_insertion_point(destructor:google.protobuf.compiler.CodeGeneratorResponse)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void CodeGeneratorResponse::SharedDtor() {
@@ -1334,12 +1316,6 @@
   error_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void CodeGeneratorResponse::ArenaDtor(void* object) {
-  CodeGeneratorResponse* _this = reinterpret_cast< CodeGeneratorResponse* >(object);
-  (void)_this;
-}
-void CodeGeneratorResponse::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void CodeGeneratorResponse::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1360,22 +1336,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string error = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_error();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.error");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.compiler.CodeGeneratorResponse.error");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1445,19 +1421,19 @@
   // optional uint64 supported_features = 2;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(2, this->_internal_supported_features(), target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(2, this->_internal_supported_features(), target);
   }
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_file_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_file(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(15, this->_internal_file(i), target, stream);
+        InternalWriteMessage(15, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse)
@@ -1490,7 +1466,7 @@
 
     // optional uint64 supported_features = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_supported_features());
+      total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_supported_features());
     }
 
   }
@@ -1557,7 +1533,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]);
 }
@@ -1566,16 +1542,20 @@
 }  // namespace compiler
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::Version* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::Version*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::Version >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorRequest >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_File >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index d558f5b..4c4994b 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -50,14 +49,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOC_EXPORT TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[4]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOC_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto;
@@ -225,9 +216,6 @@
   protected:
   explicit Version(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -433,9 +421,6 @@
   protected:
   explicit CodeGeneratorRequest(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -662,9 +647,6 @@
   protected:
   explicit CodeGeneratorResponse_File(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -885,9 +867,6 @@
   protected:
   explicit CodeGeneratorResponse(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1141,7 +1120,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = suffix_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (suffix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (suffix_.IsDefault()) {
     suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1156,7 +1135,7 @@
   suffix_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), suffix,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (suffix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (suffix_.IsDefault()) {
     suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1289,7 +1268,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = parameter_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (parameter_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (parameter_.IsDefault()) {
     parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1304,7 +1283,7 @@
   parameter_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), parameter,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (parameter_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (parameter_.IsDefault()) {
     parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1489,7 +1468,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1504,7 +1483,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1558,7 +1537,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = insertion_point_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (insertion_point_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (insertion_point_.IsDefault()) {
     insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1573,7 +1552,7 @@
   insertion_point_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), insertion_point,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (insertion_point_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (insertion_point_.IsDefault()) {
     insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1627,7 +1606,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = content_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (content_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (content_.IsDefault()) {
     content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1642,7 +1621,7 @@
   content_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), content,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (content_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (content_.IsDefault()) {
     content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1788,7 +1767,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = error_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (error_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (error_.IsDefault()) {
     error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1803,7 +1782,7 @@
   error_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), error,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (error_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (error_.IsDefault()) {
     error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 9ad7a33..7d9e7ea 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -55,12 +55,14 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/compiler/python/python_helpers.h>
+#include <google/protobuf/compiler/python/python_pyi_generator.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/descriptor.pb.h>
 
 namespace google {
 namespace protobuf {
@@ -68,16 +70,6 @@
 namespace python {
 
 namespace {
-
-
-// Returns the Python module name expected for a given .proto filename.
-std::string ModuleName(const std::string& filename) {
-  std::string basename = StripProto(filename);
-  ReplaceCharacters(&basename, "-", '_');
-  ReplaceCharacters(&basename, "/", '.');
-  return basename + "_pb2";
-}
-
 // Returns the alias we assign to the module of the given .proto filename
 // when importing. See testPackageInitializationImport in
 // net/proto2/python/internal/reflection_test.py
@@ -92,78 +84,18 @@
   return module_name;
 }
 
-// Keywords reserved by the Python language.
-const char* const kKeywords[] = {
-    "False",  "None",     "True",  "and",    "as",       "assert",
-    "async",  "await",    "break", "class",  "continue", "def",
-    "del",    "elif",     "else",  "except", "finally",  "for",
-    "from",   "global",   "if",    "import", "in",       "is",
-    "lambda", "nonlocal", "not",   "or",     "pass",     "raise",
-    "return", "try",      "while", "with",   "yield",    "print",
-};
-const char* const* kKeywordsEnd =
-    kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
-
-bool ContainsPythonKeyword(const std::string& module_name) {
-  std::vector<std::string> tokens = Split(module_name, ".");
-  for (int i = 0; i < tokens.size(); ++i) {
-    if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
-      return true;
-    }
-  }
-  return false;
-}
-
-inline bool IsPythonKeyword(const std::string& name) {
-  return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd);
-}
-
-std::string ResolveKeyword(const std::string& name) {
-  if (IsPythonKeyword(name)) {
-    return "globals()['" + name + "']";
-  }
-  return name;
-}
-
-// Returns the name of all containing types for descriptor,
-// in order from outermost to innermost, followed by descriptor's
-// own name.  Each name is separated by |separator|.
-template <typename DescriptorT>
-std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
-                                        const std::string& separator) {
-  std::string name = descriptor.name();
-  const Descriptor* parent = descriptor.containing_type();
-  if (parent != nullptr) {
-    std::string prefix = NamePrefixedWithNestedTypes(*parent, separator);
-    if (separator == "." && IsPythonKeyword(name)) {
-      return "getattr(" + prefix + ", '" + name + "')";
-    } else {
-      return prefix + separator + name;
-    }
-  }
-  if (separator == ".") {
-    name = ResolveKeyword(name);
-  }
-  return name;
-}
-
 // Name of the class attribute where we store the Python
 // descriptor.Descriptor instance for the generated class.
 // Must stay consistent with the _DESCRIPTOR_KEY constant
 // in proto2/public/reflection.py.
 const char kDescriptorKey[] = "DESCRIPTOR";
 
+
 // Does the file have top-level enums?
 inline bool HasTopLevelEnums(const FileDescriptor* file) {
   return file->enum_type_count() > 0;
 }
 
-// Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor* file) {
-  return file->service_count() > 0 && file->options().py_generic_services();
-}
-
-// Prints the common boilerplate needed at the top of every .py
 // file output by this generator.
 void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file,
                          bool descriptor_proto) {
@@ -174,27 +106,16 @@
       "# source: $filename$\n"
       "\"\"\"Generated protocol buffer code.\"\"\"\n",
       "filename", file->name());
-  if (HasTopLevelEnums(file)) {
-    printer->Print(
-        "from google.protobuf.internal import enum_type_wrapper\n");
-  }
   printer->Print(
+      "from google.protobuf.internal import builder as _builder\n"
       "from google.protobuf import descriptor as _descriptor\n"
       "from google.protobuf import descriptor_pool as "
       "_descriptor_pool\n"
-      "from google.protobuf import message as _message\n"
-      "from google.protobuf import reflection as _reflection\n"
       "from google.protobuf import symbol_database as "
       "_symbol_database\n");
-  if (HasGenericServices(file)) {
-    printer->Print(
-        "from google.protobuf import service as _service\n"
-        "from google.protobuf import service_reflection\n");
-  }
 
-  printer->Print(
-      "# @@protoc_insertion_point(imports)\n\n"
-      "_sym_db = _symbol_database.Default()\n");
+  printer->Print("# @@protoc_insertion_point(imports)\n\n");
+  printer->Print("_sym_db = _symbol_database.Default()\n");
   printer->Print("\n\n");
 }
 
@@ -309,6 +230,11 @@
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "cpp_generated_lib_linked") {
       cpp_generated_lib_linked = true;
+    } else if (options[i].first == "pyi_out") {
+      python::PyiGenerator pyi_generator;
+      if (!pyi_generator.Generate(file, "", context, error)) {
+        return false;
+      }
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
@@ -324,11 +250,8 @@
   //   to have any mutable members.  Then it is implicitly thread-safe.
   MutexLock lock(&mutex_);
   file_ = file;
-  std::string module_name = ModuleName(file->name());
-  std::string filename = module_name;
-  ReplaceCharacters(&filename, ".", '/');
-  filename += ".py";
 
+  std::string filename = GetFileName(file, ".py");
   pure_python_workable_ = !cpp_generated_lib_linked;
   if (HasPrefixString(file->name(), "google/protobuf/")) {
     pure_python_workable_ = true;
@@ -349,15 +272,13 @@
     PrintImports();
   }
   PrintFileDescriptor();
-  PrintTopLevelEnums();
-  PrintTopLevelExtensions();
   if (pure_python_workable_) {
     if (GeneratingDescriptorProto()) {
       printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
       printer_->Indent();
       // Create enums before message descriptors
-      PrintAllNestedEnumsInFile(StripPrintDescriptor::kCreate);
-      PrintMessageDescriptors(StripPrintDescriptor::kCreate);
+      PrintAllNestedEnumsInFile();
+      PrintMessageDescriptors();
       FixForeignFieldsInDescriptors();
       printer_->Outdent();
       printer_->Print("else:\n");
@@ -365,16 +286,18 @@
     }
     // Find the message descriptors first and then use the message
     // descriptor to find enums.
-    PrintMessageDescriptors(StripPrintDescriptor::kFind);
-    PrintAllNestedEnumsInFile(StripPrintDescriptor::kFind);
+    printer_->Print(
+        "_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n");
     if (GeneratingDescriptorProto()) {
       printer_->Outdent();
     }
   }
-  PrintMessages();
+  std::string module_name = ModuleName(file->name());
+  printer_->Print(
+      "_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, '$module_name$', "
+      "globals())\n",
+      "module_name", module_name);
   if (pure_python_workable_) {
-    PrintServiceDescriptors();
-
     printer.Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
     printer_->Indent();
 
@@ -395,7 +318,9 @@
     printer_->Outdent();
   }
   if (HasGenericServices(file)) {
-    PrintServices();
+    printer_->Print(
+        "_builder.BuildServices(DESCRIPTOR, '$module_name$', globals())\n",
+        "module_name", module_name);
   }
 
   printer.Print("# @@protoc_insertion_point(module_scope)\n");
@@ -403,7 +328,6 @@
   return !printer.failed();
 }
 
-
 // Prints Python imports for all modules imported by |file|.
 void Generator::PrintImports() const {
   for (int i = 0; i < file_->dependency_count(); ++i) {
@@ -516,47 +440,17 @@
   printer_->Print("\n");
 }
 
-// Prints descriptors and module-level constants for all top-level
-// enums defined in |file|.
-void Generator::PrintTopLevelEnums() const {
-  std::vector<std::pair<std::string, int> > top_level_enum_values;
-  for (int i = 0; i < file_->enum_type_count(); ++i) {
-    const EnumDescriptor& enum_descriptor = *file_->enum_type(i);
-    PrintFindEnum(enum_descriptor);
-    printer_->Print(
-        "$name$ = "
-        "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)",
-        "name", ResolveKeyword(enum_descriptor.name()), "descriptor_name",
-        ModuleLevelDescriptorName(enum_descriptor));
-    printer_->Print("\n");
-
-    for (int j = 0; j < enum_descriptor.value_count(); ++j) {
-      const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j);
-      top_level_enum_values.push_back(
-          std::make_pair(value_descriptor.name(), value_descriptor.number()));
-    }
-  }
-
-  for (int i = 0; i < top_level_enum_values.size(); ++i) {
-    printer_->Print("$name$ = $value$\n", "name",
-                    ResolveKeyword(top_level_enum_values[i].first), "value",
-                    StrCat(top_level_enum_values[i].second));
-  }
-  printer_->Print("\n");
-}
-
 // Prints all enums contained in all message types in |file|.
-void Generator::PrintAllNestedEnumsInFile(
-    StripPrintDescriptor print_mode) const {
+void Generator::PrintAllNestedEnumsInFile() const {
   for (int i = 0; i < file_->message_type_count(); ++i) {
-    PrintNestedEnums(*file_->message_type(i), print_mode);
+    PrintNestedEnums(*file_->message_type(i));
   }
 }
 
 // Prints a Python statement assigning the appropriate module-level
 // enum name to a Python EnumDescriptor object equivalent to
 // enum_descriptor.
-void Generator::PrintCreateEnum(const EnumDescriptor& enum_descriptor) const {
+void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
   std::map<std::string, std::string> m;
   std::string module_level_descriptor_name =
       ModuleLevelDescriptorName(enum_descriptor);
@@ -600,68 +494,23 @@
   printer_->Print("\n");
 }
 
-void Generator::PrintFindEnum(const EnumDescriptor& enum_descriptor) const {
-  std::map<std::string, std::string> m;
-  m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor);
-  m["name"] = enum_descriptor.name();
-  m["file"] = kDescriptorKey;
-  if (enum_descriptor.containing_type()) {
-    m["containing_type"] =
-        ModuleLevelDescriptorName(*enum_descriptor.containing_type());
-    printer_->Print(m,
-                    "$descriptor_name$ = "
-                    "$containing_type$.enum_types_by_name['$name$']\n");
-  } else {
-    printer_->Print(
-        m, "$descriptor_name$ = $file$.enum_types_by_name['$name$']\n");
-  }
-}
-
 // Recursively prints enums in nested types within descriptor, then
 // prints enums contained at the top level in descriptor.
-void Generator::PrintNestedEnums(const Descriptor& descriptor,
-                                 StripPrintDescriptor print_mode) const {
+void Generator::PrintNestedEnums(const Descriptor& descriptor) const {
   for (int i = 0; i < descriptor.nested_type_count(); ++i) {
-    PrintNestedEnums(*descriptor.nested_type(i), print_mode);
+    PrintNestedEnums(*descriptor.nested_type(i));
   }
 
   for (int i = 0; i < descriptor.enum_type_count(); ++i) {
-    if (print_mode == StripPrintDescriptor::kCreate) {
-      PrintCreateEnum(*descriptor.enum_type(i));
-    } else {
-      PrintFindEnum(*descriptor.enum_type(i));
-    }
+    PrintEnum(*descriptor.enum_type(i));
   }
 }
 
-void Generator::PrintTopLevelExtensions() const {
-  for (int i = 0; i < file_->extension_count(); ++i) {
-    const FieldDescriptor& extension_field = *file_->extension(i);
-    std::string constant_name = extension_field.name() + "_FIELD_NUMBER";
-    ToUpper(&constant_name);
-    printer_->Print("$constant_name$ = $number$\n", "constant_name",
-                    constant_name, "number",
-                    StrCat(extension_field.number()));
-    printer_->Print(
-        "$resolved_name$ = "
-        "$file$.extensions_by_name['$name$']\n",
-        "resolved_name", ResolveKeyword(extension_field.name()), "file",
-        kDescriptorKey, "name", extension_field.name());
-  }
-  printer_->Print("\n");
-}
-
 // Prints Python equivalents of all Descriptors in |file|.
-void Generator::PrintMessageDescriptors(StripPrintDescriptor print_mode) const {
-  if (print_mode == StripPrintDescriptor::kCreate) {
-    for (int i = 0; i < file_->message_type_count(); ++i) {
-      PrintCreateDescriptor(*file_->message_type(i));
-      printer_->Print("\n");
-    }
-  } else {
-    for (int i = 0; i < file_->message_type_count(); ++i) {
-      PrintFindDescriptor(*file_->message_type(i));
-    }
+void Generator::PrintMessageDescriptors() const {
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    PrintDescriptor(*file_->message_type(i));
+    printer_->Print("\n");
   }
 }
 
@@ -730,14 +579,13 @@
 // to a Python Descriptor object for message_descriptor.
 //
 // Mutually recursive with PrintNestedDescriptors().
-void Generator::PrintCreateDescriptor(
-    const Descriptor& message_descriptor) const {
+void Generator::PrintDescriptor(const Descriptor& message_descriptor) const {
   std::map<std::string, std::string> m;
   m["name"] = message_descriptor.name();
   m["full_name"] = message_descriptor.full_name();
   m["file"] = kDescriptorKey;
 
-  PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kCreate);
+  PrintNestedDescriptors(message_descriptor);
 
   printer_->Print("\n");
   printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n",
@@ -823,41 +671,14 @@
   printer_->Print(")\n");
 }
 
-void Generator::PrintFindDescriptor(
-    const Descriptor& message_descriptor) const {
-  std::map<std::string, std::string> m;
-  m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
-  m["name"] = message_descriptor.name();
-
-  if (message_descriptor.containing_type()) {
-    m["containing_type"] =
-        ModuleLevelDescriptorName(*message_descriptor.containing_type());
-    printer_->Print(m,
-                    "$descriptor_name$ = "
-                    "$containing_type$.nested_types_by_name['$name$']\n");
-  } else {
-    m["file"] = kDescriptorKey;
-    printer_->Print(
-        m, "$descriptor_name$ = $file$.message_types_by_name['$name$']\n");
-  }
-
-  PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kFind);
-}
-
 // Prints Python Descriptor objects for all nested types contained in
 // message_descriptor.
 //
 // Mutually recursive with PrintDescriptor().
-void Generator::PrintNestedDescriptors(const Descriptor& containing_descriptor,
-                                       StripPrintDescriptor print_mode) const {
-  if (print_mode == StripPrintDescriptor::kCreate) {
-    for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
-      PrintCreateDescriptor(*containing_descriptor.nested_type(i));
-    }
-  } else {
-    for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
-      PrintFindDescriptor(*containing_descriptor.nested_type(i));
-    }
+void Generator::PrintNestedDescriptors(
+    const Descriptor& containing_descriptor) const {
+  for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
+    PrintDescriptor(*containing_descriptor.nested_type(i));
   }
 }
 
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index 3b4c132..a77cf33 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -40,6 +40,7 @@
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/stubs/mutex.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -59,8 +60,6 @@
 namespace compiler {
 namespace python {
 
-enum class StripPrintDescriptor { kCreate, kFind };
-
 // CodeGenerator implementation for generated Python protocol buffer classes.
 // If you create your own protocol compiler binary and you want it to support
 // Python output, you can do so by registering an instance of this
@@ -68,7 +67,7 @@
 class PROTOC_EXPORT Generator : public CodeGenerator {
  public:
   Generator();
-  virtual ~Generator();
+  ~Generator() override;
 
   // CodeGenerator methods.
   bool Generate(const FileDescriptor* file, const std::string& parameter,
@@ -80,14 +79,9 @@
  private:
   void PrintImports() const;
   void PrintFileDescriptor() const;
-  void PrintTopLevelEnums() const;
-  void PrintAllNestedEnumsInFile(StripPrintDescriptor print_mode) const;
-  void PrintNestedEnums(const Descriptor& descriptor,
-                        StripPrintDescriptor print_mode) const;
-  void PrintCreateEnum(const EnumDescriptor& enum_descriptor) const;
-  void PrintFindEnum(const EnumDescriptor& enum_descriptor) const;
-
-  void PrintTopLevelExtensions() const;
+  void PrintAllNestedEnumsInFile() const;
+  void PrintNestedEnums(const Descriptor& descriptor) const;
+  void PrintEnum(const EnumDescriptor& enum_descriptor) const;
 
   void PrintFieldDescriptor(const FieldDescriptor& field,
                             bool is_extension) const;
@@ -97,11 +91,9 @@
       const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const;
   void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const;
   void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const;
-  void PrintMessageDescriptors(StripPrintDescriptor print_mode) const;
-  void PrintCreateDescriptor(const Descriptor& message_descriptor) const;
-  void PrintFindDescriptor(const Descriptor& message_descriptor) const;
-  void PrintNestedDescriptors(const Descriptor& containing_descriptor,
-                              StripPrintDescriptor print_mode) const;
+  void PrintMessageDescriptors() const;
+  void PrintDescriptor(const Descriptor& message_descriptor) const;
+  void PrintNestedDescriptors(const Descriptor& containing_descriptor) const;
 
   void PrintMessages() const;
   void PrintMessage(const Descriptor& message_descriptor,
diff --git a/src/google/protobuf/compiler/python/python_helpers.cc b/src/google/protobuf/compiler/python/python_helpers.cc
new file mode 100644
index 0000000..eae236f
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_helpers.cc
@@ -0,0 +1,131 @@
+// 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/python/python_helpers.h>
+
+#include <algorithm>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+// Returns the Python module name expected for a given .proto filename.
+std::string ModuleName(const std::string& filename) {
+  std::string basename = StripProto(filename);
+  ReplaceCharacters(&basename, "-", '_');
+  ReplaceCharacters(&basename, "/", '.');
+  return basename + "_pb2";
+}
+
+std::string StrippedModuleName(const std::string& filename) {
+  std::string module_name = ModuleName(filename);
+  return module_name;
+}
+
+// Keywords reserved by the Python language.
+const char* const kKeywords[] = {
+    "False",  "None",     "True",  "and",    "as",       "assert",
+    "async",  "await",    "break", "class",  "continue", "def",
+    "del",    "elif",     "else",  "except", "finally",  "for",
+    "from",   "global",   "if",    "import", "in",       "is",
+    "lambda", "nonlocal", "not",   "or",     "pass",     "raise",
+    "return", "try",      "while", "with",   "yield",    "print",
+};
+const char* const* kKeywordsEnd =
+    kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
+
+bool ContainsPythonKeyword(const std::string& module_name) {
+  std::vector<std::string> tokens = Split(module_name, ".");
+  for (int i = 0; i < static_cast<int>(tokens.size()); ++i) {
+    if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool IsPythonKeyword(const std::string& name) {
+  return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd);
+}
+
+std::string ResolveKeyword(const std::string& name) {
+  if (IsPythonKeyword(name)) {
+    return "globals()['" + name + "']";
+  }
+  return name;
+}
+
+std::string GetFileName(const FileDescriptor* file_des,
+                        const std::string& suffix) {
+  std::string module_name = ModuleName(file_des->name());
+  std::string filename = module_name;
+  ReplaceCharacters(&filename, ".", '/');
+  filename += suffix;
+  return filename;
+}
+
+bool HasGenericServices(const FileDescriptor* file) {
+  return file->service_count() > 0 && file->options().py_generic_services();
+}
+
+template <typename DescriptorT>
+std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
+                                        const std::string& separator) {
+  std::string name = descriptor.name();
+  const Descriptor* parent = descriptor.containing_type();
+  if (parent != nullptr) {
+    std::string prefix = NamePrefixedWithNestedTypes(*parent, separator);
+    if (separator == "." && IsPythonKeyword(name)) {
+      return "getattr(" + prefix + ", '" + name + "')";
+    } else {
+      return prefix + separator + name;
+    }
+  }
+  if (separator == ".") {
+    name = ResolveKeyword(name);
+  }
+  return name;
+}
+
+template std::string NamePrefixedWithNestedTypes<Descriptor>(
+    const Descriptor& descriptor, const std::string& separator);
+template std::string NamePrefixedWithNestedTypes<EnumDescriptor>(
+    const EnumDescriptor& descriptor, const std::string& separator);
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/src/google/protobuf/compiler/python/python_helpers.h
similarity index 61%
copy from java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
copy to src/google/protobuf/compiler/python/python_helpers.h
index baa6d08..a68ceb1 100644
--- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java
+++ b/src/google/protobuf/compiler/python/python_helpers.h
@@ -28,20 +28,35 @@
 // (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;
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
 
-/**
- * A prerun for a test suite that allows running the full protocol buffer tests in a mode that
- * disables the optimization for not using {@link RepeatedFieldBuilder} and {@link
- * SingleFieldBuilder} until they are requested. This allows us to run all the tests through both
- * code paths and ensures that both code paths produce identical results.
- *
- * @author jonp@google.com (Jon Perlow)
- */
-public class ForceFieldBuildersPreRun implements Runnable {
+#include <string>
 
-  @Override
-  public void run() {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
-  }
-}
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+
+std::string ModuleName(const std::string& filename);
+std::string StrippedModuleName(const std::string& filename);
+bool ContainsPythonKeyword(const std::string& module_name);
+bool IsPythonKeyword(const std::string& name);
+std::string ResolveKeyword(const std::string& name);
+std::string GetFileName(const FileDescriptor* file_des,
+                        const std::string& suffix);
+bool HasGenericServices(const FileDescriptor* file);
+
+template <typename DescriptorT>
+std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
+                                        const std::string& separator);
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
index 76ceef3..bc92b23 100644
--- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -55,11 +55,10 @@
 class TestGenerator : public CodeGenerator {
  public:
   TestGenerator() {}
-  ~TestGenerator() {}
+  ~TestGenerator() override {}
 
-  virtual bool Generate(const FileDescriptor* file,
-                        const std::string& parameter, GeneratorContext* context,
-                        std::string* error) const {
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* context, std::string* error) const override {
     TryInsert("test_pb2.py", "imports", context);
     TryInsert("test_pb2.py", "module_scope", context);
     TryInsert("test_pb2.py", "class_scope:foo.Bar", context);
@@ -77,37 +76,6 @@
   }
 };
 
-// This test verifies that all the expected insertion points exist.  It does
-// not verify that they are correctly-placed; that would require actually
-// compiling the output which is a bit more than I care to do for this test.
-TEST(PythonPluginTest, PluginTest) {
-  GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
-                             "syntax = \"proto2\";\n"
-                             "package foo;\n"
-                             "message Bar {\n"
-                             "  message Baz {}\n"
-                             "}\n",
-                             true));
-
-  compiler::CommandLineInterface cli;
-  cli.SetInputsAreProtoPathRelative(true);
-
-  python::Generator python_generator;
-  TestGenerator test_generator;
-  cli.RegisterGenerator("--python_out", &python_generator, "");
-  cli.RegisterGenerator("--test_out", &test_generator, "");
-
-  std::string proto_path = "-I" + TestTempDir();
-  std::string python_out = "--python_out=" + TestTempDir();
-  std::string test_out = "--test_out=" + TestTempDir();
-
-  const char* argv[] = {"protoc", proto_path.c_str(), python_out.c_str(),
-                        test_out.c_str(), "test.proto"};
-
-  EXPECT_EQ(0, cli.Run(5, argv));
-}
-
-// This test verifies that the generated Python output uses regular imports (as
 // opposed to importlib) in the usual case where the .proto file paths do not
 // not contain any Python keywords.
 TEST(PythonPluginTest, ImportTest) {
diff --git a/src/google/protobuf/compiler/python/python_pyi_generator.cc b/src/google/protobuf/compiler/python/python_pyi_generator.cc
new file mode 100644
index 0000000..d78d766
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_pyi_generator.cc
@@ -0,0 +1,558 @@
+// 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/python/python_pyi_generator.h>
+
+#include <string>
+
+#include <google/protobuf/compiler/python/python_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace python {
+
+template <typename DescriptorT>
+struct SortByName {
+  bool operator()(const DescriptorT* l, const DescriptorT* r) const {
+    return l->name() < r->name();
+  }
+};
+
+PyiGenerator::PyiGenerator() : file_(nullptr) {}
+
+PyiGenerator::~PyiGenerator() {}
+
+void PyiGenerator::PrintItemMap(
+    const std::map<std::string, std::string>& item_map) const {
+  for (const auto& entry : item_map) {
+    printer_->Print("$key$: $value$\n", "key", entry.first, "value",
+                    entry.second);
+  }
+}
+
+template <typename DescriptorT>
+std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
+  std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
+  if (descriptor.file() != file_) {
+    std::string module_name = ModuleName(descriptor.file()->name());
+    std::vector<std::string> tokens = Split(module_name, ".");
+    name = "_" + tokens.back() + "." + name;
+  }
+  return name;
+}
+
+struct ImportModules {
+  bool has_repeated = false;    // _containers
+  bool has_iterable = false;    // typing.Iterable
+  bool has_messages = false;    // _message
+  bool has_enums = false;       // _enum_type_wrapper
+  bool has_extendable = false;  // _python_message
+  bool has_mapping = false;     // typing.Mapping
+  bool has_optional = false;    // typing.Optional
+  bool has_union = false;       // typing.Uion
+};
+
+// Checks what modules should be imported for this message
+// descriptor.
+void CheckImportModules(const Descriptor* descriptor,
+                        ImportModules* import_modules) {
+  if (descriptor->extension_range_count() > 0) {
+    import_modules->has_extendable = true;
+  }
+  if (descriptor->enum_type_count() > 0) {
+    import_modules->has_enums = true;
+  }
+  for (int i = 0; i < descriptor->field_count(); ++i) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (IsPythonKeyword(field->name())) {
+      continue;
+    }
+    import_modules->has_optional = true;
+    if (field->is_repeated()) {
+      import_modules->has_repeated = true;
+    }
+    if (field->is_map()) {
+      import_modules->has_mapping = true;
+      const FieldDescriptor* value_des = field->message_type()->field(1);
+      if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
+          value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        import_modules->has_union = true;
+      }
+    } else {
+      if (field->is_repeated()) {
+        import_modules->has_iterable = true;
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        import_modules->has_union = true;
+        import_modules->has_mapping = true;
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        import_modules->has_union = true;
+      }
+    }
+  }
+  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+    CheckImportModules(descriptor->nested_type(i), import_modules);
+  }
+}
+
+void PyiGenerator::PrintImports(
+    std::map<std::string, std::string>* item_map) const {
+  // Prints imported dependent _pb2 files.
+  for (int i = 0; i < file_->dependency_count(); ++i) {
+    const std::string& filename = file_->dependency(i)->name();
+    std::string module_name = StrippedModuleName(filename);
+    size_t last_dot_pos = module_name.rfind('.');
+    std::string import_statement;
+    if (last_dot_pos == std::string::npos) {
+      import_statement = "import " + module_name;
+    } else {
+      import_statement = "from " + module_name.substr(0, last_dot_pos) +
+                         " import " + module_name.substr(last_dot_pos + 1);
+      module_name = module_name.substr(last_dot_pos + 1);
+    }
+    printer_->Print("$statement$ as _$module_name$\n", "statement",
+                    import_statement, "module_name", module_name);
+  }
+
+  // Checks what modules should be imported.
+  ImportModules import_modules;
+  if (file_->message_type_count() > 0) {
+    import_modules.has_messages = true;
+  }
+  if (file_->enum_type_count() > 0) {
+    import_modules.has_enums = true;
+  }
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    CheckImportModules(file_->message_type(i), &import_modules);
+  }
+
+  // Prints modules (e.g. _containers, _messages, typing) that are
+  // required in the proto file.
+  if (import_modules.has_repeated) {
+    printer_->Print(
+        "from google.protobuf.internal import containers as "
+        "_containers\n");
+  }
+  if (import_modules.has_enums) {
+    printer_->Print(
+        "from google.protobuf.internal import enum_type_wrapper"
+        " as _enum_type_wrapper\n");
+  }
+  if (import_modules.has_extendable) {
+    printer_->Print(
+        "from google.protobuf.internal import python_message"
+        " as _python_message\n");
+  }
+  printer_->Print(
+      "from google.protobuf import"
+      " descriptor as _descriptor\n");
+  if (import_modules.has_messages) {
+    printer_->Print(
+        "from google.protobuf import message as _message\n");
+  }
+  if (HasGenericServices(file_)) {
+    printer_->Print(
+        "from google.protobuf import service as"
+        " _service\n");
+  }
+  printer_->Print("from typing import ");
+  printer_->Print("ClassVar");
+  if (import_modules.has_iterable) {
+    printer_->Print(", Iterable");
+  }
+  if (import_modules.has_mapping) {
+    printer_->Print(", Mapping");
+  }
+  if (import_modules.has_optional) {
+    printer_->Print(", Optional");
+  }
+  if (file_->service_count() > 0) {
+    printer_->Print(", Text");
+  }
+  if (import_modules.has_union) {
+    printer_->Print(", Union");
+  }
+  printer_->Print("\n\n");
+
+  // Public imports
+  for (int i = 0; i < file_->public_dependency_count(); ++i) {
+    const FileDescriptor* public_dep = file_->public_dependency(i);
+    std::string module_name = StrippedModuleName(public_dep->name());
+    // Top level messages in public imports
+    for (int i = 0; i < public_dep->message_type_count(); ++i) {
+      printer_->Print("from $module$ import $message_class$\n", "module",
+                      module_name, "message_class",
+                      public_dep->message_type(i)->name());
+    }
+    // Top level enums for public imports
+    for (int i = 0; i < public_dep->enum_type_count(); ++i) {
+      printer_->Print("from $module$ import $enum_class$\n", "module",
+                      module_name, "enum_class",
+                      public_dep->enum_type(i)->name());
+    }
+    // Enum values for public imports
+    for (int i = 0; i < public_dep->enum_type_count(); ++i) {
+      const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
+      for (int j = 0; j < enum_descriptor->value_count(); ++j) {
+        (*item_map)[enum_descriptor->value(j)->name()] =
+            ModuleLevelName(*enum_descriptor);
+      }
+    }
+    // Top level extensions for public imports
+    AddExtensions(*public_dep, item_map);
+  }
+}
+
+void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
+  std::string enum_name = enum_descriptor.name();
+  printer_->Print(
+      "class $enum_name$(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):\n"
+      "    __slots__ = []\n",
+      "enum_name", enum_name);
+}
+
+// Adds enum value to item map which will be ordered and printed later.
+void PyiGenerator::AddEnumValue(
+    const EnumDescriptor& enum_descriptor,
+    std::map<std::string, std::string>* item_map) const {
+  // enum values
+  std::string module_enum_name = ModuleLevelName(enum_descriptor);
+  for (int j = 0; j < enum_descriptor.value_count(); ++j) {
+    const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j);
+    (*item_map)[value_descriptor->name()] = module_enum_name;
+  }
+}
+
+// Prints top level enums
+void PyiGenerator::PrintTopLevelEnums() const {
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    printer_->Print("\n");
+    PrintEnum(*file_->enum_type(i));
+  }
+}
+
+// Add top level extensions to item_map which will be ordered and
+// printed later.
+template <typename DescriptorT>
+void PyiGenerator::AddExtensions(
+    const DescriptorT& descriptor,
+    std::map<std::string, std::string>* item_map) const {
+  for (int i = 0; i < descriptor.extension_count(); ++i) {
+    const FieldDescriptor* extension_field = descriptor.extension(i);
+    std::string constant_name = extension_field->name() + "_FIELD_NUMBER";
+    ToUpper(&constant_name);
+    (*item_map)[constant_name] = "ClassVar[int]";
+    (*item_map)[extension_field->name()] = "_descriptor.FieldDescriptor";
+  }
+}
+
+// Returns the string format of a field's cpp_type
+std::string PyiGenerator::GetFieldType(const FieldDescriptor& field_des) const {
+  switch (field_des.cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return "int";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return "float";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return "bool";
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return ModuleLevelName(*field_des.enum_type());
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field_des.type() == FieldDescriptor::TYPE_STRING) {
+        return "str";
+      } else {
+        return "bytes";
+      }
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return ModuleLevelName(*field_des.message_type());
+    default:
+      GOOGLE_LOG(FATAL) << "Unsuppoted field type.";
+  }
+  return "";
+}
+
+void PyiGenerator::PrintMessage(const Descriptor& message_descriptor,
+                                bool is_nested) const {
+  if (!is_nested) {
+    printer_->Print("\n");
+  }
+  std::string class_name = message_descriptor.name();
+  printer_->Print("class $class_name$(_message.Message):\n", "class_name",
+                  class_name);
+  printer_->Indent();
+  printer_->Indent();
+
+  std::vector<const FieldDescriptor*> fields;
+  fields.reserve(message_descriptor.field_count());
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    fields.push_back(message_descriptor.field(i));
+  }
+  std::sort(fields.begin(), fields.end(), SortByName<FieldDescriptor>());
+
+  // Prints slots
+  printer_->Print("__slots__ = [", "class_name", class_name);
+  bool first_item = true;
+  for (const auto& field_des : fields) {
+    if (IsPythonKeyword(field_des->name())) {
+      continue;
+    }
+    if (first_item) {
+      first_item = false;
+    } else {
+      printer_->Print(", ");
+    }
+    printer_->Print("\"$field_name$\"", "field_name", field_des->name());
+  }
+  printer_->Print("]\n");
+
+  std::map<std::string, std::string> item_map;
+  // Prints Extensions for extendable messages
+  if (message_descriptor.extension_range_count() > 0) {
+    item_map["Extensions"] = "_python_message._ExtensionDict";
+  }
+
+  // Prints nested enums
+  std::vector<const EnumDescriptor*> nested_enums;
+  nested_enums.reserve(message_descriptor.enum_type_count());
+  for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
+    nested_enums.push_back(message_descriptor.enum_type(i));
+  }
+  std::sort(nested_enums.begin(), nested_enums.end(),
+            SortByName<EnumDescriptor>());
+
+  for (const auto& entry : nested_enums) {
+    PrintEnum(*entry);
+    // Adds enum value to item_map which will be ordered and printed later
+    AddEnumValue(*entry, &item_map);
+  }
+
+  // Prints nested messages
+  std::vector<const Descriptor*> nested_messages;
+  nested_messages.reserve(message_descriptor.nested_type_count());
+  for (int i = 0; i < message_descriptor.nested_type_count(); ++i) {
+    nested_messages.push_back(message_descriptor.nested_type(i));
+  }
+  std::sort(nested_messages.begin(), nested_messages.end(),
+            SortByName<Descriptor>());
+
+  for (const auto& entry : nested_messages) {
+    PrintMessage(*entry, true);
+  }
+
+  // Adds extensions to item_map which will be ordered and printed later
+  AddExtensions(message_descriptor, &item_map);
+
+  // Adds field number and field descriptor to item_map
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    const FieldDescriptor& field_des = *message_descriptor.field(i);
+    item_map[ToUpper(field_des.name()) + "_FIELD_NUMBER"] =
+        "ClassVar[int]";
+    if (IsPythonKeyword(field_des.name())) {
+      continue;
+    }
+    std::string field_type = "";
+    if (field_des.is_map()) {
+      const FieldDescriptor* key_des = field_des.message_type()->field(0);
+      const FieldDescriptor* value_des = field_des.message_type()->field(1);
+      field_type = (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+                        ? "_containers.MessageMap["
+                        : "_containers.ScalarMap[");
+      field_type += GetFieldType(*key_des);
+      field_type += ", ";
+      field_type += GetFieldType(*value_des);
+    } else {
+      if (field_des.is_repeated()) {
+        field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
+                          ? "_containers.RepeatedCompositeFieldContainer["
+                          : "_containers.RepeatedScalarFieldContainer[");
+      }
+      field_type += GetFieldType(field_des);
+    }
+
+    if (field_des.is_repeated()) {
+      field_type += "]";
+    }
+    item_map[field_des.name()] = field_type;
+  }
+
+  // Prints all items in item_map
+  PrintItemMap(item_map);
+
+  // Prints __init__
+  printer_->Print("def __init__(self");
+  bool has_key_words = false;
+  bool is_first = true;
+  for (int i = 0; i < message_descriptor.field_count(); ++i) {
+    const FieldDescriptor* field_des = message_descriptor.field(i);
+    if (IsPythonKeyword(field_des->name())) {
+      has_key_words = true;
+      continue;
+    }
+    std::string field_name = field_des->name();
+    if (is_first && field_name == "self") {
+      // See b/144146793 for an example of real code that generates a (self,
+      // self) method signature. Since repeating a parameter name is illegal in
+      // Python, we rename the duplicate self.
+      field_name = "self_";
+    }
+    is_first = false;
+    printer_->Print(", $field_name$: ", "field_name", field_name);
+    if (field_des->is_repeated() ||
+        field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
+      printer_->Print("Optional[");
+    }
+    if (field_des->is_map()) {
+      const Descriptor* map_entry = field_des->message_type();
+      printer_->Print("Mapping[$key_type$, $value_type$]", "key_type",
+                      GetFieldType(*map_entry->field(0)), "value_type",
+                      GetFieldType(*map_entry->field(1)));
+    } else {
+      if (field_des->is_repeated()) {
+        printer_->Print("Iterable[");
+      }
+      if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        printer_->Print("Union[$type_name$, Mapping]", "type_name",
+                        GetFieldType(*field_des));
+      } else {
+        if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+          printer_->Print("Union[$type_name$, str]", "type_name",
+                          ModuleLevelName(*field_des->enum_type()));
+        } else {
+          printer_->Print("$type_name$", "type_name", GetFieldType(*field_des));
+        }
+      }
+      if (field_des->is_repeated()) {
+        printer_->Print("]");
+      }
+    }
+    if (field_des->is_repeated() ||
+        field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
+      printer_->Print("]");
+    }
+    printer_->Print(" = ...");
+  }
+  if (has_key_words) {
+    printer_->Print(", **kwargs");
+  }
+  printer_->Print(") -> None: ...\n");
+
+  printer_->Outdent();
+  printer_->Outdent();
+}
+
+void PyiGenerator::PrintMessages() const {
+  // Order the descriptors by name to have same output with proto_to_pyi.py
+  std::vector<const Descriptor*> messages;
+  messages.reserve(file_->message_type_count());
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    messages.push_back(file_->message_type(i));
+  }
+  std::sort(messages.begin(), messages.end(), SortByName<Descriptor>());
+
+  for (const auto& entry : messages) {
+    PrintMessage(*entry, false);
+  }
+}
+
+void PyiGenerator::PrintServices() const {
+  std::vector<const ServiceDescriptor*> services;
+  services.reserve(file_->service_count());
+  for (int i = 0; i < file_->service_count(); ++i) {
+    services.push_back(file_->service(i));
+  }
+  std::sort(services.begin(), services.end(), SortByName<ServiceDescriptor>());
+
+  // Prints $Service$ and $Service$_Stub classes
+  for (const auto& entry : services) {
+    printer_->Print("\n");
+    printer_->Print(
+        "class $service_name$(_service.service): ...\n\n"
+        "class $service_name$_Stub($service_name$): ...\n",
+        "service_name", entry->name());
+  }
+}
+
+bool PyiGenerator::Generate(const FileDescriptor* file,
+                            const std::string& parameter,
+                            GeneratorContext* context,
+                            std::string* error) const {
+  MutexLock lock(&mutex_);
+  // Calculate file name.
+  file_ = file;
+  // proto_to_pyi.py may set the output file name directly. To replace
+  // proto_to_pyi.py in google3, protoc also accept --pyi_out to set
+  // the output file name.
+  std::string filename =
+      parameter.empty() ? GetFileName(file, ".pyi") : parameter;
+
+  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  GOOGLE_CHECK(output.get());
+  io::Printer printer(output.get(), '$');
+  printer_ = &printer;
+
+  // item map will store "DESCRIPTOR", top level extensions, top level enum
+  // values. The items will be sorted and printed later.
+  std::map<std::string, std::string> item_map;
+
+  // Adds "DESCRIPTOR" into item_map.
+  item_map["DESCRIPTOR"] = "_descriptor.FileDescriptor";
+  PrintImports(&item_map);
+  // Adds top level enum values to item_map.
+  for (int i = 0; i < file_->enum_type_count(); ++i) {
+    AddEnumValue(*file_->enum_type(i), &item_map);
+  }
+  // Adds top level extensions to item_map.
+  AddExtensions(*file_, &item_map);
+  // Prints item map
+  PrintItemMap(item_map);
+
+  PrintMessages();
+  PrintTopLevelEnums();
+  if (HasGenericServices(file)) {
+    PrintServices();
+  }
+  return true;
+}
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/python/python_pyi_generator.h b/src/google/protobuf/compiler/python/python_pyi_generator.h
new file mode 100644
index 0000000..5d382be
--- /dev/null
+++ b/src/google/protobuf/compiler/python/python_pyi_generator.h
@@ -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.
+
+// Author: jieluo@google.com (Jie Luo)
+//
+// Generates Python stub (.pyi) for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/stubs/mutex.h>
+
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+class Descriptor;
+class EnumDescriptor;
+class FieldDescriptor;
+class MethodDescriptor;
+class ServiceDescriptor;
+
+namespace io {
+class Printer;
+}
+
+namespace compiler {
+namespace python {
+
+class PROTOC_EXPORT PyiGenerator : public google::protobuf::compiler::CodeGenerator {
+ public:
+  PyiGenerator();
+  ~PyiGenerator() override;
+
+  // CodeGenerator methods.
+  bool Generate(const FileDescriptor* file, const std::string& parameter,
+                GeneratorContext* generator_context,
+                std::string* error) const override;
+
+ private:
+  void PrintImports(std::map<std::string, std::string>* item_map) const;
+  void PrintEnum(const EnumDescriptor& enum_descriptor) const;
+  void AddEnumValue(const EnumDescriptor& enum_descriptor,
+                    std::map<std::string, std::string>* item_map) const;
+  void PrintTopLevelEnums() const;
+  template <typename DescriptorT>
+  void AddExtensions(const DescriptorT& descriptor,
+                     std::map<std::string, std::string>* item_map) const;
+  void PrintMessages() const;
+  void PrintMessage(const Descriptor& message_descriptor, bool is_nested) const;
+  void PrintServices() const;
+  void PrintItemMap(const std::map<std::string, std::string>& item_map) const;
+  std::string GetFieldType(const FieldDescriptor& field_des) const;
+  template <typename DescriptorT>
+  std::string ModuleLevelName(const DescriptorT& descriptor) const;
+
+  // Very coarse-grained lock to ensure that Generate() is reentrant.
+  // Guards file_ and printer_.
+  mutable Mutex mutex_;
+  mutable const FileDescriptor* file_;  // Set in Generate().  Under mutex_.
+  mutable io::Printer* printer_;        // Set in Generate().  Under mutex_.
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PyiGenerator);
+};
+
+}  // namespace python
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/scc.h b/src/google/protobuf/compiler/scc.h
index a139460..7b95689 100644
--- a/src/google/protobuf/compiler/scc.h
+++ b/src/google/protobuf/compiler/scc.h
@@ -37,6 +37,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 7e59cd7..f79d127 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -55,7 +55,7 @@
 namespace {
 char* portable_strdup(const char* s) {
   char* ns = (char*)malloc(strlen(s) + 1);
-  if (ns != NULL) {
+  if (ns != nullptr) {
     strcpy(ns, s);
   }
   return ns;
@@ -309,7 +309,7 @@
   GOOGLE_CHECK(pipe(stdin_pipe) != -1);
   GOOGLE_CHECK(pipe(stdout_pipe) != -1);
 
-  char* argv[2] = {portable_strdup(program.c_str()), NULL};
+  char* argv[2] = {portable_strdup(program.c_str()), nullptr};
 
   child_pid_ = fork();
   if (child_pid_ == -1) {
@@ -386,7 +386,7 @@
       FD_SET(child_stdin_, &write_fds);
     }
 
-    if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
+    if (select(max_fd + 1, &read_fds, &write_fds, nullptr, nullptr) < 0) {
       if (errno == EINTR) {
         // Interrupted by signal.  Try again.
         continue;
diff --git a/src/google/protobuf/compiler/subprocess.h b/src/google/protobuf/compiler/subprocess.h
index c1ddaae..5cb784d 100644
--- a/src/google/protobuf/compiler/subprocess.h
+++ b/src/google/protobuf/compiler/subprocess.h
@@ -46,6 +46,7 @@
 
 #include <string>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 9a984c4..8738df9 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -42,6 +42,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <type_traits>
 #include <unordered_map>
 #include <unordered_set>
 #include <vector>
@@ -50,21 +51,21 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/any.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/stubs/once.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/descriptor_database.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/io/strtod.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/stubs/substitute.h>
-#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/hash.h>
@@ -72,11 +73,444 @@
 #undef PACKAGE  // autoheader #defines this.  :(
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
 
+namespace {
+const int kPackageLimit = 100;
+
+// Note:  I distrust ctype.h due to locales.
+char ToUpper(char ch) {
+  return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
+}
+
+char ToLower(char ch) {
+  return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
+}
+
+std::string ToCamelCase(const std::string& input, bool lower_first) {
+  bool capitalize_next = !lower_first;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  // Lower-case the first letter.
+  if (lower_first && !result.empty()) {
+    result[0] = ToLower(result[0]);
+  }
+
+  return result;
+}
+
+std::string ToJsonName(const std::string& input) {
+  bool capitalize_next = false;
+  std::string result;
+  result.reserve(input.size());
+
+  for (char character : input) {
+    if (character == '_') {
+      capitalize_next = true;
+    } else if (capitalize_next) {
+      result.push_back(ToUpper(character));
+      capitalize_next = false;
+    } else {
+      result.push_back(character);
+    }
+  }
+
+  return result;
+}
+
+// Backport of fold expressions for the comma operator to C++11.
+// Usage:  Fold({expr...});
+// Guaranteed to evaluate left-to-right
+struct ExpressionEater {
+  template <typename T>
+  ExpressionEater(T&&) {}  // NOLINT
+};
+void Fold(std::initializer_list<ExpressionEater>) {}
+
+constexpr size_t RoundUp(size_t n) { return (n + 7) & ~7; }
+
+template <typename T>
+constexpr int FindTypeIndex() {
+  return -1;
+}
+
+template <typename T, typename T1, typename... Ts>
+constexpr int FindTypeIndex() {
+  return std::is_same<T, T1>::value ? 0 : FindTypeIndex<T, Ts...>() + 1;
+}
+
+// A type to value map, where the possible keys as specified in `Keys...`.
+// The values for key `K` is `ValueT<K>`
+template <template <typename> class ValueT, typename... Keys>
+class TypeMap {
+ public:
+  template <typename K>
+  ValueT<K>& Get() {
+    return static_cast<Base<K>&>(payload_).value;
+  }
+
+  template <typename K>
+  const ValueT<K>& Get() const {
+    return static_cast<const Base<K>&>(payload_).value;
+  }
+
+ private:
+  template <typename K>
+  struct Base {
+    ValueT<K> value{};
+  };
+  struct Payload : Base<Keys>... {};
+  Payload payload_;
+};
+
+template <typename T>
+using IntT = int;
+template <typename T>
+using PointerT = T*;
+
+// Manages an allocation of sequential arrays of type `T...`.
+// It is more space efficient than storing N (ptr, size) pairs, by storing only
+// the pointer to the head and the boundaries between the arrays.
+template <typename... T>
+class FlatAllocation {
+ public:
+  FlatAllocation(const TypeMap<IntT, T...>& ends) : ends_(ends) {
+    // The arrays start just after FlatAllocation, so adjust the ends.
+    Fold({(ends_.template Get<T>() += RoundUp(sizeof(FlatAllocation)))...});
+    Fold({Init<T>()...});
+  }
+
+  void Destroy() {
+    Fold({Destroy<T>()...});
+    internal::SizedDelete(this, total_bytes());
+  }
+
+  template <int I>
+  using type = typename std::tuple_element<I, std::tuple<T...>>::type;
+
+  // Gets a tuple of the head pointers for the arrays
+  TypeMap<PointerT, T...> Pointers() const {
+    TypeMap<PointerT, T...> out;
+    Fold({(out.template Get<T>() = Begin<T>())...});
+    return out;
+  }
+
+
+ private:
+  // Total number of bytes used by all arrays.
+  int total_bytes() const {
+    // Get the last end.
+    return ends_.template Get<typename std::tuple_element<
+        sizeof...(T) - 1, std::tuple<T...>>::type>();
+  }
+
+
+  template <typename U>
+  int BeginOffset() const {
+    constexpr int type_index = FindTypeIndex<U, T...>();
+    // Avoid a negative value here to keep it compiling when type_index == 0
+    constexpr int prev_type_index = type_index == 0 ? 0 : type_index - 1;
+    using PrevType =
+        typename std::tuple_element<prev_type_index, std::tuple<T...>>::type;
+    return type_index == 0 ? RoundUp(sizeof(FlatAllocation))
+                           : ends_.template Get<PrevType>();
+  }
+
+  template <typename U>
+  U* Begin() const {
+    auto begin = BeginOffset<U>();
+    // Avoid the reinterpret_cast if the array is empty.
+    // Clang's Control Flow Integrity does not like the cast pointing to memory
+    // that is not yet initialized to be of that type.
+    // (from -fsanitize=cfi-unrelated-cast)
+    if (begin == ends_.template Get<U>()) return nullptr;
+    return reinterpret_cast<U*>(data() + begin);
+  }
+
+  // Due to alignment the end offset could contain some extra bytes that do not
+  // belong to any object.
+  // Calculate the actual size by dividing the space by sizeof(U) to drop the
+  // extra bytes. If we calculate end as `data + offset` we can have an invalid
+  // pointer.
+  template <typename U>
+  size_t Size() const {
+    return static_cast<size_t>(ends_.template Get<U>() - BeginOffset<U>()) /
+           sizeof(U);
+  }
+
+  template <typename U>
+  bool Init() {
+    // Skip for the `char` block. No need to zero initialize it.
+    if (std::is_same<U, char>::value) return true;
+    for (int i = 0, size = Size<U>(); i < size; ++i) {
+      ::new (data() + BeginOffset<U>() + sizeof(U) * i) U{};
+    }
+    return true;
+  }
+
+  template <typename U>
+  bool Destroy() {
+    if (std::is_trivially_destructible<U>::value) return true;
+    for (U* it = Begin<U>(), *end = it + Size<U>(); it != end; ++it) {
+      it->~U();
+    }
+    return true;
+  }
+
+  char* data() const {
+    return const_cast<char*>(reinterpret_cast<const char*>(this));
+  }
+
+  TypeMap<IntT, T...> ends_;
+};
+
+template <typename... T>
+TypeMap<IntT, T...> CalculateEnds(const TypeMap<IntT, T...>& sizes) {
+  int total = 0;
+  TypeMap<IntT, T...> out;
+  Fold({(out.template Get<T>() = total +=
+         RoundUp(sizeof(T) * sizes.template Get<T>()))...});
+  return out;
+}
+
+// The implementation for FlatAllocator below.
+// This separate class template makes it easier to have methods that fold on
+// `T...`.
+template <typename... T>
+class FlatAllocatorImpl {
+ public:
+  using Allocation = FlatAllocation<T...>;
+
+  template <typename U>
+  void PlanArray(int array_size) {
+    // We can't call PlanArray after FinalizePlanning has been called.
+    GOOGLE_CHECK(!has_allocated());
+    if (std::is_trivially_destructible<U>::value) {
+      total_.template Get<char>() += RoundUp(array_size * sizeof(U));
+    } else {
+      // Since we can't use `if constexpr`, just make the expression compile
+      // when this path is not taken.
+      using TypeToUse =
+          typename std::conditional<std::is_trivially_destructible<U>::value,
+                                    char, U>::type;
+      total_.template Get<TypeToUse>() += array_size;
+    }
+  }
+
+  template <typename U>
+  U* AllocateArray(int array_size) {
+    constexpr bool trivial = std::is_trivially_destructible<U>::value;
+    using TypeToUse = typename std::conditional<trivial, char, U>::type;
+
+    // We can only allocate after FinalizePlanning has been called.
+    GOOGLE_CHECK(has_allocated());
+
+    TypeToUse*& data = pointers_.template Get<TypeToUse>();
+    int& used = used_.template Get<TypeToUse>();
+    U* res = reinterpret_cast<U*>(data + used);
+    used += trivial ? RoundUp(array_size * sizeof(U)) : array_size;
+    GOOGLE_CHECK_LE(used, total_.template Get<TypeToUse>());
+    return res;
+  }
+
+  template <typename... In>
+  const std::string* AllocateStrings(In&&... in) {
+    std::string* strings = AllocateArray<std::string>(sizeof...(in));
+    std::string* res = strings;
+    Fold({(*strings++ = std::string(std::forward<In>(in)))...});
+    return res;
+  }
+
+  // Allocate all 5 names of the field:
+  // name, full name, lowercase, camelcase and json.
+  // It will dedup the strings when possible.
+  // The resulting array contains `name` at index 0, `full_name` at index 1
+  // and the other 3 indices are specified in the result.
+  void PlanFieldNames(const std::string& name,
+                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(!has_allocated());
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return PlanArray<std::string>(2);
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return PlanArray<std::string>(3);
+        default:
+          break;
+      }
+    }
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+
+    std::string camelcase_name = ToCamelCase(name, /* lower_first = */ true);
+    std::string json_name =
+        opt_json_name != nullptr ? *opt_json_name : ToJsonName(name);
+
+    StringPiece all_names[] = {name, lowercase_name, camelcase_name,
+                                     json_name};
+    std::sort(all_names, all_names + 4);
+    int unique =
+        static_cast<int>(std::unique(all_names, all_names + 4) - all_names);
+
+    PlanArray<std::string>(unique + 1);
+  }
+
+  struct FieldNamesResult {
+    const std::string* array;
+    int lowercase_index;
+    int camelcase_index;
+    int json_index;
+  };
+  FieldNamesResult AllocateFieldNames(const std::string& name,
+                                      const std::string& scope,
+                                      const std::string* opt_json_name) {
+    GOOGLE_CHECK(has_allocated());
+
+    std::string full_name =
+        scope.empty() ? name : StrCat(scope, ".", name);
+
+    // Fast path for snake_case names, which follow the style guide.
+    if (opt_json_name == nullptr) {
+      switch (GetFieldNameCase(name)) {
+        case FieldNameCase::kAllLower:
+          // Case 1: they are all the same.
+          return {AllocateStrings(name, std::move(full_name)), 0, 0, 0};
+        case FieldNameCase::kSnakeCase:
+          // Case 2: name==lower, camel==json
+          return {AllocateStrings(name, std::move(full_name),
+                                  ToCamelCase(name, /* lower_first = */ true)),
+                  0, 2, 2};
+        default:
+          break;
+      }
+    }
+
+    std::vector<std::string> names;
+    names.push_back(name);
+    names.push_back(std::move(full_name));
+
+    const auto push_name = [&](std::string new_name) {
+      for (size_t i = 0; i < names.size(); ++i) {
+        if (names[i] == new_name) return i;
+      }
+      names.push_back(std::move(new_name));
+      return names.size() - 1;
+    };
+
+    FieldNamesResult result{nullptr, 0, 0, 0};
+
+    std::string lowercase_name = name;
+    LowerString(&lowercase_name);
+    result.lowercase_index = push_name(std::move(lowercase_name));
+    result.camelcase_index =
+        push_name(ToCamelCase(name, /* lower_first = */ true));
+    result.json_index =
+        push_name(opt_json_name != nullptr ? *opt_json_name : ToJsonName(name));
+
+    std::string* all_names = AllocateArray<std::string>(names.size());
+    result.array = all_names;
+    std::move(names.begin(), names.end(), all_names);
+
+    return result;
+  }
+
+  template <typename Alloc>
+  void FinalizePlanning(Alloc& alloc) {
+    GOOGLE_CHECK(!has_allocated());
+
+    pointers_ = alloc->CreateFlatAlloc(total_)->Pointers();
+
+    GOOGLE_CHECK(has_allocated());
+  }
+
+  void ExpectConsumed() const {
+    // We verify that we consumed all the memory requested if there was no
+    // error in processing.
+    Fold({ExpectConsumed<T>()...});
+  }
+
+ private:
+  bool has_allocated() const {
+    return pointers_.template Get<char>() != nullptr;
+  }
+
+  static bool IsLower(char c) { return 'a' <= c && c <= 'z'; }
+  static bool IsDigit(char c) { return '0' <= c && c <= '9'; }
+  static bool IsLowerOrDigit(char c) { return IsLower(c) || IsDigit(c); }
+
+  enum class FieldNameCase { kAllLower, kSnakeCase, kOther };
+  FieldNameCase GetFieldNameCase(const std::string& name) {
+    if (!IsLower(name[0])) return FieldNameCase::kOther;
+    FieldNameCase best = FieldNameCase::kAllLower;
+    for (char c : name) {
+      if (IsLowerOrDigit(c)) {
+        // nothing to do
+      } else if (c == '_') {
+        best = FieldNameCase::kSnakeCase;
+      } else {
+        return FieldNameCase::kOther;
+      }
+    }
+    return best;
+  }
+
+  template <typename U>
+  bool ExpectConsumed() const {
+    GOOGLE_CHECK_EQ(total_.template Get<U>(), used_.template Get<U>());
+    return true;
+  }
+
+  TypeMap<PointerT, T...> pointers_;
+  TypeMap<IntT, T...> total_;
+  TypeMap<IntT, T...> used_;
+};
+
+}  // namespace
+
+namespace internal {
+
+// Small sequential allocator to be used within a single file.
+// Most of the memory for a single FileDescriptor and everything under it is
+// allocated in a single block of memory, with the FlatAllocator giving it out
+// in parts later.
+// The code first plans the total number of bytes needed by calling PlanArray
+// with all the allocations that will happen afterwards, then calls
+// FinalizePlanning passing the underlying allocator (the DescriptorPool::Tables
+// instance), and then proceeds to get the memory via
+// `AllocateArray`/`AllocateString` calls. The calls to PlanArray and
+// The calls have to match between planning and allocating, though not
+// necessarily in the same order.
+class FlatAllocator
+    : public FlatAllocatorImpl<
+          char, std::string, SourceCodeInfo, FileDescriptorTables,
+          // Option types
+          MessageOptions, FieldOptions, EnumOptions, EnumValueOptions,
+          ExtensionRangeOptions, OneofOptions, ServiceOptions, MethodOptions,
+          FileOptions> {};
+
+}  // namespace internal
+
 class Symbol {
  public:
   enum Type {
@@ -89,11 +523,17 @@
     ENUM_VALUE_OTHER_PARENT,
     SERVICE,
     METHOD,
-    PACKAGE,
+    FULL_PACKAGE,
+    SUB_PACKAGE,
     QUERY_KEY
   };
 
-  Symbol() : ptr_(nullptr) {}
+  Symbol() {
+    static constexpr internal::SymbolBase null_symbol{};
+    static_assert(null_symbol.symbol_type_ == NULL_SYMBOL, "");
+    // Initialize with a sentinel to make sure `ptr_` is never null.
+    ptr_ = &null_symbol;
+  }
 
   // Every object we store derives from internal::SymbolBase, where we store the
   // symbol type enum.
@@ -113,15 +553,16 @@
   DEFINE_MEMBERS(EnumDescriptor, ENUM, enum_descriptor)
   DEFINE_MEMBERS(ServiceDescriptor, SERVICE, service_descriptor)
   DEFINE_MEMBERS(MethodDescriptor, METHOD, method_descriptor)
+  DEFINE_MEMBERS(FileDescriptor, FULL_PACKAGE, file_descriptor)
 
-  // We use a special node for FileDescriptor.
+  // We use a special node for subpackage FileDescriptor.
   // It is potentially added to the table with multiple different names, so we
   // need a separate place to put the name.
-  struct Package : internal::SymbolBase {
-    const std::string* name;
+  struct Subpackage : internal::SymbolBase {
+    int name_size;
     const FileDescriptor* file;
   };
-  DEFINE_MEMBERS(Package, PACKAGE, package_file_descriptor)
+  DEFINE_MEMBERS(Subpackage, SUB_PACKAGE, sub_package_file_descriptor)
 
   // Enum values have two different parents.
   // We use two different identitied for the same object to determine the two
@@ -153,23 +594,42 @@
   // Not a real symbol.
   // Only used for heterogeneous lookups and never actually inserted in the
   // tables.
+  // TODO(b/215557658): If we templetize QueryKey on the expected object type we
+  // can skip the switches for the eq function altogether.
   struct QueryKey : internal::SymbolBase {
     StringPiece name;
     const void* parent;
     int field_number;
+
+    // Adaptor functions to look like a Symbol to the comparators.
+    StringPiece full_name() const { return name; }
+    std::pair<const void*, int> parent_number_key() const {
+      return {parent, field_number};
+    }
+    std::pair<const void*, StringPiece> parent_name_key() const {
+      return {parent, name};
+    }
   };
-  DEFINE_MEMBERS(QueryKey, QUERY_KEY, query_key);
+  // This constructor is implicit to allow for non-transparent lookups when
+  // necessary.
+  // For transparent lookup cases we query directly with the object without the
+  // type erasure layer.
+  Symbol(QueryKey& value) : ptr_(&value) {  // NOLINT
+    value.symbol_type_ = QUERY_KEY;
+  }
+  const QueryKey* query_key() const {
+    return type() == QUERY_KEY ? static_cast<const QueryKey*>(ptr_) : nullptr;
+  }
 #undef DEFINE_MEMBERS
 
-  Type type() const {
-    return ptr_ == nullptr ? NULL_SYMBOL
-                           : static_cast<Type>(ptr_->symbol_type_);
-  }
+  Type type() const { return static_cast<Type>(ptr_->symbol_type_); }
   bool IsNull() const { return type() == NULL_SYMBOL; }
   bool IsType() const { return type() == MESSAGE || type() == ENUM; }
   bool IsAggregate() const {
-    return type() == MESSAGE || type() == PACKAGE || type() == ENUM ||
-           type() == SERVICE;
+    return IsType() || IsPackage() || type() == SERVICE;
+  }
+  bool IsPackage() const {
+    return type() == FULL_PACKAGE || type() == SUB_PACKAGE;
   }
 
   const FileDescriptor* GetFile() const {
@@ -188,8 +648,10 @@
         return service_descriptor()->file();
       case METHOD:
         return method_descriptor()->service()->file();
-      case PACKAGE:
-        return package_file_descriptor()->file;
+      case FULL_PACKAGE:
+        return file_descriptor();
+      case SUB_PACKAGE:
+        return sub_package_file_descriptor()->file;
       default:
         return nullptr;
     }
@@ -211,10 +673,13 @@
         return service_descriptor()->full_name();
       case METHOD:
         return method_descriptor()->full_name();
-      case PACKAGE:
-        return *package_file_descriptor()->name;
+      case FULL_PACKAGE:
+        return file_descriptor()->package();
+      case SUB_PACKAGE:
+        return StringPiece(sub_package_file_descriptor()->file->package())
+            .substr(0, sub_package_file_descriptor()->name_size);
       case QUERY_KEY:
-        return query_key()->name;
+        return query_key()->full_name();
       default:
         GOOGLE_CHECK(false);
     }
@@ -249,7 +714,7 @@
       case METHOD:
         return {method_descriptor()->service(), method_descriptor()->name()};
       case QUERY_KEY:
-        return {query_key()->parent, query_key()->name};
+        return query_key()->parent_name_key();
       default:
         GOOGLE_CHECK(false);
     }
@@ -265,7 +730,7 @@
         return {enum_value_descriptor()->type(),
                 enum_value_descriptor()->number()};
       case QUERY_KEY:
-        return {query_key()->parent, query_key()->field_number};
+        return query_key()->parent_number_key();
       default:
         GOOGLE_CHECK(false);
     }
@@ -369,58 +834,6 @@
 
 namespace {
 
-// Note:  I distrust ctype.h due to locales.
-char ToUpper(char ch) {
-  return (ch >= 'a' && ch <= 'z') ? (ch - 'a' + 'A') : ch;
-}
-
-char ToLower(char ch) {
-  return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
-}
-
-std::string ToCamelCase(const std::string& input, bool lower_first) {
-  bool capitalize_next = !lower_first;
-  std::string result;
-  result.reserve(input.size());
-
-  for (char character : input) {
-    if (character == '_') {
-      capitalize_next = true;
-    } else if (capitalize_next) {
-      result.push_back(ToUpper(character));
-      capitalize_next = false;
-    } else {
-      result.push_back(character);
-    }
-  }
-
-  // Lower-case the first letter.
-  if (lower_first && !result.empty()) {
-    result[0] = ToLower(result[0]);
-  }
-
-  return result;
-}
-
-std::string ToJsonName(const std::string& input) {
-  bool capitalize_next = false;
-  std::string result;
-  result.reserve(input.size());
-
-  for (char character : input) {
-    if (character == '_') {
-      capitalize_next = true;
-    } else if (capitalize_next) {
-      result.push_back(ToUpper(character));
-      capitalize_next = false;
-    } else {
-      result.push_back(character);
-    }
-  }
-
-  return result;
-}
-
 std::string EnumValueToPascalCase(const std::string& input) {
   bool next_upper = true;
   std::string result;
@@ -560,15 +973,19 @@
 };
 
 
-const Symbol kNullSymbol;
-
 struct SymbolByFullNameHash {
-  size_t operator()(Symbol s) const {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
     return HASH_FXN<StringPiece>{}(s.full_name());
   }
 };
 struct SymbolByFullNameEq {
-  bool operator()(Symbol a, Symbol b) const {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
     return a.full_name() == b.full_name();
   }
 };
@@ -576,12 +993,18 @@
     HASH_SET<Symbol, SymbolByFullNameHash, SymbolByFullNameEq>;
 
 struct SymbolByParentHash {
-  size_t operator()(Symbol s) const {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
     return PointerStringPairHash{}(s.parent_name_key());
   }
 };
 struct SymbolByParentEq {
-  bool operator()(Symbol a, Symbol b) const {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
     return a.parent_name_key() == b.parent_name_key();
   }
 };
@@ -597,13 +1020,19 @@
     FieldsByNameMap;
 
 struct FieldsByNumberHash {
-  size_t operator()(Symbol s) const {
+  using is_transparent = void;
+
+  template <typename T>
+  size_t operator()(const T& s) const {
     return PointerIntegerPairHash<std::pair<const void*, int>>{}(
         s.parent_number_key());
   }
 };
 struct FieldsByNumberEq {
-  bool operator()(Symbol a, Symbol b) const {
+  using is_transparent = void;
+
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
     return a.parent_number_key() == b.parent_number_key();
   }
 };
@@ -649,403 +1078,6 @@
          allowed_proto3_extendees->end();
 }
 
-// This bump allocator arena is optimized for the use case of this file. It is
-// mostly optimized for memory usage, since these objects are expected to live
-// for the entirety of the program.
-//
-// Some differences from other arenas:
-//  - It has a fixed number of non-trivial types it can hold. This allows
-//    tracking the allocations with a single byte. In contrast, google::protobuf::Arena
-//    uses 16 bytes per non-trivial object created.
-//  - It has some extra metadata for rollbacks. This is necessary for
-//    implementing the API below. This metadata is flushed at the end and would
-//    not cause persistent memory usage.
-//  - It tries to squeeze every byte of out the blocks. If an allocation is too
-//    large for the current block we move the block to a secondary area where we
-//    can still use it for smaller objects. This complicates rollback logic but
-//    makes it much more memory efficient.
-//
-//  The allocation strategy is as follows:
-//   - Memory is allocated from the front, with a forced 8 byte alignment.
-//   - Metadata is allocated from the back, one byte per element.
-//   - The metadata encodes one of two things:
-//     * For types we want to track, the index into KnownTypes.
-//     * For raw memory blocks, the size of the block (in 8 byte increments
-//       to allow for a larger limit).
-//   - When the raw data is too large to represent in the metadata byte, we
-//     allocate this memory separately in the heap and store an OutOfLineAlloc
-//     object instead. These come from large array allocations and alike.
-//
-//  Blocks are kept in 3 areas:
-//   - `current_` is the one we are currently allocating from. When we need to
-//     allocate a block that doesn't fit there, we make a new block and move the
-//     old `current_` to one of the areas below.
-//   - Blocks that have no more usable space left (ie less than 9 bytes) are
-//     stored in `full_blocks_`.
-//   - Blocks that have some usable space are categorized in
-//     `small_size_blocks_` depending on how much space they have left.
-//     See `kSmallSizes` to see which sizes we track.
-//
-class TableArena {
- public:
-  // Allocate a block on `n` bytes, with no destructor information saved.
-  void* AllocateMemory(uint32_t n) {
-    uint32_t tag = SizeToRawTag(n) + kFirstRawTag;
-    if (tag > 255) {
-      // We can't fit the size, use an OutOfLineAlloc.
-      return Create<OutOfLineAlloc>(OutOfLineAlloc{::operator new(n), n})->ptr;
-    }
-
-    return AllocRawInternal(n, static_cast<Tag>(tag));
-  }
-
-  // Allocate and construct an element of type `T` as if by
-  // `T(std::forward<Args>(args...))`.
-  // The object is registered for destruction, if its destructor is not trivial.
-  template <typename T, typename... Args>
-  T* Create(Args&&... args) {
-    static_assert(alignof(T) <= 8, "");
-    return ::new (AllocRawInternal(sizeof(T), TypeTag<T>(KnownTypes{})))
-        T(std::forward<Args>(args)...);
-  }
-
-  TableArena() {}
-
-  TableArena(const TableArena&) = delete;
-  TableArena& operator=(const TableArena&) = delete;
-
-  ~TableArena() {
-    // Uncomment this to debug usage statistics of the arena blocks.
-    // PrintUsageInfo();
-
-    for (Block* list : GetLists()) {
-      while (list != nullptr) {
-        Block* b = list;
-        list = list->next;
-        b->VisitBlock(DestroyVisitor{});
-        b->Destroy();
-      }
-    }
-  }
-
-
-  // This function exists for debugging only.
-  // It can be called from the destructor to dump some info in the tests to
-  // inspect the usage of the arena.
-  void PrintUsageInfo() const {
-    const auto print_histogram = [](Block* b, int size) {
-      std::map<uint32_t, uint32_t> unused_space_count;
-      int count = 0;
-      for (; b != nullptr; b = b->next) {
-        ++unused_space_count[b->space_left()];
-        ++count;
-      }
-      if (size > 0) {
-        fprintf(stderr, "  Blocks `At least %d`", size);
-      } else {
-        fprintf(stderr, "  Blocks `full`");
-      }
-      fprintf(stderr, ": %d blocks.\n", count);
-      for (auto p : unused_space_count) {
-        fprintf(stderr, "    space=%4u, count=%3u\n", p.first, p.second);
-      }
-    };
-
-    fprintf(stderr, "TableArena unused space histogram:\n");
-    fprintf(stderr, "  Current: %u\n",
-            current_ != nullptr ? current_->space_left() : 0);
-    print_histogram(full_blocks_, 0);
-    for (size_t i = 0; i < kSmallSizes.size(); ++i) {
-      print_histogram(small_size_blocks_[i], kSmallSizes[i]);
-    }
-  }
-
-  // Current allocation count.
-  // This can be used for checkpointing.
-  size_t num_allocations() const { return num_allocations_; }
-
-  // Rollback the latest allocations until we reach back to `checkpoint`
-  // num_allocations.
-  void RollbackTo(size_t checkpoint) {
-    while (num_allocations_ > checkpoint) {
-      GOOGLE_DCHECK(!rollback_info_.empty());
-      auto& info = rollback_info_.back();
-      Block* b = info.block;
-
-      VisitAlloc(b->data(), &b->start_offset, &b->end_offset, DestroyVisitor{},
-                 KnownTypes{});
-      if (--info.count == 0) {
-        rollback_info_.pop_back();
-      }
-      --num_allocations_;
-    }
-
-    // Reconstruct the lists and destroy empty blocks.
-    auto lists = GetLists();
-    current_ = full_blocks_ = nullptr;
-    small_size_blocks_.fill(nullptr);
-
-    for (Block* list : lists) {
-      while (list != nullptr) {
-        Block* b = list;
-        list = list->next;
-
-        if (b->start_offset == 0) {
-          // This is empty, free it.
-          b->Destroy();
-        } else {
-          RelocateToUsedList(b);
-        }
-      }
-    }
-  }
-
-  // Clear all rollback information. Reduces memory usage.
-  // Trying to rollback past num_allocations() is now impossible.
-  void ClearRollbackData() {
-    rollback_info_.clear();
-    rollback_info_.shrink_to_fit();
-  }
-
- private:
-  static constexpr size_t RoundUp(size_t n) { return (n + 7) & ~7; }
-
-  using Tag = unsigned char;
-
-  void* AllocRawInternal(uint32_t size, Tag tag) {
-    GOOGLE_DCHECK_GT(size, 0);
-    size = RoundUp(size);
-
-    Block* to_relocate = nullptr;
-    Block* to_use = nullptr;
-
-    for (size_t i = 0; i < kSmallSizes.size(); ++i) {
-      if (small_size_blocks_[i] != nullptr && size <= kSmallSizes[i]) {
-        to_use = to_relocate = PopBlock(small_size_blocks_[i]);
-        break;
-      }
-    }
-
-    if (to_relocate != nullptr) {
-      // We found one in the loop.
-    } else if (current_ != nullptr && size + 1 <= current_->space_left()) {
-      to_use = current_;
-    } else {
-      // No space left anywhere, make a new block.
-      to_relocate = current_;
-      // For now we hardcode the size to one page. Note that the maximum we can
-      // allocate in the block according to the limits of Tag is less than 2k,
-      // so this can fit anything that Tag can represent.
-      constexpr size_t kBlockSize = 4096;
-      to_use = current_ = ::new (::operator new(kBlockSize)) Block(kBlockSize);
-      GOOGLE_DCHECK_GE(current_->space_left(), size + 1);
-    }
-
-    ++num_allocations_;
-    if (!rollback_info_.empty() && rollback_info_.back().block == to_use) {
-      ++rollback_info_.back().count;
-    } else {
-      rollback_info_.push_back({to_use, 1});
-    }
-
-    void* p = to_use->Allocate(size, tag);
-    if (to_relocate != nullptr) {
-      RelocateToUsedList(to_relocate);
-    }
-    return p;
-  }
-
-  static void OperatorDelete(void* p, size_t s) {
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
-    ::operator delete(p, s);
-#else
-    ::operator delete(p);
-#endif
-  }
-
-  struct OutOfLineAlloc {
-    void* ptr;
-    uint32_t size;
-  };
-
-  template <typename... T>
-  struct TypeList {
-    static constexpr Tag kSize = static_cast<Tag>(sizeof...(T));
-  };
-
-  template <typename T, typename Visitor>
-  static void RunVisitor(char* p, uint16_t* start, Visitor visit) {
-    *start -= RoundUp(sizeof(T));
-    visit(reinterpret_cast<T*>(p + *start));
-  }
-
-  // Visit the allocation at the passed location.
-  // It updates start/end to be after the visited object.
-  // This allows visiting a whole block by calling the function in a loop.
-  template <typename Visitor, typename... T>
-  static void VisitAlloc(char* p, uint16_t* start, uint16_t* end, Visitor visit,
-                         TypeList<T...>) {
-    const Tag tag = static_cast<Tag>(p[*end]);
-    if (tag >= kFirstRawTag) {
-      // Raw memory. Skip it.
-      *start -= TagToSize(tag);
-    } else {
-      using F = void (*)(char*, uint16_t*, Visitor);
-      static constexpr F kFuncs[] = {&RunVisitor<T, Visitor>...};
-      kFuncs[tag](p, start, visit);
-    }
-    ++*end;
-  }
-
-  template <typename U, typename... Ts>
-  static constexpr Tag TypeTag(TypeList<U, Ts...>) {
-    return 0;
-  }
-
-  template <
-      typename U, typename T, typename... Ts,
-      typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
-  static constexpr Tag TypeTag(TypeList<T, Ts...>) {
-    return 1 + TypeTag<U>(TypeList<Ts...>{});
-  }
-
-  template <typename U>
-  static constexpr Tag TypeTag(TypeList<>) {
-    static_assert(std::is_trivially_destructible<U>::value, "");
-    return SizeToRawTag(sizeof(U));
-  }
-
-  using KnownTypes =
-      TypeList<OutOfLineAlloc, std::string,
-               // For name arrays
-               std::array<std::string, 2>, std::array<std::string, 3>,
-               std::array<std::string, 4>, std::array<std::string, 5>,
-               FileDescriptorTables, SourceCodeInfo, FileOptions,
-               MessageOptions, FieldOptions, ExtensionRangeOptions,
-               OneofOptions, EnumOptions, EnumValueOptions, ServiceOptions,
-               MethodOptions>;
-  static constexpr Tag kFirstRawTag = KnownTypes::kSize;
-
-
-  struct DestroyVisitor {
-    template <typename T>
-    void operator()(T* p) {
-      p->~T();
-    }
-    void operator()(OutOfLineAlloc* p) { OperatorDelete(p->ptr, p->size); }
-  };
-
-  static uint32_t SizeToRawTag(size_t n) { return (RoundUp(n) / 8) - 1; }
-
-  static uint32_t TagToSize(Tag tag) {
-    GOOGLE_DCHECK_GE(tag, kFirstRawTag);
-    return static_cast<uint32_t>(tag - kFirstRawTag + 1) * 8;
-  }
-
-  struct Block {
-    uint16_t start_offset;
-    uint16_t end_offset;
-    uint16_t capacity;
-    Block* next;
-
-    // `allocated_size` is the total size of the memory block allocated.
-    // The `Block` structure is constructed at the start and the rest of the
-    // memory is used as the payload of the `Block`.
-    explicit Block(uint32_t allocated_size) {
-      start_offset = 0;
-      end_offset = capacity =
-          reinterpret_cast<char*>(this) + allocated_size - data();
-      next = nullptr;
-    }
-
-    char* data() {
-      return reinterpret_cast<char*>(this) + RoundUp(sizeof(Block));
-    }
-
-    uint32_t memory_used() {
-      return data() + capacity - reinterpret_cast<char*>(this);
-    }
-    uint32_t space_left() const { return end_offset - start_offset; }
-
-    void* Allocate(uint32_t n, Tag tag) {
-      GOOGLE_DCHECK_LE(n + 1, space_left());
-      void* p = data() + start_offset;
-      start_offset += n;
-      data()[--end_offset] = tag;
-      return p;
-    }
-
-    void Destroy() { OperatorDelete(this, memory_used()); }
-
-    void PrependTo(Block*& list) {
-      next = list;
-      list = this;
-    }
-
-    template <typename Visitor>
-    void VisitBlock(Visitor visit) {
-      for (uint16_t s = start_offset, e = end_offset; s != 0;) {
-        VisitAlloc(data(), &s, &e, visit, KnownTypes{});
-      }
-    }
-  };
-
-  Block* PopBlock(Block*& list) {
-    Block* res = list;
-    list = list->next;
-    return res;
-  }
-
-  void RelocateToUsedList(Block* to_relocate) {
-    if (current_ == nullptr) {
-      current_ = to_relocate;
-      current_->next = nullptr;
-      return;
-    } else if (current_->space_left() < to_relocate->space_left()) {
-      std::swap(current_, to_relocate);
-      current_->next = nullptr;
-    }
-
-    for (int i = kSmallSizes.size(); --i >= 0;) {
-      if (to_relocate->space_left() >= 1U + kSmallSizes[i]) {
-        to_relocate->PrependTo(small_size_blocks_[i]);
-        return;
-      }
-    }
-
-    to_relocate->PrependTo(full_blocks_);
-  }
-
-  static constexpr std::array<uint8_t, 6> kSmallSizes = {
-      {// Sizes for pointer arrays.
-       8, 16, 24, 32,
-       // Sizes for string arrays (for descriptor names).
-       // The most common array sizes are 2 and 3.
-       2 * sizeof(std::string), 3 * sizeof(std::string)}};
-
-  // Helper function to iterate all lists.
-  std::array<Block*, 2 + kSmallSizes.size()> GetLists() const {
-    std::array<Block*, 2 + kSmallSizes.size()> res;
-    res[0] = current_;
-    res[1] = full_blocks_;
-    std::copy(small_size_blocks_.begin(), small_size_blocks_.end(), &res[2]);
-    return res;
-  }
-
-  Block* current_ = nullptr;
-  std::array<Block*, kSmallSizes.size()> small_size_blocks_ = {{}};
-  Block* full_blocks_ = nullptr;
-
-  size_t num_allocations_ = 0;
-  struct RollbackInfo {
-    Block* block;
-    size_t count;
-  };
-  std::vector<RollbackInfo> rollback_info_;
-};
-
-constexpr std::array<uint8_t, 6> TableArena::kSmallSizes;
-
 }  // anonymous namespace
 
 // ===================================================================
@@ -1162,59 +1194,36 @@
   template <typename Type>
   Type* Allocate();
 
-  // Allocate an array of objects which will be reclaimed when the
-  // pool in destroyed.  Again, destructors are never called.
-  template <typename Type>
-  Type* AllocateArray(int count);
+  // Allocate some bytes which will be reclaimed when the pool is
+  // destroyed.
+  void* AllocateBytes(int size);
 
-  // Allocate a string which will be destroyed when the pool is destroyed.
-  // The string is initialized to the given value for convenience.
-  const std::string* AllocateString(StringPiece value);
+  // Create a FlatAllocation for the corresponding sizes.
+  // All objects within it will be default constructed.
+  // The whole allocation, including the non-trivial objects within, will be
+  // destroyed with the pool.
+  template <typename... T>
+  internal::FlatAllocator::Allocation* CreateFlatAlloc(
+      const TypeMap<IntT, T...>& sizes);
 
-  // Copy the input into a NUL terminated string whose lifetime is managed by
-  // the pool.
-  const char* Strdup(StringPiece value);
-
-  // Allocates an array of strings which will be destroyed when the pool is
-  // destroyed. The array is initialized with the input values.
-  template <typename... In>
-  const std::string* AllocateStringArray(In&&... values);
-
-  struct FieldNamesResult {
-    std::string* array;
-    int lowercase_index;
-    int camelcase_index;
-    int json_index;
-  };
-  // Allocate all 5 names of the field:
-  // name, full name, lowercase, camelcase and json.
-  // This function will dedup the strings when possible.
-  // The resulting array contains `name` at index 0, `full_name` at index 1 and
-  // the other 3 indices are specified in the result.
-  FieldNamesResult AllocateFieldNames(const std::string& name,
-                                      const std::string& scope,
-                                      const std::string* opt_json_name);
-
-  // Create an object that will be deleted when the pool is destroyed.
-  // The object is value initialized, and its destructor will be called if
-  // non-trivial.
-  template <typename Type>
-  Type* Create();
-
-  // Allocate a protocol message object.  Some older versions of GCC have
-  // trouble understanding explicit template instantiations in some cases, so
-  // in those cases we have to pass a dummy pointer of the right type as the
-  // parameter instead of specifying the type explicitly.
-  template <typename Type>
-  Type* AllocateMessage(Type* dummy = nullptr);
-
-  // Allocate a FileDescriptorTables object.
-  FileDescriptorTables* AllocateFileTables();
 
  private:
-  // All other memory allocated in the pool.  Must be first as other objects can
+  // All memory allocated in the pool.  Must be first as other objects can
   // point into these.
-  TableArena arena_;
+  struct MiscDeleter {
+    void operator()(int* p) const { internal::SizedDelete(p, *p + 8); }
+  };
+  // Miscellaneous allocations are length prefixed. The paylaod is 8 bytes after
+  // the `int` that contains the size. This keeps the payload aligned.
+  std::vector<std::unique_ptr<int, MiscDeleter>> misc_allocs_;
+  struct FlatAllocDeleter {
+    void operator()(internal::FlatAllocator::Allocation* p) const {
+      p->Destroy();
+    }
+  };
+  std::vector<
+      std::unique_ptr<internal::FlatAllocator::Allocation, FlatAllocDeleter>>
+      flat_allocs_;
 
   SymbolsByNameSet symbols_by_name_;
   FilesByNameMap files_by_name_;
@@ -1222,26 +1231,26 @@
 
   struct CheckPoint {
     explicit CheckPoint(const Tables* tables)
-        : arena_before_checkpoint(tables->arena_.num_allocations()),
+        : flat_allocations_before_checkpoint(
+              static_cast<int>(tables->flat_allocs_.size())),
+          misc_allocations_before_checkpoint(
+              static_cast<int>(tables->misc_allocs_.size())),
           pending_symbols_before_checkpoint(
               tables->symbols_after_checkpoint_.size()),
           pending_files_before_checkpoint(
               tables->files_after_checkpoint_.size()),
           pending_extensions_before_checkpoint(
               tables->extensions_after_checkpoint_.size()) {}
-    int arena_before_checkpoint;
+    int flat_allocations_before_checkpoint;
+    int misc_allocations_before_checkpoint;
     int pending_symbols_before_checkpoint;
     int pending_files_before_checkpoint;
     int pending_extensions_before_checkpoint;
   };
   std::vector<CheckPoint> checkpoints_;
-  std::vector<const char*> symbols_after_checkpoint_;
-  std::vector<const char*> files_after_checkpoint_;
+  std::vector<Symbol> symbols_after_checkpoint_;
+  std::vector<const FileDescriptor*> files_after_checkpoint_;
   std::vector<DescriptorIntPair> extensions_after_checkpoint_;
-
-  // Allocate some bytes which will be reclaimed when the pool is
-  // destroyed.
-  void* AllocateBytes(int size);
 };
 
 // Contains tables specific to a particular file.  These tables are not
@@ -1285,9 +1294,7 @@
   // Adding items.
 
   // These add items to the corresponding tables.  They return false if
-  // the key already exists in the table.  For AddAliasUnderParent(), the
-  // string passed in must be one that was constructed using AllocateString(),
-  // as it will be used as a key in the symbols_by_parent_ map without copying.
+  // the key already exists in the table.
   bool AddAliasUnderParent(const void* parent, const std::string& name,
                            Symbol symbol);
   bool AddFieldByNumber(FieldDescriptor* field);
@@ -1391,7 +1398,6 @@
     symbols_after_checkpoint_.clear();
     files_after_checkpoint_.clear();
     extensions_after_checkpoint_.clear();
-    arena_.ClearRollbackData();
   }
 }
 
@@ -1401,13 +1407,11 @@
 
   for (size_t i = checkpoint.pending_symbols_before_checkpoint;
        i < symbols_after_checkpoint_.size(); i++) {
-    Symbol::QueryKey name;
-    name.name = symbols_after_checkpoint_[i];
-    symbols_by_name_.erase(Symbol(&name));
+    symbols_by_name_.erase(symbols_after_checkpoint_[i]);
   }
   for (size_t i = checkpoint.pending_files_before_checkpoint;
        i < files_after_checkpoint_.size(); i++) {
-    files_by_name_.erase(files_after_checkpoint_[i]);
+    files_by_name_.erase(files_after_checkpoint_[i]->name());
   }
   for (size_t i = checkpoint.pending_extensions_before_checkpoint;
        i < extensions_after_checkpoint_.size(); i++) {
@@ -1420,7 +1424,8 @@
   extensions_after_checkpoint_.resize(
       checkpoint.pending_extensions_before_checkpoint);
 
-  arena_.RollbackTo(checkpoint.arena_before_checkpoint);
+  flat_allocs_.resize(checkpoint.flat_allocations_before_checkpoint);
+  misc_allocs_.resize(checkpoint.misc_allocations_before_checkpoint);
   checkpoints_.pop_back();
 }
 
@@ -1429,8 +1434,8 @@
 inline Symbol DescriptorPool::Tables::FindSymbol(StringPiece key) const {
   Symbol::QueryKey name;
   name.name = key;
-  auto it = symbols_by_name_.find(Symbol(&name));
-  return it == symbols_by_name_.end() ? kNullSymbol : *it;
+  auto it = symbols_by_name_.find(name);
+  return it == symbols_by_name_.end() ? Symbol() : *it;
 }
 
 inline Symbol FileDescriptorTables::FindNestedSymbol(
@@ -1438,8 +1443,8 @@
   Symbol::QueryKey query;
   query.name = name;
   query.parent = parent;
-  auto it = symbols_by_parent_.find(Symbol(&query));
-  return it == symbols_by_parent_.end() ? kNullSymbol : *it;
+  auto it = symbols_by_parent_.find(query);
+  return it == symbols_by_parent_.end() ? Symbol() : *it;
 }
 
 Symbol DescriptorPool::Tables::FindByNameHelper(const DescriptorPool* pool,
@@ -1492,7 +1497,7 @@
   query.parent = parent;
   query.field_number = number;
 
-  auto it = fields_by_number_.find(Symbol(&query));
+  auto it = fields_by_number_.find(query);
   return it == fields_by_number_.end() ? nullptr : it->field_descriptor();
 }
 
@@ -1571,7 +1576,7 @@
   query.parent = parent;
   query.field_number = number;
 
-  auto it = enum_values_by_number_.find(Symbol(&query));
+  auto it = enum_values_by_number_.find(query);
   return it == enum_values_by_number_.end() ? nullptr
                                             : it->enum_value_descriptor();
 }
@@ -1594,7 +1599,7 @@
   // Second try, with reader lock held on unknown enum values: common case.
   {
     ReaderMutexLock l(&unknown_enum_values_mu_);
-    auto it = unknown_enum_values_by_number_.find(Symbol(&query));
+    auto it = unknown_enum_values_by_number_.find(query);
     if (it != unknown_enum_values_by_number_.end() &&
         it->enum_value_descriptor() != nullptr) {
       return it->enum_value_descriptor();
@@ -1604,7 +1609,7 @@
   // necessary.
   {
     WriterMutexLock l(&unknown_enum_values_mu_);
-    auto it = unknown_enum_values_by_number_.find(Symbol(&query));
+    auto it = unknown_enum_values_by_number_.find(query);
     if (it != unknown_enum_values_by_number_.end() &&
         it->enum_value_descriptor() != nullptr) {
       return it->enum_value_descriptor();
@@ -1618,15 +1623,19 @@
                                                parent->name().c_str(), number);
     auto* pool = DescriptorPool::generated_pool();
     auto* tables = const_cast<DescriptorPool::Tables*>(pool->tables_.get());
-    EnumValueDescriptor* result;
+    internal::FlatAllocator alloc;
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);
+
     {
       // Must lock the pool because we will do allocations in the shared arena.
       MutexLockMaybe l2(pool->mutex_);
-      result = tables->Allocate<EnumValueDescriptor>();
-      result->all_names_ = tables->AllocateStringArray(
-          enum_value_name,
-          StrCat(parent->full_name(), ".", enum_value_name));
+      alloc.FinalizePlanning(tables);
     }
+    EnumValueDescriptor* result = alloc.AllocateArray<EnumValueDescriptor>(1);
+    result->all_names_ = alloc.AllocateStrings(
+        enum_value_name,
+        StrCat(parent->full_name(), ".", enum_value_name));
     result->number_ = number;
     result->type_ = parent;
     result->options_ = &EnumValueOptions::default_instance();
@@ -1656,7 +1665,7 @@
                                        Symbol symbol) {
   GOOGLE_DCHECK_EQ(full_name, symbol.full_name());
   if (symbols_by_name_.insert(symbol).second) {
-    symbols_after_checkpoint_.push_back(full_name.c_str());
+    symbols_after_checkpoint_.push_back(symbol);
     return true;
   } else {
     return false;
@@ -1673,7 +1682,7 @@
 
 bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
   if (InsertIfNotPresent(&files_by_name_, file->name(), file)) {
-    files_after_checkpoint_.push_back(file->name().c_str());
+    files_after_checkpoint_.push_back(file);
     return true;
   } else {
     return false;
@@ -1754,123 +1763,33 @@
 
 template <typename Type>
 Type* DescriptorPool::Tables::Allocate() {
-  return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type)));
-}
-
-template <typename Type>
-Type* DescriptorPool::Tables::AllocateArray(int count) {
-  return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type) * count));
-}
-
-const std::string* DescriptorPool::Tables::AllocateString(
-    StringPiece value) {
-  return arena_.Create<std::string>(value);
-}
-
-const char* DescriptorPool::Tables::Strdup(StringPiece value) {
-  char* p = AllocateArray<char>(static_cast<int>(value.size() + 1));
-  memcpy(p, value.data(), value.size());
-  p[value.size()] = 0;
-  return p;
-}
-
-template <typename... In>
-const std::string* DescriptorPool::Tables::AllocateStringArray(In&&... values) {
-  auto& array = *arena_.Create<std::array<std::string, sizeof...(In)>>();
-  array = {{std::string(std::forward<In>(values))...}};
-  return array.data();
-}
-
-DescriptorPool::Tables::FieldNamesResult
-DescriptorPool::Tables::AllocateFieldNames(const std::string& name,
-                                           const std::string& scope,
-                                           const std::string* opt_json_name) {
-  std::string lowercase_name = name;
-  LowerString(&lowercase_name);
-
-  std::string camelcase_name = ToCamelCase(name, /* lower_first = */ true);
-  std::string json_name;
-  if (opt_json_name != nullptr) {
-    json_name = *opt_json_name;
-  } else {
-    json_name = ToJsonName(name);
-  }
-
-  const bool lower_eq_name = lowercase_name == name;
-  const bool camel_eq_name = camelcase_name == name;
-  const bool json_eq_name = json_name == name;
-  const bool json_eq_camel = json_name == camelcase_name;
-
-  const int total_count = 2 + (lower_eq_name ? 0 : 1) +
-                          (camel_eq_name ? 0 : 1) +
-                          (json_eq_name || json_eq_camel ? 0 : 1);
-  FieldNamesResult result{nullptr, 0, 0, 0};
-  // We use std::array to allow handling of the destruction of the strings.
-  switch (total_count) {
-    case 2:
-      result.array = arena_.Create<std::array<std::string, 2>>()->data();
-      break;
-    case 3:
-      result.array = arena_.Create<std::array<std::string, 3>>()->data();
-      break;
-    case 4:
-      result.array = arena_.Create<std::array<std::string, 4>>()->data();
-      break;
-    case 5:
-      result.array = arena_.Create<std::array<std::string, 5>>()->data();
-      break;
-  }
-
-  result.array[0] = name;
-  if (scope.empty()) {
-    result.array[1] = name;
-  } else {
-    result.array[1] = StrCat(scope, ".", name);
-  }
-  int index = 2;
-  if (lower_eq_name) {
-    result.lowercase_index = 0;
-  } else {
-    result.lowercase_index = index;
-    result.array[index++] = std::move(lowercase_name);
-  }
-
-  if (camel_eq_name) {
-    result.camelcase_index = 0;
-  } else {
-    result.camelcase_index = index;
-    result.array[index++] = std::move(camelcase_name);
-  }
-
-  if (json_eq_name) {
-    result.json_index = 0;
-  } else if (json_eq_camel) {
-    result.json_index = result.camelcase_index;
-  } else {
-    result.json_index = index;
-    result.array[index] = std::move(json_name);
-  }
-
-  return result;
-}
-
-template <typename Type>
-Type* DescriptorPool::Tables::Create() {
-  return arena_.Create<Type>();
-}
-
-template <typename Type>
-Type* DescriptorPool::Tables::AllocateMessage(Type* /* dummy */) {
-  return arena_.Create<Type>();
-}
-
-FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() {
-  return arena_.Create<FileDescriptorTables>();
+  static_assert(std::is_trivially_destructible<Type>::value, "");
+  return ::new (AllocateBytes(sizeof(Type))) Type{};
 }
 
 void* DescriptorPool::Tables::AllocateBytes(int size) {
   if (size == 0) return nullptr;
-  return arena_.AllocateMemory(size);
+  void* p = ::operator new(size + RoundUp(sizeof(int)));
+  int* sizep = static_cast<int*>(p);
+  misc_allocs_.emplace_back(sizep);
+  *sizep = size;
+  return static_cast<char*>(p) + RoundUp(sizeof(int));
+}
+
+template <typename... T>
+internal::FlatAllocator::Allocation* DescriptorPool::Tables::CreateFlatAlloc(
+    const TypeMap<IntT, T...>& sizes) {
+  auto ends = CalculateEnds(sizes);
+  using FlatAlloc = internal::FlatAllocator::Allocation;
+
+  int last_end = ends.template Get<
+      typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type>();
+  size_t total_size = last_end + RoundUp(sizeof(FlatAlloc));
+  char* data = static_cast<char*>(::operator new(total_size));
+  auto* res = ::new (data) FlatAlloc(ends);
+  flat_allocs_.emplace_back(res);
+
+  return res;
 }
 
 void FileDescriptorTables::BuildLocationsByPath(
@@ -2469,7 +2388,7 @@
     Symbol symbol = tables_->FindSymbol(prefix);
     // If the symbol type is anything other than PACKAGE, then its complete
     // definition is already known.
-    if (!symbol.IsNull() && symbol.type() != Symbol::PACKAGE) {
+    if (!symbol.IsNull() && !symbol.IsPackage()) {
       return true;
     }
   }
@@ -3532,7 +3451,6 @@
   comment_printer.AddPostComment(contents);
 }
 
-
 // Location methods ===============================================
 
 bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,
@@ -3718,7 +3636,8 @@
   friend class OptionInterpreter;
 
   // Non-recursive part of BuildFile functionality.
-  FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto);
+  FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto,
+                                internal::FlatAllocator& alloc);
 
   const DescriptorPool* pool_;
   DescriptorPool::Tables* tables_;  // for convenience
@@ -3754,6 +3673,13 @@
   // to report a more useful error message.
   std::string undefine_resolved_name_;
 
+  // Tracker for current recursion depth to implement recursion protection.
+  //
+  // Counts down to 0 when there is no depth remaining.
+  //
+  // Maximum recursion depth corresponds to 32 nested message declarations.
+  int recursion_depth_ = 32;
+
   void AddError(const std::string& element_name, const Message& descriptor,
                 DescriptorPool::ErrorCollector::ErrorLocation location,
                 const std::string& error);
@@ -3847,13 +3773,6 @@
   void ValidateSymbolName(const std::string& name, const std::string& full_name,
                           const Message& proto);
 
-  // Used by BUILD_ARRAY macro (below) to avoid having to have the type
-  // specified as a macro parameter.
-  template <typename Type>
-  inline void AllocateArray(int size, Type** output) {
-    *output = tables_->AllocateArray<Type>(size);
-  }
-
   // Allocates a copy of orig_options in tables_ and stores it in the
   // descriptor. Remembers its uninterpreted options, to be interpreted
   // later. DescriptorT must be one of the Descriptor messages from
@@ -3861,10 +3780,12 @@
   template <class DescriptorT>
   void AllocateOptions(const typename DescriptorT::OptionsType& orig_options,
                        DescriptorT* descriptor, int options_field_tag,
-                       const std::string& option_name);
+                       const std::string& option_name,
+                       internal::FlatAllocator& alloc);
   // Specialization for FileOptions.
   void AllocateOptions(const FileOptions& orig_options,
-                       FileDescriptor* descriptor);
+                       FileDescriptor* descriptor,
+                       internal::FlatAllocator& alloc);
 
   // Implementation for AllocateOptions(). Don't call this directly.
   template <class DescriptorT>
@@ -3872,52 +3793,57 @@
       const std::string& name_scope, const std::string& element_name,
       const typename DescriptorT::OptionsType& orig_options,
       DescriptorT* descriptor, const std::vector<int>& options_path,
-      const std::string& option_name);
+      const std::string& option_name, internal::FlatAllocator& alloc);
 
   // Allocates an array of two strings, the first one is a copy of `proto_name`,
   // and the second one is the full name.
   // Full proto name is "scope.proto_name" if scope is non-empty and
   // "proto_name" otherwise.
   const std::string* AllocateNameStrings(const std::string& scope,
-                                         const std::string& proto_name);
+                                         const std::string& proto_name,
+                                         internal::FlatAllocator& alloc);
 
   // These methods all have the same signature for the sake of the BUILD_ARRAY
   // macro, below.
   void BuildMessage(const DescriptorProto& proto, const Descriptor* parent,
-                    Descriptor* result);
+                    Descriptor* result, internal::FlatAllocator& alloc);
   void BuildFieldOrExtension(const FieldDescriptorProto& proto,
                              Descriptor* parent, FieldDescriptor* result,
-                             bool is_extension);
+                             bool is_extension, internal::FlatAllocator& alloc);
   void BuildField(const FieldDescriptorProto& proto, Descriptor* parent,
-                  FieldDescriptor* result) {
-    BuildFieldOrExtension(proto, parent, result, false);
+                  FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, false, alloc);
   }
   void BuildExtension(const FieldDescriptorProto& proto, Descriptor* parent,
-                      FieldDescriptor* result) {
-    BuildFieldOrExtension(proto, parent, result, true);
+                      FieldDescriptor* result, internal::FlatAllocator& alloc) {
+    BuildFieldOrExtension(proto, parent, result, true, alloc);
   }
   void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
                            const Descriptor* parent,
-                           Descriptor::ExtensionRange* result);
+                           Descriptor::ExtensionRange* result,
+                           internal::FlatAllocator& alloc);
   void BuildReservedRange(const DescriptorProto::ReservedRange& proto,
                           const Descriptor* parent,
-                          Descriptor::ReservedRange* result);
+                          Descriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
   void BuildReservedRange(const EnumDescriptorProto::EnumReservedRange& proto,
                           const EnumDescriptor* parent,
-                          EnumDescriptor::ReservedRange* result);
+                          EnumDescriptor::ReservedRange* result,
+                          internal::FlatAllocator& alloc);
   void BuildOneof(const OneofDescriptorProto& proto, Descriptor* parent,
-                  OneofDescriptor* result);
+                  OneofDescriptor* result, internal::FlatAllocator& alloc);
   void CheckEnumValueUniqueness(const EnumDescriptorProto& proto,
                                 const EnumDescriptor* result);
   void BuildEnum(const EnumDescriptorProto& proto, const Descriptor* parent,
-                 EnumDescriptor* result);
+                 EnumDescriptor* result, internal::FlatAllocator& alloc);
   void BuildEnumValue(const EnumValueDescriptorProto& proto,
-                      const EnumDescriptor* parent,
-                      EnumValueDescriptor* result);
+                      const EnumDescriptor* parent, EnumValueDescriptor* result,
+                      internal::FlatAllocator& alloc);
   void BuildService(const ServiceDescriptorProto& proto, const void* dummy,
-                    ServiceDescriptor* result);
+                    ServiceDescriptor* result, internal::FlatAllocator& alloc);
   void BuildMethod(const MethodDescriptorProto& proto,
-                   const ServiceDescriptor* parent, MethodDescriptor* result);
+                   const ServiceDescriptor* parent, MethodDescriptor* result,
+                   internal::FlatAllocator& alloc);
 
   void LogUnusedDependency(const FileDescriptorProto& proto,
                            const FileDescriptor* result);
@@ -4331,7 +4257,7 @@
     return result;
   }
 
-  if (result.type() == Symbol::PACKAGE) {
+  if (result.IsPackage()) {
     // Arg, this is overcomplicated.  The symbol is a package name.  It could
     // be that the package was defined in multiple files.  result.GetFile()
     // returns the first file we saw that used this package.  We've determined
@@ -4350,7 +4276,7 @@
 
   possible_undeclared_dependency_ = file;
   possible_undeclared_dependency_name_ = name;
-  return kNullSymbol;
+  return Symbol();
 }
 
 Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
@@ -4478,7 +4404,7 @@
   StringPiece placeholder_name;
   const std::string* placeholder_package;
 
-  if (!ValidateQualifiedName(name)) return kNullSymbol;
+  if (!ValidateQualifiedName(name)) return Symbol();
   if (name[0] == '.') {
     // Fully-qualified.
     placeholder_full_name = name.substr(1);
@@ -4486,30 +4412,47 @@
     placeholder_full_name = name;
   }
 
-  std::string::size_type dotpos = placeholder_full_name.find_last_of('.');
+  // Create the placeholders.
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(2);
+  if (placeholder_type == PLACEHOLDER_ENUM) {
+    alloc.PlanArray<EnumDescriptor>(1);
+    alloc.PlanArray<EnumValueDescriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    alloc.PlanArray<std::string>(2);  // names for the value.
+  } else {
+    alloc.PlanArray<Descriptor>(1);
+    alloc.PlanArray<std::string>(2);  // names for the descriptor.
+    if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
+      alloc.PlanArray<Descriptor::ExtensionRange>(1);
+    }
+  }
+  alloc.FinalizePlanning(tables_);
+
+  const std::string::size_type dotpos = placeholder_full_name.find_last_of('.');
   if (dotpos != std::string::npos) {
     placeholder_package =
-        tables_->AllocateString(placeholder_full_name.substr(0, dotpos));
+        alloc.AllocateStrings(placeholder_full_name.substr(0, dotpos));
     placeholder_name = placeholder_full_name.substr(dotpos + 1);
   } else {
-    placeholder_package = &internal::GetEmptyString();
+    placeholder_package = alloc.AllocateStrings("");
     placeholder_name = placeholder_full_name;
   }
 
-  // Create the placeholders.
   FileDescriptor* placeholder_file = NewPlaceholderFileWithMutexHeld(
-      StrCat(placeholder_full_name, ".placeholder.proto"));
+      StrCat(placeholder_full_name, ".placeholder.proto"), alloc);
   placeholder_file->package_ = placeholder_package;
 
   if (placeholder_type == PLACEHOLDER_ENUM) {
     placeholder_file->enum_type_count_ = 1;
-    placeholder_file->enum_types_ = tables_->AllocateArray<EnumDescriptor>(1);
+    placeholder_file->enum_types_ = alloc.AllocateArray<EnumDescriptor>(1);
 
     EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
     memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
 
     placeholder_enum->all_names_ =
-        tables_->AllocateStringArray(placeholder_name, placeholder_full_name);
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
     placeholder_enum->file_ = placeholder_file;
     placeholder_enum->options_ = &EnumOptions::default_instance();
     placeholder_enum->is_placeholder_ = true;
@@ -4517,7 +4460,7 @@
 
     // Enums must have at least one value.
     placeholder_enum->value_count_ = 1;
-    placeholder_enum->values_ = tables_->AllocateArray<EnumValueDescriptor>(1);
+    placeholder_enum->values_ = alloc.AllocateArray<EnumValueDescriptor>(1);
     // Disable fast-path lookup for this enum.
     placeholder_enum->sequential_value_limit_ = -1;
 
@@ -4526,7 +4469,7 @@
            sizeof(*placeholder_value));
 
     // Note that enum value names are siblings of their type, not children.
-    placeholder_value->all_names_ = tables_->AllocateStringArray(
+    placeholder_value->all_names_ = alloc.AllocateStrings(
         "PLACEHOLDER_VALUE", placeholder_package->empty()
                                  ? "PLACEHOLDER_VALUE"
                                  : *placeholder_package + ".PLACEHOLDER_VALUE");
@@ -4538,14 +4481,14 @@
     return Symbol(placeholder_enum);
   } else {
     placeholder_file->message_type_count_ = 1;
-    placeholder_file->message_types_ = tables_->AllocateArray<Descriptor>(1);
+    placeholder_file->message_types_ = alloc.AllocateArray<Descriptor>(1);
 
     Descriptor* placeholder_message = &placeholder_file->message_types_[0];
     memset(static_cast<void*>(placeholder_message), 0,
            sizeof(*placeholder_message));
 
     placeholder_message->all_names_ =
-        tables_->AllocateStringArray(placeholder_name, placeholder_full_name);
+        alloc.AllocateStrings(placeholder_name, placeholder_full_name);
     placeholder_message->file_ = placeholder_file;
     placeholder_message->options_ = &MessageOptions::default_instance();
     placeholder_message->is_placeholder_ = true;
@@ -4554,12 +4497,12 @@
     if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
       placeholder_message->extension_range_count_ = 1;
       placeholder_message->extension_ranges_ =
-          tables_->AllocateArray<Descriptor::ExtensionRange>(1);
-      placeholder_message->extension_ranges_->start = 1;
+          alloc.AllocateArray<Descriptor::ExtensionRange>(1);
+      placeholder_message->extension_ranges_[0].start = 1;
       // kMaxNumber + 1 because ExtensionRange::end is exclusive.
-      placeholder_message->extension_ranges_->end =
+      placeholder_message->extension_ranges_[0].end =
           FieldDescriptor::kMaxNumber + 1;
-      placeholder_message->extension_ranges_->options_ = nullptr;
+      placeholder_message->extension_ranges_[0].options_ = nullptr;
     }
 
     return Symbol(placeholder_message);
@@ -4569,18 +4512,23 @@
 FileDescriptor* DescriptorPool::NewPlaceholderFile(
     StringPiece name) const {
   MutexLockMaybe lock(mutex_);
-  return NewPlaceholderFileWithMutexHeld(name);
+  internal::FlatAllocator alloc;
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<std::string>(1);
+  alloc.FinalizePlanning(tables_);
+
+  return NewPlaceholderFileWithMutexHeld(name, alloc);
 }
 
 FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld(
-    StringPiece name) const {
+    StringPiece name, internal::FlatAllocator& alloc) const {
   if (mutex_) {
     mutex_->AssertHeld();
   }
-  FileDescriptor* placeholder = tables_->Allocate<FileDescriptor>();
+  FileDescriptor* placeholder = alloc.AllocateArray<FileDescriptor>(1);
   memset(static_cast<void*>(placeholder), 0, sizeof(*placeholder));
 
-  placeholder->name_ = tables_->AllocateString(name);
+  placeholder->name_ = alloc.AllocateStrings(name);
   placeholder->package_ = &internal::GetEmptyString();
   placeholder->pool_ = this;
   placeholder->options_ = &FileOptions::default_instance();
@@ -4654,13 +4602,17 @@
   Symbol existing_symbol = tables_->FindSymbol(name);
   // It's OK to redefine a package.
   if (existing_symbol.IsNull()) {
-    auto* package = tables_->AllocateArray<Symbol::Package>(1);
-    // If the name is the package name, then it is already in the arena.
-    // If not, copy it there. It came from the call to AddPackage below.
-    package->name =
-        &name == &file->package() ? &name : tables_->AllocateString(name);
-    package->file = file;
-    tables_->AddSymbol(*package->name, Symbol(package));
+    if (&name == &file->package()) {
+      // It is the toplevel package name, so insert the descriptor directly.
+      tables_->AddSymbol(file->package(), Symbol(file));
+    } else {
+      auto* package = tables_->Allocate<Symbol::Subpackage>();
+      // If the name is the package name, then it is already in the arena.
+      // If not, copy it there. It came from the call to AddPackage below.
+      package->name_size = static_cast<int>(name.size());
+      package->file = file;
+      tables_->AddSymbol(name, Symbol(package));
+    }
     // Also add parent package, if any.
     std::string::size_type dot_pos = name.find_last_of('.');
     if (dot_pos == std::string::npos) {
@@ -4671,13 +4623,14 @@
       AddPackage(name.substr(0, dot_pos), proto, file);
       ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
     }
-  } else if (existing_symbol.type() != Symbol::PACKAGE) {
+  } else if (!existing_symbol.IsPackage()) {
     // Symbol seems to have been defined in a different file.
+    const FileDescriptor* other_file = existing_symbol.GetFile();
     AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
              "\"" + name +
                  "\" is already defined (as something other than "
                  "a package) in file \"" +
-                 existing_symbol.GetFile()->name() + "\".");
+                 (other_file == nullptr ? "null" : other_file->name()) + "\".");
   }
 }
 
@@ -4695,6 +4648,7 @@
           (character < '0' || '9' < character) && (character != '_')) {
         AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
                  "\"" + name + "\" is not a valid identifier.");
+        return;
       }
     }
   }
@@ -4708,23 +4662,25 @@
 void DescriptorBuilder::AllocateOptions(
     const typename DescriptorT::OptionsType& orig_options,
     DescriptorT* descriptor, int options_field_tag,
-    const std::string& option_name) {
+    const std::string& option_name, internal::FlatAllocator& alloc) {
   std::vector<int> options_path;
   descriptor->GetLocationPath(&options_path);
   options_path.push_back(options_field_tag);
   AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(),
-                      orig_options, descriptor, options_path, option_name);
+                      orig_options, descriptor, options_path, option_name,
+                      alloc);
 }
 
 // We specialize for FileDescriptor.
 void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options,
-                                        FileDescriptor* descriptor) {
+                                        FileDescriptor* descriptor,
+                                        internal::FlatAllocator& alloc) {
   std::vector<int> options_path;
   options_path.push_back(FileDescriptorProto::kOptionsFieldNumber);
   // We add the dummy token so that LookupSymbol does the right thing.
   AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(),
                       orig_options, descriptor, options_path,
-                      "google.protobuf.FileOptions");
+                      "google.protobuf.FileOptions", alloc);
 }
 
 template <class DescriptorT>
@@ -4732,13 +4688,8 @@
     const std::string& name_scope, const std::string& element_name,
     const typename DescriptorT::OptionsType& orig_options,
     DescriptorT* descriptor, const std::vector<int>& options_path,
-    const std::string& option_name) {
-  // We need to use a dummy pointer to work around a bug in older versions of
-  // GCC.  Otherwise, the following two lines could be replaced with:
-  //   typename DescriptorT::OptionsType* options =
-  //       tables_->AllocateMessage<typename DescriptorT::OptionsType>();
-  typename DescriptorT::OptionsType* const dummy = nullptr;
-  typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy);
+    const std::string& option_name, internal::FlatAllocator& alloc) {
+  auto* options = alloc.AllocateArray<typename DescriptorT::OptionsType>(1);
 
   if (!orig_options.IsInitialized()) {
     AddError(name_scope + "." + element_name, orig_options,
@@ -4788,11 +4739,13 @@
 
 // A common pattern:  We want to convert a repeated field in the descriptor
 // to an array of values, calling some method to build each value.
-#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
-  OUTPUT->NAME##_count_ = INPUT.NAME##_size();           \
-  AllocateArray(INPUT.NAME##_size(), &OUTPUT->NAME##s_); \
-  for (int i = 0; i < INPUT.NAME##_size(); i++) {        \
-    METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i); \
+#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT)               \
+  OUTPUT->NAME##_count_ = INPUT.NAME##_size();                         \
+  OUTPUT->NAME##s_ = alloc.AllocateArray<                              \
+      typename std::remove_pointer<decltype(OUTPUT->NAME##s_)>::type>( \
+      INPUT.NAME##_size());                                            \
+  for (int i = 0; i < INPUT.NAME##_size(); i++) {                      \
+    METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc);        \
   }
 
 void DescriptorBuilder::AddRecursiveImportError(
@@ -4848,6 +4801,130 @@
   return existing_proto.SerializeAsString() == proto.SerializeAsString();
 }
 
+// These PlanAllocationSize functions will gather into the FlatAllocator all the
+// necessary memory allocations that BuildXXX functions below will do on the
+// Tables object.
+// They *must* be kept in sync. If we miss some PlanArray call we won't have
+// enough memory and will GOOGLE_CHECK-fail.
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumValueDescriptorProto>& values,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumValueDescriptor>(values.size());
+  alloc.PlanArray<std::string>(2 * values.size());  // name + full_name
+  for (const auto& v : values) {
+    if (v.has_options()) alloc.PlanArray<EnumValueOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<EnumDescriptorProto>& enums,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<EnumDescriptor>(enums.size());
+  alloc.PlanArray<std::string>(2 * enums.size());  // name + full_name
+  for (const auto& e : enums) {
+    if (e.has_options()) alloc.PlanArray<EnumOptions>(1);
+    PlanAllocationSize(e.value(), alloc);
+    alloc.PlanArray<EnumDescriptor::ReservedRange>(e.reserved_range_size());
+    alloc.PlanArray<const std::string*>(e.reserved_name_size());
+    alloc.PlanArray<std::string>(e.reserved_name_size());
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<OneofDescriptorProto>& oneofs,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<OneofDescriptor>(oneofs.size());
+  alloc.PlanArray<std::string>(2 * oneofs.size());  // name + full_name
+  for (const auto& oneof : oneofs) {
+    if (oneof.has_options()) alloc.PlanArray<OneofOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<FieldDescriptorProto>& fields,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FieldDescriptor>(fields.size());
+  for (const auto& field : fields) {
+    if (field.has_options()) alloc.PlanArray<FieldOptions>(1);
+    alloc.PlanFieldNames(field.name(),
+                         field.has_json_name() ? &field.json_name() : nullptr);
+    if (field.has_default_value() && field.has_type() &&
+        (field.type() == FieldDescriptorProto::TYPE_STRING ||
+         field.type() == FieldDescriptorProto::TYPE_BYTES)) {
+      // For the default string value.
+      alloc.PlanArray<std::string>(1);
+    }
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto::ExtensionRange>& ranges,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor::ExtensionRange>(ranges.size());
+  for (const auto& r : ranges) {
+    if (r.has_options()) alloc.PlanArray<ExtensionRangeOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<DescriptorProto>& messages,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<Descriptor>(messages.size());
+  alloc.PlanArray<std::string>(2 * messages.size());  // name + full_name
+
+  for (const auto& message : messages) {
+    if (message.has_options()) alloc.PlanArray<MessageOptions>(1);
+    PlanAllocationSize(message.nested_type(), alloc);
+    PlanAllocationSize(message.field(), alloc);
+    PlanAllocationSize(message.extension(), alloc);
+    PlanAllocationSize(message.extension_range(), alloc);
+    alloc.PlanArray<Descriptor::ReservedRange>(message.reserved_range_size());
+    alloc.PlanArray<const std::string*>(message.reserved_name_size());
+    alloc.PlanArray<std::string>(message.reserved_name_size());
+    PlanAllocationSize(message.enum_type(), alloc);
+    PlanAllocationSize(message.oneof_decl(), alloc);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<MethodDescriptorProto>& methods,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<MethodDescriptor>(methods.size());
+  alloc.PlanArray<std::string>(2 * methods.size());  // name + full_name
+  for (const auto& m : methods) {
+    if (m.has_options()) alloc.PlanArray<MethodOptions>(1);
+  }
+}
+
+static void PlanAllocationSize(
+    const RepeatedPtrField<ServiceDescriptorProto>& services,
+    internal::FlatAllocator& alloc) {
+  alloc.PlanArray<ServiceDescriptor>(services.size());
+  alloc.PlanArray<std::string>(2 * services.size());  // name + full_name
+  for (const auto& service : services) {
+    if (service.has_options()) alloc.PlanArray<ServiceOptions>(1);
+    PlanAllocationSize(service.method(), alloc);
+  }
+}
+
+static void PlanAllocationSize(const FileDescriptorProto& proto,
+                               internal::FlatAllocator& alloc) {
+  alloc.PlanArray<FileDescriptor>(1);
+  alloc.PlanArray<FileDescriptorTables>(1);
+  alloc.PlanArray<std::string>(2);  // name + package
+  if (proto.has_options()) alloc.PlanArray<FileOptions>(1);
+  if (proto.has_source_code_info()) alloc.PlanArray<SourceCodeInfo>(1);
+
+  PlanAllocationSize(proto.service(), alloc);
+  PlanAllocationSize(proto.message_type(), alloc);
+  PlanAllocationSize(proto.enum_type(), alloc);
+  PlanAllocationSize(proto.extension(), alloc);
+
+  alloc.PlanArray<int>(proto.weak_dependency_size());
+  alloc.PlanArray<int>(proto.public_dependency_size());
+  alloc.PlanArray<const FileDescriptor*>(proto.dependency_size());
+}
+
 const FileDescriptor* DescriptorBuilder::BuildFile(
     const FileDescriptorProto& proto) {
   filename_ = proto.name();
@@ -4906,12 +4983,16 @@
   // Checkpoint the tables so that we can roll back if something goes wrong.
   tables_->AddCheckpoint();
 
-  FileDescriptor* result = BuildFileImpl(proto);
+  internal::FlatAllocator alloc;
+  PlanAllocationSize(proto, alloc);
+  alloc.FinalizePlanning(tables_);
+  FileDescriptor* result = BuildFileImpl(proto, alloc);
 
   file_tables_->FinalizeTables();
   if (result) {
     tables_->ClearLastCheckpoint();
     result->finished_building_ = true;
+    alloc.ExpectConsumed();
   } else {
     tables_->RollbackToLastCheckpoint();
   }
@@ -4920,22 +5001,22 @@
 }
 
 FileDescriptor* DescriptorBuilder::BuildFileImpl(
-    const FileDescriptorProto& proto) {
-  FileDescriptor* result = tables_->Allocate<FileDescriptor>();
+    const FileDescriptorProto& proto, internal::FlatAllocator& alloc) {
+  FileDescriptor* result = alloc.AllocateArray<FileDescriptor>(1);
   file_ = result;
 
   result->is_placeholder_ = false;
   result->finished_building_ = false;
   SourceCodeInfo* info = nullptr;
   if (proto.has_source_code_info()) {
-    info = tables_->AllocateMessage<SourceCodeInfo>();
+    info = alloc.AllocateArray<SourceCodeInfo>(1);
     info->CopyFrom(proto.source_code_info());
     result->source_code_info_ = info;
   } else {
     result->source_code_info_ = &SourceCodeInfo::default_instance();
   }
 
-  file_tables_ = tables_->AllocateFileTables();
+  file_tables_ = alloc.AllocateArray<FileDescriptorTables>(1);
   file_->tables_ = file_tables_;
 
   if (!proto.has_name()) {
@@ -4955,15 +5036,15 @@
              "Unrecognized syntax: " + proto.syntax());
   }
 
-  result->name_ = tables_->AllocateString(proto.name());
+  result->name_ = alloc.AllocateStrings(proto.name());
   if (proto.has_package()) {
-    result->package_ = tables_->AllocateString(proto.package());
+    result->package_ = alloc.AllocateStrings(proto.package());
   } else {
     // We cannot rely on proto.package() returning a valid string if
     // proto.has_package() is false, because we might be running at static
     // initialization time, in which case default values have not yet been
     // initialized.
-    result->package_ = tables_->AllocateString("");
+    result->package_ = alloc.AllocateStrings("");
   }
   result->pool_ = pool_;
 
@@ -4982,6 +5063,12 @@
     return nullptr;
   }
   if (!result->package().empty()) {
+    if (std::count(result->package().begin(), result->package().end(), '.') >
+        kPackageLimit) {
+      AddError(result->package(), proto, DescriptorPool::ErrorCollector::NAME,
+               "Exceeds Maximum Package Depth");
+      return nullptr;
+    }
     AddPackage(result->package(), proto, result);
   }
 
@@ -4989,13 +5076,15 @@
   std::set<std::string> seen_dependencies;
   result->dependency_count_ = proto.dependency_size();
   result->dependencies_ =
-      tables_->AllocateArray<const FileDescriptor*>(proto.dependency_size());
+      alloc.AllocateArray<const FileDescriptor*>(proto.dependency_size());
   result->dependencies_once_ = nullptr;
   unused_dependency_.clear();
   std::set<int> weak_deps;
   for (int i = 0; i < proto.weak_dependency_size(); ++i) {
     weak_deps.insert(proto.weak_dependency(i));
   }
+
+  bool need_lazy_deps = false;
   for (int i = 0; i < proto.dependency_size(); i++) {
     if (!seen_dependencies.insert(proto.dependency(i)).second) {
       AddTwiceListedError(proto, i);
@@ -5017,8 +5106,12 @@
       if (!pool_->lazily_build_dependencies_) {
         if (pool_->allow_unknown_ ||
             (!pool_->enforce_weak_ && weak_deps.find(i) != weak_deps.end())) {
-          dependency =
-              pool_->NewPlaceholderFileWithMutexHeld(proto.dependency(i));
+          internal::FlatAllocator lazy_dep_alloc;
+          lazy_dep_alloc.PlanArray<FileDescriptor>(1);
+          lazy_dep_alloc.PlanArray<std::string>(1);
+          lazy_dep_alloc.FinalizePlanning(tables_);
+          dependency = pool_->NewPlaceholderFileWithMutexHeld(
+              proto.dependency(i), lazy_dep_alloc);
         } else {
           AddImportError(proto, i);
         }
@@ -5036,26 +5129,37 @@
 
     result->dependencies_[i] = dependency;
     if (pool_->lazily_build_dependencies_ && !dependency) {
-      if (result->dependencies_once_ == nullptr) {
-        result->dependencies_once_ =
-            tables_->Create<FileDescriptor::LazyInitData>();
-        result->dependencies_once_->dependencies_names =
-            tables_->AllocateArray<const char*>(proto.dependency_size());
-        if (proto.dependency_size() > 0) {
-          std::fill_n(result->dependencies_once_->dependencies_names,
-                      proto.dependency_size(), nullptr);
-        }
+      need_lazy_deps = true;
+    }
+  }
+  if (need_lazy_deps) {
+    int total_char_size = 0;
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        total_char_size += static_cast<int>(proto.dependency(i).size());
       }
+      ++total_char_size;  // For NUL char
+    }
 
-      result->dependencies_once_->dependencies_names[i] =
-          tables_->Strdup(proto.dependency(i));
+    void* data = tables_->AllocateBytes(
+        static_cast<int>(sizeof(internal::once_flag) + total_char_size));
+    result->dependencies_once_ = ::new (data) internal::once_flag{};
+    char* name_data = reinterpret_cast<char*>(result->dependencies_once_ + 1);
+
+    for (int i = 0; i < proto.dependency_size(); i++) {
+      if (result->dependencies_[i] == nullptr) {
+        memcpy(name_data, proto.dependency(i).c_str(),
+               proto.dependency(i).size());
+        name_data += proto.dependency(i).size();
+      }
+      *name_data++ = '\0';
     }
   }
 
   // Check public dependencies.
   int public_dependency_count = 0;
   result->public_dependencies_ =
-      tables_->AllocateArray<int>(proto.public_dependency_size());
+      alloc.AllocateArray<int>(proto.public_dependency_size());
   for (int i = 0; i < proto.public_dependency_size(); i++) {
     // Only put valid public dependency indexes.
     int index = proto.public_dependency(i);
@@ -5089,7 +5193,7 @@
   // Check weak dependencies.
   int weak_dependency_count = 0;
   result->weak_dependencies_ =
-      tables_->AllocateArray<int>(proto.weak_dependency_size());
+      alloc.AllocateArray<int>(proto.weak_dependency_size());
   for (int i = 0; i < proto.weak_dependency_size(); i++) {
     int index = proto.weak_dependency(i);
     if (index >= 0 && index < proto.dependency_size()) {
@@ -5110,7 +5214,7 @@
   // Copy options.
   result->options_ = nullptr;  // Set to default_instance later if necessary.
   if (proto.has_options()) {
-    AllocateOptions(proto.options(), result);
+    AllocateOptions(proto.options(), result, alloc);
   }
 
   // Note that the following steps must occur in exactly the specified order.
@@ -5166,21 +5270,33 @@
 
 
 const std::string* DescriptorBuilder::AllocateNameStrings(
-    const std::string& scope, const std::string& proto_name) {
+    const std::string& scope, const std::string& proto_name,
+    internal::FlatAllocator& alloc) {
   if (scope.empty()) {
-    return tables_->AllocateStringArray(proto_name, proto_name);
+    return alloc.AllocateStrings(proto_name, proto_name);
   } else {
-    return tables_->AllocateStringArray(proto_name,
-                                        StrCat(scope, ".", proto_name));
+    return alloc.AllocateStrings(proto_name,
+                                 StrCat(scope, ".", proto_name));
   }
 }
 
+namespace {
+
+// Helper for BuildMessage below.
+struct IncrementWhenDestroyed {
+  ~IncrementWhenDestroyed() { ++to_increment; }
+  int& to_increment;
+};
+
+}  // namespace
+
 void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
                                      const Descriptor* parent,
-                                     Descriptor* result) {
+                                     Descriptor* result,
+                                     internal::FlatAllocator& alloc) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
-  result->all_names_ = AllocateNameStrings(scope, proto.name());
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
   ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   result->file_ = file_;
@@ -5188,6 +5304,7 @@
   result->is_placeholder_ = false;
   result->is_unqualified_placeholder_ = false;
   result->well_known_type_ = Descriptor::WELLKNOWNTYPE_UNSPECIFIED;
+  result->options_ = nullptr;  // Set to default_instance later if necessary.
 
   auto it = pool_->tables_->well_known_types_.find(result->full_name());
   if (it != pool_->tables_->well_known_types_.end()) {
@@ -5210,28 +5327,38 @@
   // Build oneofs first so that fields and extension ranges can refer to them.
   BUILD_ARRAY(proto, result, oneof_decl, BuildOneof, result);
   BUILD_ARRAY(proto, result, field, BuildField, result);
-  BUILD_ARRAY(proto, result, nested_type, BuildMessage, result);
   BUILD_ARRAY(proto, result, enum_type, BuildEnum, result);
   BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
   BUILD_ARRAY(proto, result, extension, BuildExtension, result);
   BUILD_ARRAY(proto, result, reserved_range, BuildReservedRange, result);
 
+  // Before building submessages, check recursion limit.
+  --recursion_depth_;
+  IncrementWhenDestroyed revert{recursion_depth_};
+  if (recursion_depth_ <= 0) {
+    AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
+             "Reached maximum recursion limit for nested messages.");
+    result->nested_types_ = nullptr;
+    result->nested_type_count_ = 0;
+    return;
+  }
+  BUILD_ARRAY(proto, result, nested_type, BuildMessage, result);
+
   // Copy reserved names.
   int reserved_name_count = proto.reserved_name_size();
   result->reserved_name_count_ = reserved_name_count;
   result->reserved_names_ =
-      tables_->AllocateArray<const std::string*>(reserved_name_count);
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
   for (int i = 0; i < reserved_name_count; ++i) {
     result->reserved_names_[i] =
-        tables_->AllocateString(proto.reserved_name(i));
+        alloc.AllocateStrings(proto.reserved_name(i));
   }
 
   // Copy options.
-  result->options_ = nullptr;  // Set to default_instance later if necessary.
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     DescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.MessageOptions");
+                    "google.protobuf.MessageOptions", alloc);
   }
 
   AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
@@ -5327,13 +5454,14 @@
 void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
                                               Descriptor* parent,
                                               FieldDescriptor* result,
-                                              bool is_extension) {
+                                              bool is_extension,
+                                              internal::FlatAllocator& alloc) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
 
   // We allocate all names in a single array, and dedup them.
   // We remember the indices for the potentially deduped values.
-  auto all_names = tables_->AllocateFieldNames(
+  auto all_names = alloc.AllocateFieldNames(
       proto.name(), scope,
       proto.has_json_name() ? &proto.json_name() : nullptr);
   result->all_names_ = all_names.array;
@@ -5459,11 +5587,11 @@
           break;
         case FieldDescriptor::CPPTYPE_STRING:
           if (result->type() == FieldDescriptor::TYPE_BYTES) {
-            result->default_value_string_ = tables_->AllocateString(
+            result->default_value_string_ = alloc.AllocateStrings(
                 UnescapeCEscapeString(proto.default_value()));
           } else {
             result->default_value_string_ =
-                tables_->AllocateString(proto.default_value());
+                alloc.AllocateStrings(proto.default_value());
           }
           break;
         case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -5593,16 +5721,15 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     FieldDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.FieldOptions");
+                    "google.protobuf.FieldOptions", alloc);
   }
 
-
   AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
 }
 
 void DescriptorBuilder::BuildExtensionRange(
     const DescriptorProto::ExtensionRange& proto, const Descriptor* parent,
-    Descriptor::ExtensionRange* result) {
+    Descriptor::ExtensionRange* result, internal::FlatAllocator& alloc) {
   result->start = proto.start();
   result->end = proto.end();
   if (result->start <= 0) {
@@ -5633,13 +5760,13 @@
     options_path.push_back(DescriptorProto_ExtensionRange::kOptionsFieldNumber);
     AllocateOptionsImpl(parent->full_name(), parent->full_name(),
                         proto.options(), result, options_path,
-                        "google.protobuf.ExtensionRangeOptions");
+                        "google.protobuf.ExtensionRangeOptions", alloc);
   }
 }
 
 void DescriptorBuilder::BuildReservedRange(
     const DescriptorProto::ReservedRange& proto, const Descriptor* parent,
-    Descriptor::ReservedRange* result) {
+    Descriptor::ReservedRange* result, internal::FlatAllocator&) {
   result->start = proto.start();
   result->end = proto.end();
   if (result->start <= 0) {
@@ -5650,7 +5777,8 @@
 
 void DescriptorBuilder::BuildReservedRange(
     const EnumDescriptorProto::EnumReservedRange& proto,
-    const EnumDescriptor* parent, EnumDescriptor::ReservedRange* result) {
+    const EnumDescriptor* parent, EnumDescriptor::ReservedRange* result,
+    internal::FlatAllocator&) {
   result->start = proto.start();
   result->end = proto.end();
 
@@ -5661,9 +5789,10 @@
 }
 
 void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
-                                   Descriptor* parent,
-                                   OneofDescriptor* result) {
-  result->all_names_ = AllocateNameStrings(parent->full_name(), proto.name());
+                                   Descriptor* parent, OneofDescriptor* result,
+                                   internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
   ValidateSymbolName(proto.name(), result->full_name(), proto);
 
   result->containing_type_ = parent;
@@ -5677,7 +5806,7 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     OneofDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.OneofOptions");
+                    "google.protobuf.OneofOptions", alloc);
   }
 
   AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
@@ -5751,11 +5880,12 @@
 
 void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
                                   const Descriptor* parent,
-                                  EnumDescriptor* result) {
+                                  EnumDescriptor* result,
+                                  internal::FlatAllocator& alloc) {
   const std::string& scope =
       (parent == nullptr) ? file_->package() : parent->full_name();
 
-  result->all_names_ = AllocateNameStrings(scope, proto.name());
+  result->all_names_ = AllocateNameStrings(scope, proto.name(), alloc);
   ValidateSymbolName(proto.name(), result->full_name(), proto);
   result->file_ = file_;
   result->containing_type_ = parent;
@@ -5791,10 +5921,10 @@
   int reserved_name_count = proto.reserved_name_size();
   result->reserved_name_count_ = reserved_name_count;
   result->reserved_names_ =
-      tables_->AllocateArray<const std::string*>(reserved_name_count);
+      alloc.AllocateArray<const std::string*>(reserved_name_count);
   for (int i = 0; i < reserved_name_count; ++i) {
     result->reserved_names_[i] =
-        tables_->AllocateString(proto.reserved_name(i));
+        alloc.AllocateStrings(proto.reserved_name(i));
   }
 
   CheckEnumValueUniqueness(proto, result);
@@ -5804,7 +5934,7 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     EnumDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.EnumOptions");
+                    "google.protobuf.EnumOptions", alloc);
   }
 
   AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result));
@@ -5860,7 +5990,8 @@
 
 void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
                                        const EnumDescriptor* parent,
-                                       EnumValueDescriptor* result) {
+                                       EnumValueDescriptor* result,
+                                       internal::FlatAllocator& alloc) {
   // Note:  full_name for enum values is a sibling to the parent's name, not a
   //   child of it.
   std::string full_name;
@@ -5870,7 +6001,7 @@
   full_name.append(proto.name());
 
   result->all_names_ =
-      tables_->AllocateStringArray(proto.name(), std::move(full_name));
+      alloc.AllocateStrings(proto.name(), std::move(full_name));
   result->number_ = proto.number();
   result->type_ = parent;
 
@@ -5881,7 +6012,7 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     EnumValueDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.EnumValueOptions");
+                    "google.protobuf.EnumValueOptions", alloc);
   }
 
   // Again, enum values are weird because we makes them appear as siblings
@@ -5931,8 +6062,10 @@
 
 void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
                                      const void* /* dummy */,
-                                     ServiceDescriptor* result) {
-  result->all_names_ = AllocateNameStrings(file_->package(), proto.name());
+                                     ServiceDescriptor* result,
+                                     internal::FlatAllocator& alloc) {
+  result->all_names_ =
+      AllocateNameStrings(file_->package(), proto.name(), alloc);
   result->file_ = file_;
   ValidateSymbolName(proto.name(), result->full_name(), proto);
 
@@ -5943,7 +6076,7 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     ServiceDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.ServiceOptions");
+                    "google.protobuf.ServiceOptions", alloc);
   }
 
   AddSymbol(result->full_name(), nullptr, result->name(), proto,
@@ -5952,9 +6085,11 @@
 
 void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
                                     const ServiceDescriptor* parent,
-                                    MethodDescriptor* result) {
+                                    MethodDescriptor* result,
+                                    internal::FlatAllocator& alloc) {
   result->service_ = parent;
-  result->all_names_ = AllocateNameStrings(parent->full_name(), proto.name());
+  result->all_names_ =
+      AllocateNameStrings(parent->full_name(), proto.name(), alloc);
 
   ValidateSymbolName(proto.name(), result->full_name(), proto);
 
@@ -5967,7 +6102,7 @@
   if (proto.has_options()) {
     AllocateOptions(proto.options(), result,
                     MethodDescriptorProto::kOptionsFieldNumber,
-                    "google.protobuf.MethodOptions");
+                    "google.protobuf.MethodOptions", alloc);
   }
 
   result->client_streaming_ = proto.client_streaming();
@@ -6214,12 +6349,18 @@
       if (is_lazy) {
         // Save the symbol names for later for lookup, and allocate the once
         // object needed for the accessors.
-        std::string name = proto.type_name();
-        field->type_once_ = tables_->Create<internal::once_flag>();
-        field->type_descriptor_.lazy_type_name = tables_->Strdup(name);
-        field->lazy_default_value_enum_name_ =
-            proto.has_default_value() ? tables_->Strdup(proto.default_value())
-                                      : nullptr;
+        const std::string& name = proto.type_name();
+
+        int name_sizes = static_cast<int>(name.size() + 1 +
+                                          proto.default_value().size() + 1);
+
+        field->type_once_ = ::new (tables_->AllocateBytes(static_cast<int>(
+            sizeof(internal::once_flag) + name_sizes))) internal::once_flag{};
+        char* names = reinterpret_cast<char*>(field->type_once_ + 1);
+
+        memcpy(names, name.c_str(), name.size() + 1);
+        memcpy(names + name.size() + 1, proto.default_value().c_str(),
+               proto.default_value().size() + 1);
 
         // AddFieldByNumber and AddExtension are done later in this function,
         // and can/must be done if the field type was not found. The related
@@ -6466,7 +6607,6 @@
     method->output_type_.Set(output_type.descriptor());
   }
 }
-
 // -------------------------------------------------------------------
 
 #define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \
@@ -6660,7 +6800,7 @@
     return;
   }
   // Only message type fields may be lazy.
-  if (field->options().lazy()) {
+  if (field->options().lazy() || field->options().unverified_lazy()) {
     if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
       AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
                "[lazy = true] can only be specified for submessage fields.");
@@ -6877,6 +7017,7 @@
                  DescriptorPool::ErrorCollector::NAME,
                  "Expanded map entry type " + nested->name() +
                      " conflicts with an existing nested message type.");
+        break;
       }
     }
     // Recursively test on the nested types.
@@ -7218,11 +7359,9 @@
         new UnknownFieldSet());
     switch ((*iter)->type()) {
       case FieldDescriptor::TYPE_MESSAGE: {
-        io::StringOutputStream outstr(
-            parent_unknown_fields->AddLengthDelimited((*iter)->number()));
-        io::CodedOutputStream out(&outstr);
-        internal::WireFormat::SerializeUnknownFields(*unknown_fields, &out);
-        GOOGLE_CHECK(!out.HadError())
+        std::string* outstr =
+            parent_unknown_fields->AddLengthDelimited((*iter)->number());
+        GOOGLE_CHECK(unknown_fields->SerializeToString(outstr))
             << "Unexpected failure while serializing option submessage "
             << debug_msg_name << "\".";
         break;
@@ -7880,8 +8019,11 @@
 void FieldDescriptor::InternalTypeOnceInit() const {
   GOOGLE_CHECK(file()->finished_building_ == true);
   const EnumDescriptor* enum_type = nullptr;
+  const char* lazy_type_name = reinterpret_cast<const char*>(type_once_ + 1);
+  const char* lazy_default_value_enum_name =
+      lazy_type_name + strlen(lazy_type_name) + 1;
   Symbol result = file()->pool()->CrossLinkOnDemandHelper(
-      type_descriptor_.lazy_type_name, type_ == FieldDescriptor::TYPE_ENUM);
+      lazy_type_name, type_ == FieldDescriptor::TYPE_ENUM);
   if (result.type() == Symbol::MESSAGE) {
     type_ = FieldDescriptor::TYPE_MESSAGE;
     type_descriptor_.message_type = result.descriptor();
@@ -7891,16 +8033,16 @@
   }
 
   if (enum_type) {
-    if (lazy_default_value_enum_name_) {
+    if (lazy_default_value_enum_name[0] != '\0') {
       // Have to build the full name now instead of at CrossLink time,
       // because enum_type may not be known at the time.
       std::string name = enum_type->full_name();
       // Enum values reside in the same scope as the enum type.
       std::string::size_type last_dot = name.find_last_of('.');
       if (last_dot != std::string::npos) {
-        name = name.substr(0, last_dot) + "." + lazy_default_value_enum_name_;
+        name = name.substr(0, last_dot) + "." + lazy_default_value_enum_name;
       } else {
-        name = lazy_default_value_enum_name_;
+        name = lazy_default_value_enum_name;
       }
       Symbol result = file()->pool()->CrossLinkOnDemandHelper(name, true);
       default_value_enum_ = result.enum_value_descriptor();
@@ -7957,10 +8099,12 @@
 
 void FileDescriptor::InternalDependenciesOnceInit() const {
   GOOGLE_CHECK(finished_building_ == true);
-  auto* names = dependencies_once_->dependencies_names;
+  const char* names_ptr = reinterpret_cast<const char*>(dependencies_once_ + 1);
   for (int i = 0; i < dependency_count(); i++) {
-    if (names[i]) {
-      dependencies_[i] = pool_->FindFileByName(names[i]);
+    const char* name = names_ptr;
+    names_ptr += strlen(name) + 1;
+    if (name[0] != '\0') {
+      dependencies_[i] = pool_->FindFileByName(name);
     }
   }
 }
@@ -7973,7 +8117,7 @@
   if (dependencies_once_) {
     // Do once init for all indices, as it's unlikely only a single index would
     // be called, and saves on internal::call_once allocations.
-    internal::call_once(dependencies_once_->once,
+    internal::call_once(*dependencies_once_,
                         FileDescriptor::DependenciesOnceInit, this);
   }
   return dependencies_[index];
@@ -7987,7 +8131,6 @@
   return output_type_.Get(service());
 }
 
-
 namespace internal {
 void LazyDescriptor::Set(const Descriptor* descriptor) {
   GOOGLE_CHECK(!once_);
@@ -8002,8 +8145,11 @@
   GOOGLE_CHECK(file && file->pool_);
   GOOGLE_CHECK(file->pool_->lazily_build_dependencies_);
   GOOGLE_CHECK(!file->finished_building_);
-  once_ = file->pool_->tables_->Create<internal::once_flag>();
-  lazy_name_ = file->pool_->tables_->Strdup(name);
+  once_ = ::new (file->pool_->tables_->AllocateBytes(static_cast<int>(
+      sizeof(internal::once_flag) + name.size() + 1))) internal::once_flag{};
+  char* lazy_name = reinterpret_cast<char*>(once_ + 1);
+  memcpy(lazy_name, name.data(), name.size());
+  lazy_name[name.size()] = 0;
 }
 
 void LazyDescriptor::Once(const ServiceDescriptor* service) {
@@ -8011,8 +8157,9 @@
     internal::call_once(*once_, [&] {
       auto* file = service->file();
       GOOGLE_CHECK(file->finished_building_);
+      const char* lazy_name = reinterpret_cast<const char*>(once_ + 1);
       descriptor_ =
-          file->pool_->CrossLinkOnDemandHelper(lazy_name_, false).descriptor();
+          file->pool_->CrossLinkOnDemandHelper(lazy_name, false).descriptor();
     });
   }
 }
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index e74e355..1b8728e 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -54,6 +54,7 @@
 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
 #define GOOGLE_PROTOBUF_DESCRIPTOR_H__
 
+
 #include <atomic>
 #include <map>
 #include <memory>
@@ -66,6 +67,8 @@
 #include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/port.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 // TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
@@ -184,6 +187,19 @@
 // Must be instantiated as mutable in a descriptor.
 namespace internal {
 
+// The classes in this file represent a significant memory footprint for the
+// library. We make sure we are not accidentally making them larger by
+// hardcoding the struct size for a specific platform. Use as:
+//
+//   PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(type, expected_size_in_x84-64);
+//
+
+#if !defined(PROTOBUF_INTERNAL_CHECK_CLASS_SIZE)
+#define PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(t, expected)
+#endif
+
+class FlatAllocator;
+
 class PROTOBUF_EXPORT LazyDescriptor {
  public:
   // Init function to be called at init time of a descriptor containing
@@ -217,10 +233,8 @@
  private:
   void Once(const ServiceDescriptor* service);
 
-  union {
-    const Descriptor* descriptor_;
-    const char* lazy_name_;
-  };
+  const Descriptor* descriptor_;
+  // The once_ flag is followed by a NUL terminated string for the type name.
   internal::once_flag* once_;
 };
 
@@ -598,6 +612,7 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 136);
 
 // Describes a single field of a message.  To get the descriptor for a given
 // field, first get the Descriptor for the message in which it is defined,
@@ -924,6 +939,8 @@
   const std::string* all_names_;
   const FileDescriptor* file_;
 
+  // The once_flag is followed by a NUL terminated string for the type name and
+  // enum default value (or empty string if no default enum).
   internal::once_flag* type_once_;
   static void TypeOnceInit(const FieldDescriptor* to_init);
   void InternalTypeOnceInit() const;
@@ -935,7 +952,6 @@
   union {
     mutable const Descriptor* message_type;
     mutable const EnumDescriptor* enum_type;
-    const char* lazy_type_name;
   } type_descriptor_;
   const FieldOptions* options_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
@@ -952,7 +968,6 @@
     bool default_value_bool_;
 
     mutable const EnumValueDescriptor* default_value_enum_;
-    const char* lazy_default_value_enum_name_;
     const std::string* default_value_string_;
     mutable std::atomic<const Message*> default_generated_instance_;
   };
@@ -974,6 +989,7 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 72);
 
 // Describes a oneof defined in a message type.
 class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
@@ -1054,6 +1070,8 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OneofDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 40);
+
 // Describes an enum type defined in a .proto file.  To get the EnumDescriptor
 // for a generated enum type, call TypeName_descriptor().  Use DescriptorPool
 // to construct your own descriptors.
@@ -1223,6 +1241,8 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 72);
+
 // Describes an individual enum constant of a particular type.  To get the
 // EnumValueDescriptor for a given enum value, first get the EnumDescriptor
 // for its type, then use EnumDescriptor::FindValueByName() or
@@ -1306,6 +1326,8 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 32);
+
 // Describes an RPC service. Use DescriptorPool to construct your own
 // descriptors.
 class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
@@ -1336,6 +1358,7 @@
 
   // Look up a MethodDescriptor by name.
   const MethodDescriptor* FindMethodByName(ConstStringParam name) const;
+
   // See Descriptor::CopyTo().
   void CopyTo(ServiceDescriptorProto* proto) const;
 
@@ -1386,6 +1409,7 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 48);
 
 // Describes an individual service method.  To obtain a MethodDescriptor given
 // a service, first get its ServiceDescriptor, then call
@@ -1474,11 +1498,12 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 64);
 
 // Describes a whole .proto file.  To get the FileDescriptor for a compiled-in
 // file, get the descriptor for something defined in that file and call
 // descriptor->file().  Use DescriptorPool to construct your own descriptors.
-class PROTOBUF_EXPORT FileDescriptor {
+class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
  public:
   typedef FileDescriptorProto Proto;
 
@@ -1615,32 +1640,9 @@
                          SourceLocation* out_location) const;
 
  private:
+  friend class Symbol;
   typedef FileOptions OptionsType;
 
-  const std::string* name_;
-  const std::string* package_;
-  const DescriptorPool* pool_;
-
-  // Data required to do lazy initialization.
-  struct PROTOBUF_EXPORT LazyInitData {
-#ifndef SWIG
-    internal::once_flag once;
-#endif
-    const char** dependencies_names;
-  };
-
-  LazyInitData* dependencies_once_;
-  static void DependenciesOnceInit(const FileDescriptor* to_init);
-  void InternalDependenciesOnceInit() const;
-
-  // These are arranged to minimize padding on 64-bit.
-  int dependency_count_;
-  int public_dependency_count_;
-  int weak_dependency_count_;
-  int message_type_count_;
-  int enum_type_count_;
-  int service_count_;
-
   bool is_placeholder_;
   // Indicates the FileDescriptor is completed building. Used to verify
   // that type accessor functions that can possibly build a dependent file
@@ -1651,6 +1653,25 @@
   // This one is here to fill the padding.
   int extension_count_;
 
+  const std::string* name_;
+  const std::string* package_;
+  const DescriptorPool* pool_;
+
+  // dependencies_once_ contain a once_flag followed by N NUL terminated
+  // strings. Dependencies that do not need to be loaded will be empty. ie just
+  // {'\0'}
+  internal::once_flag* dependencies_once_;
+  static void DependenciesOnceInit(const FileDescriptor* to_init);
+  void InternalDependenciesOnceInit() const;
+
+  // These are arranged to minimize padding on 64-bit.
+  int dependency_count_;
+  int public_dependency_count_;
+  int weak_dependency_count_;
+  int message_type_count_;
+  int enum_type_count_;
+  int service_count_;
+
   mutable const FileDescriptor** dependencies_;
   int* public_dependencies_;
   int* weak_dependencies_;
@@ -1681,6 +1702,7 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor);
 };
 
+PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 144);
 
 // ===================================================================
 
@@ -1973,7 +1995,6 @@
   friend class ServiceDescriptor;
   friend class MethodDescriptor;
   friend class FileDescriptor;
-  friend class StreamDescriptor;
   friend class DescriptorBuilder;
   friend class FileDescriptorTables;
 
@@ -2013,7 +2034,8 @@
 
   // Create a placeholder FileDescriptor of the specified name
   FileDescriptor* NewPlaceholderFile(StringPiece name) const;
-  FileDescriptor* NewPlaceholderFileWithMutexHeld(StringPiece name) const;
+  FileDescriptor* NewPlaceholderFileWithMutexHeld(
+      StringPiece name, internal::FlatAllocator& alloc) const;
 
   enum PlaceholderType {
     PLACEHOLDER_MESSAGE,
@@ -2412,6 +2434,7 @@
 }  // namespace protobuf
 }  // namespace google
 
+#undef PROTOBUF_INTERNAL_CHECK_CLASS_SIZE
 #include <google/protobuf/port_undef.inc>
 
 #endif  // GOOGLE_PROTOBUF_DESCRIPTOR_H__
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 5229e77..f20705c 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -16,21 +16,25 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr FileDescriptorSet::FileDescriptorSet(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : file_(){}
 struct FileDescriptorSetDefaultTypeInternal {
   constexpr FileDescriptorSetDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FileDescriptorSetDefaultTypeInternal() {}
   union {
     FileDescriptorSet _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorSetDefaultTypeInternal _FileDescriptorSet_default_instance_;
 constexpr FileDescriptorProto::FileDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : dependency_()
   , message_type_()
   , enum_type_()
@@ -45,42 +49,42 @@
   , source_code_info_(nullptr){}
 struct FileDescriptorProtoDefaultTypeInternal {
   constexpr FileDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FileDescriptorProtoDefaultTypeInternal() {}
   union {
     FileDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileDescriptorProtoDefaultTypeInternal _FileDescriptorProto_default_instance_;
 constexpr DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : options_(nullptr)
   , start_(0)
   , end_(0){}
 struct DescriptorProto_ExtensionRangeDefaultTypeInternal {
   constexpr DescriptorProto_ExtensionRangeDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~DescriptorProto_ExtensionRangeDefaultTypeInternal() {}
   union {
     DescriptorProto_ExtensionRange _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ExtensionRangeDefaultTypeInternal _DescriptorProto_ExtensionRange_default_instance_;
 constexpr DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : start_(0)
   , end_(0){}
 struct DescriptorProto_ReservedRangeDefaultTypeInternal {
   constexpr DescriptorProto_ReservedRangeDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~DescriptorProto_ReservedRangeDefaultTypeInternal() {}
   union {
     DescriptorProto_ReservedRange _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProto_ReservedRangeDefaultTypeInternal _DescriptorProto_ReservedRange_default_instance_;
 constexpr DescriptorProto::DescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : field_()
   , nested_type_()
   , enum_type_()
@@ -93,27 +97,27 @@
   , options_(nullptr){}
 struct DescriptorProtoDefaultTypeInternal {
   constexpr DescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~DescriptorProtoDefaultTypeInternal() {}
   union {
     DescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DescriptorProtoDefaultTypeInternal _DescriptorProto_default_instance_;
 constexpr ExtensionRangeOptions::ExtensionRangeOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_(){}
 struct ExtensionRangeOptionsDefaultTypeInternal {
   constexpr ExtensionRangeOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ExtensionRangeOptionsDefaultTypeInternal() {}
   union {
     ExtensionRangeOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExtensionRangeOptionsDefaultTypeInternal _ExtensionRangeOptions_default_instance_;
 constexpr FieldDescriptorProto::FieldDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , extendee_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , type_name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -129,41 +133,41 @@
 {}
 struct FieldDescriptorProtoDefaultTypeInternal {
   constexpr FieldDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FieldDescriptorProtoDefaultTypeInternal() {}
   union {
     FieldDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDescriptorProtoDefaultTypeInternal _FieldDescriptorProto_default_instance_;
 constexpr OneofDescriptorProto::OneofDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , options_(nullptr){}
 struct OneofDescriptorProtoDefaultTypeInternal {
   constexpr OneofDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~OneofDescriptorProtoDefaultTypeInternal() {}
   union {
     OneofDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofDescriptorProtoDefaultTypeInternal _OneofDescriptorProto_default_instance_;
 constexpr EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : start_(0)
   , end_(0){}
 struct EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal {
   constexpr EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal() {}
   union {
     EnumDescriptorProto_EnumReservedRange _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProto_EnumReservedRangeDefaultTypeInternal _EnumDescriptorProto_EnumReservedRange_default_instance_;
 constexpr EnumDescriptorProto::EnumDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_()
   , reserved_range_()
   , reserved_name_()
@@ -171,43 +175,43 @@
   , options_(nullptr){}
 struct EnumDescriptorProtoDefaultTypeInternal {
   constexpr EnumDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumDescriptorProtoDefaultTypeInternal() {}
   union {
     EnumDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDescriptorProtoDefaultTypeInternal _EnumDescriptorProto_default_instance_;
 constexpr EnumValueDescriptorProto::EnumValueDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , options_(nullptr)
   , number_(0){}
 struct EnumValueDescriptorProtoDefaultTypeInternal {
   constexpr EnumValueDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumValueDescriptorProtoDefaultTypeInternal() {}
   union {
     EnumValueDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDescriptorProtoDefaultTypeInternal _EnumValueDescriptorProto_default_instance_;
 constexpr ServiceDescriptorProto::ServiceDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : method_()
   , name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , options_(nullptr){}
 struct ServiceDescriptorProtoDefaultTypeInternal {
   constexpr ServiceDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ServiceDescriptorProtoDefaultTypeInternal() {}
   union {
     ServiceDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceDescriptorProtoDefaultTypeInternal _ServiceDescriptorProto_default_instance_;
 constexpr MethodDescriptorProto::MethodDescriptorProto(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , input_type_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , output_type_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -216,15 +220,15 @@
   , server_streaming_(false){}
 struct MethodDescriptorProtoDefaultTypeInternal {
   constexpr MethodDescriptorProtoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~MethodDescriptorProtoDefaultTypeInternal() {}
   union {
     MethodDescriptorProto _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodDescriptorProtoDefaultTypeInternal _MethodDescriptorProto_default_instance_;
 constexpr FileOptions::FileOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , java_package_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , java_outer_classname_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -249,15 +253,15 @@
   , cc_enable_arenas_(true){}
 struct FileOptionsDefaultTypeInternal {
   constexpr FileOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FileOptionsDefaultTypeInternal() {}
   union {
     FileOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FileOptionsDefaultTypeInternal _FileOptions_default_instance_;
 constexpr MessageOptions::MessageOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , message_set_wire_format_(false)
   , no_standard_descriptor_accessor_(false)
@@ -265,115 +269,116 @@
   , map_entry_(false){}
 struct MessageOptionsDefaultTypeInternal {
   constexpr MessageOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~MessageOptionsDefaultTypeInternal() {}
   union {
     MessageOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MessageOptionsDefaultTypeInternal _MessageOptions_default_instance_;
 constexpr FieldOptions::FieldOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , ctype_(0)
 
+  , jstype_(0)
+
   , packed_(false)
   , lazy_(false)
+  , unverified_lazy_(false)
   , deprecated_(false)
-  , weak_(false)
-  , jstype_(0)
-{}
+  , weak_(false){}
 struct FieldOptionsDefaultTypeInternal {
   constexpr FieldOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FieldOptionsDefaultTypeInternal() {}
   union {
     FieldOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldOptionsDefaultTypeInternal _FieldOptions_default_instance_;
 constexpr OneofOptions::OneofOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_(){}
 struct OneofOptionsDefaultTypeInternal {
   constexpr OneofOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~OneofOptionsDefaultTypeInternal() {}
   union {
     OneofOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OneofOptionsDefaultTypeInternal _OneofOptions_default_instance_;
 constexpr EnumOptions::EnumOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , allow_alias_(false)
   , deprecated_(false){}
 struct EnumOptionsDefaultTypeInternal {
   constexpr EnumOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumOptionsDefaultTypeInternal() {}
   union {
     EnumOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumOptionsDefaultTypeInternal _EnumOptions_default_instance_;
 constexpr EnumValueOptions::EnumValueOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , deprecated_(false){}
 struct EnumValueOptionsDefaultTypeInternal {
   constexpr EnumValueOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumValueOptionsDefaultTypeInternal() {}
   union {
     EnumValueOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueOptionsDefaultTypeInternal _EnumValueOptions_default_instance_;
 constexpr ServiceOptions::ServiceOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , deprecated_(false){}
 struct ServiceOptionsDefaultTypeInternal {
   constexpr ServiceOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ServiceOptionsDefaultTypeInternal() {}
   union {
     ServiceOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ServiceOptionsDefaultTypeInternal _ServiceOptions_default_instance_;
 constexpr MethodOptions::MethodOptions(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : uninterpreted_option_()
   , deprecated_(false)
   , idempotency_level_(0)
 {}
 struct MethodOptionsDefaultTypeInternal {
   constexpr MethodOptionsDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~MethodOptionsDefaultTypeInternal() {}
   union {
     MethodOptions _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 MethodOptionsDefaultTypeInternal _MethodOptions_default_instance_;
 constexpr UninterpretedOption_NamePart::UninterpretedOption_NamePart(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_part_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , is_extension_(false){}
 struct UninterpretedOption_NamePartDefaultTypeInternal {
   constexpr UninterpretedOption_NamePartDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~UninterpretedOption_NamePartDefaultTypeInternal() {}
   union {
     UninterpretedOption_NamePart _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOption_NamePartDefaultTypeInternal _UninterpretedOption_NamePart_default_instance_;
 constexpr UninterpretedOption::UninterpretedOption(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_()
   , identifier_value_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , string_value_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -383,15 +388,15 @@
   , double_value_(0){}
 struct UninterpretedOptionDefaultTypeInternal {
   constexpr UninterpretedOptionDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~UninterpretedOptionDefaultTypeInternal() {}
   union {
     UninterpretedOption _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UninterpretedOptionDefaultTypeInternal _UninterpretedOption_default_instance_;
 constexpr SourceCodeInfo_Location::SourceCodeInfo_Location(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : path_()
   , _path_cached_byte_size_(0)
   , span_()
@@ -401,27 +406,27 @@
   , trailing_comments_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){}
 struct SourceCodeInfo_LocationDefaultTypeInternal {
   constexpr SourceCodeInfo_LocationDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~SourceCodeInfo_LocationDefaultTypeInternal() {}
   union {
     SourceCodeInfo_Location _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfo_LocationDefaultTypeInternal _SourceCodeInfo_Location_default_instance_;
 constexpr SourceCodeInfo::SourceCodeInfo(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : location_(){}
 struct SourceCodeInfoDefaultTypeInternal {
   constexpr SourceCodeInfoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~SourceCodeInfoDefaultTypeInternal() {}
   union {
     SourceCodeInfo _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceCodeInfoDefaultTypeInternal _SourceCodeInfo_default_instance_;
 constexpr GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : path_()
   , _path_cached_byte_size_(0)
   , source_file_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -429,29 +434,29 @@
   , end_(0){}
 struct GeneratedCodeInfo_AnnotationDefaultTypeInternal {
   constexpr GeneratedCodeInfo_AnnotationDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~GeneratedCodeInfo_AnnotationDefaultTypeInternal() {}
   union {
     GeneratedCodeInfo_Annotation _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfo_AnnotationDefaultTypeInternal _GeneratedCodeInfo_Annotation_default_instance_;
 constexpr GeneratedCodeInfo::GeneratedCodeInfo(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : annotation_(){}
 struct GeneratedCodeInfoDefaultTypeInternal {
   constexpr GeneratedCodeInfoDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~GeneratedCodeInfoDefaultTypeInternal() {}
   union {
     GeneratedCodeInfo _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
-static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -726,15 +731,17 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, packed_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, jstype_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, lazy_),
+  PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, unverified_lazy_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, deprecated_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, weak_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldOptions, uninterpreted_option_),
   0,
-  1,
-  5,
   2,
+  1,
   3,
   4,
+  5,
+  6,
   ~0u,
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::OneofOptions, _internal_metadata_),
@@ -862,7 +869,7 @@
   ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, annotation_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorSet)},
   { 7, 25, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileDescriptorProto)},
   { 37, 46, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange)},
@@ -878,48 +885,48 @@
   { 180, 192, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto)},
   { 198, 225, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FileOptions)},
   { 246, 257, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MessageOptions)},
-  { 262, 275, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldOptions)},
-  { 282, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofOptions)},
-  { 289, 298, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumOptions)},
-  { 301, 309, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
-  { 311, 319, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceOptions)},
-  { 321, 330, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodOptions)},
-  { 333, 341, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
-  { 343, 356, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
-  { 363, 374, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
-  { 379, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
-  { 386, 396, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
-  { 400, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
+  { 262, 276, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldOptions)},
+  { 284, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::OneofOptions)},
+  { 291, 300, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumOptions)},
+  { 303, 311, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValueOptions)},
+  { 313, 321, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ServiceOptions)},
+  { 323, 332, -1, sizeof(::PROTOBUF_NAMESPACE_ID::MethodOptions)},
+  { 335, 343, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart)},
+  { 345, 358, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
+  { 365, 376, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
+  { 381, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
+  { 388, 398, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
+  { 402, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FileDescriptorSet_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FileDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ExtensionRange_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ReservedRange_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_DescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FieldDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_OneofDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_EnumReservedRange_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumValueDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_ServiceDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_MethodDescriptorProto_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_NamePart_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_Location_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_Annotation_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorSet_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ExtensionRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_ReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_DescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ExtensionRangeOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_EnumReservedRange_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodDescriptorProto_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FileOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MessageOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FieldOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_OneofOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValueOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ServiceOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_MethodOptions_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_NamePart_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UninterpretedOption_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_Location_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_SourceCodeInfo_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_Annotation_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_GeneratedCodeInfo_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -1023,72 +1030,74 @@
   "ed\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024un"
   "interpreted_option\030\347\007 \003(\0132$.google.proto"
   "buf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005"
-  "J\004\010\005\020\006J\004\010\006\020\007J\004\010\010\020\tJ\004\010\t\020\n\"\236\003\n\014FieldOption"
+  "J\004\010\005\020\006J\004\010\006\020\007J\004\010\010\020\tJ\004\010\t\020\n\"\276\003\n\014FieldOption"
   "s\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Field"
   "Options.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n"
   "\006jstype\030\006 \001(\0162$.google.protobuf.FieldOpt"
   "ions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005fa"
-  "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n"
+  "lse\022\036\n\017unverified_lazy\030\017 \001(\010:\005false\022\031\n\nd"
+  "eprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005fa"
+  "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+  "gle.protobuf.UninterpretedOption\"/\n\005CTyp"
+  "e\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020"
+  "\002\"5\n\006JSType\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\002J\004\010\004\020\005\"^\n\014One"
+  "ofOptions\022C\n\024uninterpreted_option\030\347\007 \003(\013"
+  "2$.google.protobuf.UninterpretedOption*\t"
+  "\010\350\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013allow_alias"
+  "\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\005\020\006\""
+  "}\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\ndeprecated\030!"
   " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
   "(\0132$.google.protobuf.UninterpretedOption"
-  "\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRIN"
-  "G_PIECE\020\002\"5\n\006JSType\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\002J\004\010\004\020"
-  "\005\"^\n\014OneofOptions\022C\n\024uninterpreted_optio"
-  "n\030\347\007 \003(\0132$.google.protobuf.Uninterpreted"
-  "Option*\t\010\350\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013all"
-  "ow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fals"
-  "e\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.googl"
-  "e.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200"
-  "\002J\004\010\005\020\006\"}\n\020EnumValueOptions\022\031\n\ndeprecate"
-  "d\030\001 \001(\010:\005false\022C\n\024uninterpreted_option\030\347"
-  "\007 \003(\0132$.google.protobuf.UninterpretedOpt"
-  "ion*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\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\"\255\002\n\rMethodOptions\022\031\n"
-  "\ndeprecated\030! \001(\010:\005false\022_\n\021idempotency_"
-  "level\030\" \001(\0162/.google.protobuf.MethodOpti"
-  "ons.IdempotencyLevel:\023IDEMPOTENCY_UNKNOW"
-  "N\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.googl"
-  "e.protobuf.UninterpretedOption\"P\n\020Idempo"
-  "tencyLevel\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017N"
-  "O_SIDE_EFFECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200"
-  "\200\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003("
-  "\0132-.google.protobuf.UninterpretedOption."
-  "NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022po"
-  "sitive_int_value\030\004 \001(\004\022\032\n\022negative_int_v"
-  "alue\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014stri"
-  "ng_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\032"
-  "3\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_ext"
-  "ension\030\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010locat"
-  "ion\030\001 \003(\0132(.google.protobuf.SourceCodeIn"
-  "fo.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\020leading_comments"
-  "\030\003 \001(\t\022\031\n\021trailing_comments\030\004 \001(\t\022!\n\031lea"
-  "ding_detached_comments\030\006 \003(\t\"\247\001\n\021Generat"
-  "edCodeInfo\022A\n\nannotation\030\001 \003(\0132-.google."
-  "protobuf.GeneratedCodeInfo.Annotation\032O\n"
-  "\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source_"
-  "file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B~"
-  "\n\023com.google.protobufB\020DescriptorProtosH"
-  "\001Z-google.golang.org/protobuf/types/desc"
-  "riptorpb\370\001\001\242\002\003GPB\252\002\032Google.Protobuf.Refl"
-  "ection"
+  "*\t\010\350\007\020\200\200\200\200\002\"\255\002\n\rMethodOptions\022\031\n\ndepreca"
+  "ted\030! \001(\010:\005false\022_\n\021idempotency_level\030\" "
+  "\001(\0162/.google.protobuf.MethodOptions.Idem"
+  "potencyLevel:\023IDEMPOTENCY_UNKNOWN\022C\n\024uni"
+  "nterpreted_option\030\347\007 \003(\0132$.google.protob"
+  "uf.UninterpretedOption\"P\n\020IdempotencyLev"
+  "el\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017NO_SIDE_E"
+  "FFECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023"
+  "UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goog"
+  "le.protobuf.UninterpretedOption.NamePart"
+  "\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_i"
+  "nt_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_value"
+  "\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NameP"
+  "art\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.Locat"
+  "ion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004sp"
+  "an\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_det"
+  "ached_comments\030\006 \003(\t\"\247\001\n\021GeneratedCodeIn"
+  "fo\022A\n\nannotation\030\001 \003(\0132-.google.protobuf"
+  ".GeneratedCodeInfo.Annotation\032O\n\nAnnotat"
+  "ion\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source_file\030\002 \001"
+  "(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B~\n\023com.go"
+  "ogle.protobufB\020DescriptorProtosH\001Z-googl"
+  "e.golang.org/protobuf/types/descriptorpb"
+  "\370\001\001\242\002\003GPB\252\002\032Google.Protobuf.Reflection"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
-  false, false, 6046, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto, "google/protobuf/descriptor.proto", 
-  &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, nullptr, 0, 27,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto, file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+    false, false, 6078, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
+    "google/protobuf/descriptor.proto",
+    &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, nullptr, 0, 27,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fdescriptor_2eproto(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fdescriptor_2eproto(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
@@ -1270,9 +1279,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   file_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorSet)
 }
 FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from)
@@ -1287,21 +1293,17 @@
 
 FileDescriptorSet::~FileDescriptorSet() {
   // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorSet)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FileDescriptorSet::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void FileDescriptorSet::ArenaDtor(void* object) {
-  FileDescriptorSet* _this = reinterpret_cast< FileDescriptorSet* >(object);
-  (void)_this;
-}
-void FileDescriptorSet::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FileDescriptorSet::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1316,11 +1318,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FileDescriptorSet::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FileDescriptorSet::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.FileDescriptorProto file = 1;
       case 1:
@@ -1365,15 +1367,15 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.FileDescriptorProto file = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_file_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_file_size()); i < n; i++) {
+    const auto& repfield = this->_internal_file(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(1, this->_internal_file(i), target, stream);
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorSet)
@@ -1441,7 +1443,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorSet::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]);
 }
@@ -1489,9 +1491,6 @@
   public_dependency_(arena),
   weak_dependency_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FileDescriptorProto)
 }
 FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
@@ -1505,7 +1504,7 @@
       public_dependency_(from.public_dependency_),
       weak_dependency_(from.weak_dependency_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1513,7 +1512,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  package_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1521,7 +1520,7 @@
     package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_package(), 
       GetArenaForAllocation());
   }
-  syntax_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  syntax_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     syntax_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1543,15 +1542,15 @@
 }
 
 inline void FileDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+package_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-syntax_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+syntax_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   syntax_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1563,9 +1562,11 @@
 
 FileDescriptorProto::~FileDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.FileDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FileDescriptorProto::SharedDtor() {
@@ -1577,12 +1578,6 @@
   if (this != internal_default_instance()) delete source_code_info_;
 }
 
-void FileDescriptorProto::ArenaDtor(void* object) {
-  FileDescriptorProto* _this = reinterpret_cast< FileDescriptorProto* >(object);
-  (void)_this;
-}
-void FileDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FileDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1624,22 +1619,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FileDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FileDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1647,11 +1642,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_package();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.package");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.package");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1662,11 +1657,11 @@
           do {
             ptr += 1;
             auto str = _internal_add_dependency();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            #ifndef NDEBUG
-            ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.dependency");
-            #endif  // !NDEBUG
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.dependency");
+            #endif  // !NDEBUG
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
         } else
@@ -1776,11 +1771,11 @@
       case 12:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
           auto str = _internal_mutable_syntax();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.syntax");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileDescriptorProto.syntax");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -1846,63 +1841,61 @@
   }
 
   // repeated .google.protobuf.DescriptorProto message_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_message_type_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_message_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_message_type(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(4, this->_internal_message_type(i), target, stream);
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_enum_type_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(5, this->_internal_enum_type(i), target, stream);
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_service_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_service_size()); i < n; i++) {
+    const auto& repfield = this->_internal_service(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(6, this->_internal_service(i), target, stream);
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_extension_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(7, this->_internal_extension(i), target, stream);
+        InternalWriteMessage(7, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // optional .google.protobuf.FileOptions options = 8;
   if (cached_has_bits & 0x00000008u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        8, _Internal::options(this), target, stream);
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
   if (cached_has_bits & 0x00000010u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        9, _Internal::source_code_info(this), target, stream);
+      InternalWriteMessage(9, _Internal::source_code_info(this),
+        _Internal::source_code_info(this).GetCachedSize(), target, stream);
   }
 
   // repeated int32 public_dependency = 10;
   for (int i = 0, n = this->_internal_public_dependency_size(); i < n; i++) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(10, this->_internal_public_dependency(i), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(10, this->_internal_public_dependency(i), target);
   }
 
   // repeated int32 weak_dependency = 11;
   for (int i = 0, n = this->_internal_weak_dependency_size(); i < n; i++) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(11, this->_internal_weak_dependency(i), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(11, this->_internal_weak_dependency(i), target);
   }
 
   // optional string syntax = 12;
@@ -1916,7 +1909,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorProto)
@@ -1969,19 +1962,19 @@
 
   // repeated int32 public_dependency = 10;
   {
-    size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+    size_t data_size = ::_pbi::WireFormatLite::
       Int32Size(this->public_dependency_);
     total_size += 1 *
-                  ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_public_dependency_size());
+                  ::_pbi::FromIntSize(this->_internal_public_dependency_size());
     total_size += data_size;
   }
 
   // repeated int32 weak_dependency = 11;
   {
-    size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+    size_t data_size = ::_pbi::WireFormatLite::
       Int32Size(this->weak_dependency_);
     total_size += 1 *
-                  ::PROTOBUF_NAMESPACE_ID::internal::FromIntSize(this->_internal_weak_dependency_size());
+                  ::_pbi::FromIntSize(this->_internal_weak_dependency_size());
     total_size += data_size;
   }
 
@@ -2132,7 +2125,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FileDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]);
 }
@@ -2162,9 +2155,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ExtensionRange)
 }
 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from)
@@ -2191,9 +2181,11 @@
 
 DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() {
   // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ExtensionRange)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void DescriptorProto_ExtensionRange::SharedDtor() {
@@ -2201,12 +2193,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void DescriptorProto_ExtensionRange::ArenaDtor(void* object) {
-  DescriptorProto_ExtensionRange* _this = reinterpret_cast< DescriptorProto_ExtensionRange* >(object);
-  (void)_this;
-}
-void DescriptorProto_ExtensionRange::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void DescriptorProto_ExtensionRange::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -2231,12 +2217,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1:
@@ -2298,25 +2284,24 @@
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
   }
 
   // optional .google.protobuf.ExtensionRangeOptions options = 3;
   if (cached_has_bits & 0x00000001u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        3, _Internal::options(this), target, stream);
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ExtensionRange)
@@ -2342,12 +2327,12 @@
 
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
@@ -2416,7 +2401,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ExtensionRange::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]);
 }
@@ -2438,9 +2423,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto.ReservedRange)
 }
 DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from)
@@ -2462,21 +2444,17 @@
 
 DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() {
   // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void DescriptorProto_ReservedRange::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void DescriptorProto_ReservedRange::ArenaDtor(void* object) {
-  DescriptorProto_ReservedRange* _this = reinterpret_cast< DescriptorProto_ReservedRange* >(object);
-  (void)_this;
-}
-void DescriptorProto_ReservedRange::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void DescriptorProto_ReservedRange::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -2497,12 +2475,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1:
@@ -2556,17 +2534,17 @@
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
@@ -2585,12 +2563,12 @@
   if (cached_has_bits & 0x00000003u) {
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000001u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
@@ -2653,7 +2631,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]);
 }
@@ -2688,9 +2666,6 @@
   reserved_range_(arena),
   reserved_name_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.DescriptorProto)
 }
 DescriptorProto::DescriptorProto(const DescriptorProto& from)
@@ -2705,7 +2680,7 @@
       reserved_range_(from.reserved_range_),
       reserved_name_(from.reserved_name_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2722,7 +2697,7 @@
 }
 
 inline void DescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2731,9 +2706,11 @@
 
 DescriptorProto::~DescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void DescriptorProto::SharedDtor() {
@@ -2742,12 +2719,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void DescriptorProto::ArenaDtor(void* object) {
-  DescriptorProto* _this = reinterpret_cast< DescriptorProto* >(object);
-  (void)_this;
-}
-void DescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void DescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -2780,22 +2751,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* DescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* DescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.DescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -2905,11 +2876,11 @@
           do {
             ptr += 1;
             auto str = _internal_add_reserved_name();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            #ifndef NDEBUG
-            ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.DescriptorProto.reserved_name");
-            #endif  // !NDEBUG
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.DescriptorProto.reserved_name");
+            #endif  // !NDEBUG
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<82>(ptr));
         } else
@@ -2957,67 +2928,66 @@
   }
 
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_field_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_field_size()); i < n; i++) {
+    const auto& repfield = this->_internal_field(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_field(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_nested_type_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_nested_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_nested_type(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(3, this->_internal_nested_type(i), target, stream);
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_enum_type_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enum_type_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enum_type(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(4, this->_internal_enum_type(i), target, stream);
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_extension_range_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension_range(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(5, this->_internal_extension_range(i), target, stream);
+        InternalWriteMessage(5, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_extension_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_extension_size()); i < n; i++) {
+    const auto& repfield = this->_internal_extension(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(6, this->_internal_extension(i), target, stream);
+        InternalWriteMessage(6, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // optional .google.protobuf.MessageOptions options = 7;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        7, _Internal::options(this), target, stream);
+      InternalWriteMessage(7, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_oneof_decl_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_oneof_decl_size()); i < n; i++) {
+    const auto& repfield = this->_internal_oneof_decl(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(8, this->_internal_oneof_decl(i), target, stream);
+        InternalWriteMessage(8, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_reserved_range_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(9, this->_internal_reserved_range(i), target, stream);
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated string reserved_name = 10;
@@ -3031,7 +3001,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto)
@@ -3211,7 +3181,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata DescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]);
 }
@@ -3228,9 +3198,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.ExtensionRangeOptions)
 }
 ExtensionRangeOptions::ExtensionRangeOptions(const ExtensionRangeOptions& from)
@@ -3246,21 +3213,17 @@
 
 ExtensionRangeOptions::~ExtensionRangeOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.ExtensionRangeOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void ExtensionRangeOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void ExtensionRangeOptions::ArenaDtor(void* object) {
-  ExtensionRangeOptions* _this = reinterpret_cast< ExtensionRangeOptions* >(object);
-  (void)_this;
-}
-void ExtensionRangeOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void ExtensionRangeOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -3276,11 +3239,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -3330,11 +3293,11 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -3342,7 +3305,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ExtensionRangeOptions)
@@ -3418,7 +3381,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata ExtensionRangeOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]);
 }
@@ -3472,16 +3435,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldDescriptorProto)
 }
 FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3489,7 +3449,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  extendee_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  extendee_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     extendee_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3497,7 +3457,7 @@
     extendee_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_extendee(), 
       GetArenaForAllocation());
   }
-  type_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  type_name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     type_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3505,7 +3465,7 @@
     type_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_type_name(), 
       GetArenaForAllocation());
   }
-  default_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  default_value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3513,7 +3473,7 @@
     default_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_default_value(), 
       GetArenaForAllocation());
   }
-  json_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  json_name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3533,23 +3493,23 @@
 }
 
 inline void FieldDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-extendee_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+extendee_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   extendee_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-type_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+type_name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   type_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-default_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+default_value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-json_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+json_name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -3563,9 +3523,11 @@
 
 FieldDescriptorProto::~FieldDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.FieldDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FieldDescriptorProto::SharedDtor() {
@@ -3578,12 +3540,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void FieldDescriptorProto::ArenaDtor(void* object) {
-  FieldDescriptorProto* _this = reinterpret_cast< FieldDescriptorProto* >(object);
-  (void)_this;
-}
-void FieldDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FieldDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -3630,22 +3586,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -3653,11 +3609,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_extendee();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.extendee");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.extendee");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -3700,11 +3656,11 @@
       case 6:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
           auto str = _internal_mutable_type_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.type_name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.type_name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -3712,11 +3668,11 @@
       case 7:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
           auto str = _internal_mutable_default_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.default_value");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.default_value");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -3741,11 +3697,11 @@
       case 10:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
           auto str = _internal_mutable_json_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.json_name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FieldDescriptorProto.json_name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -3812,20 +3768,20 @@
   // optional int32 number = 3;
   if (cached_has_bits & 0x00000040u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
   }
 
   // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
   if (cached_has_bits & 0x00000200u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       4, this->_internal_label(), target);
   }
 
   // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
   if (cached_has_bits & 0x00000400u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       5, this->_internal_type(), target);
   }
 
@@ -3851,16 +3807,15 @@
 
   // optional .google.protobuf.FieldOptions options = 8;
   if (cached_has_bits & 0x00000020u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        8, _Internal::options(this), target, stream);
+      InternalWriteMessage(8, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   // optional int32 oneof_index = 9;
   if (cached_has_bits & 0x00000080u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(9, this->_internal_oneof_index(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(9, this->_internal_oneof_index(), target);
   }
 
   // optional string json_name = 10;
@@ -3876,11 +3831,11 @@
   // optional bool proto3_optional = 17;
   if (cached_has_bits & 0x00000100u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(17, this->_internal_proto3_optional(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_proto3_optional(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldDescriptorProto)
@@ -3941,12 +3896,12 @@
 
     // optional int32 number = 3;
     if (cached_has_bits & 0x00000040u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
     }
 
     // optional int32 oneof_index = 9;
     if (cached_has_bits & 0x00000080u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
     }
 
   }
@@ -3959,13 +3914,13 @@
     // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
     if (cached_has_bits & 0x00000200u) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_label());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_label());
     }
 
     // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
     if (cached_has_bits & 0x00000400u) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_type());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_type());
     }
 
   }
@@ -4090,7 +4045,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FieldDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]);
 }
@@ -4117,16 +4072,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofDescriptorProto)
 }
 OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -4143,7 +4095,7 @@
 }
 
 inline void OneofDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -4152,9 +4104,11 @@
 
 OneofDescriptorProto::~OneofDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.OneofDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void OneofDescriptorProto::SharedDtor() {
@@ -4163,12 +4117,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void OneofDescriptorProto::ArenaDtor(void* object) {
-  OneofDescriptorProto* _this = reinterpret_cast< OneofDescriptorProto* >(object);
-  (void)_this;
-}
-void OneofDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void OneofDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -4193,22 +4141,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.OneofDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.OneofDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -4263,14 +4211,13 @@
 
   // optional .google.protobuf.OneofOptions options = 2;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        2, _Internal::options(this), target, stream);
+      InternalWriteMessage(2, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofDescriptorProto)
@@ -4365,7 +4312,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata OneofDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]);
 }
@@ -4387,9 +4334,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
 }
 EnumDescriptorProto_EnumReservedRange::EnumDescriptorProto_EnumReservedRange(const EnumDescriptorProto_EnumReservedRange& from)
@@ -4411,21 +4355,17 @@
 
 EnumDescriptorProto_EnumReservedRange::~EnumDescriptorProto_EnumReservedRange() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto.EnumReservedRange)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumDescriptorProto_EnumReservedRange::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void EnumDescriptorProto_EnumReservedRange::ArenaDtor(void* object) {
-  EnumDescriptorProto_EnumReservedRange* _this = reinterpret_cast< EnumDescriptorProto_EnumReservedRange* >(object);
-  (void)_this;
-}
-void EnumDescriptorProto_EnumReservedRange::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumDescriptorProto_EnumReservedRange::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -4446,12 +4386,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1:
@@ -4505,17 +4445,17 @@
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_end(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto.EnumReservedRange)
@@ -4534,12 +4474,12 @@
   if (cached_has_bits & 0x00000003u) {
     // optional int32 start = 1;
     if (cached_has_bits & 0x00000001u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_start());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_start());
     }
 
     // optional int32 end = 2;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
@@ -4602,7 +4542,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto_EnumReservedRange::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]);
 }
@@ -4632,9 +4572,6 @@
   reserved_range_(arena),
   reserved_name_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumDescriptorProto)
 }
 EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
@@ -4644,7 +4581,7 @@
       reserved_range_(from.reserved_range_),
       reserved_name_(from.reserved_name_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -4661,7 +4598,7 @@
 }
 
 inline void EnumDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -4670,9 +4607,11 @@
 
 EnumDescriptorProto::~EnumDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumDescriptorProto::SharedDtor() {
@@ -4681,12 +4620,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void EnumDescriptorProto::ArenaDtor(void* object) {
-  EnumDescriptorProto* _this = reinterpret_cast< EnumDescriptorProto* >(object);
-  (void)_this;
-}
-void EnumDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -4714,22 +4647,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -4774,11 +4707,11 @@
           do {
             ptr += 1;
             auto str = _internal_add_reserved_name();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            #ifndef NDEBUG
-            ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.reserved_name");
-            #endif  // !NDEBUG
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.EnumDescriptorProto.reserved_name");
+            #endif  // !NDEBUG
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<42>(ptr));
         } else
@@ -4826,27 +4759,26 @@
   }
 
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_value_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_value_size()); i < n; i++) {
+    const auto& repfield = this->_internal_value(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_value(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // optional .google.protobuf.EnumOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        3, _Internal::options(this), target, stream);
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_reserved_range_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_reserved_range_size()); i < n; i++) {
+    const auto& repfield = this->_internal_reserved_range(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(4, this->_internal_reserved_range(i), target, stream);
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated string reserved_name = 5;
@@ -4860,7 +4792,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto)
@@ -4985,7 +4917,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]);
 }
@@ -5015,16 +4947,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueDescriptorProto)
 }
 EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5042,7 +4971,7 @@
 }
 
 inline void EnumValueDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5054,9 +4983,11 @@
 
 EnumValueDescriptorProto::~EnumValueDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumValueDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumValueDescriptorProto::SharedDtor() {
@@ -5065,12 +4996,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void EnumValueDescriptorProto::ArenaDtor(void* object) {
-  EnumValueDescriptorProto* _this = reinterpret_cast< EnumValueDescriptorProto* >(object);
-  (void)_this;
-}
-void EnumValueDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumValueDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -5096,22 +5021,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumValueDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.EnumValueDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -5176,19 +5101,18 @@
   // optional int32 number = 2;
   if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
   }
 
   // optional .google.protobuf.EnumValueOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        3, _Internal::options(this), target, stream);
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueDescriptorProto)
@@ -5221,7 +5145,7 @@
 
     // optional int32 number = 2;
     if (cached_has_bits & 0x00000004u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
     }
 
   }
@@ -5297,7 +5221,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumValueDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]);
 }
@@ -5325,9 +5249,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   method_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceDescriptorProto)
 }
 ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from)
@@ -5335,7 +5256,7 @@
       _has_bits_(from._has_bits_),
       method_(from.method_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5352,7 +5273,7 @@
 }
 
 inline void ServiceDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5361,9 +5282,11 @@
 
 ServiceDescriptorProto::~ServiceDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.ServiceDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void ServiceDescriptorProto::SharedDtor() {
@@ -5372,12 +5295,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void ServiceDescriptorProto::ArenaDtor(void* object) {
-  ServiceDescriptorProto* _this = reinterpret_cast< ServiceDescriptorProto* >(object);
-  (void)_this;
-}
-void ServiceDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void ServiceDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -5403,22 +5320,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.ServiceDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.ServiceDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -5485,23 +5402,22 @@
   }
 
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_method_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_method_size()); i < n; i++) {
+    const auto& repfield = this->_internal_method(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_method(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // optional .google.protobuf.ServiceOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        3, _Internal::options(this), target, stream);
+      InternalWriteMessage(3, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceDescriptorProto)
@@ -5607,7 +5523,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata ServiceDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]);
 }
@@ -5646,16 +5562,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodDescriptorProto)
 }
 MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5663,7 +5576,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  input_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  input_type_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     input_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5671,7 +5584,7 @@
     input_type_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_input_type(), 
       GetArenaForAllocation());
   }
-  output_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  output_type_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     output_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5691,15 +5604,15 @@
 }
 
 inline void MethodDescriptorProto::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-input_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+input_type_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   input_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-output_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+output_type_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   output_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -5711,9 +5624,11 @@
 
 MethodDescriptorProto::~MethodDescriptorProto() {
   // @@protoc_insertion_point(destructor:google.protobuf.MethodDescriptorProto)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void MethodDescriptorProto::SharedDtor() {
@@ -5724,12 +5639,6 @@
   if (this != internal_default_instance()) delete options_;
 }
 
-void MethodDescriptorProto::ArenaDtor(void* object) {
-  MethodDescriptorProto* _this = reinterpret_cast< MethodDescriptorProto* >(object);
-  (void)_this;
-}
-void MethodDescriptorProto::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void MethodDescriptorProto::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -5763,22 +5672,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.name");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.name");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -5786,11 +5695,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_input_type();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.input_type");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.input_type");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -5798,11 +5707,11 @@
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
           auto str = _internal_mutable_output_type();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.output_type");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.MethodDescriptorProto.output_type");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -5895,26 +5804,25 @@
 
   // optional .google.protobuf.MethodOptions options = 4;
   if (cached_has_bits & 0x00000008u) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        4, _Internal::options(this), target, stream);
+      InternalWriteMessage(4, _Internal::options(this),
+        _Internal::options(this).GetCachedSize(), target, stream);
   }
 
   // optional bool client_streaming = 5 [default = false];
   if (cached_has_bits & 0x00000010u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->_internal_client_streaming(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_client_streaming(), target);
   }
 
   // optional bool server_streaming = 6 [default = false];
   if (cached_has_bits & 0x00000020u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(6, this->_internal_server_streaming(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(6, this->_internal_server_streaming(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodDescriptorProto)
@@ -6061,7 +5969,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata MethodDescriptorProto::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]);
 }
@@ -6139,9 +6047,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FileOptions)
 }
 FileOptions::FileOptions(const FileOptions& from)
@@ -6150,7 +6055,7 @@
       uninterpreted_option_(from.uninterpreted_option_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
   _extensions_.MergeFrom(internal_default_instance(), from._extensions_);
-  java_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  java_package_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     java_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6158,7 +6063,7 @@
     java_package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_java_package(), 
       GetArenaForAllocation());
   }
-  java_outer_classname_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  java_outer_classname_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     java_outer_classname_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6166,7 +6071,7 @@
     java_outer_classname_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_java_outer_classname(), 
       GetArenaForAllocation());
   }
-  go_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  go_package_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     go_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6174,7 +6079,7 @@
     go_package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_go_package(), 
       GetArenaForAllocation());
   }
-  objc_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  objc_class_prefix_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     objc_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6182,7 +6087,7 @@
     objc_class_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_objc_class_prefix(), 
       GetArenaForAllocation());
   }
-  csharp_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  csharp_namespace_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     csharp_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6190,7 +6095,7 @@
     csharp_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_csharp_namespace(), 
       GetArenaForAllocation());
   }
-  swift_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  swift_prefix_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     swift_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6198,7 +6103,7 @@
     swift_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_swift_prefix(), 
       GetArenaForAllocation());
   }
-  php_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  php_class_prefix_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     php_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6206,7 +6111,7 @@
     php_class_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_class_prefix(), 
       GetArenaForAllocation());
   }
-  php_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  php_namespace_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     php_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6214,7 +6119,7 @@
     php_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_namespace(), 
       GetArenaForAllocation());
   }
-  php_metadata_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  php_metadata_namespace_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     php_metadata_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6222,7 +6127,7 @@
     php_metadata_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_metadata_namespace(), 
       GetArenaForAllocation());
   }
-  ruby_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  ruby_package_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     ruby_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6237,43 +6142,43 @@
 }
 
 inline void FileOptions::SharedCtor() {
-java_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+java_package_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   java_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-java_outer_classname_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+java_outer_classname_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   java_outer_classname_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-go_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+go_package_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   go_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-objc_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+objc_class_prefix_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   objc_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-csharp_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+csharp_namespace_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   csharp_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-swift_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+swift_prefix_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   swift_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-php_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+php_class_prefix_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   php_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-php_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+php_namespace_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   php_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-php_metadata_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+php_metadata_namespace_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   php_metadata_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-ruby_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+ruby_package_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   ruby_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -6287,9 +6192,11 @@
 
 FileOptions::~FileOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.FileOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FileOptions::SharedDtor() {
@@ -6306,12 +6213,6 @@
   ruby_package_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void FileOptions::ArenaDtor(void* object) {
-  FileOptions* _this = reinterpret_cast< FileOptions* >(object);
-  (void)_this;
-}
-void FileOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FileOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -6375,22 +6276,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FileOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FileOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional string java_package = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_java_package();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.java_package");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_package");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6398,11 +6299,11 @@
       case 8:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
           auto str = _internal_mutable_java_outer_classname();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.java_outer_classname");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.java_outer_classname");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6432,11 +6333,11 @@
       case 11:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
           auto str = _internal_mutable_go_package();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.go_package");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.go_package");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6507,11 +6408,11 @@
       case 36:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_objc_class_prefix();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.objc_class_prefix");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.objc_class_prefix");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6519,11 +6420,11 @@
       case 37:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 42)) {
           auto str = _internal_mutable_csharp_namespace();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.csharp_namespace");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.csharp_namespace");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6531,11 +6432,11 @@
       case 39:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
           auto str = _internal_mutable_swift_prefix();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.swift_prefix");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.swift_prefix");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6543,11 +6444,11 @@
       case 40:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
           auto str = _internal_mutable_php_class_prefix();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_class_prefix");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_class_prefix");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6555,11 +6456,11 @@
       case 41:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 74)) {
           auto str = _internal_mutable_php_namespace();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_namespace");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_namespace");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6576,11 +6477,11 @@
       case 44:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 98)) {
           auto str = _internal_mutable_php_metadata_namespace();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.php_metadata_namespace");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.php_metadata_namespace");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6588,11 +6489,11 @@
       case 45:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 106)) {
           auto str = _internal_mutable_ruby_package();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FileOptions.ruby_package");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.FileOptions.ruby_package");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -6668,14 +6569,14 @@
   // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
   if (cached_has_bits & 0x00040000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       9, this->_internal_optimize_for(), target);
   }
 
   // optional bool java_multiple_files = 10 [default = false];
   if (cached_has_bits & 0x00000400u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->_internal_java_multiple_files(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_java_multiple_files(), target);
   }
 
   // optional string go_package = 11;
@@ -6691,43 +6592,43 @@
   // optional bool cc_generic_services = 16 [default = false];
   if (cached_has_bits & 0x00002000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(16, this->_internal_cc_generic_services(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(16, this->_internal_cc_generic_services(), target);
   }
 
   // optional bool java_generic_services = 17 [default = false];
   if (cached_has_bits & 0x00004000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(17, this->_internal_java_generic_services(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(17, this->_internal_java_generic_services(), target);
   }
 
   // optional bool py_generic_services = 18 [default = false];
   if (cached_has_bits & 0x00008000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(18, this->_internal_py_generic_services(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(18, this->_internal_py_generic_services(), target);
   }
 
   // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
   if (cached_has_bits & 0x00000800u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(20, this->_internal_java_generate_equals_and_hash(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(20, this->_internal_java_generate_equals_and_hash(), target);
   }
 
   // optional bool deprecated = 23 [default = false];
   if (cached_has_bits & 0x00020000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(23, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(23, this->_internal_deprecated(), target);
   }
 
   // optional bool java_string_check_utf8 = 27 [default = false];
   if (cached_has_bits & 0x00001000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(27, this->_internal_java_string_check_utf8(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(27, this->_internal_java_string_check_utf8(), target);
   }
 
   // optional bool cc_enable_arenas = 31 [default = true];
   if (cached_has_bits & 0x00080000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(31, this->_internal_cc_enable_arenas(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(31, this->_internal_cc_enable_arenas(), target);
   }
 
   // optional string objc_class_prefix = 36;
@@ -6783,7 +6684,7 @@
   // optional bool php_generic_services = 42 [default = false];
   if (cached_has_bits & 0x00010000u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(42, this->_internal_php_generic_services(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(42, this->_internal_php_generic_services(), target);
   }
 
   // optional string php_metadata_namespace = 44;
@@ -6807,11 +6708,11 @@
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -6819,7 +6720,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileOptions)
@@ -6962,7 +6863,7 @@
     // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
     if (cached_has_bits & 0x00040000u) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_optimize_for());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_optimize_for());
     }
 
     // optional bool cc_enable_arenas = 31 [default = true];
@@ -7153,7 +7054,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FileOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]);
 }
@@ -7183,9 +7084,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.MessageOptions)
 }
 MessageOptions::MessageOptions(const MessageOptions& from)
@@ -7209,21 +7107,17 @@
 
 MessageOptions::~MessageOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.MessageOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void MessageOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void MessageOptions::ArenaDtor(void* object) {
-  MessageOptions* _this = reinterpret_cast< MessageOptions* >(object);
-  (void)_this;
-}
-void MessageOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void MessageOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -7243,12 +7137,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* MessageOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* MessageOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional bool message_set_wire_format = 1 [default = false];
       case 1:
@@ -7338,33 +7232,33 @@
   // optional bool message_set_wire_format = 1 [default = false];
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->_internal_message_set_wire_format(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_message_set_wire_format(), target);
   }
 
   // optional bool no_standard_descriptor_accessor = 2 [default = false];
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->_internal_no_standard_descriptor_accessor(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_no_standard_descriptor_accessor(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
   if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
   }
 
   // optional bool map_entry = 7;
   if (cached_has_bits & 0x00000008u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(7, this->_internal_map_entry(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(7, this->_internal_map_entry(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -7372,7 +7266,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MessageOptions)
@@ -7494,7 +7388,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata MessageOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]);
 }
@@ -7508,20 +7402,23 @@
     (*has_bits)[0] |= 1u;
   }
   static void set_has_packed(HasBits* has_bits) {
-    (*has_bits)[0] |= 2u;
-  }
-  static void set_has_jstype(HasBits* has_bits) {
-    (*has_bits)[0] |= 32u;
-  }
-  static void set_has_lazy(HasBits* has_bits) {
     (*has_bits)[0] |= 4u;
   }
-  static void set_has_deprecated(HasBits* has_bits) {
+  static void set_has_jstype(HasBits* has_bits) {
+    (*has_bits)[0] |= 2u;
+  }
+  static void set_has_lazy(HasBits* has_bits) {
     (*has_bits)[0] |= 8u;
   }
-  static void set_has_weak(HasBits* has_bits) {
+  static void set_has_unverified_lazy(HasBits* has_bits) {
     (*has_bits)[0] |= 16u;
   }
+  static void set_has_deprecated(HasBits* has_bits) {
+    (*has_bits)[0] |= 32u;
+  }
+  static void set_has_weak(HasBits* has_bits) {
+    (*has_bits)[0] |= 64u;
+  }
 };
 
 FieldOptions::FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
@@ -7530,9 +7427,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldOptions)
 }
 FieldOptions::FieldOptions(const FieldOptions& from)
@@ -7542,35 +7436,31 @@
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
   _extensions_.MergeFrom(internal_default_instance(), from._extensions_);
   ::memcpy(&ctype_, &from.ctype_,
-    static_cast<size_t>(reinterpret_cast<char*>(&jstype_) -
-    reinterpret_cast<char*>(&ctype_)) + sizeof(jstype_));
+    static_cast<size_t>(reinterpret_cast<char*>(&weak_) -
+    reinterpret_cast<char*>(&ctype_)) + sizeof(weak_));
   // @@protoc_insertion_point(copy_constructor:google.protobuf.FieldOptions)
 }
 
 inline void FieldOptions::SharedCtor() {
 ::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
     reinterpret_cast<char*>(&ctype_) - reinterpret_cast<char*>(this)),
-    0, static_cast<size_t>(reinterpret_cast<char*>(&jstype_) -
-    reinterpret_cast<char*>(&ctype_)) + sizeof(jstype_));
+    0, static_cast<size_t>(reinterpret_cast<char*>(&weak_) -
+    reinterpret_cast<char*>(&ctype_)) + sizeof(weak_));
 }
 
 FieldOptions::~FieldOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.FieldOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FieldOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void FieldOptions::ArenaDtor(void* object) {
-  FieldOptions* _this = reinterpret_cast< FieldOptions* >(object);
-  (void)_this;
-}
-void FieldOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FieldOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -7584,21 +7474,21 @@
   _extensions_.Clear();
   uninterpreted_option_.Clear();
   cached_has_bits = _has_bits_[0];
-  if (cached_has_bits & 0x0000003fu) {
+  if (cached_has_bits & 0x0000007fu) {
     ::memset(&ctype_, 0, static_cast<size_t>(
-        reinterpret_cast<char*>(&jstype_) -
-        reinterpret_cast<char*>(&ctype_)) + sizeof(jstype_));
+        reinterpret_cast<char*>(&weak_) -
+        reinterpret_cast<char*>(&ctype_)) + sizeof(weak_));
   }
   _has_bits_.Clear();
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FieldOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FieldOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
       case 1:
@@ -7662,6 +7552,15 @@
         } else
           goto handle_unusual;
         continue;
+      // optional bool unverified_lazy = 15 [default = false];
+      case 15:
+        if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 120)) {
+          _Internal::set_has_unverified_lazy(&has_bits);
+          unverified_lazy_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
+          CHK_(ptr);
+        } else
+          goto handle_unusual;
+        continue;
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
@@ -7714,47 +7613,53 @@
   // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       1, this->_internal_ctype(), target);
   }
 
   // optional bool packed = 2;
-  if (cached_has_bits & 0x00000002u) {
+  if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->_internal_packed(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_packed(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
-  if (cached_has_bits & 0x00000008u) {
+  if (cached_has_bits & 0x00000020u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
   }
 
   // optional bool lazy = 5 [default = false];
-  if (cached_has_bits & 0x00000004u) {
+  if (cached_has_bits & 0x00000008u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->_internal_lazy(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(5, this->_internal_lazy(), target);
   }
 
   // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
-  if (cached_has_bits & 0x00000020u) {
+  if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       6, this->_internal_jstype(), target);
   }
 
   // optional bool weak = 10 [default = false];
+  if (cached_has_bits & 0x00000040u) {
+    target = stream->EnsureSpace(target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(10, this->_internal_weak(), target);
+  }
+
+  // optional bool unverified_lazy = 15 [default = false];
   if (cached_has_bits & 0x00000010u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->_internal_weak(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(15, this->_internal_unverified_lazy(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -7762,7 +7667,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldOptions)
@@ -7787,37 +7692,42 @@
   }
 
   cached_has_bits = _has_bits_[0];
-  if (cached_has_bits & 0x0000003fu) {
+  if (cached_has_bits & 0x0000007fu) {
     // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
     if (cached_has_bits & 0x00000001u) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_ctype());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_ctype());
+    }
+
+    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    if (cached_has_bits & 0x00000002u) {
+      total_size += 1 +
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_jstype());
     }
 
     // optional bool packed = 2;
-    if (cached_has_bits & 0x00000002u) {
-      total_size += 1 + 1;
-    }
-
-    // optional bool lazy = 5 [default = false];
     if (cached_has_bits & 0x00000004u) {
       total_size += 1 + 1;
     }
 
-    // optional bool deprecated = 3 [default = false];
+    // optional bool lazy = 5 [default = false];
     if (cached_has_bits & 0x00000008u) {
       total_size += 1 + 1;
     }
 
-    // optional bool weak = 10 [default = false];
+    // optional bool unverified_lazy = 15 [default = false];
     if (cached_has_bits & 0x00000010u) {
       total_size += 1 + 1;
     }
 
-    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    // optional bool deprecated = 3 [default = false];
     if (cached_has_bits & 0x00000020u) {
-      total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_jstype());
+      total_size += 1 + 1;
+    }
+
+    // optional bool weak = 10 [default = false];
+    if (cached_has_bits & 0x00000040u) {
+      total_size += 1 + 1;
     }
 
   }
@@ -7845,24 +7755,27 @@
 
   uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
   cached_has_bits = from._has_bits_[0];
-  if (cached_has_bits & 0x0000003fu) {
+  if (cached_has_bits & 0x0000007fu) {
     if (cached_has_bits & 0x00000001u) {
       ctype_ = from.ctype_;
     }
     if (cached_has_bits & 0x00000002u) {
-      packed_ = from.packed_;
+      jstype_ = from.jstype_;
     }
     if (cached_has_bits & 0x00000004u) {
-      lazy_ = from.lazy_;
+      packed_ = from.packed_;
     }
     if (cached_has_bits & 0x00000008u) {
-      deprecated_ = from.deprecated_;
+      lazy_ = from.lazy_;
     }
     if (cached_has_bits & 0x00000010u) {
-      weak_ = from.weak_;
+      unverified_lazy_ = from.unverified_lazy_;
     }
     if (cached_has_bits & 0x00000020u) {
-      jstype_ = from.jstype_;
+      deprecated_ = from.deprecated_;
+    }
+    if (cached_has_bits & 0x00000040u) {
+      weak_ = from.weak_;
     }
     _has_bits_[0] |= cached_has_bits;
   }
@@ -7894,15 +7807,15 @@
   swap(_has_bits_[0], other->_has_bits_[0]);
   uninterpreted_option_.InternalSwap(&other->uninterpreted_option_);
   ::PROTOBUF_NAMESPACE_ID::internal::memswap<
-      PROTOBUF_FIELD_OFFSET(FieldOptions, jstype_)
-      + sizeof(FieldOptions::jstype_)
+      PROTOBUF_FIELD_OFFSET(FieldOptions, weak_)
+      + sizeof(FieldOptions::weak_)
       - PROTOBUF_FIELD_OFFSET(FieldOptions, ctype_)>(
           reinterpret_cast<char*>(&ctype_),
           reinterpret_cast<char*>(&other->ctype_));
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FieldOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]);
 }
@@ -7919,9 +7832,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.OneofOptions)
 }
 OneofOptions::OneofOptions(const OneofOptions& from)
@@ -7937,21 +7847,17 @@
 
 OneofOptions::~OneofOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.OneofOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void OneofOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void OneofOptions::ArenaDtor(void* object) {
-  OneofOptions* _this = reinterpret_cast< OneofOptions* >(object);
-  (void)_this;
-}
-void OneofOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void OneofOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -7967,11 +7873,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* OneofOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* OneofOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999:
@@ -8021,11 +7927,11 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -8033,7 +7939,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
@@ -8109,7 +8015,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata OneofOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]);
 }
@@ -8133,9 +8039,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumOptions)
 }
 EnumOptions::EnumOptions(const EnumOptions& from)
@@ -8159,21 +8062,17 @@
 
 EnumOptions::~EnumOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void EnumOptions::ArenaDtor(void* object) {
-  EnumOptions* _this = reinterpret_cast< EnumOptions* >(object);
-  (void)_this;
-}
-void EnumOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -8193,12 +8092,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional bool allow_alias = 2;
       case 2:
@@ -8270,21 +8169,21 @@
   // optional bool allow_alias = 2;
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->_internal_allow_alias(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_allow_alias(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(3, this->_internal_deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -8292,7 +8191,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumOptions)
@@ -8398,7 +8297,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]);
 }
@@ -8419,9 +8318,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValueOptions)
 }
 EnumValueOptions::EnumValueOptions(const EnumValueOptions& from)
@@ -8440,21 +8336,17 @@
 
 EnumValueOptions::~EnumValueOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumValueOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumValueOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void EnumValueOptions::ArenaDtor(void* object) {
-  EnumValueOptions* _this = reinterpret_cast< EnumValueOptions* >(object);
-  (void)_this;
-}
-void EnumValueOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumValueOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -8472,12 +8364,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumValueOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumValueOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional bool deprecated = 1 [default = false];
       case 1:
@@ -8540,15 +8432,15 @@
   // optional bool deprecated = 1 [default = false];
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -8556,7 +8448,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueOptions)
@@ -8643,7 +8535,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumValueOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]);
 }
@@ -8664,9 +8556,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.ServiceOptions)
 }
 ServiceOptions::ServiceOptions(const ServiceOptions& from)
@@ -8685,21 +8574,17 @@
 
 ServiceOptions::~ServiceOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.ServiceOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void ServiceOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void ServiceOptions::ArenaDtor(void* object) {
-  ServiceOptions* _this = reinterpret_cast< ServiceOptions* >(object);
-  (void)_this;
-}
-void ServiceOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void ServiceOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -8717,12 +8602,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* ServiceOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* ServiceOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional bool deprecated = 33 [default = false];
       case 33:
@@ -8785,15 +8670,15 @@
   // optional bool deprecated = 33 [default = false];
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -8801,7 +8686,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceOptions)
@@ -8888,7 +8773,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata ServiceOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]);
 }
@@ -8912,9 +8797,6 @@
   _extensions_(arena),
   uninterpreted_option_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.MethodOptions)
 }
 MethodOptions::MethodOptions(const MethodOptions& from)
@@ -8938,21 +8820,17 @@
 
 MethodOptions::~MethodOptions() {
   // @@protoc_insertion_point(destructor:google.protobuf.MethodOptions)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void MethodOptions::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void MethodOptions::ArenaDtor(void* object) {
-  MethodOptions* _this = reinterpret_cast< MethodOptions* >(object);
-  (void)_this;
-}
-void MethodOptions::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void MethodOptions::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -8975,12 +8853,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* MethodOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* MethodOptions::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // optional bool deprecated = 33 [default = false];
       case 33:
@@ -9056,22 +8934,22 @@
   // optional bool deprecated = 33 [default = false];
   if (cached_has_bits & 0x00000001u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(33, this->_internal_deprecated(), target);
   }
 
   // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       34, this->_internal_idempotency_level(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_uninterpreted_option_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_uninterpreted_option_size()); i < n; i++) {
+    const auto& repfield = this->_internal_uninterpreted_option(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(999, this->_internal_uninterpreted_option(i), target, stream);
+        InternalWriteMessage(999, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // Extension range [1000, 536870912)
@@ -9079,7 +8957,7 @@
   internal_default_instance(), 1000, 536870912, target, stream);
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodOptions)
@@ -9113,7 +8991,7 @@
     // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
     if (cached_has_bits & 0x00000002u) {
       total_size += 2 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_idempotency_level());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_idempotency_level());
     }
 
   }
@@ -9186,7 +9064,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata MethodOptions::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]);
 }
@@ -9211,16 +9089,13 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption.NamePart)
 }
 UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       _has_bits_(from._has_bits_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_part_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_part_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_part_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9233,7 +9108,7 @@
 }
 
 inline void UninterpretedOption_NamePart::SharedCtor() {
-name_part_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_part_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_part_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9242,9 +9117,11 @@
 
 UninterpretedOption_NamePart::~UninterpretedOption_NamePart() {
   // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption.NamePart)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void UninterpretedOption_NamePart::SharedDtor() {
@@ -9252,12 +9129,6 @@
   name_part_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void UninterpretedOption_NamePart::ArenaDtor(void* object) {
-  UninterpretedOption_NamePart* _this = reinterpret_cast< UninterpretedOption_NamePart* >(object);
-  (void)_this;
-}
-void UninterpretedOption_NamePart::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void UninterpretedOption_NamePart::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -9277,22 +9148,22 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // required string name_part = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name_part();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.NamePart.name_part");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.NamePart.name_part");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -9349,11 +9220,11 @@
   // required bool is_extension = 2;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->_internal_is_extension(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(2, this->_internal_is_extension(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption.NamePart)
@@ -9460,7 +9331,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption_NamePart::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]);
 }
@@ -9495,9 +9366,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   name_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.UninterpretedOption)
 }
 UninterpretedOption::UninterpretedOption(const UninterpretedOption& from)
@@ -9505,7 +9373,7 @@
       _has_bits_(from._has_bits_),
       name_(from.name_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  identifier_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  identifier_value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     identifier_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9513,7 +9381,7 @@
     identifier_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_identifier_value(), 
       GetArenaForAllocation());
   }
-  string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  string_value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     string_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9521,7 +9389,7 @@
     string_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_string_value(), 
       GetArenaForAllocation());
   }
-  aggregate_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  aggregate_value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     aggregate_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9536,15 +9404,15 @@
 }
 
 inline void UninterpretedOption::SharedCtor() {
-identifier_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+identifier_value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   identifier_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+string_value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   string_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-aggregate_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+aggregate_value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   aggregate_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9556,9 +9424,11 @@
 
 UninterpretedOption::~UninterpretedOption() {
   // @@protoc_insertion_point(destructor:google.protobuf.UninterpretedOption)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void UninterpretedOption::SharedDtor() {
@@ -9568,12 +9438,6 @@
   aggregate_value_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void UninterpretedOption::ArenaDtor(void* object) {
-  UninterpretedOption* _this = reinterpret_cast< UninterpretedOption* >(object);
-  (void)_this;
-}
-void UninterpretedOption::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void UninterpretedOption::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -9606,12 +9470,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* UninterpretedOption::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* UninterpretedOption::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
       case 2:
@@ -9630,11 +9494,11 @@
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
           auto str = _internal_mutable_identifier_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.identifier_value");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.identifier_value");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -9669,7 +9533,7 @@
       case 7:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 58)) {
           auto str = _internal_mutable_string_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
         } else
           goto handle_unusual;
@@ -9678,11 +9542,11 @@
       case 8:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 66)) {
           auto str = _internal_mutable_aggregate_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.UninterpretedOption.aggregate_value");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.UninterpretedOption.aggregate_value");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -9717,11 +9581,11 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_name_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_name_size()); i < n; i++) {
+    const auto& repfield = this->_internal_name(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_name(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   cached_has_bits = _has_bits_[0];
@@ -9738,19 +9602,19 @@
   // optional uint64 positive_int_value = 4;
   if (cached_has_bits & 0x00000008u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(4, this->_internal_positive_int_value(), target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(4, this->_internal_positive_int_value(), target);
   }
 
   // optional int64 negative_int_value = 5;
   if (cached_has_bits & 0x00000010u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(5, this->_internal_negative_int_value(), target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(5, this->_internal_negative_int_value(), target);
   }
 
   // optional double double_value = 6;
   if (cached_has_bits & 0x00000020u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(6, this->_internal_double_value(), target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(6, this->_internal_double_value(), target);
   }
 
   // optional bytes string_value = 7;
@@ -9770,7 +9634,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption)
@@ -9817,12 +9681,12 @@
 
     // optional uint64 positive_int_value = 4;
     if (cached_has_bits & 0x00000008u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_positive_int_value());
+      total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_positive_int_value());
     }
 
     // optional int64 negative_int_value = 5;
     if (cached_has_bits & 0x00000010u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_negative_int_value());
+      total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_negative_int_value());
     }
 
     // optional double double_value = 6;
@@ -9923,7 +9787,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata UninterpretedOption::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]);
 }
@@ -9948,9 +9812,6 @@
   span_(arena),
   leading_detached_comments_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo.Location)
 }
 SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location& from)
@@ -9960,7 +9821,7 @@
       span_(from.span_),
       leading_detached_comments_(from.leading_detached_comments_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  leading_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  leading_comments_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     leading_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9968,7 +9829,7 @@
     leading_comments_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_leading_comments(), 
       GetArenaForAllocation());
   }
-  trailing_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  trailing_comments_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     trailing_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9980,11 +9841,11 @@
 }
 
 inline void SourceCodeInfo_Location::SharedCtor() {
-leading_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+leading_comments_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   leading_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-trailing_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+trailing_comments_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   trailing_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9992,9 +9853,11 @@
 
 SourceCodeInfo_Location::~SourceCodeInfo_Location() {
   // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo.Location)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void SourceCodeInfo_Location::SharedDtor() {
@@ -10003,12 +9866,6 @@
   trailing_comments_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void SourceCodeInfo_Location::ArenaDtor(void* object) {
-  SourceCodeInfo_Location* _this = reinterpret_cast< SourceCodeInfo_Location* >(object);
-  (void)_this;
-}
-void SourceCodeInfo_Location::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void SourceCodeInfo_Location::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -10035,12 +9892,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated int32 path = 1 [packed = true];
       case 1:
@@ -10068,11 +9925,11 @@
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
           auto str = _internal_mutable_leading_comments();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_comments");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_comments");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -10080,11 +9937,11 @@
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_trailing_comments();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -10095,11 +9952,11 @@
           do {
             ptr += 1;
             auto str = _internal_add_leading_detached_comments();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            #ifndef NDEBUG
-            ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
-            #endif  // !NDEBUG
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            #ifndef NDEBUG
+            ::_pbi::VerifyUTF8(str, "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
+            #endif  // !NDEBUG
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<50>(ptr));
         } else
@@ -10185,7 +10042,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo.Location)
@@ -10202,14 +10059,13 @@
 
   // repeated int32 path = 1 [packed = true];
   {
-    size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+    size_t data_size = ::_pbi::WireFormatLite::
       Int32Size(this->path_);
     if (data_size > 0) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-            static_cast<int32_t>(data_size));
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
     }
-    int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size);
+    int cached_size = ::_pbi::ToCachedSize(data_size);
     _path_cached_byte_size_.store(cached_size,
                                     std::memory_order_relaxed);
     total_size += data_size;
@@ -10217,14 +10073,13 @@
 
   // repeated int32 span = 2 [packed = true];
   {
-    size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+    size_t data_size = ::_pbi::WireFormatLite::
       Int32Size(this->span_);
     if (data_size > 0) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-            static_cast<int32_t>(data_size));
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
     }
-    int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size);
+    int cached_size = ::_pbi::ToCachedSize(data_size);
     _span_cached_byte_size_.store(cached_size,
                                     std::memory_order_relaxed);
     total_size += data_size;
@@ -10325,7 +10180,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo_Location::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]);
 }
@@ -10341,9 +10196,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   location_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceCodeInfo)
 }
 SourceCodeInfo::SourceCodeInfo(const SourceCodeInfo& from)
@@ -10358,21 +10210,17 @@
 
 SourceCodeInfo::~SourceCodeInfo() {
   // @@protoc_insertion_point(destructor:google.protobuf.SourceCodeInfo)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void SourceCodeInfo::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void SourceCodeInfo::ArenaDtor(void* object) {
-  SourceCodeInfo* _this = reinterpret_cast< SourceCodeInfo* >(object);
-  (void)_this;
-}
-void SourceCodeInfo::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void SourceCodeInfo::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -10387,11 +10235,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* SourceCodeInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* SourceCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
       case 1:
@@ -10436,15 +10284,15 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_location_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_location_size()); i < n; i++) {
+    const auto& repfield = this->_internal_location(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(1, this->_internal_location(i), target, stream);
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo)
@@ -10510,7 +10358,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata SourceCodeInfo::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]);
 }
@@ -10536,9 +10384,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   path_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
 }
 GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeInfo_Annotation& from)
@@ -10546,7 +10391,7 @@
       _has_bits_(from._has_bits_),
       path_(from.path_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  source_file_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  source_file_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     source_file_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10561,7 +10406,7 @@
 }
 
 inline void GeneratedCodeInfo_Annotation::SharedCtor() {
-source_file_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+source_file_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   source_file_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10573,9 +10418,11 @@
 
 GeneratedCodeInfo_Annotation::~GeneratedCodeInfo_Annotation() {
   // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo.Annotation)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void GeneratedCodeInfo_Annotation::SharedDtor() {
@@ -10583,12 +10430,6 @@
   source_file_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void GeneratedCodeInfo_Annotation::ArenaDtor(void* object) {
-  GeneratedCodeInfo_Annotation* _this = reinterpret_cast< GeneratedCodeInfo_Annotation* >(object);
-  (void)_this;
-}
-void GeneratedCodeInfo_Annotation::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void GeneratedCodeInfo_Annotation::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -10613,12 +10454,12 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   _Internal::HasBits has_bits{};
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated int32 path = 1 [packed = true];
       case 1:
@@ -10635,11 +10476,11 @@
       case 2:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
           auto str = _internal_mutable_source_file();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          #ifndef NDEBUG
-          ::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
-          #endif  // !NDEBUG
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          #ifndef NDEBUG
+          ::_pbi::VerifyUTF8(str, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
+          #endif  // !NDEBUG
         } else
           goto handle_unusual;
         continue;
@@ -10714,17 +10555,17 @@
   // optional int32 begin = 3;
   if (cached_has_bits & 0x00000002u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_begin(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_begin(), target);
   }
 
   // optional int32 end = 4;
   if (cached_has_bits & 0x00000004u) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(4, this->_internal_end(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(4, this->_internal_end(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
@@ -10741,14 +10582,13 @@
 
   // repeated int32 path = 1 [packed = true];
   {
-    size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+    size_t data_size = ::_pbi::WireFormatLite::
       Int32Size(this->path_);
     if (data_size > 0) {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size(
-            static_cast<int32_t>(data_size));
+        ::_pbi::WireFormatLite::Int32Size(static_cast<int32_t>(data_size));
     }
-    int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size);
+    int cached_size = ::_pbi::ToCachedSize(data_size);
     _path_cached_byte_size_.store(cached_size,
                                     std::memory_order_relaxed);
     total_size += data_size;
@@ -10765,12 +10605,12 @@
 
     // optional int32 begin = 3;
     if (cached_has_bits & 0x00000002u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_begin());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_begin());
     }
 
     // optional int32 end = 4;
     if (cached_has_bits & 0x00000004u) {
-      total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_end());
+      total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
     }
 
   }
@@ -10845,7 +10685,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]);
 }
@@ -10861,9 +10701,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   annotation_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.GeneratedCodeInfo)
 }
 GeneratedCodeInfo::GeneratedCodeInfo(const GeneratedCodeInfo& from)
@@ -10878,21 +10715,17 @@
 
 GeneratedCodeInfo::~GeneratedCodeInfo() {
   // @@protoc_insertion_point(destructor:google.protobuf.GeneratedCodeInfo)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void GeneratedCodeInfo::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void GeneratedCodeInfo::ArenaDtor(void* object) {
-  GeneratedCodeInfo* _this = reinterpret_cast< GeneratedCodeInfo* >(object);
-  (void)_this;
-}
-void GeneratedCodeInfo::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void GeneratedCodeInfo::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -10907,11 +10740,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
       case 1:
@@ -10956,15 +10789,15 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_annotation_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_annotation_size()); i < n; i++) {
+    const auto& repfield = this->_internal_annotation(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(1, this->_internal_annotation(i), target, stream);
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
@@ -11030,7 +10863,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata GeneratedCodeInfo::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]);
 }
@@ -11038,85 +10871,112 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorSet >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ExtensionRange >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto_ReservedRange >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ExtensionRangeOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto_EnumReservedRange >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodDescriptorProto >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FileOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FileOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FileOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MessageOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MessageOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MessageOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::OneofOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::OneofOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValueOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValueOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ServiceOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ServiceOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodOptions* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::MethodOptions*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::MethodOptions >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption_NamePart >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UninterpretedOption*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceCodeInfo >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 82fdb7f..43b5212 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -43,14 +42,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fdescriptor_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[27]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto;
@@ -443,9 +434,6 @@
   protected:
   explicit FileDescriptorSet(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -605,9 +593,6 @@
   protected:
   explicit FileDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1002,9 +987,6 @@
   protected:
   explicit DescriptorProto_ExtensionRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1195,9 +1177,6 @@
   protected:
   explicit DescriptorProto_ReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1368,9 +1347,6 @@
   protected:
   explicit DescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1720,9 +1696,6 @@
   protected:
   explicit ExtensionRangeOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -2074,9 +2047,6 @@
   protected:
   explicit FieldDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -2506,9 +2476,6 @@
   protected:
   explicit OneofDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -2689,9 +2656,6 @@
   protected:
   explicit EnumDescriptorProto_EnumReservedRange(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -2862,9 +2826,6 @@
   protected:
   explicit EnumDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -3113,9 +3074,6 @@
   protected:
   explicit EnumValueDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -3311,9 +3269,6 @@
   protected:
   explicit ServiceDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -3514,9 +3469,6 @@
   protected:
   explicit MethodDescriptorProto(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -3767,9 +3719,6 @@
   protected:
   explicit FileOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -4504,9 +4453,6 @@
   protected:
   explicit MessageOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -4919,9 +4865,6 @@
   protected:
   explicit FieldOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -5000,11 +4943,12 @@
   enum : int {
     kUninterpretedOptionFieldNumber = 999,
     kCtypeFieldNumber = 1,
+    kJstypeFieldNumber = 6,
     kPackedFieldNumber = 2,
     kLazyFieldNumber = 5,
+    kUnverifiedLazyFieldNumber = 15,
     kDeprecatedFieldNumber = 3,
     kWeakFieldNumber = 10,
-    kJstypeFieldNumber = 6,
   };
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   int uninterpreted_option_size() const;
@@ -5037,6 +4981,19 @@
   void _internal_set_ctype(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType value);
   public:
 
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  bool has_jstype() const;
+  private:
+  bool _internal_has_jstype() const;
+  public:
+  void clear_jstype();
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType jstype() const;
+  void set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  private:
+  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType _internal_jstype() const;
+  void _internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
+  public:
+
   // optional bool packed = 2;
   bool has_packed() const;
   private:
@@ -5063,6 +5020,19 @@
   void _internal_set_lazy(bool value);
   public:
 
+  // optional bool unverified_lazy = 15 [default = false];
+  bool has_unverified_lazy() const;
+  private:
+  bool _internal_has_unverified_lazy() const;
+  public:
+  void clear_unverified_lazy();
+  bool unverified_lazy() const;
+  void set_unverified_lazy(bool value);
+  private:
+  bool _internal_unverified_lazy() const;
+  void _internal_set_unverified_lazy(bool value);
+  public:
+
   // optional bool deprecated = 3 [default = false];
   bool has_deprecated() const;
   private:
@@ -5089,19 +5059,6 @@
   void _internal_set_weak(bool value);
   public:
 
-  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
-  bool has_jstype() const;
-  private:
-  bool _internal_has_jstype() const;
-  public:
-  void clear_jstype();
-  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType jstype() const;
-  void set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
-  private:
-  ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType _internal_jstype() const;
-  void _internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value);
-  public:
-
 
   template <typename _proto_TypeTraits,
             ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type,
@@ -5305,11 +5262,12 @@
   mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
   ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::UninterpretedOption > uninterpreted_option_;
   int ctype_;
+  int jstype_;
   bool packed_;
   bool lazy_;
+  bool unverified_lazy_;
   bool deprecated_;
   bool weak_;
-  int jstype_;
   friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
 };
 // -------------------------------------------------------------------
@@ -5428,9 +5386,6 @@
   protected:
   explicit OneofOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -5782,9 +5737,6 @@
   protected:
   explicit EnumOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -6167,9 +6119,6 @@
   protected:
   explicit EnumValueOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -6537,9 +6486,6 @@
   protected:
   explicit ServiceOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -6907,9 +6853,6 @@
   protected:
   explicit MethodOptions(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -7324,9 +7267,6 @@
   protected:
   explicit UninterpretedOption_NamePart(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -7505,9 +7445,6 @@
   protected:
   explicit UninterpretedOption(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -7775,9 +7712,6 @@
   protected:
   explicit SourceCodeInfo_Location(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -8034,9 +7968,6 @@
   protected:
   explicit SourceCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -8198,9 +8129,6 @@
   protected:
   explicit GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -8416,9 +8344,6 @@
   protected:
   explicit GeneratedCodeInfo(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -8566,7 +8491,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -8581,7 +8506,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -8635,7 +8560,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = package_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (package_.IsDefault()) {
     package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -8650,7 +8575,7 @@
   package_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), package,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (package_.IsDefault()) {
     package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9213,7 +9138,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = syntax_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (syntax_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (syntax_.IsDefault()) {
     syntax_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9228,7 +9153,7 @@
   syntax_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), syntax,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (syntax_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (syntax_.IsDefault()) {
     syntax_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9496,7 +9421,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -9511,7 +9436,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10058,7 +9983,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10073,7 +9998,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10213,7 +10138,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = type_name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (type_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (type_name_.IsDefault()) {
     type_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10228,7 +10153,7 @@
   type_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), type_name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (type_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (type_name_.IsDefault()) {
     type_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10282,7 +10207,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = extendee_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (extendee_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (extendee_.IsDefault()) {
     extendee_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10297,7 +10222,7 @@
   extendee_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), extendee,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (extendee_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (extendee_.IsDefault()) {
     extendee_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10351,7 +10276,7 @@
   _has_bits_[0] &= ~0x00000008u;
   auto* p = default_value_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (default_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (default_value_.IsDefault()) {
     default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10366,7 +10291,7 @@
   default_value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), default_value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (default_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (default_value_.IsDefault()) {
     default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10448,7 +10373,7 @@
   _has_bits_[0] &= ~0x00000010u;
   auto* p = json_name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (json_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (json_name_.IsDefault()) {
     json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10463,7 +10388,7 @@
   json_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), json_name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (json_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (json_name_.IsDefault()) {
     json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10639,7 +10564,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10654,7 +10579,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10862,7 +10787,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -10877,7 +10802,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11180,7 +11105,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11195,7 +11120,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11371,7 +11296,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11386,7 +11311,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11574,7 +11499,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11589,7 +11514,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11643,7 +11568,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = input_type_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (input_type_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (input_type_.IsDefault()) {
     input_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11658,7 +11583,7 @@
   input_type_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), input_type,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (input_type_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (input_type_.IsDefault()) {
     input_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11712,7 +11637,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = output_type_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (output_type_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (output_type_.IsDefault()) {
     output_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11727,7 +11652,7 @@
   output_type_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), output_type,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (output_type_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (output_type_.IsDefault()) {
     output_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11931,7 +11856,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = java_package_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (java_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (java_package_.IsDefault()) {
     java_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -11946,7 +11871,7 @@
   java_package_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), java_package,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (java_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (java_package_.IsDefault()) {
     java_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12000,7 +11925,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = java_outer_classname_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (java_outer_classname_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (java_outer_classname_.IsDefault()) {
     java_outer_classname_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12015,7 +11940,7 @@
   java_outer_classname_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), java_outer_classname,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (java_outer_classname_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (java_outer_classname_.IsDefault()) {
     java_outer_classname_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12182,7 +12107,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = go_package_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (go_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (go_package_.IsDefault()) {
     go_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12197,7 +12122,7 @@
   go_package_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), go_package,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (go_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (go_package_.IsDefault()) {
     go_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12419,7 +12344,7 @@
   _has_bits_[0] &= ~0x00000008u;
   auto* p = objc_class_prefix_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (objc_class_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (objc_class_prefix_.IsDefault()) {
     objc_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12434,7 +12359,7 @@
   objc_class_prefix_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), objc_class_prefix,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (objc_class_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (objc_class_prefix_.IsDefault()) {
     objc_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12488,7 +12413,7 @@
   _has_bits_[0] &= ~0x00000010u;
   auto* p = csharp_namespace_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (csharp_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (csharp_namespace_.IsDefault()) {
     csharp_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12503,7 +12428,7 @@
   csharp_namespace_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), csharp_namespace,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (csharp_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (csharp_namespace_.IsDefault()) {
     csharp_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12557,7 +12482,7 @@
   _has_bits_[0] &= ~0x00000020u;
   auto* p = swift_prefix_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (swift_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (swift_prefix_.IsDefault()) {
     swift_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12572,7 +12497,7 @@
   swift_prefix_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), swift_prefix,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (swift_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (swift_prefix_.IsDefault()) {
     swift_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12626,7 +12551,7 @@
   _has_bits_[0] &= ~0x00000040u;
   auto* p = php_class_prefix_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_class_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_class_prefix_.IsDefault()) {
     php_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12641,7 +12566,7 @@
   php_class_prefix_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), php_class_prefix,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_class_prefix_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_class_prefix_.IsDefault()) {
     php_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12695,7 +12620,7 @@
   _has_bits_[0] &= ~0x00000080u;
   auto* p = php_namespace_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_namespace_.IsDefault()) {
     php_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12710,7 +12635,7 @@
   php_namespace_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), php_namespace,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_namespace_.IsDefault()) {
     php_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12764,7 +12689,7 @@
   _has_bits_[0] &= ~0x00000100u;
   auto* p = php_metadata_namespace_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_metadata_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_metadata_namespace_.IsDefault()) {
     php_metadata_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12779,7 +12704,7 @@
   php_metadata_namespace_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), php_metadata_namespace,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (php_metadata_namespace_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (php_metadata_namespace_.IsDefault()) {
     php_metadata_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12833,7 +12758,7 @@
   _has_bits_[0] &= ~0x00000200u;
   auto* p = ruby_package_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (ruby_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (ruby_package_.IsDefault()) {
     ruby_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -12848,7 +12773,7 @@
   ruby_package_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ruby_package,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (ruby_package_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (ruby_package_.IsDefault()) {
     ruby_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -13086,7 +13011,7 @@
 
 // optional bool packed = 2;
 inline bool FieldOptions::_internal_has_packed() const {
-  bool value = (_has_bits_[0] & 0x00000002u) != 0;
+  bool value = (_has_bits_[0] & 0x00000004u) != 0;
   return value;
 }
 inline bool FieldOptions::has_packed() const {
@@ -13094,7 +13019,7 @@
 }
 inline void FieldOptions::clear_packed() {
   packed_ = false;
-  _has_bits_[0] &= ~0x00000002u;
+  _has_bits_[0] &= ~0x00000004u;
 }
 inline bool FieldOptions::_internal_packed() const {
   return packed_;
@@ -13104,7 +13029,7 @@
   return _internal_packed();
 }
 inline void FieldOptions::_internal_set_packed(bool value) {
-  _has_bits_[0] |= 0x00000002u;
+  _has_bits_[0] |= 0x00000004u;
   packed_ = value;
 }
 inline void FieldOptions::set_packed(bool value) {
@@ -13114,7 +13039,7 @@
 
 // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
 inline bool FieldOptions::_internal_has_jstype() const {
-  bool value = (_has_bits_[0] & 0x00000020u) != 0;
+  bool value = (_has_bits_[0] & 0x00000002u) != 0;
   return value;
 }
 inline bool FieldOptions::has_jstype() const {
@@ -13122,7 +13047,7 @@
 }
 inline void FieldOptions::clear_jstype() {
   jstype_ = 0;
-  _has_bits_[0] &= ~0x00000020u;
+  _has_bits_[0] &= ~0x00000002u;
 }
 inline ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType FieldOptions::_internal_jstype() const {
   return static_cast< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType >(jstype_);
@@ -13133,7 +13058,7 @@
 }
 inline void FieldOptions::_internal_set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
   assert(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(value));
-  _has_bits_[0] |= 0x00000020u;
+  _has_bits_[0] |= 0x00000002u;
   jstype_ = value;
 }
 inline void FieldOptions::set_jstype(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType value) {
@@ -13143,7 +13068,7 @@
 
 // optional bool lazy = 5 [default = false];
 inline bool FieldOptions::_internal_has_lazy() const {
-  bool value = (_has_bits_[0] & 0x00000004u) != 0;
+  bool value = (_has_bits_[0] & 0x00000008u) != 0;
   return value;
 }
 inline bool FieldOptions::has_lazy() const {
@@ -13151,7 +13076,7 @@
 }
 inline void FieldOptions::clear_lazy() {
   lazy_ = false;
-  _has_bits_[0] &= ~0x00000004u;
+  _has_bits_[0] &= ~0x00000008u;
 }
 inline bool FieldOptions::_internal_lazy() const {
   return lazy_;
@@ -13161,7 +13086,7 @@
   return _internal_lazy();
 }
 inline void FieldOptions::_internal_set_lazy(bool value) {
-  _has_bits_[0] |= 0x00000004u;
+  _has_bits_[0] |= 0x00000008u;
   lazy_ = value;
 }
 inline void FieldOptions::set_lazy(bool value) {
@@ -13169,9 +13094,37 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.lazy)
 }
 
+// optional bool unverified_lazy = 15 [default = false];
+inline bool FieldOptions::_internal_has_unverified_lazy() const {
+  bool value = (_has_bits_[0] & 0x00000010u) != 0;
+  return value;
+}
+inline bool FieldOptions::has_unverified_lazy() const {
+  return _internal_has_unverified_lazy();
+}
+inline void FieldOptions::clear_unverified_lazy() {
+  unverified_lazy_ = false;
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline bool FieldOptions::_internal_unverified_lazy() const {
+  return unverified_lazy_;
+}
+inline bool FieldOptions::unverified_lazy() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.unverified_lazy)
+  return _internal_unverified_lazy();
+}
+inline void FieldOptions::_internal_set_unverified_lazy(bool value) {
+  _has_bits_[0] |= 0x00000010u;
+  unverified_lazy_ = value;
+}
+inline void FieldOptions::set_unverified_lazy(bool value) {
+  _internal_set_unverified_lazy(value);
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.unverified_lazy)
+}
+
 // optional bool deprecated = 3 [default = false];
 inline bool FieldOptions::_internal_has_deprecated() const {
-  bool value = (_has_bits_[0] & 0x00000008u) != 0;
+  bool value = (_has_bits_[0] & 0x00000020u) != 0;
   return value;
 }
 inline bool FieldOptions::has_deprecated() const {
@@ -13179,7 +13132,7 @@
 }
 inline void FieldOptions::clear_deprecated() {
   deprecated_ = false;
-  _has_bits_[0] &= ~0x00000008u;
+  _has_bits_[0] &= ~0x00000020u;
 }
 inline bool FieldOptions::_internal_deprecated() const {
   return deprecated_;
@@ -13189,7 +13142,7 @@
   return _internal_deprecated();
 }
 inline void FieldOptions::_internal_set_deprecated(bool value) {
-  _has_bits_[0] |= 0x00000008u;
+  _has_bits_[0] |= 0x00000020u;
   deprecated_ = value;
 }
 inline void FieldOptions::set_deprecated(bool value) {
@@ -13199,7 +13152,7 @@
 
 // optional bool weak = 10 [default = false];
 inline bool FieldOptions::_internal_has_weak() const {
-  bool value = (_has_bits_[0] & 0x00000010u) != 0;
+  bool value = (_has_bits_[0] & 0x00000040u) != 0;
   return value;
 }
 inline bool FieldOptions::has_weak() const {
@@ -13207,7 +13160,7 @@
 }
 inline void FieldOptions::clear_weak() {
   weak_ = false;
-  _has_bits_[0] &= ~0x00000010u;
+  _has_bits_[0] &= ~0x00000040u;
 }
 inline bool FieldOptions::_internal_weak() const {
   return weak_;
@@ -13217,7 +13170,7 @@
   return _internal_weak();
 }
 inline void FieldOptions::_internal_set_weak(bool value) {
-  _has_bits_[0] |= 0x00000010u;
+  _has_bits_[0] |= 0x00000040u;
   weak_ = value;
 }
 inline void FieldOptions::set_weak(bool value) {
@@ -13705,7 +13658,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = name_part_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_part_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_part_.IsDefault()) {
     name_part_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -13720,7 +13673,7 @@
   name_part_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name_part,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_part_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_part_.IsDefault()) {
     name_part_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -13846,7 +13799,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = identifier_value_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (identifier_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (identifier_value_.IsDefault()) {
     identifier_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -13861,7 +13814,7 @@
   identifier_value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), identifier_value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (identifier_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (identifier_value_.IsDefault()) {
     identifier_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -13999,7 +13952,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = string_value_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (string_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (string_value_.IsDefault()) {
     string_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14014,7 +13967,7 @@
   string_value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), string_value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (string_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (string_value_.IsDefault()) {
     string_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14068,7 +14021,7 @@
   _has_bits_[0] &= ~0x00000004u;
   auto* p = aggregate_value_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (aggregate_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (aggregate_value_.IsDefault()) {
     aggregate_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14083,7 +14036,7 @@
   aggregate_value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), aggregate_value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (aggregate_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (aggregate_value_.IsDefault()) {
     aggregate_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14235,7 +14188,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = leading_comments_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (leading_comments_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (leading_comments_.IsDefault()) {
     leading_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14250,7 +14203,7 @@
   leading_comments_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), leading_comments,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (leading_comments_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (leading_comments_.IsDefault()) {
     leading_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14304,7 +14257,7 @@
   _has_bits_[0] &= ~0x00000002u;
   auto* p = trailing_comments_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (trailing_comments_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (trailing_comments_.IsDefault()) {
     trailing_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14319,7 +14272,7 @@
   trailing_comments_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), trailing_comments,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (trailing_comments_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (trailing_comments_.IsDefault()) {
     trailing_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14543,7 +14496,7 @@
   _has_bits_[0] &= ~0x00000001u;
   auto* p = source_file_.ReleaseNonDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (source_file_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (source_file_.IsDefault()) {
     source_file_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -14558,7 +14511,7 @@
   source_file_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), source_file,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (source_file_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (source_file_.IsDefault()) {
     source_file_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index f307be7..298e584 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -199,7 +199,6 @@
   // 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?
   optional string default_value = 7;
 
   // If set, gives the index of a oneof in the containing type's oneof_decl
@@ -604,8 +603,19 @@
   // implementation must either *always* check its required fields, or *never*
   // check its required fields, regardless of whether or not the message has
   // been parsed.
+  //
+  // As of 2021, lazy does no correctness checks on the byte stream during
+  // parsing.  This may lead to crashes if and when an invalid byte stream is
+  // finally parsed upon access.
+  //
+  // TODO(b/211906113):  Enable validation on lazy fields.
   optional bool lazy = 5 [default = false];
 
+  // unverified_lazy does no correctness checks on the byte stream. This should
+  // only be used where lazy with verification is prohibitive for performance
+  // reasons.
+  optional bool unverified_lazy = 15 [default = false];
+
   // 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
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index f2d144d..665e4ed 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -37,13 +37,16 @@
 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
 #define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
 
+
 #include <map>
 #include <string>
 #include <utility>
 #include <vector>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index fba0b95..9e5cf5d 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -580,7 +580,7 @@
       : forward_merged_(&database1_, &database2_),
         reverse_merged_(&database2_, &database1_) {}
 
-  virtual void SetUp() {
+  void SetUp() override {
     AddToDatabase(
         &database1_,
         "name: \"foo.proto\" "
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 6202f4f..ec92f3f 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -63,6 +63,7 @@
 #include <google/protobuf/stubs/substitute.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -198,7 +199,7 @@
 class MockErrorCollector : public DescriptorPool::ErrorCollector {
  public:
   MockErrorCollector() {}
-  ~MockErrorCollector() {}
+  ~MockErrorCollector() override {}
 
   std::string text_;
   std::string warning_text_;
@@ -1645,7 +1646,6 @@
   EXPECT_EQ("Foo", foo_->name());
   EXPECT_EQ("Bar", bar_->name());
 }
-
 TEST_F(ServiceDescriptorTest, MethodFullName) {
   EXPECT_EQ("TestService.Foo", foo_->full_name());
   EXPECT_EQ("TestService.Bar", bar_->full_name());
@@ -2738,9 +2738,9 @@
   ASSERT_TRUE(message->field(10)->has_default_value());
 
   EXPECT_EQ(-1, message->field(0)->default_value_int32());
-  EXPECT_EQ(int64{-1000000000000}, message->field(1)->default_value_int64());
+  EXPECT_EQ(int64_t{-1000000000000}, message->field(1)->default_value_int64());
   EXPECT_EQ(42, message->field(2)->default_value_uint32());
-  EXPECT_EQ(uint64{2000000000000}, message->field(3)->default_value_uint64());
+  EXPECT_EQ(uint64_t{2000000000000}, message->field(3)->default_value_uint64());
   EXPECT_EQ(4.5, message->field(4)->default_value_float());
   EXPECT_EQ(10e100, message->field(5)->default_value_double());
   EXPECT_TRUE(message->field(6)->default_value_bool());
@@ -3156,11 +3156,11 @@
       file->FindServiceByName("TestServiceWithCustomOptions");
   const MethodDescriptor* method = service->FindMethodByName("Foo");
 
-  EXPECT_EQ(int64{9876543210},
+  EXPECT_EQ(int64_t{9876543210},
             file->options().GetExtension(protobuf_unittest::file_opt1));
   EXPECT_EQ(-56,
             message->options().GetExtension(protobuf_unittest::message_opt1));
-  EXPECT_EQ(int64{8765432109},
+  EXPECT_EQ(int64_t{8765432109},
             field->options().GetExtension(protobuf_unittest::field_opt1));
   EXPECT_EQ(42,  // Check that we get the default for an option we don't set.
             field->options().GetExtension(protobuf_unittest::field_opt2));
@@ -3170,7 +3170,7 @@
   EXPECT_EQ(-789, enm->options().GetExtension(protobuf_unittest::enum_opt1));
   EXPECT_EQ(123, enm->value(1)->options().GetExtension(
                      protobuf_unittest::enum_value_opt1));
-  EXPECT_EQ(int64{-9876543210},
+  EXPECT_EQ(int64_t{-9876543210},
             service->options().GetExtension(protobuf_unittest::service_opt1));
   EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
             method->options().GetExtension(protobuf_unittest::method_opt1));
@@ -3982,14 +3982,10 @@
       "} "
       "}",
       STATIC_STR("bar.proto: foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a "
-                 "valid identifier.\nbar.proto: foo.\0\x1\v.Bar: NAME: "
-                 "\"\0\x1\v.Bar\" is not a valid identifier.\nbar.proto: "
-                 "foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a valid "
-                 "identifier.\nbar.proto: foo.\0\x1\v.Bar: NAME: "
-                 "\"\0\x1\v.Bar\" is not a valid identifier.\nbar.proto: "
-                 "foo.\0\x1\v.Bar.foo: NAME: \"foo.\0\x1\v.Bar.foo\" contains "
-                 "null character.\nbar.proto: foo.\0\x1\v.Bar: NAME: "
-                 "\"foo.\0\x1\v.Bar\" contains null character.\n"));
+                 "valid identifier.\nbar.proto: foo.\0\x1\v.Bar.foo: NAME: "
+                 "\"foo.\0\x1\v.Bar.foo\" contains null character.\nbar.proto: "
+                 "foo.\0\x1\v.Bar: NAME: \"foo.\0\x1\v.Bar\" contains null "
+                 "character.\n"));
 }
 
 TEST_F(ValidationErrorTest, NullCharFileName) {
@@ -6837,7 +6833,7 @@
   class ErrorDescriptorDatabase : public DescriptorDatabase {
    public:
     ErrorDescriptorDatabase() {}
-    ~ErrorDescriptorDatabase() {}
+    ~ErrorDescriptorDatabase() override {}
 
     // implements DescriptorDatabase ---------------------------------
     bool FindFileByName(const std::string& filename,
@@ -6876,7 +6872,7 @@
         : wrapped_db_(wrapped_db) {
       Clear();
     }
-    ~CallCountingDatabase() {}
+    ~CallCountingDatabase() override {}
 
     DescriptorDatabase* wrapped_db_;
 
@@ -6911,7 +6907,7 @@
    public:
     FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
         : wrapped_db_(wrapped_db) {}
-    ~FalsePositiveDatabase() {}
+    ~FalsePositiveDatabase() override {}
 
     DescriptorDatabase* wrapped_db_;
 
@@ -7198,7 +7194,7 @@
 class ExponentialErrorDatabase : public DescriptorDatabase {
  public:
   ExponentialErrorDatabase() {}
-  ~ExponentialErrorDatabase() {}
+  ~ExponentialErrorDatabase() override {}
 
   // implements DescriptorDatabase ---------------------------------
   bool FindFileByName(const std::string& filename,
@@ -7482,7 +7478,6 @@
   const MethodDescriptor* m_desc = s_desc->FindMethodByName("Method");
   EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
   EXPECT_EQ("29:3-29:31", PrintSourceLocation(loc));
-
 }
 
 TEST_F(SourceLocationTest, ExtensionSourceLocation) {
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 5a1bf18..714b6c8 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -16,24 +16,28 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Duration::Duration(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : seconds_(int64_t{0})
   , nanos_(0){}
 struct DurationDefaultTypeInternal {
   constexpr DurationDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~DurationDefaultTypeInternal() {}
   union {
     Duration _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DurationDefaultTypeInternal _Duration_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DurationDefaultTypeInternal _Duration_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fduration_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -45,12 +49,12 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, seconds_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Duration, nanos_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Duration)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Duration_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Duration_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -61,19 +65,21 @@
   "uf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Goo"
   "gle.Protobuf.WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fduration_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
-  false, false, 235, descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto, "google/protobuf/duration.proto", 
-  &descriptor_table_google_2fprotobuf_2fduration_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fduration_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fduration_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto, file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fduration_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+    false, false, 235, descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
+    "google/protobuf/duration.proto",
+    &descriptor_table_google_2fprotobuf_2fduration_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fduration_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fduration_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fduration_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fduration_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fduration_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fduration_2eproto(&descriptor_table_google_2fprotobuf_2fduration_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fduration_2eproto(&descriptor_table_google_2fprotobuf_2fduration_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -86,9 +92,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Duration)
 }
 Duration::Duration(const Duration& from)
@@ -109,21 +112,17 @@
 
 Duration::~Duration() {
   // @@protoc_insertion_point(destructor:google.protobuf.Duration)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Duration::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void Duration::ArenaDtor(void* object) {
-  Duration* _this = reinterpret_cast< Duration* >(object);
-  (void)_this;
-}
-void Duration::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Duration::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -140,11 +139,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Duration::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Duration::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // int64 seconds = 1;
       case 1:
@@ -194,17 +193,17 @@
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
@@ -221,12 +220,12 @@
 
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -283,7 +282,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Duration::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fduration_2eproto_getter, &descriptor_table_google_2fprotobuf_2fduration_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fduration_2eproto[0]);
 }
@@ -291,7 +290,8 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Duration* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Duration >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Duration*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Duration >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Duration >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 2cfada9..816f670 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fduration_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto;
@@ -172,9 +163,6 @@
   protected:
   explicit Duration(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 88c9844..d1044d7 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -70,8 +70,8 @@
 #include <new>
 #include <unordered_map>
 
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/unknown_field_set.h>
@@ -85,7 +85,8 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format.h>
 
-#include <google/protobuf/port_def.inc>  // NOLINT
+// Must be included last.
+#include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
@@ -100,14 +101,6 @@
 // ===================================================================
 // Some helper tables and functions...
 
-class DynamicMessageReflectionHelper {
- public:
-  static bool IsLazyField(const Reflection* reflection,
-                          const FieldDescriptor* field) {
-    return reflection->IsLazyField(field);
-  }
-};
-
 namespace {
 
 bool IsMapFieldInApi(const FieldDescriptor* field) { return field->is_map(); }
@@ -232,7 +225,7 @@
   // This should only be used by GetPrototypeNoLock() to avoid dead lock.
   DynamicMessage(DynamicMessageFactory::TypeInfo* type_info, bool lock_factory);
 
-  ~DynamicMessage();
+  ~DynamicMessage() override;
 
   // Called on the prototype after construction to initialize message fields.
   // Cross linking the default instances allows for fast reflection access of
@@ -277,13 +270,6 @@
 
   bool is_prototype() const;
 
-  inline int OffsetValue(int v, FieldDescriptor::Type type) const {
-    if (type == FieldDescriptor::TYPE_MESSAGE) {
-      return v & ~0x1u;
-    }
-    return v;
-  }
-
   inline void* OffsetToPointer(int offset) {
     return reinterpret_cast<uint8_t*>(this) + offset;
   }
@@ -355,23 +341,20 @@
 }
 
 inline void* DynamicMessage::MutableRaw(int i) {
-  return OffsetToPointer(
-      OffsetValue(type_info_->offsets[i], type_info_->type->field(i)->type()));
+  return OffsetToPointer(type_info_->offsets[i]);
 }
-void* DynamicMessage::MutableExtensionsRaw() {
+inline void* DynamicMessage::MutableExtensionsRaw() {
   return OffsetToPointer(type_info_->extensions_offset);
 }
-void* DynamicMessage::MutableWeakFieldMapRaw() {
+inline void* DynamicMessage::MutableWeakFieldMapRaw() {
   return OffsetToPointer(type_info_->weak_field_map_offset);
 }
-void* DynamicMessage::MutableOneofCaseRaw(int i) {
+inline void* DynamicMessage::MutableOneofCaseRaw(int i) {
   return OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32_t) * i);
 }
-void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) {
-  return OffsetToPointer(
-      OffsetValue(type_info_->offsets[type_info_->type->field_count() +
-                                      f->containing_oneof()->index()],
-                  f->type()));
+inline void* DynamicMessage::MutableOneofFieldRaw(const FieldDescriptor* f) {
+  return OffsetToPointer(type_info_->offsets[type_info_->type->field_count() +
+                                             f->containing_oneof()->index()]);
 }
 
 void DynamicMessage::SharedCtor(bool lock_factory) {
@@ -433,12 +416,12 @@
           default:  // TODO(kenton):  Support other string reps.
           case FieldOptions::STRING:
             if (!field->is_repeated()) {
-              const std::string* default_value =
-                  field->default_value_string().empty()
-                      ? &internal::GetEmptyStringAlreadyInited()
-                      : nullptr;
               ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
-              asp->UnsafeSetDefault(default_value);
+              if (field->default_value_string().empty()) {
+                asp->InitDefault();
+              } else {
+                asp->InitDefault(nullptr);
+              }
             } else {
               new (field_ptr)
                   RepeatedPtrField<std::string>(GetArenaForAllocation());
diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h
index d0af57c..6fa6425 100644
--- a/src/google/protobuf/dynamic_message.h
+++ b/src/google/protobuf/dynamic_message.h
@@ -38,14 +38,15 @@
 #ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
 #define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
 
+
 #include <algorithm>
 #include <memory>
 #include <unordered_map>
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/message.h>
 #include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/message.h>
 #include <google/protobuf/reflection.h>
 #include <google/protobuf/repeated_field.h>
 
@@ -53,6 +54,7 @@
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -94,7 +96,7 @@
   //   the zero-arg constructor.
   DynamicMessageFactory(const DescriptorPool* pool);
 
-  ~DynamicMessageFactory();
+  ~DynamicMessageFactory() override;
 
   // Call this to tell the DynamicMessageFactory that if it is given a
   // Descriptor d for which:
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 415cd41..fdea0c0 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -16,22 +16,26 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Empty::Empty(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized){}
+    ::_pbi::ConstantInitialized){}
 struct EmptyDefaultTypeInternal {
   constexpr EmptyDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EmptyDefaultTypeInternal() {}
   union {
     Empty _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EmptyDefaultTypeInternal _Empty_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EmptyDefaultTypeInternal _Empty_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fempty_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -41,12 +45,12 @@
   ~0u,  // no _weak_field_map_
   ~0u,  // no _inlined_string_donated_
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Empty)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Empty_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Empty_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -56,19 +60,21 @@
   "/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.P"
   "rotobuf.WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fempty_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
-  false, false, 190, descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto, "google/protobuf/empty.proto", 
-  &descriptor_table_google_2fprotobuf_2fempty_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fempty_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fempty_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto, file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fempty_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+    false, false, 190, descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
+    "google/protobuf/empty.proto",
+    &descriptor_table_google_2fprotobuf_2fempty_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fempty_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fempty_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fempty_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fempty_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fempty_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fempty_2eproto(&descriptor_table_google_2fprotobuf_2fempty_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fempty_2eproto(&descriptor_table_google_2fprotobuf_2fempty_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -105,7 +111,7 @@
 
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Empty::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fempty_2eproto_getter, &descriptor_table_google_2fprotobuf_2fempty_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fempty_2eproto[0]);
 }
@@ -113,7 +119,8 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Empty* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Empty >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Empty*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Empty >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Empty >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index be4f73b..668f740 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -24,7 +24,6 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_bases.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -43,14 +42,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fempty_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto;
@@ -160,7 +151,6 @@
   protected:
   explicit Empty(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
   public:
 
   static const ClassData _class_data_;
@@ -179,7 +169,6 @@
   template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
   typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
-  mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
   friend struct ::TableStruct_google_2fprotobuf_2fempty_2eproto;
 };
 // ===================================================================
diff --git a/src/google/protobuf/explicitly_constructed.h b/src/google/protobuf/explicitly_constructed.h
index e4a6d07..174c59a 100644
--- a/src/google/protobuf/explicitly_constructed.h
+++ b/src/google/protobuf/explicitly_constructed.h
@@ -59,7 +59,7 @@
 // 3. Call get() and get_mutable() only if the object is initialized.
 // 4. Call Destruct() only if the object is initialized.
 //    After the call, the object becomes uninitialized.
-template <typename T>
+template <typename T, size_t min_align = 1>
 class ExplicitlyConstructed {
  public:
   void DefaultConstruct() { new (&union_) T(); }
@@ -76,12 +76,18 @@
 
  private:
   union AlignedUnion {
-    alignas(T) char space[sizeof(T)];
+    alignas(min_align > alignof(T) ? min_align
+                                   : alignof(T)) char space[sizeof(T)];
     int64_t align_to_int64;
     void* align_to_ptr;
   } union_;
 };
 
+// ArenaStringPtr compatible explicitly constructed string type.
+// This empty string type is aligned with a minimum alignment of 8 bytes
+// which is the minimum requirement of ArenaStringPtr
+using ExplicitlyConstructedArenaString = ExplicitlyConstructed<std::string, 8>;
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 1bf7a36..9c8dd6d 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -39,13 +39,14 @@
 #include <utility>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/extension_set_inl.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/extension_set_inl.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/hash.h>
@@ -152,11 +153,13 @@
 
 void ExtensionSet::RegisterExtension(const MessageLite* extendee, int number,
                                      FieldType type, bool is_repeated,
-                                     bool is_packed) {
+                                     bool is_packed,
+                                     LazyEagerVerifyFnType verify_func) {
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_ENUM);
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_MESSAGE);
   GOOGLE_CHECK_NE(type, WireFormatLite::TYPE_GROUP);
-  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
   Register(info);
 }
 
@@ -178,7 +181,7 @@
                                          bool is_repeated, bool is_packed,
                                          EnumValidityFunc* is_valid) {
   GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM);
-  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed, nullptr);
   info.enum_validity_check.func = CallNoArgValidityFunc;
   // See comment in CallNoArgValidityFunc() about why we use a c-style cast.
   info.enum_validity_check.arg = (void*)is_valid;
@@ -188,10 +191,12 @@
 void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
                                             int number, FieldType type,
                                             bool is_repeated, bool is_packed,
-                                            const MessageLite* prototype) {
+                                            const MessageLite* prototype,
+                                            LazyEagerVerifyFnType verify_func) {
   GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
         type == WireFormatLite::TYPE_GROUP);
-  ExtensionInfo info(extendee, number, type, is_repeated, is_packed);
+  ExtensionInfo info(extendee, number, type, is_repeated, is_packed,
+                     verify_func);
   info.message_info = {prototype};
   Register(info);
 }
@@ -221,18 +226,14 @@
 
 void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
                                  uint16_t flat_capacity) {
-#ifdef __cpp_sized_deallocation
   // Arena::CreateArray already requires a trivially destructible type, but
   // ensure this constraint is not violated in the future.
   static_assert(std::is_trivially_destructible<KeyValue>::value,
                 "CreateArray requires a trivially destructible type");
   // A const-cast is needed, but this is safe as we are about to deallocate the
   // array.
-  ::operator delete[](const_cast<ExtensionSet::KeyValue*>(flat),
-                      sizeof(*flat) * flat_capacity);
-#else   // !__cpp_sized_deallocation
-  delete[] flat;
-#endif  // !__cpp_sized_deallocation
+  internal::SizedArrayDelete(const_cast<KeyValue*>(flat),
+                             sizeof(*flat) * flat_capacity);
 }
 
 // Defined in extension_set_heavy.cc.
@@ -1268,21 +1269,6 @@
   return expected_wire_type == wire_type;
 }
 
-bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
-                              ExtensionFinder* extension_finder,
-                              FieldSkipper* field_skipper) {
-  int number;
-  bool was_packed_on_wire;
-  ExtensionInfo extension;
-  if (!FindExtensionInfoFromTag(tag, extension_finder, &number, &extension,
-                                &was_packed_on_wire)) {
-    return field_skipper->SkipField(input, tag);
-  } else {
-    return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
-                                       input, field_skipper);
-  }
-}
-
 const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
                                      const MessageLite* extendee,
                                      internal::InternalMetadata* metadata,
@@ -1307,249 +1293,6 @@
                                                            metadata, ctx);
 }
 
-bool ExtensionSet::ParseFieldWithExtensionInfo(int number,
-                                               bool was_packed_on_wire,
-                                               const ExtensionInfo& extension,
-                                               io::CodedInputStream* input,
-                                               FieldSkipper* field_skipper) {
-  // Explicitly not read extension.is_packed, instead check whether the field
-  // was encoded in packed form on the wire.
-  if (was_packed_on_wire) {
-    uint32_t size;
-    if (!input->ReadVarint32(&size)) return false;
-    io::CodedInputStream::Limit limit = input->PushLimit(size);
-
-    switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE)                \
-  case WireFormatLite::TYPE_##UPPERCASE:                                    \
-    while (input->BytesUntilLimit() > 0) {                                  \
-      CPP_LOWERCASE value;                                                  \
-      if (!WireFormatLite::ReadPrimitive<CPP_LOWERCASE,                     \
-                                         WireFormatLite::TYPE_##UPPERCASE>( \
-              input, &value))                                               \
-        return false;                                                       \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    }                                                                       \
-    break
-
-      HANDLE_TYPE(INT32, Int32, int32_t);
-      HANDLE_TYPE(INT64, Int64, int64_t);
-      HANDLE_TYPE(UINT32, UInt32, uint32_t);
-      HANDLE_TYPE(UINT64, UInt64, uint64_t);
-      HANDLE_TYPE(SINT32, Int32, int32_t);
-      HANDLE_TYPE(SINT64, Int64, int64_t);
-      HANDLE_TYPE(FIXED32, UInt32, uint32_t);
-      HANDLE_TYPE(FIXED64, UInt64, uint64_t);
-      HANDLE_TYPE(SFIXED32, Int32, int32_t);
-      HANDLE_TYPE(SFIXED64, Int64, int64_t);
-      HANDLE_TYPE(FLOAT, Float, float);
-      HANDLE_TYPE(DOUBLE, Double, double);
-      HANDLE_TYPE(BOOL, Bool, bool);
-#undef HANDLE_TYPE
-
-      case WireFormatLite::TYPE_ENUM:
-        while (input->BytesUntilLimit() > 0) {
-          int value;
-          if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
-                  input, &value))
-            return false;
-          if (extension.enum_validity_check.func(
-                  extension.enum_validity_check.arg, value)) {
-            AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
-                    value, extension.descriptor);
-          } else {
-            // Invalid value.  Treat as unknown.
-            field_skipper->SkipUnknownEnum(number, value);
-          }
-        }
-        break;
-
-      case WireFormatLite::TYPE_STRING:
-      case WireFormatLite::TYPE_BYTES:
-      case WireFormatLite::TYPE_GROUP:
-      case WireFormatLite::TYPE_MESSAGE:
-        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
-        break;
-    }
-
-    input->PopLimit(limit);
-  } else {
-    switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE)                \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    CPP_LOWERCASE value;                                                    \
-    if (!WireFormatLite::ReadPrimitive<CPP_LOWERCASE,                       \
-                                       WireFormatLite::TYPE_##UPPERCASE>(   \
-            input, &value))                                                 \
-      return false;                                                         \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_TYPE(INT32, Int32, int32_t);
-      HANDLE_TYPE(INT64, Int64, int64_t);
-      HANDLE_TYPE(UINT32, UInt32, uint32_t);
-      HANDLE_TYPE(UINT64, UInt64, uint64_t);
-      HANDLE_TYPE(SINT32, Int32, int32_t);
-      HANDLE_TYPE(SINT64, Int64, int64_t);
-      HANDLE_TYPE(FIXED32, UInt32, uint32_t);
-      HANDLE_TYPE(FIXED64, UInt64, uint64_t);
-      HANDLE_TYPE(SFIXED32, Int32, int32_t);
-      HANDLE_TYPE(SFIXED64, Int64, int64_t);
-      HANDLE_TYPE(FLOAT, Float, float);
-      HANDLE_TYPE(DOUBLE, Double, double);
-      HANDLE_TYPE(BOOL, Bool, bool);
-#undef HANDLE_TYPE
-
-      case WireFormatLite::TYPE_ENUM: {
-        int value;
-        if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
-                input, &value))
-          return false;
-
-        if (!extension.enum_validity_check.func(
-                extension.enum_validity_check.arg, value)) {
-          // Invalid value.  Treat as unknown.
-          field_skipper->SkipUnknownEnum(number, value);
-        } else if (extension.is_repeated) {
-          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
-                  extension.descriptor);
-        } else {
-          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
-                  extension.descriptor);
-        }
-        break;
-      }
-
-      case WireFormatLite::TYPE_STRING: {
-        std::string* value =
-            extension.is_repeated
-                ? AddString(number, WireFormatLite::TYPE_STRING,
-                            extension.descriptor)
-                : MutableString(number, WireFormatLite::TYPE_STRING,
-                                extension.descriptor);
-        if (!WireFormatLite::ReadString(input, value)) return false;
-        break;
-      }
-
-      case WireFormatLite::TYPE_BYTES: {
-        std::string* value =
-            extension.is_repeated
-                ? AddString(number, WireFormatLite::TYPE_BYTES,
-                            extension.descriptor)
-                : MutableString(number, WireFormatLite::TYPE_BYTES,
-                                extension.descriptor);
-        if (!WireFormatLite::ReadBytes(input, value)) return false;
-        break;
-      }
-
-      case WireFormatLite::TYPE_GROUP: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
-                             *extension.message_info.prototype,
-                             extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
-                                 *extension.message_info.prototype,
-                                 extension.descriptor);
-        if (!WireFormatLite::ReadGroup(number, input, value)) return false;
-        break;
-      }
-
-      case WireFormatLite::TYPE_MESSAGE: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
-                             *extension.message_info.prototype,
-                             extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
-                                 *extension.message_info.prototype,
-                                 extension.descriptor);
-        if (!WireFormatLite::ReadMessage(input, value)) return false;
-        break;
-      }
-    }
-  }
-
-  return true;
-}
-
-bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
-                              const MessageLite* extendee) {
-  FieldSkipper skipper;
-  GeneratedExtensionFinder finder(extendee);
-  return ParseField(tag, input, &finder, &skipper);
-}
-
-bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
-                              const MessageLite* extendee,
-                              io::CodedOutputStream* unknown_fields) {
-  CodedOutputStreamFieldSkipper skipper(unknown_fields);
-  GeneratedExtensionFinder finder(extendee);
-  return ParseField(tag, input, &finder, &skipper);
-}
-
-bool ExtensionSet::ParseMessageSetLite(io::CodedInputStream* input,
-                                       ExtensionFinder* extension_finder,
-                                       FieldSkipper* field_skipper) {
-  while (true) {
-    const uint32_t tag = input->ReadTag();
-    switch (tag) {
-      case 0:
-        return true;
-      case WireFormatLite::kMessageSetItemStartTag:
-        if (!ParseMessageSetItemLite(input, extension_finder, field_skipper)) {
-          return false;
-        }
-        break;
-      default:
-        if (!ParseField(tag, input, extension_finder, field_skipper)) {
-          return false;
-        }
-        break;
-    }
-  }
-}
-
-bool ExtensionSet::ParseMessageSetItemLite(io::CodedInputStream* input,
-                                           ExtensionFinder* extension_finder,
-                                           FieldSkipper* field_skipper) {
-  struct MSLite {
-    bool ParseField(int type_id, io::CodedInputStream* input) {
-      return me->ParseField(
-          WireFormatLite::WIRETYPE_LENGTH_DELIMITED + 8 * type_id, input,
-          extension_finder, field_skipper);
-    }
-
-    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
-      return field_skipper->SkipField(input, tag);
-    }
-
-    ExtensionSet* me;
-    ExtensionFinder* extension_finder;
-    FieldSkipper* field_skipper;
-  };
-
-  return ParseMessageSetItemImpl(input,
-                                 MSLite{this, extension_finder, field_skipper});
-}
-
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
-                                   const MessageLite* extendee,
-                                   std::string* unknown_fields) {
-  io::StringOutputStream zcis(unknown_fields);
-  io::CodedOutputStream output(&zcis);
-  CodedOutputStreamFieldSkipper skipper(&output);
-  GeneratedExtensionFinder finder(extendee);
-  return ParseMessageSetLite(input, &finder, &skipper);
-}
-
 uint8_t* ExtensionSet::_InternalSerializeImpl(
     const MessageLite* extendee, int start_field_number, int end_field_number,
     uint8_t* target, io::EpsCopyOutputStream* stream) const {
@@ -2093,18 +1836,20 @@
         HANDLE_TYPE(STRING, String, string);
         HANDLE_TYPE(BYTES, Bytes, string);
 #undef HANDLE_TYPE
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                     \
-  case WireFormatLite::TYPE_##UPPERCASE:                                 \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {     \
-      target = stream->EnsureSpace(target);                              \
-      target = WireFormatLite::InternalWrite##CAMELCASE(                 \
-          number, repeated_##LOWERCASE##_value->Get(i), target, stream); \
-    }                                                                    \
-    break
-
-        HANDLE_TYPE(GROUP, Group, message);
-        HANDLE_TYPE(MESSAGE, Message, message);
-#undef HANDLE_TYPE
+        case WireFormatLite::TYPE_GROUP:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            target = stream->EnsureSpace(target);
+            target = WireFormatLite::InternalWriteGroup(
+                number, repeated_message_value->Get(i), target, stream);
+          }
+          break;
+        case WireFormatLite::TYPE_MESSAGE:
+          for (int i = 0; i < repeated_message_value->size(); i++) {
+            auto& msg = repeated_message_value->Get(i);
+            target = WireFormatLite::InternalWriteMessage(
+                number, msg, msg.GetCachedSize(), target, stream);
+          }
+          break;
       }
     }
   } else if (!is_cleared) {
@@ -2150,9 +1895,9 @@
           target = lazymessage_value->WriteMessageToArray(prototype, number,
                                                           target, stream);
         } else {
-          target = stream->EnsureSpace(target);
-          target = WireFormatLite::InternalWriteMessage(number, *message_value,
-                                                        target, stream);
+          target = WireFormatLite::InternalWriteMessage(
+              number, *message_value, message_value->GetCachedSize(), target,
+              stream);
         }
         break;
     }
@@ -2201,8 +1946,8 @@
         prototype, WireFormatLite::kMessageSetMessageNumber, target, stream);
   } else {
     target = WireFormatLite::InternalWriteMessage(
-        WireFormatLite::kMessageSetMessageNumber, *message_value, target,
-        stream);
+        WireFormatLite::kMessageSetMessageNumber, *message_value,
+        message_value->GetCachedSize(), target, stream);
   }
   // End group.
   target = stream->EnsureSpace(target);
@@ -2247,6 +1992,15 @@
   return total_size;
 }
 
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number) {
+  const ExtensionInfo* registered = FindRegisteredExtension(extendee, number);
+  if (registered != nullptr) {
+    return registered->lazy_eager_verify_func;
+  }
+  return nullptr;
+}
+
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index beb4202..c175a28 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -38,6 +38,7 @@
 #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__
 #define GOOGLE_PROTOBUF_EXTENSION_SET_H__
 
+
 #include <algorithm>
 #include <cassert>
 #include <map>
@@ -47,9 +48,9 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
 
@@ -74,6 +75,7 @@
 class UnknownFieldSet;  // unknown_field_set.h
 namespace internal {
 class FieldSkipper;  // wire_format_lite.h
+enum class LazyVerifyOption;
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
@@ -103,13 +105,15 @@
 struct ExtensionInfo {
   constexpr ExtensionInfo() : enum_validity_check() {}
   constexpr ExtensionInfo(const MessageLite* extendee, int param_number,
-                          FieldType type_param, bool isrepeated, bool ispacked)
+                          FieldType type_param, bool isrepeated, bool ispacked,
+                          LazyEagerVerifyFnType verify_func)
       : message(extendee),
         number(param_number),
         type(type_param),
         is_repeated(isrepeated),
         is_packed(ispacked),
-        enum_validity_check() {}
+        enum_validity_check(),
+        lazy_eager_verify_func(verify_func) {}
 
   const MessageLite* message = nullptr;
   int number = 0;
@@ -136,6 +140,11 @@
   // nullptr.  Must not be nullptr if the descriptor for the extension does not
   // live in the same pool as the descriptor for the containing type.
   const FieldDescriptor* descriptor = nullptr;
+
+  // If this field is potentially lazy this function can be used as a cheap
+  // verification of the raw bytes.
+  // If nullptr then no verification is performed.
+  LazyEagerVerifyFnType lazy_eager_verify_func = nullptr;
 };
 
 // Abstract interface for an object which looks up extension definitions.  Used
@@ -163,9 +172,6 @@
   const MessageLite* extendee_;
 };
 
-// A FieldSkipper used for parsing MessageSet.
-class MessageSetFieldSkipper;
-
 // Note:  extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
 // finding extensions from a DescriptorPool.
 
@@ -193,14 +199,16 @@
   // methods do.
   static void RegisterExtension(const MessageLite* extendee, int number,
                                 FieldType type, bool is_repeated,
-                                bool is_packed);
+                                bool is_packed,
+                                LazyEagerVerifyFnType verify_func);
   static void RegisterEnumExtension(const MessageLite* extendee, int number,
                                     FieldType type, bool is_repeated,
                                     bool is_packed, EnumValidityFunc* is_valid);
   static void RegisterMessageExtension(const MessageLite* extendee, int number,
                                        FieldType type, bool is_repeated,
                                        bool is_packed,
-                                       const MessageLite* prototype);
+                                       const MessageLite* prototype,
+                                       LazyEagerVerifyFnType verify_func);
 
   // =================================================================
 
@@ -368,9 +376,6 @@
   MessageLite* UnsafeArenaReleaseLast(int number);
   void SwapElements(int number, int index1, int index2);
 
-  // -----------------------------------------------------------------
-  // TODO(kenton):  Hardcore memory management accessors
-
   // =================================================================
   // convenience methods for implementing methods of Message
   //
@@ -386,26 +391,6 @@
   void UnsafeShallowSwapExtension(ExtensionSet* other, int number);
   bool IsInitialized() const;
 
-  // Parses a single extension from the input. The input should start out
-  // positioned immediately after the tag.
-  bool ParseField(uint32_t tag, io::CodedInputStream* input,
-                  ExtensionFinder* extension_finder,
-                  FieldSkipper* field_skipper);
-
-  // Specific versions for lite or full messages (constructs the appropriate
-  // FieldSkipper automatically).  |extendee| is the default
-  // instance for the containing message; it is used only to look up the
-  // extension by number.  See RegisterExtension(), above.  Unlike the other
-  // methods of ExtensionSet, this only works for generated message types --
-  // it looks up extensions registered using RegisterExtension().
-  bool ParseField(uint32_t tag, io::CodedInputStream* input,
-                  const MessageLite* extendee);
-  bool ParseField(uint32_t tag, io::CodedInputStream* input,
-                  const Message* extendee, UnknownFieldSet* unknown_fields);
-  bool ParseField(uint32_t tag, io::CodedInputStream* input,
-                  const MessageLite* extendee,
-                  io::CodedOutputStream* unknown_fields);
-
   // Lite parser
   const char* ParseField(uint64_t tag, const char* ptr,
                          const MessageLite* extendee,
@@ -446,22 +431,6 @@
     return ptr;
   }
 
-  // Parse an entire message in MessageSet format.  Such messages have no
-  // fields, only extensions.
-  bool ParseMessageSetLite(io::CodedInputStream* input,
-                           ExtensionFinder* extension_finder,
-                           FieldSkipper* field_skipper);
-  bool ParseMessageSet(io::CodedInputStream* input,
-                       ExtensionFinder* extension_finder,
-                       MessageSetFieldSkipper* field_skipper);
-
-  // Specific versions for lite or full messages (constructs the appropriate
-  // FieldSkipper automatically).
-  bool ParseMessageSet(io::CodedInputStream* input, const MessageLite* extendee,
-                       std::string* unknown_fields);
-  bool ParseMessageSet(io::CodedInputStream* input, const Message* extendee,
-                       UnknownFieldSet* unknown_fields);
-
   // Write all extension fields with field numbers in the range
   //   [start_field_number, end_field_number)
   // to the output stream, using the cached sizes computed when ByteSize() was
@@ -601,10 +570,9 @@
     virtual void MergeFromMessage(const MessageLite& msg, Arena* arena) = 0;
     virtual void Clear() = 0;
 
-    virtual bool ReadMessage(const MessageLite& prototype,
-                             io::CodedInputStream* input) = 0;
     virtual const char* _InternalParse(const Message& prototype, Arena* arena,
-                                       const char* ptr, ParseContext* ctx) = 0;
+                                       LazyVerifyOption option, const char* ptr,
+                                       ParseContext* ctx) = 0;
     virtual uint8_t* WriteMessageToArray(
         const MessageLite* prototype, int number, uint8_t* target,
         io::EpsCopyOutputStream* stream) const = 0;
@@ -799,22 +767,6 @@
   const MessageLite* GetPrototypeForLazyMessage(const MessageLite* extendee,
                                                 int number) const;
 
-  // Parses a single extension from the input. The input should start out
-  // positioned immediately after the wire tag. This method is called in
-  // ParseField() after field number and was_packed_on_wire is extracted from
-  // the wire tag and ExtensionInfo is found by the field number.
-  bool ParseFieldWithExtensionInfo(int field_number, bool was_packed_on_wire,
-                                   const ExtensionInfo& extension,
-                                   io::CodedInputStream* input,
-                                   FieldSkipper* field_skipper);
-
-  // Like ParseField(), but this method may parse singular message extensions
-  // lazily depending on the value of FLAGS_eagerly_parse_message_sets.
-  bool ParseFieldMaybeLazily(int wire_type, int field_number,
-                             io::CodedInputStream* input,
-                             ExtensionFinder* extension_finder,
-                             MessageSetFieldSkipper* field_skipper);
-
   // Returns true if extension is present and lazy.
   bool HasLazy(int number) const;
 
@@ -827,17 +779,6 @@
   // it does not exist.
   Extension* MaybeNewRepeatedExtension(const FieldDescriptor* descriptor);
 
-  // Parse a single MessageSet item -- called just after the item group start
-  // tag has been read.
-  bool ParseMessageSetItemLite(io::CodedInputStream* input,
-                               ExtensionFinder* extension_finder,
-                               FieldSkipper* field_skipper);
-  // Parse a single MessageSet item -- called just after the item group start
-  // tag has been read.
-  bool ParseMessageSetItem(io::CodedInputStream* input,
-                           ExtensionFinder* extension_finder,
-                           MessageSetFieldSkipper* field_skipper);
-
   bool FindExtension(int wire_type, uint32_t field, const MessageLite* extendee,
                      const internal::ParseContext* /*ctx*/,
                      ExtensionInfo* extension, bool* was_packed_on_wire) {
@@ -1023,9 +964,10 @@
   static inline void Set(int number, FieldType field_type, ConstType value,
                          ExtensionSet* set);
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
     ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
-                                    type, false, is_packed);
+                                    type, false, is_packed, verify_func);
   }
 };
 
@@ -1056,9 +998,10 @@
 
   static const RepeatedFieldType* GetDefaultRepeatedField();
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
     ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
-                                    type, true, is_packed);
+                                    type, true, is_packed, verify_func);
   }
 };
 
@@ -1178,9 +1121,10 @@
     return set->MutableString(number, field_type, nullptr);
   }
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType verify_func) {
     ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
-                                    type, false, is_packed);
+                                    type, false, is_packed, verify_func);
   }
 };
 
@@ -1234,9 +1178,10 @@
   static const RepeatedFieldType* GetDefaultRepeatedField();
 
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
     ExtensionSet::RegisterExtension(&ExtendeeT::default_instance(), number,
-                                    type, true, is_packed);
+                                    type, true, is_packed, fn);
   }
 
  private:
@@ -1271,7 +1216,8 @@
     set->SetEnum(number, field_type, value, nullptr);
   }
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
     ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
                                         type, false, is_packed, IsValid);
   }
@@ -1336,7 +1282,8 @@
         RepeatedPrimitiveTypeTraits<int32_t>::GetDefaultRepeatedField());
   }
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
     ExtensionSet::RegisterEnumExtension(&ExtendeeT::default_instance(), number,
                                         type, true, is_packed, IsValid);
   }
@@ -1359,7 +1306,8 @@
                               ConstType default_value) {
     return static_cast<const Type&>(set.GetMessage(number, default_value));
   }
-  static inline std::nullptr_t GetPtr(int /* number */, const ExtensionSet& /* set */,
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
                                       ConstType /* default_value */) {
     // Cannot be implemented because of forward declared messages?
     return nullptr;
@@ -1390,13 +1338,18 @@
         set->UnsafeArenaReleaseMessage(number, Type::default_instance()));
   }
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
     ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
                                            number, type, false, is_packed,
-                                           &Type::default_instance());
+                                           &Type::default_instance(), fn);
   }
 };
 
+// Used by WireFormatVerify to extract the verify function from the registry.
+LazyEagerVerifyFnType FindExtensionLazyEagerVerifyFn(
+    const MessageLite* extendee, int number);
+
 // forward declaration.
 class RepeatedMessageGenericTypeTraits;
 
@@ -1412,7 +1365,8 @@
   static inline ConstType Get(int number, const ExtensionSet& set, int index) {
     return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
   }
-  static inline std::nullptr_t GetPtr(int /* number */, const ExtensionSet& /* set */,
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
                                       int /* index */) {
     // Cannot be implemented because of forward declared messages?
     return nullptr;
@@ -1450,10 +1404,11 @@
 
   static const RepeatedFieldType* GetDefaultRepeatedField();
   template <typename ExtendeeT>
-  static void Register(int number, FieldType type, bool is_packed) {
+  static void Register(int number, FieldType type, bool is_packed,
+                       LazyEagerVerifyFnType fn) {
     ExtensionSet::RegisterMessageExtension(&ExtendeeT::default_instance(),
                                            number, type, true, is_packed,
-                                           &Type::default_instance());
+                                           &Type::default_instance(), fn);
   }
 };
 
@@ -1490,17 +1445,19 @@
   typedef TypeTraitsType TypeTraits;
   typedef ExtendeeType Extendee;
 
-  ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value)
+  ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value,
+                      LazyEagerVerifyFnType verify_func = nullptr)
       : number_(number), default_value_(default_value) {
-    Register(number);
+    Register(number, verify_func);
   }
   inline int number() const { return number_; }
   typename TypeTraits::ConstType default_value() const {
     return default_value_;
   }
 
-  static void Register(int number) {
-    TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed);
+  static void Register(int number, LazyEagerVerifyFnType verify_func) {
+    TypeTraits::template Register<ExtendeeType>(number, field_type, is_packed,
+                                                verify_func);
   }
 
   typename TypeTraits::ConstType const& default_value_ref() const {
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 91187af..0b23572 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -36,50 +36,28 @@
 // lite library because they use descriptors or reflection.
 
 #include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/extension_set_inl.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/extension_set.h>
+#include <google/protobuf/extension_set_inl.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
 namespace internal {
 
-// A FieldSkipper used to store unknown MessageSet fields into UnknownFieldSet.
-class MessageSetFieldSkipper : public UnknownFieldSetFieldSkipper {
- public:
-  explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
-      : UnknownFieldSetFieldSkipper(unknown_fields) {}
-  ~MessageSetFieldSkipper() override {}
-
-  virtual bool SkipMessageSetField(io::CodedInputStream* input,
-                                   int field_number);
-};
-bool MessageSetFieldSkipper::SkipMessageSetField(io::CodedInputStream* input,
-                                                 int field_number) {
-  uint32_t length;
-  if (!input->ReadVarint32(&length)) return false;
-  if (unknown_fields_ == nullptr) {
-    return input->Skip(length);
-  } else {
-    return input->ReadString(unknown_fields_->AddLengthDelimited(field_number),
-                             length);
-  }
-}
-
-
 // Implementation of ExtensionFinder which finds extensions in a given
 // DescriptorPool, using the given MessageFactory to construct sub-objects.
 // This class is implemented in extension_set_heavy.cc.
@@ -376,36 +354,6 @@
                                                            metadata, ctx);
 }
 
-bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
-                              const Message* containing_type,
-                              UnknownFieldSet* unknown_fields) {
-  UnknownFieldSetFieldSkipper skipper(unknown_fields);
-  if (input->GetExtensionPool() == nullptr) {
-    GeneratedExtensionFinder finder(containing_type);
-    return ParseField(tag, input, &finder, &skipper);
-  } else {
-    DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
-                                         input->GetExtensionFactory(),
-                                         containing_type->GetDescriptor());
-    return ParseField(tag, input, &finder, &skipper);
-  }
-}
-
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
-                                   const Message* containing_type,
-                                   UnknownFieldSet* unknown_fields) {
-  MessageSetFieldSkipper skipper(unknown_fields);
-  if (input->GetExtensionPool() == nullptr) {
-    GeneratedExtensionFinder finder(containing_type);
-    return ParseMessageSet(input, &finder, &skipper);
-  } else {
-    DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
-                                         input->GetExtensionFactory(),
-                                         containing_type->GetDescriptor());
-    return ParseMessageSet(input, &finder, &skipper);
-  }
-}
-
 int ExtensionSet::SpaceUsedExcludingSelf() const {
   return internal::FromIntSize(SpaceUsedExcludingSelfLong());
 }
@@ -485,60 +433,6 @@
                                                            &stream);
 }
 
-bool ExtensionSet::ParseFieldMaybeLazily(
-    int wire_type, int field_number, io::CodedInputStream* input,
-    ExtensionFinder* extension_finder, MessageSetFieldSkipper* field_skipper) {
-  return ParseField(
-      WireFormatLite::MakeTag(field_number,
-                              static_cast<WireFormatLite::WireType>(wire_type)),
-      input, extension_finder, field_skipper);
-}
-
-bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
-                                   ExtensionFinder* extension_finder,
-                                   MessageSetFieldSkipper* field_skipper) {
-  while (true) {
-    const uint32_t tag = input->ReadTag();
-    switch (tag) {
-      case 0:
-        return true;
-      case WireFormatLite::kMessageSetItemStartTag:
-        if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
-          return false;
-        }
-        break;
-      default:
-        if (!ParseField(tag, input, extension_finder, field_skipper)) {
-          return false;
-        }
-        break;
-    }
-  }
-}
-
-bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
-                                       ExtensionFinder* extension_finder,
-                                       MessageSetFieldSkipper* field_skipper) {
-  struct MSFull {
-    bool ParseField(int type_id, io::CodedInputStream* input) {
-      return me->ParseFieldMaybeLazily(
-          WireFormatLite::WIRETYPE_LENGTH_DELIMITED, type_id, input,
-          extension_finder, field_skipper);
-    }
-
-    bool SkipField(uint32_t tag, io::CodedInputStream* input) {
-      return field_skipper->SkipField(input, tag);
-    }
-
-    ExtensionSet* me;
-    ExtensionFinder* extension_finder;
-    MessageSetFieldSkipper* field_skipper;
-  };
-
-  return ParseMessageSetItemImpl(input,
-                                 MSFull{this, extension_finder, field_skipper});
-}
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
index 291990f..95936cc 100644
--- a/src/google/protobuf/extension_set_inl.h
+++ b/src/google/protobuf/extension_set_inl.h
@@ -31,9 +31,9 @@
 #ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
 #define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index debdd66..5e145f8 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -133,7 +133,7 @@
   unittest::TestAllExtensions message;
 
   TestUtil::SetAllExtensions(&message);
-  int64 original_value =
+  int64_t original_value =
       message.GetExtension(unittest::optional_int64_extension);
 
   // Clear the field and make sure it shows up as cleared.
@@ -520,8 +520,8 @@
   size_t size = source.ByteSizeLong();
   std::string data;
   data.resize(size);
-  uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data));
-  uint8* end = source.SerializeWithCachedSizesToArray(target);
+  uint8_t* target = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = source.SerializeWithCachedSizesToArray(target);
   EXPECT_EQ(size, end - target);
   EXPECT_TRUE(destination.ParseFromString(data));
   TestUtil::ExpectAllFieldsSet(destination);
@@ -564,8 +564,8 @@
   size_t size = source.ByteSizeLong();
   std::string data;
   data.resize(size);
-  uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data));
-  uint8* end = source.SerializeWithCachedSizesToArray(target);
+  uint8_t* target = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = source.SerializeWithCachedSizesToArray(target);
   EXPECT_EQ(size, end - target);
   EXPECT_TRUE(destination.ParseFromString(data));
   TestUtil::ExpectPackedFieldsSet(destination);
@@ -800,7 +800,8 @@
 
   // Repeated primitive extensions will increase space used by at least a
   // RepeatedField<T>, and will cause additional allocations when the array
-  // gets too big for the initial space.
+  // gets too big for the initial space.  Note, we explicitly allocate on the
+  // heap to avoid message-owned arenas.
   // This macro:
   //   - Adds a value to the repeated extension, then clears it, establishing
   //     the base size.
@@ -808,46 +809,47 @@
   //     SpaceUsedLong()
   //   - Adds a large number of values (requiring allocation in the repeated
   //     field), and ensures that that allocation is included in SpaceUsedLong()
-#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value)             \
-  do {                                                                        \
-    unittest::TestAllExtensions message;                                      \
-    const size_t base_size = message.SpaceUsedLong();                         \
-    size_t min_expected_size = sizeof(RepeatedField<cpptype>) + base_size;    \
-    message.AddExtension(unittest::repeated_##type##_extension, value);       \
-    message.ClearExtension(unittest::repeated_##type##_extension);            \
-    const size_t empty_repeated_field_size = message.SpaceUsedLong();         \
-    EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type;         \
-    message.AddExtension(unittest::repeated_##type##_extension, value);       \
-    message.AddExtension(unittest::repeated_##type##_extension, value);       \
-    EXPECT_EQ(empty_repeated_field_size, message.SpaceUsedLong()) << #type;   \
-    message.ClearExtension(unittest::repeated_##type##_extension);            \
-    const size_t old_capacity =                                               \
-        message.GetRepeatedExtension(unittest::repeated_##type##_extension)   \
-            .Capacity();                                                      \
-    EXPECT_GE(old_capacity, kRepeatedFieldLowerClampLimit);                   \
-    for (int i = 0; i < 16; ++i) {                                            \
-      message.AddExtension(unittest::repeated_##type##_extension, value);     \
-    }                                                                         \
-    int expected_size =                                                       \
-        sizeof(cpptype) *                                                     \
-            (message                                                          \
-                 .GetRepeatedExtension(unittest::repeated_##type##_extension) \
-                 .Capacity() -                                                \
-             old_capacity) +                                                  \
-        empty_repeated_field_size;                                            \
-    EXPECT_LE(expected_size, message.SpaceUsedLong()) << #type;               \
+#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value)              \
+  do {                                                                         \
+    std::unique_ptr<unittest::TestAllExtensions> message(                      \
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));           \
+    const size_t base_size = message->SpaceUsedLong();                         \
+    size_t min_expected_size = sizeof(RepeatedField<cpptype>) + base_size;     \
+    message->AddExtension(unittest::repeated_##type##_extension, value);       \
+    message->ClearExtension(unittest::repeated_##type##_extension);            \
+    const size_t empty_repeated_field_size = message->SpaceUsedLong();         \
+    EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type;          \
+    message->AddExtension(unittest::repeated_##type##_extension, value);       \
+    EXPECT_EQ(empty_repeated_field_size, message->SpaceUsedLong()) << #type;   \
+    message->ClearExtension(unittest::repeated_##type##_extension);            \
+    const size_t old_capacity =                                                \
+        message->GetRepeatedExtension(unittest::repeated_##type##_extension)   \
+            .Capacity();                                                       \
+    EXPECT_GE(old_capacity,                                                    \
+              (RepeatedFieldLowerClampLimit<cpptype, sizeof(void*)>()));       \
+    for (int i = 0; i < 16; ++i) {                                             \
+      message->AddExtension(unittest::repeated_##type##_extension, value);     \
+    }                                                                          \
+    int expected_size =                                                        \
+        sizeof(cpptype) *                                                      \
+            (message                                                           \
+                 ->GetRepeatedExtension(unittest::repeated_##type##_extension) \
+                 .Capacity() -                                                 \
+             old_capacity) +                                                   \
+        empty_repeated_field_size;                                             \
+    EXPECT_LE(expected_size, message->SpaceUsedLong()) << #type;               \
   } while (0)
 
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(int32, int32, 101);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(int64, int64, 102);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32, uint32, 103);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64, uint64, 104);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32, int32, 105);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64, int64, 106);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32, uint32, 107);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64, uint64, 108);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32, 109);
-  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64, 110);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(int32, int32_t, 101);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(int64, int64_t, 102);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32, uint32_t, 103);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64, uint64_t, 104);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32, int32_t, 105);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64, int64_t, 106);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32, uint32_t, 107);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64, uint64_t, 108);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32_t, 109);
+  TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64_t, 110);
   TEST_REPEATED_EXTENSIONS_SPACE_USED(float, float, 111);
   TEST_REPEATED_EXTENSIONS_SPACE_USED(double, double, 112);
   TEST_REPEATED_EXTENSIONS_SPACE_USED(bool, bool, true);
@@ -856,8 +858,9 @@
 #undef TEST_REPEATED_EXTENSIONS_SPACE_USED
   // Repeated strings
   {
-    unittest::TestAllExtensions message;
-    const size_t base_size = message.SpaceUsedLong();
+    std::unique_ptr<unittest::TestAllExtensions> message(
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));
+    const size_t base_size = message->SpaceUsedLong();
     size_t min_expected_size =
         sizeof(RepeatedPtrField<std::string>) + base_size;
     const std::string value(256, 'x');
@@ -865,27 +868,30 @@
     // without the hardcore memory management accessors there isn't a notion of
     // the empty repeated field memory usage as there is with primitive types.
     for (int i = 0; i < 16; ++i) {
-      message.AddExtension(unittest::repeated_string_extension, value);
+      message->AddExtension(unittest::repeated_string_extension, value);
     }
     min_expected_size +=
-        (sizeof(value) + value.size()) * (16 - kRepeatedFieldLowerClampLimit);
-    EXPECT_LE(min_expected_size, message.SpaceUsedLong());
+        (sizeof(value) + value.size()) *
+        (16 - RepeatedFieldLowerClampLimit<void*, sizeof(void*)>());
+    EXPECT_LE(min_expected_size, message->SpaceUsedLong());
   }
   // Repeated messages
   {
-    unittest::TestAllExtensions message;
-    const size_t base_size = message.SpaceUsedLong();
+    std::unique_ptr<unittest::TestAllExtensions> message(
+        Arena::CreateMessage<unittest::TestAllExtensions>(nullptr));
+    const size_t base_size = message->SpaceUsedLong();
     size_t min_expected_size =
         sizeof(RepeatedPtrField<unittest::ForeignMessage>) + base_size;
     unittest::ForeignMessage prototype;
     prototype.set_c(2);
     for (int i = 0; i < 16; ++i) {
-      message.AddExtension(unittest::repeated_foreign_message_extension)
-          ->CopyFrom(prototype);
+      *message->AddExtension(unittest::repeated_foreign_message_extension) =
+          prototype;
     }
     min_expected_size +=
-        (16 - kRepeatedFieldLowerClampLimit) * prototype.SpaceUsedLong();
-    EXPECT_LE(min_expected_size, message.SpaceUsedLong());
+        (16 - RepeatedFieldLowerClampLimit<void*, sizeof(void*)>()) *
+        prototype.SpaceUsedLong();
+    EXPECT_LE(min_expected_size, message->SpaceUsedLong());
   }
 }
 
@@ -961,52 +967,52 @@
     message.AddExtension(unittest::repeated_nested_enum_extension, nested_enum);
   }
 
-  ASSERT_EQ(10, SumAllExtensions<int32>(message,
-                                        unittest::repeated_int32_extension, 0));
-  IncAllExtensions<int32>(&message, unittest::repeated_int32_extension, 1);
-  ASSERT_EQ(20, SumAllExtensions<int32>(message,
-                                        unittest::repeated_int32_extension, 0));
+  ASSERT_EQ(10, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_int32_extension, 0));
+  IncAllExtensions<int32_t>(&message, unittest::repeated_int32_extension, 1);
+  ASSERT_EQ(20, SumAllExtensions<int32_t>(
+                    message, unittest::repeated_int32_extension, 0));
 
-  ASSERT_EQ(20, SumAllExtensions<int64>(message,
-                                        unittest::repeated_int64_extension, 0));
-  IncAllExtensions<int64>(&message, unittest::repeated_int64_extension, 1);
-  ASSERT_EQ(30, SumAllExtensions<int64>(message,
-                                        unittest::repeated_int64_extension, 0));
+  ASSERT_EQ(20, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_int64_extension, 0));
+  IncAllExtensions<int64_t>(&message, unittest::repeated_int64_extension, 1);
+  ASSERT_EQ(30, SumAllExtensions<int64_t>(
+                    message, unittest::repeated_int64_extension, 0));
 
-  ASSERT_EQ(30, SumAllExtensions<uint32>(
+  ASSERT_EQ(30, SumAllExtensions<uint32_t>(
                     message, unittest::repeated_uint32_extension, 0));
-  IncAllExtensions<uint32>(&message, unittest::repeated_uint32_extension, 1);
-  ASSERT_EQ(40, SumAllExtensions<uint32>(
+  IncAllExtensions<uint32_t>(&message, unittest::repeated_uint32_extension, 1);
+  ASSERT_EQ(40, SumAllExtensions<uint32_t>(
                     message, unittest::repeated_uint32_extension, 0));
 
-  ASSERT_EQ(40, SumAllExtensions<uint64>(
+  ASSERT_EQ(40, SumAllExtensions<uint64_t>(
                     message, unittest::repeated_uint64_extension, 0));
-  IncAllExtensions<uint64>(&message, unittest::repeated_uint64_extension, 1);
-  ASSERT_EQ(50, SumAllExtensions<uint64>(
+  IncAllExtensions<uint64_t>(&message, unittest::repeated_uint64_extension, 1);
+  ASSERT_EQ(50, SumAllExtensions<uint64_t>(
                     message, unittest::repeated_uint64_extension, 0));
 
-  ASSERT_EQ(50, SumAllExtensions<int32>(
+  ASSERT_EQ(50, SumAllExtensions<int32_t>(
                     message, unittest::repeated_sint32_extension, 0));
-  IncAllExtensions<int32>(&message, unittest::repeated_sint32_extension, 1);
-  ASSERT_EQ(60, SumAllExtensions<int32>(
+  IncAllExtensions<int32_t>(&message, unittest::repeated_sint32_extension, 1);
+  ASSERT_EQ(60, SumAllExtensions<int32_t>(
                     message, unittest::repeated_sint32_extension, 0));
 
-  ASSERT_EQ(60, SumAllExtensions<int64>(
+  ASSERT_EQ(60, SumAllExtensions<int64_t>(
                     message, unittest::repeated_sint64_extension, 0));
-  IncAllExtensions<int64>(&message, unittest::repeated_sint64_extension, 1);
-  ASSERT_EQ(70, SumAllExtensions<int64>(
+  IncAllExtensions<int64_t>(&message, unittest::repeated_sint64_extension, 1);
+  ASSERT_EQ(70, SumAllExtensions<int64_t>(
                     message, unittest::repeated_sint64_extension, 0));
 
-  ASSERT_EQ(70, SumAllExtensions<uint32>(
+  ASSERT_EQ(70, SumAllExtensions<uint32_t>(
                     message, unittest::repeated_fixed32_extension, 0));
-  IncAllExtensions<uint32>(&message, unittest::repeated_fixed32_extension, 1);
-  ASSERT_EQ(80, SumAllExtensions<uint32>(
+  IncAllExtensions<uint32_t>(&message, unittest::repeated_fixed32_extension, 1);
+  ASSERT_EQ(80, SumAllExtensions<uint32_t>(
                     message, unittest::repeated_fixed32_extension, 0));
 
-  ASSERT_EQ(80, SumAllExtensions<uint64>(
+  ASSERT_EQ(80, SumAllExtensions<uint64_t>(
                     message, unittest::repeated_fixed64_extension, 0));
-  IncAllExtensions<uint64>(&message, unittest::repeated_fixed64_extension, 1);
-  ASSERT_EQ(90, SumAllExtensions<uint64>(
+  IncAllExtensions<uint64_t>(&message, unittest::repeated_fixed64_extension, 1);
+  ASSERT_EQ(90, SumAllExtensions<uint64_t>(
                     message, unittest::repeated_fixed64_extension, 0));
 
   // Usually, floating-point arithmetic cannot be trusted to be exact, so it is
@@ -1322,7 +1328,7 @@
 
 TEST(ExtensionSetTest, BoolExtension) {
   unittest::TestAllExtensions msg;
-  uint8 wire_bytes[2] = {13 * 8, 42 /* out of bounds payload for bool */};
+  uint8_t wire_bytes[2] = {13 * 8, 42 /* out of bounds payload for bool */};
   EXPECT_TRUE(msg.ParseFromArray(wire_bytes, 2));
   EXPECT_TRUE(msg.GetExtension(protobuf_unittest::optional_bool_extension));
 }
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index 60edb1e..5f9f16d 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -16,23 +16,27 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr FieldMask::FieldMask(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : paths_(){}
 struct FieldMaskDefaultTypeInternal {
   constexpr FieldMaskDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FieldMaskDefaultTypeInternal() {}
   union {
     FieldMask _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -43,12 +47,12 @@
   ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::FieldMask, paths_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FieldMask)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FieldMask_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_FieldMask_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -59,19 +63,21 @@
   "n/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
   ".WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
-  false, false, 223, descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto, "google/protobuf/field_mask.proto", 
-  &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+    false, false, 223, descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
+    "google/protobuf/field_mask.proto",
+    &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ffield_5fmask_2eproto(&descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ffield_5fmask_2eproto(&descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -85,9 +91,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   paths_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FieldMask)
 }
 FieldMask::FieldMask(const FieldMask& from)
@@ -102,21 +105,17 @@
 
 FieldMask::~FieldMask() {
   // @@protoc_insertion_point(destructor:google.protobuf.FieldMask)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FieldMask::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void FieldMask::ArenaDtor(void* object) {
-  FieldMask* _this = reinterpret_cast< FieldMask* >(object);
-  (void)_this;
-}
-void FieldMask::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FieldMask::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -131,11 +130,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FieldMask::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FieldMask::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated string paths = 1;
       case 1:
@@ -144,9 +143,9 @@
           do {
             ptr += 1;
             auto str = _internal_add_paths();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.FieldMask.paths"));
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.FieldMask.paths"));
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<10>(ptr));
         } else
@@ -192,7 +191,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
@@ -259,7 +258,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FieldMask::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_getter, &descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[0]);
 }
@@ -267,7 +266,8 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldMask* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldMask >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FieldMask*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FieldMask >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FieldMask >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index dac4f5f..355373c 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
@@ -172,9 +163,6 @@
   protected:
   explicit FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
diff --git a/src/google/protobuf/generated_enum_reflection.h b/src/google/protobuf/generated_enum_reflection.h
index 5debc0a..b96a9c6 100644
--- a/src/google/protobuf/generated_enum_reflection.h
+++ b/src/google/protobuf/generated_enum_reflection.h
@@ -39,16 +39,18 @@
 #ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
 #define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
 
+
 #include <string>
 
-#include <google/protobuf/generated_enum_util.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/generated_enum_util.h>
 
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/generated_enum_util.h b/src/google/protobuf/generated_enum_util.h
index f1002e2..5d10ac0 100644
--- a/src/google/protobuf/generated_enum_util.h
+++ b/src/google/protobuf/generated_enum_util.h
@@ -31,11 +31,13 @@
 #ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 #define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 
+
 #include <type_traits>
 
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/message_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
diff --git a/src/google/protobuf/generated_message_bases.cc b/src/google/protobuf/generated_message_bases.cc
index 3acfa5f..b772d9f 100644
--- a/src/google/protobuf/generated_message_bases.cc
+++ b/src/google/protobuf/generated_message_bases.cc
@@ -30,9 +30,9 @@
 
 #include <google/protobuf/generated_message_bases.h>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -52,8 +52,7 @@
 }
 
 ZeroFieldsBase::~ZeroFieldsBase() {
-  if (GetArenaForAllocation() != nullptr) return;
-  _internal_metadata_.Delete<UnknownFieldSet>();
+  (void)_internal_metadata_.DeleteReturnArena<UnknownFieldSet>();
 }
 
 size_t ZeroFieldsBase::ByteSizeLong() const {
diff --git a/src/google/protobuf/generated_message_bases.h b/src/google/protobuf/generated_message_bases.h
index 29ab66b..ebd1984 100644
--- a/src/google/protobuf/generated_message_bases.h
+++ b/src/google/protobuf/generated_message_bases.h
@@ -35,11 +35,11 @@
 #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
 #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
 
 // Must come last:
 #include <google/protobuf/port_def.inc>
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index f6de1b5..7b14d45 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -39,19 +39,18 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
-#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/stubs/strutil.h>
 
 
 // clang-format off
@@ -76,6 +75,7 @@
 using google::protobuf::internal::StringSpaceUsedExcludingSelfLong;
 using google::protobuf::internal::WrappedMutex;
 
+
 namespace google {
 namespace protobuf {
 
@@ -258,7 +258,7 @@
 }
 
 bool Reflection::IsLazilyVerifiedLazyField(const FieldDescriptor* field) const {
-  return field->options().lazy();
+  return field->options().lazy() || field->options().unverified_lazy();
 }
 
 bool Reflection::IsEagerlyVerifiedLazyField(
@@ -279,6 +279,14 @@
 
   total_size += GetUnknownFields(message).SpaceUsedExcludingSelfLong();
 
+  // If this message owns an arena, add any unused space that's been allocated.
+  auto* arena = Arena::InternalHelper<Message>::GetArenaForAllocation(&message);
+  if (arena != nullptr &&
+      Arena::InternalHelper<Message>::GetOwningArena(&message) == nullptr &&
+      Arena::InternalHelper<Message>::IsMessageOwnedArena(arena)) {
+    total_size += arena->SpaceAllocated() - arena->SpaceUsed();
+  }
+
   if (schema_.HasExtensionSet()) {
     total_size += GetExtensionSet(message).SpaceUsedExcludingSelfLong();
   }
@@ -494,6 +502,10 @@
   static void SwapMessage(const Reflection* r, Message* lhs, Arena* lhs_arena,
                           Message* rhs, Arena* rhs_arena,
                           const FieldDescriptor* field);
+
+  static void SwapNonMessageNonStringField(const Reflection* r, Message* lhs,
+                                           Message* rhs,
+                                           const FieldDescriptor* field);
 };
 
 template <bool unsafe_shallow_swap>
@@ -524,21 +536,27 @@
   Arena* rhs_arena = rhs->GetArenaForAllocation();
   auto* lhs_string = r->MutableRaw<InlinedStringField>(lhs, field);
   auto* rhs_string = r->MutableRaw<InlinedStringField>(rhs, field);
-  const uint32 index = r->schema_.InlinedStringIndex(field);
-  uint32* lhs_state = &r->MutableInlinedStringDonatedArray(lhs)[index / 32];
-  uint32* rhs_state = &r->MutableInlinedStringDonatedArray(rhs)[index / 32];
-  const uint32 mask = ~(static_cast<uint32>(1) << (index % 32));
+  uint32_t index = r->schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  uint32_t* lhs_array = r->MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = r->MutableInlinedStringDonatedArray(rhs);
+  uint32_t* lhs_state = &lhs_array[index / 32];
+  uint32_t* rhs_state = &rhs_array[index / 32];
+  bool lhs_arena_dtor_registered = (lhs_array[0] & 0x1u) == 0;
+  bool rhs_arena_dtor_registered = (rhs_array[0] & 0x1u) == 0;
+  const uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
   if (unsafe_shallow_swap || lhs_arena == rhs_arena) {
-    lhs_string->Swap(rhs_string, /*default_value=*/nullptr, lhs_arena,
-                     r->IsInlinedStringDonated(*lhs, field),
-                     r->IsInlinedStringDonated(*rhs, field),
-                     /*donating_states=*/lhs_state, rhs_state, mask);
+    InlinedStringField::InternalSwap(lhs_string, lhs_arena,
+                                     lhs_arena_dtor_registered, lhs, rhs_string,
+                                     rhs_arena, rhs_arena_dtor_registered, rhs);
   } else {
     const std::string temp = lhs_string->Get();
     lhs_string->Set(nullptr, rhs_string->Get(), lhs_arena,
-                    r->IsInlinedStringDonated(*lhs, field), lhs_state, mask);
+                    r->IsInlinedStringDonated(*lhs, field), lhs_state, mask,
+                    lhs);
     rhs_string->Set(nullptr, temp, rhs_arena,
-                    r->IsInlinedStringDonated(*rhs, field), rhs_state, mask);
+                    r->IsInlinedStringDonated(*rhs, field), rhs_state, mask,
+                    rhs);
   }
 }
 
@@ -583,18 +601,18 @@
                                          Arena* rhs_arena) {
   if (lhs_arena == rhs_arena) {
     ArenaStringPtr::InternalSwap(default_ptr, lhs, lhs_arena, rhs, rhs_arena);
-  } else if (lhs->IsDefault(default_ptr) && rhs->IsDefault(default_ptr)) {
+  } else if (lhs->IsDefault() && rhs->IsDefault()) {
     // Nothing to do.
-  } else if (lhs->IsDefault(default_ptr)) {
+  } else if (lhs->IsDefault()) {
     lhs->Set(default_ptr, rhs->Get(), lhs_arena);
     // rhs needs to be destroyed before overwritten.
     rhs->Destroy(default_ptr, rhs_arena);
-    rhs->UnsafeSetDefault(default_ptr);
-  } else if (rhs->IsDefault(default_ptr)) {
+    rhs->InitDefault(default_ptr);
+  } else if (rhs->IsDefault()) {
     rhs->Set(default_ptr, lhs->Get(), rhs_arena);
     // lhs needs to be destroyed before overwritten.
     lhs->Destroy(default_ptr, lhs_arena);
-    lhs->UnsafeSetDefault(default_ptr);
+    lhs->InitDefault(default_ptr);
   } else {
     std::string temp = lhs->Get();
     lhs->Set(default_ptr, rhs->Get(), lhs_arena);
@@ -673,6 +691,30 @@
   }
 }
 
+void SwapFieldHelper::SwapNonMessageNonStringField(
+    const Reflection* r, Message* lhs, Message* rhs,
+    const FieldDescriptor* field) {
+  switch (field->cpp_type()) {
+#define SWAP_VALUES(CPPTYPE, TYPE)               \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:       \
+    std::swap(*r->MutableRaw<TYPE>(lhs, field),  \
+              *r->MutableRaw<TYPE>(rhs, field)); \
+    break;
+
+    SWAP_VALUES(INT32, int32_t);
+    SWAP_VALUES(INT64, int64_t);
+    SWAP_VALUES(UINT32, uint32_t);
+    SWAP_VALUES(UINT64, uint64_t);
+    SWAP_VALUES(FLOAT, float);
+    SWAP_VALUES(DOUBLE, double);
+    SWAP_VALUES(BOOL, bool);
+    SWAP_VALUES(ENUM, int);
+#undef SWAP_VALUES
+    default:
+      GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+  }
+}
+
 }  // namespace internal
 
 void Reflection::SwapField(Message* message1, Message* message2,
@@ -709,21 +751,6 @@
     }
   } else {
     switch (field->cpp_type()) {
-#define SWAP_VALUES(CPPTYPE, TYPE)                 \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE:         \
-    std::swap(*MutableRaw<TYPE>(message1, field),  \
-              *MutableRaw<TYPE>(message2, field)); \
-    break;
-
-      SWAP_VALUES(INT32, int32_t);
-      SWAP_VALUES(INT64, int64_t);
-      SWAP_VALUES(UINT32, uint32_t);
-      SWAP_VALUES(UINT64, uint64_t);
-      SWAP_VALUES(FLOAT, float);
-      SWAP_VALUES(DOUBLE, double);
-      SWAP_VALUES(BOOL, bool);
-      SWAP_VALUES(ENUM, int);
-#undef SWAP_VALUES
       case FieldDescriptor::CPPTYPE_MESSAGE:
         internal::SwapFieldHelper::SwapMessageField<false>(this, message1,
                                                            message2, field);
@@ -733,9 +760,9 @@
         internal::SwapFieldHelper::SwapStringField<false>(this, message1,
                                                           message2, field);
         break;
-
       default:
-        GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
+        internal::SwapFieldHelper::SwapNonMessageNonStringField(
+            this, message1, message2, field);
     }
   }
 }
@@ -750,7 +777,8 @@
       internal::SwapFieldHelper::SwapStringField<true>(this, message1, message2,
                                                        field);
     } else {
-      SwapField(message1, message2, field);
+      internal::SwapFieldHelper::SwapNonMessageNonStringField(this, message1,
+                                                              message2, field);
     }
     return;
   }
@@ -877,8 +905,8 @@
   };
 
   GOOGLE_DCHECK(!oneof_descriptor->is_synthetic());
-  uint32 oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor);
-  uint32 oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor);
+  uint32_t oneof_case_lhs = GetOneofCase(*lhs, oneof_descriptor);
+  uint32_t oneof_case_rhs = GetOneofCase(*rhs, oneof_descriptor);
 
   LocalVarWrapper temp;
   MessageWrapper lhs_wrapper, rhs_wrapper;
@@ -1030,6 +1058,13 @@
         // may depend on the information in has bits.
         if (!field->is_repeated()) {
           SwapBit(message1, message2, field);
+          if (field->options().ctype() == FieldOptions::STRING &&
+              IsInlined(field)) {
+            GOOGLE_DCHECK(!unsafe_shallow_swap ||
+                   message1->GetArenaForAllocation() ==
+                       message2->GetArenaForAllocation());
+            SwapInlinedStringDonated(message1, message2, field);
+          }
         }
       }
     }
@@ -1096,8 +1131,8 @@
   // Swapping bits need to happen after swapping fields, because the latter may
   // depend on the has bit information.
   if (schema_.HasHasbits()) {
-    uint32* lhs_has_bits = MutableHasBits(lhs);
-    uint32* rhs_has_bits = MutableHasBits(rhs);
+    uint32_t* lhs_has_bits = MutableHasBits(lhs);
+    uint32_t* rhs_has_bits = MutableHasBits(rhs);
 
     int fields_with_has_bits = 0;
     for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1115,6 +1150,32 @@
     }
   }
 
+  if (schema_.HasInlinedString()) {
+    uint32_t* lhs_donated_array = MutableInlinedStringDonatedArray(lhs);
+    uint32_t* rhs_donated_array = MutableInlinedStringDonatedArray(rhs);
+    int inlined_string_count = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = descriptor_->field(i);
+      if (field->is_extension() || field->is_repeated() ||
+          schema_.InRealOneof(field) ||
+          field->options().ctype() != FieldOptions::STRING ||
+          !IsInlined(field)) {
+        continue;
+      }
+      inlined_string_count++;
+    }
+
+    int donated_array_size = inlined_string_count == 0
+                                 ? 0
+                                 // One extra bit for the arena dtor tracking.
+                                 : (inlined_string_count + 1 + 31) / 32;
+    GOOGLE_CHECK_EQ((lhs_donated_array[0] & 0x1u) == 0,
+             (rhs_donated_array[0] & 0x1u) == 0);
+    for (int i = 0; i < donated_array_size; i++) {
+      std::swap(lhs_donated_array[i], rhs_donated_array[i]);
+    }
+  }
+
   if (schema_.HasExtensionSet()) {
     MutableExtensionSet(lhs)->InternalSwap(MutableExtensionSet(rhs));
   }
@@ -1654,12 +1715,14 @@
       case FieldOptions::STRING: {
         if (IsInlined(field)) {
           const uint32_t index = schema_.InlinedStringIndex(field);
+          GOOGLE_DCHECK_GT(index, 0);
           uint32_t* states =
               &MutableInlinedStringDonatedArray(message)[index / 32];
           uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
           MutableField<InlinedStringField>(message, field)
               ->Set(nullptr, value, message->GetArenaForAllocation(),
-                    IsInlinedStringDonated(*message, field), states, mask);
+                    IsInlinedStringDonated(*message, field), states, mask,
+                    message);
           break;
         }
 
@@ -1674,7 +1737,7 @@
         if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) {
           ClearOneof(message, field->containing_oneof());
           MutableField<ArenaStringPtr>(message, field)
-              ->UnsafeSetDefault(default_ptr);
+              ->InitDefault(default_ptr);
         }
         MutableField<ArenaStringPtr>(message, field)
             ->Set(default_ptr, std::move(value),
@@ -2458,7 +2521,7 @@
 }
 
 uint32_t* Reflection::MutableInlinedStringDonatedArray(Message* message) const {
-  GOOGLE_DCHECK(schema_.HasHasbits());
+  GOOGLE_DCHECK(schema_.HasInlinedString());
   return GetPointerAtOffset<uint32_t>(message,
                                       schema_.InlinedStringDonatedOffset());
 }
@@ -2466,8 +2529,48 @@
 // Simple accessors for manipulating _inlined_string_donated_;
 bool Reflection::IsInlinedStringDonated(const Message& message,
                                         const FieldDescriptor* field) const {
-  return IsIndexInHasBitSet(GetInlinedStringDonatedArray(message),
-                            schema_.InlinedStringIndex(field));
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  return IsIndexInHasBitSet(GetInlinedStringDonatedArray(message), index);
+}
+
+inline void SetInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] |= (static_cast<uint32_t>(1) << (index % 32));
+}
+
+inline void ClearInlinedStringDonated(uint32_t index, uint32_t* array) {
+  array[index / 32] &= ~(static_cast<uint32_t>(1) << (index % 32));
+}
+
+void Reflection::SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                          const FieldDescriptor* field) const {
+  Arena* lhs_arena = lhs->GetArenaForAllocation();
+  Arena* rhs_arena = rhs->GetArenaForAllocation();
+  // If arenas differ, inined string fields are swapped by copying values.
+  // Donation status should not be swapped.
+  if (lhs_arena != rhs_arena) {
+    return;
+  }
+  bool lhs_donated = IsInlinedStringDonated(*lhs, field);
+  bool rhs_donated = IsInlinedStringDonated(*rhs, field);
+  if (lhs_donated == rhs_donated) {
+    return;
+  }
+  // If one is undonated, both must have already registered ArenaDtor.
+  uint32_t* lhs_array = MutableInlinedStringDonatedArray(lhs);
+  uint32_t* rhs_array = MutableInlinedStringDonatedArray(rhs);
+  GOOGLE_CHECK_EQ(lhs_array[0] & 0x1u, 0u);
+  GOOGLE_CHECK_EQ(rhs_array[0] & 0x1u, 0u);
+  // Swap donation status bit.
+  uint32_t index = schema_.InlinedStringIndex(field);
+  GOOGLE_DCHECK_GT(index, 0);
+  if (rhs_donated) {
+    SetInlinedStringDonated(index, lhs_array);
+    ClearInlinedStringDonated(index, rhs_array);
+  } else {  // lhs_donated
+    ClearInlinedStringDonated(index, lhs_array);
+    SetInlinedStringDonated(index, rhs_array);
+  }
 }
 
 // Simple accessors for manipulating has_bits_.
@@ -2632,6 +2735,7 @@
         default:
           break;
       }
+    } else {
     }
 
     *MutableOneofCase(message, oneof_descriptor) = 0;
@@ -3027,10 +3131,8 @@
   const void* ptr = base + offset;
   const InternalMetadata* metadata = static_cast<const InternalMetadata*>(ptr);
   if (metadata->have_unknown_fields()) {
-    internal::WireFormat::SerializeUnknownFields(
-        metadata->unknown_fields<UnknownFieldSet>(
-            UnknownFieldSet::default_instance),
-        output);
+    metadata->unknown_fields<UnknownFieldSet>(UnknownFieldSet::default_instance)
+        .SerializeToCodedStream(output);
   }
 }
 
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 6a570ff..c353029 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -40,15 +40,17 @@
 
 #include <string>
 #include <vector>
+
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/unknown_field_set.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -137,8 +139,8 @@
   uint32_t GetFieldOffset(const FieldDescriptor* field) const {
     if (InRealOneof(field)) {
       size_t offset =
-          static_cast<size_t>(field->containing_type()->field_count() +
-                              field->containing_oneof()->index());
+          static_cast<size_t>(field->containing_type()->field_count()) +
+          field->containing_oneof()->index();
       return OffsetValue(offsets_[offset], field->type());
     } else {
       return GetFieldOffsetNonOneof(field);
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index 8607d09..4979616 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -75,6 +75,9 @@
   static bool IsLazyExtension(const Message& msg, const FieldDescriptor* ext) {
     return msg.GetReflection()->IsLazyExtension(msg, ext);
   }
+  static bool IsLazyField(const Message& msg, const FieldDescriptor* field) {
+    return msg.GetReflection()->IsLazyField(field);
+  }
 };
 
 namespace {
@@ -303,53 +306,58 @@
 }
 
 TEST_P(GeneratedMessageReflectionSwapTest, SwapFields) {
-  unittest::TestAllTypes lhs, rhs;
-  lhs.set_optional_double(12.3);
-  lhs.mutable_repeated_int32()->Add(10);
-  lhs.mutable_repeated_int32()->Add(20);
+  std::unique_ptr<unittest::TestAllTypes> lhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  std::unique_ptr<unittest::TestAllTypes> rhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  lhs->set_optional_double(12.3);
+  lhs->mutable_repeated_int32()->Add(10);
+  lhs->mutable_repeated_int32()->Add(20);
 
-  rhs.set_optional_string("hello");
-  rhs.mutable_repeated_int64()->Add(30);
+  rhs->set_optional_string("hello");
+  rhs->mutable_repeated_int64()->Add(30);
 
   std::vector<const FieldDescriptor*> fields;
-  const Descriptor* descriptor = lhs.GetDescriptor();
+  const Descriptor* descriptor = lhs->GetDescriptor();
   fields.push_back(descriptor->FindFieldByName("optional_double"));
   fields.push_back(descriptor->FindFieldByName("repeated_int32"));
   fields.push_back(descriptor->FindFieldByName("optional_string"));
   fields.push_back(descriptor->FindFieldByName("optional_uint64"));
 
-  SwapFields(lhs.GetReflection(), &lhs, &rhs, fields);
+  SwapFields(lhs->GetReflection(), lhs.get(), rhs.get(), fields);
 
-  EXPECT_FALSE(lhs.has_optional_double());
-  EXPECT_EQ(0, lhs.repeated_int32_size());
-  EXPECT_TRUE(lhs.has_optional_string());
-  EXPECT_EQ("hello", lhs.optional_string());
-  EXPECT_EQ(0, lhs.repeated_int64_size());
-  EXPECT_FALSE(lhs.has_optional_uint64());
+  EXPECT_FALSE(lhs->has_optional_double());
+  EXPECT_EQ(0, lhs->repeated_int32_size());
+  EXPECT_TRUE(lhs->has_optional_string());
+  EXPECT_EQ("hello", lhs->optional_string());
+  EXPECT_EQ(0, lhs->repeated_int64_size());
+  EXPECT_FALSE(lhs->has_optional_uint64());
 
-  EXPECT_TRUE(rhs.has_optional_double());
-  EXPECT_EQ(12.3, rhs.optional_double());
-  EXPECT_EQ(2, rhs.repeated_int32_size());
-  EXPECT_EQ(10, rhs.repeated_int32(0));
-  EXPECT_EQ(20, rhs.repeated_int32(1));
-  EXPECT_FALSE(rhs.has_optional_string());
-  EXPECT_EQ(1, rhs.repeated_int64_size());
-  EXPECT_FALSE(rhs.has_optional_uint64());
+  EXPECT_TRUE(rhs->has_optional_double());
+  EXPECT_EQ(12.3, rhs->optional_double());
+  EXPECT_EQ(2, rhs->repeated_int32_size());
+  EXPECT_EQ(10, rhs->repeated_int32(0));
+  EXPECT_EQ(20, rhs->repeated_int32(1));
+  EXPECT_FALSE(rhs->has_optional_string());
+  EXPECT_EQ(1, rhs->repeated_int64_size());
+  EXPECT_FALSE(rhs->has_optional_uint64());
 }
 
 TEST_P(GeneratedMessageReflectionSwapTest, SwapFieldsAll) {
-  unittest::TestAllTypes lhs;
-  unittest::TestAllTypes rhs;
+  std::unique_ptr<unittest::TestAllTypes> lhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
+  std::unique_ptr<unittest::TestAllTypes> rhs(
+      Arena::CreateMessage<unittest::TestAllTypes>(nullptr));
 
-  TestUtil::SetAllFields(&rhs);
+  TestUtil::SetAllFields(rhs.get());
 
   std::vector<const FieldDescriptor*> fields;
-  const Reflection* reflection = lhs.GetReflection();
-  reflection->ListFields(rhs, &fields);
-  SwapFields(reflection, &lhs, &rhs, fields);
+  const Reflection* reflection = lhs->GetReflection();
+  reflection->ListFields(*rhs, &fields);
+  SwapFields(reflection, lhs.get(), rhs.get(), fields);
 
-  TestUtil::ExpectAllFieldsSet(lhs);
-  TestUtil::ExpectClear(rhs);
+  TestUtil::ExpectAllFieldsSet(*lhs);
+  TestUtil::ExpectClear(*rhs);
 }
 
 TEST(GeneratedMessageReflectionTest, SwapFieldsAllOnDifferentArena) {
diff --git a/src/google/protobuf/generated_message_table_driven.cc b/src/google/protobuf/generated_message_table_driven.cc
deleted file mode 100644
index f963d90..0000000
--- a/src/google/protobuf/generated_message_table_driven.cc
+++ /dev/null
@@ -1,103 +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.
-
-#include <google/protobuf/generated_message_table_driven.h>
-
-#include <type_traits>
-
-#include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/generated_message_table_driven_lite.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/wire_format.h>
-#include <google/protobuf/wire_format_lite.h>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-namespace {
-
-UnknownFieldSet* MutableUnknownFields(MessageLite* msg, int64_t arena_offset) {
-  return Raw<InternalMetadata>(msg, arena_offset)
-      ->mutable_unknown_fields<UnknownFieldSet>();
-}
-
-struct UnknownFieldHandler {
-  // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
-  // and conflating InternalMetaData into it, simplifying the template.
-  static constexpr bool IsLite() { return false; }
-
-  static bool Skip(MessageLite* msg, const ParseTable& table,
-                   io::CodedInputStream* input, int tag) {
-    GOOGLE_DCHECK(table.unknown_field_set);
-
-    return WireFormat::SkipField(input, tag,
-                                 MutableUnknownFields(msg, table.arena_offset));
-  }
-
-  static void Varint(MessageLite* msg, const ParseTable& table, int tag,
-                     int value) {
-    GOOGLE_DCHECK(table.unknown_field_set);
-
-    MutableUnknownFields(msg, table.arena_offset)
-        ->AddVarint(WireFormatLite::GetTagFieldNumber(tag), value);
-  }
-
-  static bool ParseExtension(MessageLite* msg, const ParseTable& table,
-                             io::CodedInputStream* input, int tag) {
-    ExtensionSet* extensions = GetExtensionSet(msg, table.extension_offset);
-    if (extensions == nullptr) {
-      return false;
-    }
-
-    const Message* prototype =
-        down_cast<const Message*>(table.default_instance());
-
-    GOOGLE_DCHECK(prototype != nullptr);
-    GOOGLE_DCHECK(table.unknown_field_set);
-    UnknownFieldSet* unknown_fields =
-        MutableUnknownFields(msg, table.arena_offset);
-
-    return extensions->ParseField(tag, input, prototype, unknown_fields);
-  }
-};
-
-}  // namespace
-
-bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
-                                 io::CodedInputStream* input) {
-  return MergePartialFromCodedStreamImpl<UnknownFieldHandler>(msg, table,
-                                                              input);
-}
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/generated_message_table_driven.h b/src/google/protobuf/generated_message_table_driven.h
deleted file mode 100644
index f960818..0000000
--- a/src/google/protobuf/generated_message_table_driven.h
+++ /dev/null
@@ -1,349 +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_GENERATED_MESSAGE_TABLE_DRIVEN_H__
-#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
-
-#include <google/protobuf/map.h>
-#include <google/protobuf/map_entry_lite.h>
-#include <google/protobuf/map_field_lite.h>
-#include <google/protobuf/message_lite.h>
-#include <google/protobuf/wire_format_lite.h>
-
-// We require C++11 and Clang to use constexpr for variables, as GCC 4.8
-// requires constexpr to be consistent between declarations of variables
-// unnecessarily (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58541).
-// VS 2017 Update 3 also supports this usage of constexpr.
-#if defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1911)
-#define PROTOBUF_CONSTEXPR_VAR constexpr
-#else  // !__clang__
-#define PROTOBUF_CONSTEXPR_VAR
-#endif  // !_clang
-
-#ifdef SWIG
-#error "You cannot SWIG proto headers"
-#endif
-
-#include <google/protobuf/port_def.inc>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-// Processing-type masks.
-static constexpr const unsigned char kOneofMask = 0x40;
-static constexpr const unsigned char kRepeatedMask = 0x20;
-// Mask for the raw type: either a WireFormatLite::FieldType or one of the
-// ProcessingTypes below, without the oneof or repeated flag.
-static constexpr const unsigned char kTypeMask = 0x1f;
-
-// Wire type masks.
-static constexpr const unsigned char kNotPackedMask = 0x10;
-static constexpr const unsigned char kInvalidMask = 0x20;
-
-enum ProcessingTypes {
-  TYPE_STRING_CORD = 19,
-  TYPE_STRING_STRING_PIECE = 20,
-  TYPE_BYTES_CORD = 21,
-  TYPE_BYTES_STRING_PIECE = 22,
-  TYPE_STRING_INLINED = 23,
-  TYPE_BYTES_INLINED = 24,
-  TYPE_MAP = 25,
-};
-
-static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
-
-struct PROTOBUF_EXPORT FieldMetadata {
-  uint32_t offset;  // offset of this field in the struct
-  uint32_t tag;     // field * 8 + wire_type
-  // byte offset * 8 + bit_offset;
-  // if the high bit is set then this is the byte offset of the oneof_case
-  // for this field.
-  uint32_t has_offset;
-  uint32_t type;    // the type of this field.
-  const void* ptr;  // auxiliary data
-
-  // From the serializer point of view each fundamental type can occur in
-  // 4 different ways. For simplicity we treat all combinations as a cartesion
-  // product although not all combinations are allowed.
-  enum FieldTypeClass {
-    kPresence,
-    kNoPresence,
-    kRepeated,
-    kPacked,
-    kOneOf,
-    kNumTypeClasses  // must be last enum
-  };
-  // C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
-  // and also distinguish the same types if they have different wire format.
-  static constexpr auto kCordType = 19;
-  static constexpr auto kStringPieceType = 20;
-  static constexpr auto kInlinedType = 21;
-  static constexpr auto kNumTypes = 21;
-  static constexpr auto kSpecial = kNumTypes * kNumTypeClasses;
-
-  static int CalculateType(int fundamental_type, FieldTypeClass type_class);
-};
-
-// TODO(ckennelly):  Add a static assertion to ensure that these masks do not
-// conflict with wiretypes.
-
-// ParseTableField is kept small to help simplify instructions for computing
-// offsets, as we will always need this information to parse a field.
-// Additional data, needed for some types, is stored in
-// AuxiliaryParseTableField.
-struct ParseTableField {
-  uint32_t offset;
-  // The presence_index ordinarily represents a has_bit index, but for fields
-  // inside a oneof it represents the index in _oneof_case_.
-  uint32_t presence_index;
-  unsigned char normal_wiretype;
-  unsigned char packed_wiretype;
-
-  // processing_type is given by:
-  //   (FieldDescriptor->type() << 1) | FieldDescriptor->is_packed()
-  unsigned char processing_type;
-
-  unsigned char tag_size;
-};
-
-struct ParseTable;
-
-union AuxiliaryParseTableField {
-  typedef bool (*EnumValidator)(int);
-
-  // Enums
-  struct enum_aux {
-    EnumValidator validator;
-  };
-  enum_aux enums;
-  // Group, messages
-  struct message_aux {
-    // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
-    // the tables from being constructed as a constexpr.  We use void to avoid
-    // the cast.
-    const void* default_message_void;
-    const MessageLite* default_message() const {
-      return static_cast<const MessageLite*>(default_message_void);
-    }
-  };
-  message_aux messages;
-  // Strings
-  struct string_aux {
-    const void* default_ptr;
-    const char* field_name;
-  };
-  string_aux strings;
-
-  struct map_aux {
-    bool (*parse_map)(io::CodedInputStream*, void*);
-  };
-  map_aux maps;
-
-  AuxiliaryParseTableField() = default;
-  constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::enum_aux e)
-      : enums(e) {}
-  constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::message_aux m)
-      : messages(m) {}
-  constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::string_aux s)
-      : strings(s) {}
-  constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::map_aux m)
-      : maps(m) {}
-};
-
-struct ParseTable {
-  const ParseTableField* fields;
-  const AuxiliaryParseTableField* aux;
-  int max_field_number;
-  // TODO(ckennelly): Do something with this padding.
-
-  // TODO(ckennelly): Vet these for sign extension.
-  int64_t has_bits_offset;
-  int64_t oneof_case_offset;
-  int64_t extension_offset;
-  int64_t arena_offset;
-
-  // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
-  // the tables from being constructed as a constexpr.  We use void to avoid
-  // the cast.
-  const void* default_instance_void;
-  const MessageLite* default_instance() const {
-    return static_cast<const MessageLite*>(default_instance_void);
-  }
-
-  bool unknown_field_set;
-};
-
-static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
-// The tables must be composed of POD components to ensure link-time
-// initialization.
-static_assert(std::is_standard_layout<ParseTableField>::value, "");
-static_assert(std::is_trivial<ParseTableField>::value, "");
-static_assert(std::is_standard_layout<AuxiliaryParseTableField>::value, "");
-static_assert(std::is_trivial<AuxiliaryParseTableField>::value, "");
-static_assert(
-    std::is_standard_layout<AuxiliaryParseTableField::enum_aux>::value, "");
-static_assert(std::is_trivial<AuxiliaryParseTableField::enum_aux>::value, "");
-static_assert(
-    std::is_standard_layout<AuxiliaryParseTableField::message_aux>::value, "");
-static_assert(std::is_trivial<AuxiliaryParseTableField::message_aux>::value,
-              "");
-static_assert(
-    std::is_standard_layout<AuxiliaryParseTableField::string_aux>::value, "");
-static_assert(std::is_trivial<AuxiliaryParseTableField::string_aux>::value, "");
-static_assert(std::is_standard_layout<ParseTable>::value, "");
-static_assert(std::is_trivial<ParseTable>::value, "");
-
-// TODO(ckennelly): Consolidate these implementations into a single one, using
-// dynamic dispatch to the appropriate unknown field handler.
-bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
-                                 io::CodedInputStream* input);
-bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
-                                     io::CodedInputStream* input);
-
-template <typename Entry>
-bool ParseMap(io::CodedInputStream* input, void* map_field) {
-  typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
-  typedef Map<typename Entry::EntryKeyType, typename Entry::EntryValueType>
-      MapType;
-  typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
-
-  ParserType parser(static_cast<MapFieldType*>(map_field));
-  return WireFormatLite::ReadMessageNoVirtual(input, &parser);
-}
-
-struct SerializationTable {
-  int num_fields;
-  const FieldMetadata* field_table;
-};
-
-PROTOBUF_EXPORT void SerializeInternal(const uint8_t* base,
-                                       const FieldMetadata* table,
-                                       int32_t num_fields,
-                                       io::CodedOutputStream* output);
-
-inline void TableSerialize(const MessageLite& msg,
-                           const SerializationTable* table,
-                           io::CodedOutputStream* output) {
-  const FieldMetadata* field_table = table->field_table;
-  int num_fields = table->num_fields - 1;
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
-  // TODO(gerbens) This skips the first test if we could use the fast
-  // array serialization path, we should make this
-  // int cached_size =
-  //    *reinterpret_cast<const int32_t*>(base + field_table->offset);
-  // SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
-  // But we keep conformance with the old way for now.
-  SerializeInternal(base, field_table + 1, num_fields, output);
-}
-
-PROTOBUF_EXPORT uint8_t* SerializeInternalToArray(const uint8_t* base,
-                                                  const FieldMetadata* table,
-                                                  int32_t num_fields,
-                                                  bool is_deterministic,
-                                                  uint8_t* buffer);
-
-inline uint8_t* TableSerializeToArray(const MessageLite& msg,
-                                      const SerializationTable* table,
-                                      bool is_deterministic, uint8_t* buffer) {
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
-  const FieldMetadata* field_table = table->field_table + 1;
-  int num_fields = table->num_fields - 1;
-  return SerializeInternalToArray(base, field_table, num_fields,
-                                  is_deterministic, buffer);
-}
-
-template <typename T>
-struct CompareHelper {
-  bool operator()(const T& a, const T& b) const { return a < b; }
-};
-
-template <>
-struct CompareHelper<ArenaStringPtr> {
-  bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
-    return a.Get() < b.Get();
-  }
-};
-
-struct CompareMapKey {
-  template <typename T>
-  bool operator()(const MapEntryHelper<T>& a,
-                  const MapEntryHelper<T>& b) const {
-    return Compare(a.key_, b.key_);
-  }
-  template <typename T>
-  bool Compare(const T& a, const T& b) const {
-    return CompareHelper<T>()(a, b);
-  }
-};
-
-template <typename MapFieldType, const SerializationTable* table>
-void MapFieldSerializer(const uint8_t* base, uint32_t offset, uint32_t tag,
-                        uint32_t has_offset, io::CodedOutputStream* output) {
-  typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
-  typedef typename MapFieldType::MapType::const_iterator Iter;
-
-  const MapFieldType& map_field =
-      *reinterpret_cast<const MapFieldType*>(base + offset);
-  const SerializationTable* t =
-      table +
-      has_offset;  // has_offset is overloaded for maps to mean table offset
-  if (!output->IsSerializationDeterministic()) {
-    for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
-         ++it) {
-      Entry map_entry(*it);
-      output->WriteVarint32(tag);
-      output->WriteVarint32(map_entry._cached_size_);
-      SerializeInternal(reinterpret_cast<const uint8_t*>(&map_entry),
-                        t->field_table, t->num_fields, output);
-    }
-  } else {
-    std::vector<Entry> v;
-    for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
-         ++it) {
-      v.push_back(Entry(*it));
-    }
-    std::sort(v.begin(), v.end(), CompareMapKey());
-    for (int i = 0; i < v.size(); i++) {
-      output->WriteVarint32(tag);
-      output->WriteVarint32(v[i]._cached_size_);
-      SerializeInternal(reinterpret_cast<const uint8_t*>(&v[i]), t->field_table,
-                        t->num_fields, output);
-    }
-  }
-}
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
-
-#include <google/protobuf/port_undef.inc>
-
-#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
diff --git a/src/google/protobuf/generated_message_table_driven_lite.cc b/src/google/protobuf/generated_message_table_driven_lite.cc
deleted file mode 100644
index 596f356..0000000
--- a/src/google/protobuf/generated_message_table_driven_lite.cc
+++ /dev/null
@@ -1,106 +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.
-
-#include <google/protobuf/generated_message_table_driven_lite.h>
-
-#include <type_traits>
-
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/metadata_lite.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/wire_format_lite.h>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-namespace {
-
-std::string* MutableUnknownFields(MessageLite* msg, int64_t arena_offset) {
-  return Raw<InternalMetadata>(msg, arena_offset)
-      ->mutable_unknown_fields<std::string>();
-}
-
-struct UnknownFieldHandlerLite {
-  // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
-  // and conflating InternalMetaData into it, simplifying the template.
-  static constexpr bool IsLite() { return true; }
-
-  static bool Skip(MessageLite* msg, const ParseTable& table,
-                   io::CodedInputStream* input, int tag) {
-    GOOGLE_DCHECK(!table.unknown_field_set);
-    io::StringOutputStream unknown_fields_string(
-        MutableUnknownFields(msg, table.arena_offset));
-    io::CodedOutputStream unknown_fields_stream(&unknown_fields_string, false);
-
-    return internal::WireFormatLite::SkipField(input, tag,
-                                               &unknown_fields_stream);
-  }
-
-  static void Varint(MessageLite* msg, const ParseTable& table, int tag,
-                     int value) {
-    GOOGLE_DCHECK(!table.unknown_field_set);
-
-    io::StringOutputStream unknown_fields_string(
-        MutableUnknownFields(msg, table.arena_offset));
-    io::CodedOutputStream unknown_fields_stream(&unknown_fields_string, false);
-    unknown_fields_stream.WriteVarint32(tag);
-    unknown_fields_stream.WriteVarint32(value);
-  }
-
-  static bool ParseExtension(MessageLite* msg, const ParseTable& table,
-                             io::CodedInputStream* input, int tag) {
-    ExtensionSet* extensions = GetExtensionSet(msg, table.extension_offset);
-    if (extensions == nullptr) {
-      return false;
-    }
-
-    const MessageLite* prototype = table.default_instance();
-
-    GOOGLE_DCHECK(!table.unknown_field_set);
-    io::StringOutputStream unknown_fields_string(
-        MutableUnknownFields(msg, table.arena_offset));
-    io::CodedOutputStream unknown_fields_stream(&unknown_fields_string, false);
-    return extensions->ParseField(tag, input, prototype,
-                                  &unknown_fields_stream);
-  }
-};
-
-}  // namespace
-
-bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
-                                     io::CodedInputStream* input) {
-  return MergePartialFromCodedStreamImpl<UnknownFieldHandlerLite>(msg, table,
-                                                                  input);
-}
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/generated_message_table_driven_lite.h b/src/google/protobuf/generated_message_table_driven_lite.h
deleted file mode 100644
index a05afc0..0000000
--- a/src/google/protobuf/generated_message_table_driven_lite.h
+++ /dev/null
@@ -1,874 +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_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
-#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
-
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_table_driven.h>
-#include <google/protobuf/implicit_weak_message.h>
-#include <google/protobuf/inlined_string_field.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/wire_format_lite.h>
-#include <type_traits>
-
-
-#include <google/protobuf/port_def.inc>
-
-namespace google {
-namespace protobuf {
-namespace internal {
-
-
-enum StringType {
-  StringType_STRING = 0,
-  StringType_INLINED = 3
-};
-
-// Logically a superset of StringType, consisting of all field types that
-// require special initialization.
-enum ProcessingType {
-  ProcessingType_STRING = 0,
-  ProcessingType_CORD = 1,
-  ProcessingType_STRING_PIECE = 2,
-  ProcessingType_INLINED = 3,
-  ProcessingType_MESSAGE = 4,
-};
-
-enum Cardinality {
-  Cardinality_SINGULAR = 0,
-  Cardinality_REPEATED = 1,
-  Cardinality_ONEOF = 3
-};
-
-template <typename Type>
-inline Type* Raw(MessageLite* msg, int64_t offset) {
-  return reinterpret_cast<Type*>(reinterpret_cast<uint8_t*>(msg) + offset);
-}
-
-template <typename Type>
-inline const Type* Raw(const MessageLite* msg, int64_t offset) {
-  return reinterpret_cast<const Type*>(reinterpret_cast<const uint8_t*>(msg) +
-                                       offset);
-}
-
-inline ExtensionSet* GetExtensionSet(MessageLite* msg,
-                                     int64_t extension_offset) {
-  if (extension_offset == -1) {
-    return nullptr;
-  }
-
-  return Raw<ExtensionSet>(msg, extension_offset);
-}
-
-template <typename Type>
-inline Type* AddField(MessageLite* msg, int64_t offset) {
-  static_assert(std::is_trivial<Type>::value ||
-                    std::is_same<Type, InlinedStringField>::value,
-                "Do not assign");
-
-  RepeatedField<Type>* repeated = Raw<RepeatedField<Type>>(msg, offset);
-  return repeated->Add();
-}
-
-template <>
-inline std::string* AddField<std::string>(MessageLite* msg, int64_t offset) {
-  RepeatedPtrField<std::string>* repeated =
-      Raw<RepeatedPtrField<std::string>>(msg, offset);
-  return repeated->Add();
-}
-
-
-template <typename Type>
-inline void AddField(MessageLite* msg, int64_t offset, Type value) {
-  static_assert(std::is_trivial<Type>::value, "Do not assign");
-  *AddField<Type>(msg, offset) = value;
-}
-
-inline void SetBit(uint32_t* has_bits, uint32_t has_bit_index) {
-  GOOGLE_DCHECK(has_bits != nullptr);
-
-  uint32_t mask = static_cast<uint32_t>(1u) << (has_bit_index % 32);
-  has_bits[has_bit_index / 32u] |= mask;
-}
-
-template <typename Type>
-inline Type* MutableField(MessageLite* msg, uint32_t* has_bits,
-                          uint32_t has_bit_index, int64_t offset) {
-  SetBit(has_bits, has_bit_index);
-  return Raw<Type>(msg, offset);
-}
-
-template <typename Type>
-inline void SetField(MessageLite* msg, uint32_t* has_bits,
-                     uint32_t has_bit_index, int64_t offset, Type value) {
-  static_assert(std::is_trivial<Type>::value, "Do not assign");
-  *MutableField<Type>(msg, has_bits, has_bit_index, offset) = value;
-}
-
-template <typename Type>
-inline void SetOneofField(MessageLite* msg, uint32_t* oneof_case,
-                          uint32_t oneof_case_index, int64_t offset,
-                          int field_number, Type value) {
-  oneof_case[oneof_case_index] = field_number;
-  *Raw<Type>(msg, offset) = value;
-}
-
-// Clears a oneof field. The field argument should correspond to the particular
-// field that is currently set in the oneof.
-inline void ClearOneofField(const ParseTableField& field, Arena* arena,
-                            MessageLite* msg) {
-  switch (field.processing_type & kTypeMask) {
-    case WireFormatLite::TYPE_MESSAGE:
-      if (arena == nullptr) {
-        delete *Raw<MessageLite*>(msg, field.offset);
-      }
-      break;
-
-    case WireFormatLite::TYPE_STRING:
-    case WireFormatLite::TYPE_BYTES:
-      Raw<ArenaStringPtr>(msg, field.offset)
-          ->Destroy(ArenaStringPtr::EmptyDefault{}, arena);
-      break;
-
-    case TYPE_STRING_INLINED:
-    case TYPE_BYTES_INLINED:
-      Raw<InlinedStringField>(msg, field.offset)->DestroyNoArena(nullptr);
-      break;
-
-    default:
-      // No cleanup needed.
-      break;
-  }
-}
-
-// Clears and reinitializes a oneof field as necessary, in preparation for
-// parsing a new value with type field_type and field number field_number.
-//
-// Note: the oneof_case argument should point directly to the _oneof_case_
-// element corresponding to this particular oneof, not to the beginning of the
-// _oneof_case_ array.
-template <ProcessingType field_type>
-inline void ResetOneofField(const ParseTable& table, int field_number,
-                            Arena* arena, MessageLite* msg,
-                            uint32_t* oneof_case, int64_t offset,
-                            const void* default_ptr) {
-  if (static_cast<int64_t>(*oneof_case) == field_number) {
-    // The oneof is already set to the right type, so there is no need to clear
-    // it.
-    return;
-  }
-
-  if (*oneof_case != 0) {
-    ClearOneofField(table.fields[*oneof_case], arena, msg);
-  }
-  *oneof_case = field_number;
-
-  switch (field_type) {
-    case ProcessingType_STRING:
-      Raw<ArenaStringPtr>(msg, offset)
-          ->UnsafeSetDefault(static_cast<const std::string*>(default_ptr));
-      break;
-    case ProcessingType_INLINED:
-      new (Raw<InlinedStringField>(msg, offset))
-          InlinedStringField(*static_cast<const std::string*>(default_ptr));
-      break;
-    case ProcessingType_MESSAGE:
-      MessageLite** submessage = Raw<MessageLite*>(msg, offset);
-      const MessageLite* prototype =
-          table.aux[field_number].messages.default_message();
-      *submessage = prototype->New(arena);
-      break;
-  }
-}
-
-template <typename UnknownFieldHandler, Cardinality cardinality,
-          bool is_string_type, StringType ctype>
-static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
-                                Arena* arena, uint32_t* has_bits,
-                                uint32_t has_bit_index, int64_t offset,
-                                const void* default_ptr,
-                                const char* field_name) {
-  StringPiece utf8_string_data;
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  constexpr bool kValidateUtf8 = is_string_type;
-#else
-  constexpr bool kValidateUtf8 = false;
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-
-  switch (ctype) {
-    case StringType_INLINED: {
-      std::string* value = nullptr;
-      switch (cardinality) {
-        case Cardinality_SINGULAR: {
-          // TODO(ckennelly): Is this optimal?
-          InlinedStringField* s = MutableField<InlinedStringField>(
-              msg, has_bits, has_bit_index, offset);
-          value = s->UnsafeMutablePointer();
-        } break;
-        case Cardinality_REPEATED: {
-          value = AddField<std::string>(msg, offset);
-        } break;
-        case Cardinality_ONEOF: {
-          InlinedStringField* s = Raw<InlinedStringField>(msg, offset);
-          value = s->UnsafeMutablePointer();
-        } break;
-      }
-      GOOGLE_DCHECK(value != nullptr);
-      if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
-        return false;
-      }
-      utf8_string_data = *value;
-      break;
-    }
-    case StringType_STRING: {
-      switch (cardinality) {
-        case Cardinality_SINGULAR: {
-          ArenaStringPtr* field = MutableField<ArenaStringPtr>(
-              msg, has_bits, has_bit_index, offset);
-          std::string* value = field->MutableNoCopy(
-              static_cast<const std::string*>(default_ptr), arena);
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadString(input, value))) {
-            return false;
-          }
-          utf8_string_data = field->Get();
-        } break;
-        case Cardinality_REPEATED: {
-          std::string* value = AddField<std::string>(msg, offset);
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadString(input, value))) {
-            return false;
-          }
-          utf8_string_data = *value;
-        } break;
-        case Cardinality_ONEOF: {
-          ArenaStringPtr* field = Raw<ArenaStringPtr>(msg, offset);
-          std::string* value = field->MutableNoCopy(
-              static_cast<const std::string*>(default_ptr), arena);
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadString(input, value))) {
-            return false;
-          }
-          utf8_string_data = field->Get();
-        } break;
-        default:
-          PROTOBUF_ASSUME(false);
-      }
-      break;
-    }
-    default:
-      PROTOBUF_ASSUME(false);
-  }
-
-  if (kValidateUtf8) {
-    // TODO(b/118759213): fail if proto3
-    WireFormatLite::VerifyUtf8String(utf8_string_data.data(),
-                                     utf8_string_data.length(),
-                                     WireFormatLite::PARSE, field_name);
-  }
-  return true;
-}
-
-template <typename UnknownFieldHandler, Cardinality cardinality>
-inline bool HandleEnum(const ParseTable& table, io::CodedInputStream* input,
-                       MessageLite* msg, uint32_t* presence,
-                       uint32_t presence_index, int64_t offset, uint32_t tag,
-                       int field_number) {
-  int value;
-  if (PROTOBUF_PREDICT_FALSE(
-          (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
-              input, &value)))) {
-    return false;
-  }
-
-  AuxiliaryParseTableField::EnumValidator validator =
-      table.aux[field_number].enums.validator;
-  if (validator == nullptr || validator(value)) {
-    switch (cardinality) {
-      case Cardinality_SINGULAR:
-        SetField(msg, presence, presence_index, offset, value);
-        break;
-      case Cardinality_REPEATED:
-        AddField(msg, offset, value);
-        break;
-      case Cardinality_ONEOF:
-        ClearOneofField(table.fields[presence[presence_index]], msg->GetArena(),
-                        msg);
-        SetOneofField(msg, presence, presence_index, offset, field_number,
-                      value);
-        break;
-      default:
-        PROTOBUF_ASSUME(false);
-    }
-  } else {
-    UnknownFieldHandler::Varint(msg, table, tag, value);
-  }
-
-  return true;
-}
-
-// RepeatedMessageTypeHandler allows us to operate on RepeatedPtrField fields
-// without instantiating the specific template.
-class RepeatedMessageTypeHandler {
- public:
-  typedef MessageLite Type;
-  typedef MessageLite WeakType;
-  static Arena* GetArena(Type* t) { return t->GetArena(); }
-  static inline Type* NewFromPrototype(const Type* prototype,
-                                       Arena* arena = nullptr) {
-    return prototype->New(arena);
-  }
-  static void Delete(Type* t, Arena* arena = nullptr) {
-    if (arena == nullptr) {
-      delete t;
-    }
-  }
-};
-
-class MergePartialFromCodedStreamHelper {
- public:
-  static MessageLite* Add(RepeatedPtrFieldBase* field,
-                          const MessageLite* prototype) {
-    return field->Add<RepeatedMessageTypeHandler>(
-        const_cast<MessageLite*>(prototype));
-  }
-};
-
-template <typename UnknownFieldHandler, uint32_t kMaxTag>
-bool MergePartialFromCodedStreamInlined(MessageLite* msg,
-                                        const ParseTable& table,
-                                        io::CodedInputStream* input) {
-  // We require that has_bits are present, as to avoid having to check for them
-  // for every field.
-  //
-  // TODO(ckennelly):  Make this a compile-time parameter with templates.
-  GOOGLE_DCHECK_GE(table.has_bits_offset, 0);
-  uint32_t* has_bits = Raw<uint32_t>(msg, table.has_bits_offset);
-  GOOGLE_DCHECK(has_bits != nullptr);
-
-  while (true) {
-    uint32_t tag = input->ReadTagWithCutoffNoLastTag(kMaxTag).first;
-    const WireFormatLite::WireType wire_type =
-        WireFormatLite::GetTagWireType(tag);
-    const int field_number = WireFormatLite::GetTagFieldNumber(tag);
-
-    if (PROTOBUF_PREDICT_FALSE(field_number > table.max_field_number)) {
-      // check for possible extensions
-      if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
-        // successfully parsed
-        continue;
-      }
-
-      if (PROTOBUF_PREDICT_FALSE(
-              !UnknownFieldHandler::Skip(msg, table, input, tag))) {
-        return false;
-      }
-
-      continue;
-    }
-
-    // We implicitly verify that data points to a valid field as we check the
-    // wire types.  Entries in table.fields[i] that do not correspond to valid
-    // field numbers have their normal_wiretype and packed_wiretype fields set
-    // with the kInvalidMask value.  As wire_type cannot take on that value, we
-    // will never match.
-    const ParseTableField* data = table.fields + field_number;
-
-    // TODO(ckennelly): Avoid sign extension
-    const int64_t presence_index = data->presence_index;
-    const int64_t offset = data->offset;
-    const unsigned char processing_type = data->processing_type;
-
-    if (data->normal_wiretype == static_cast<unsigned char>(wire_type)) {
-      switch (processing_type) {
-#define HANDLE_TYPE(TYPE, CPPTYPE)                                             \
-  case (WireFormatLite::TYPE_##TYPE): {                                        \
-    CPPTYPE value;                                                             \
-    if (PROTOBUF_PREDICT_FALSE(                                                \
-            (!WireFormatLite::ReadPrimitive<                                   \
-                CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) {      \
-      return false;                                                            \
-    }                                                                          \
-    SetField(msg, has_bits, presence_index, offset, value);                    \
-    break;                                                                     \
-  }                                                                            \
-  case (WireFormatLite::TYPE_##TYPE) | kRepeatedMask: {                        \
-    RepeatedField<CPPTYPE>* values = Raw<RepeatedField<CPPTYPE>>(msg, offset); \
-    if (PROTOBUF_PREDICT_FALSE((!WireFormatLite::ReadRepeatedPrimitive<        \
-                                CPPTYPE, WireFormatLite::TYPE_##TYPE>(         \
-            data->tag_size, tag, input, values)))) {                           \
-      return false;                                                            \
-    }                                                                          \
-    break;                                                                     \
-  }                                                                            \
-  case (WireFormatLite::TYPE_##TYPE) | kOneofMask: {                           \
-    uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);        \
-    CPPTYPE value;                                                             \
-    if (PROTOBUF_PREDICT_FALSE(                                                \
-            (!WireFormatLite::ReadPrimitive<                                   \
-                CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) {      \
-      return false;                                                            \
-    }                                                                          \
-    ClearOneofField(table.fields[oneof_case[presence_index]], msg->GetArena(), \
-                    msg);                                                      \
-    SetOneofField(msg, oneof_case, presence_index, offset, field_number,       \
-                  value);                                                      \
-    break;                                                                     \
-  }
-
-        HANDLE_TYPE(INT32, int32_t)
-        HANDLE_TYPE(INT64, int64_t)
-        HANDLE_TYPE(SINT32, int32_t)
-        HANDLE_TYPE(SINT64, int64_t)
-        HANDLE_TYPE(UINT32, uint32_t)
-        HANDLE_TYPE(UINT64, uint64_t)
-
-        HANDLE_TYPE(FIXED32, uint32_t)
-        HANDLE_TYPE(FIXED64, uint64_t)
-        HANDLE_TYPE(SFIXED32, int32_t)
-        HANDLE_TYPE(SFIXED64, int64_t)
-
-        HANDLE_TYPE(FLOAT, float)
-        HANDLE_TYPE(DOUBLE, double)
-
-        HANDLE_TYPE(BOOL, bool)
-#undef HANDLE_TYPE
-        case WireFormatLite::TYPE_BYTES:
-#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case WireFormatLite::TYPE_STRING:
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
-                                 false, StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, nullptr)))) {
-            return false;
-          }
-          break;
-        }
-        case TYPE_BYTES_INLINED:
-#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case TYPE_STRING_INLINED:
-#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
-                                 false, StringType_INLINED>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, nullptr)))) {
-            return false;
-          }
-          break;
-        }
-        case WireFormatLite::TYPE_BYTES | kOneofMask:
-#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case WireFormatLite::TYPE_STRING | kOneofMask:
-#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        {
-          Arena* const arena = msg->GetArena();
-          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-
-          ResetOneofField<ProcessingType_STRING>(
-              table, field_number, arena, msg, oneof_case + presence_index,
-              offset, default_ptr);
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, false,
-                                 StringType_STRING>(input, msg, arena, has_bits,
-                                                    presence_index, offset,
-                                                    default_ptr, nullptr)))) {
-            return false;
-          }
-          break;
-        }
-        case (WireFormatLite::TYPE_BYTES) | kRepeatedMask:
-        case TYPE_BYTES_INLINED | kRepeatedMask:
-#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
-        case TYPE_STRING_INLINED | kRepeatedMask:
-#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
-                                 false, StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, nullptr)))) {
-            return false;
-          }
-          break;
-        }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case (WireFormatLite::TYPE_STRING): {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-          const char* field_name = table.aux[field_number].strings.field_name;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
-                                 true, StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, field_name)))) {
-            return false;
-          }
-          break;
-        }
-        case TYPE_STRING_INLINED | kRepeatedMask:
-        case (WireFormatLite::TYPE_STRING) | kRepeatedMask: {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-          const char* field_name = table.aux[field_number].strings.field_name;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
-                                 true, StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, field_name)))) {
-            return false;
-          }
-          break;
-        }
-        case (WireFormatLite::TYPE_STRING) | kOneofMask: {
-          Arena* const arena = msg->GetArena();
-          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-          const char* field_name = table.aux[field_number].strings.field_name;
-
-          ResetOneofField<ProcessingType_STRING>(
-              table, field_number, arena, msg, oneof_case + presence_index,
-              offset, default_ptr);
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, true,
-                                 StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, field_name)))) {
-            return false;
-          }
-          break;
-        }
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case WireFormatLite::TYPE_ENUM: {
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleEnum<UnknownFieldHandler, Cardinality_SINGULAR>(
-                      table, input, msg, has_bits, presence_index, offset, tag,
-                      field_number)))) {
-            return false;
-          }
-          break;
-        }
-        case WireFormatLite::TYPE_ENUM | kRepeatedMask: {
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleEnum<UnknownFieldHandler, Cardinality_REPEATED>(
-                      table, input, msg, has_bits, presence_index, offset, tag,
-                      field_number)))) {
-            return false;
-          }
-          break;
-        }
-        case WireFormatLite::TYPE_ENUM | kOneofMask: {
-          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleEnum<UnknownFieldHandler, Cardinality_ONEOF>(
-                      table, input, msg, oneof_case, presence_index, offset,
-                      tag, field_number)))) {
-            return false;
-          }
-          break;
-        }
-        case WireFormatLite::TYPE_GROUP: {
-          MessageLite** submsg_holder =
-              MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
-          MessageLite* submsg = *submsg_holder;
-
-          if (submsg == nullptr) {
-            Arena* const arena = msg->GetArena();
-            const MessageLite* prototype =
-                table.aux[field_number].messages.default_message();
-            submsg = prototype->New(arena);
-            *submsg_holder = submsg;
-          }
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadGroup(field_number, input, submsg))) {
-            return false;
-          }
-
-          break;
-        }
-        case WireFormatLite::TYPE_GROUP | kRepeatedMask: {
-          RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
-          const MessageLite* prototype =
-              table.aux[field_number].messages.default_message();
-          GOOGLE_DCHECK(prototype != nullptr);
-
-          MessageLite* submsg =
-              MergePartialFromCodedStreamHelper::Add(field, prototype);
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadGroup(field_number, input, submsg))) {
-            return false;
-          }
-
-          break;
-        }
-        case WireFormatLite::TYPE_MESSAGE: {
-          MessageLite** submsg_holder =
-              MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
-          MessageLite* submsg = *submsg_holder;
-
-          if (submsg == nullptr) {
-            Arena* const arena = msg->GetArena();
-            const MessageLite* prototype =
-                table.aux[field_number].messages.default_message();
-            if (prototype == nullptr) {
-              prototype = ImplicitWeakMessage::default_instance();
-            }
-            submsg = prototype->New(arena);
-            *submsg_holder = submsg;
-          }
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadMessage(input, submsg))) {
-            return false;
-          }
-
-          break;
-        }
-        // TODO(ckennelly):  Adapt ReadMessageNoVirtualNoRecursionDepth and
-        // manage input->IncrementRecursionDepth() here.
-        case WireFormatLite::TYPE_MESSAGE | kRepeatedMask: {
-          RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
-          const MessageLite* prototype =
-              table.aux[field_number].messages.default_message();
-          if (prototype == nullptr) {
-            prototype = ImplicitWeakMessage::default_instance();
-          }
-
-          MessageLite* submsg =
-              MergePartialFromCodedStreamHelper::Add(field, prototype);
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadMessage(input, submsg))) {
-            return false;
-          }
-
-          break;
-        }
-        case WireFormatLite::TYPE_MESSAGE | kOneofMask: {
-          Arena* const arena = msg->GetArena();
-          uint32_t* oneof_case = Raw<uint32_t>(msg, table.oneof_case_offset);
-          MessageLite** submsg_holder = Raw<MessageLite*>(msg, offset);
-          ResetOneofField<ProcessingType_MESSAGE>(
-              table, field_number, arena, msg, oneof_case + presence_index,
-              offset, nullptr);
-          MessageLite* submsg = *submsg_holder;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  !WireFormatLite::ReadMessage(input, submsg))) {
-            return false;
-          }
-
-          break;
-        }
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case TYPE_STRING_INLINED: {
-          Arena* const arena = msg->GetArena();
-          const void* default_ptr = table.aux[field_number].strings.default_ptr;
-          const char* field_name = table.aux[field_number].strings.field_name;
-
-          if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
-                                 true, StringType_INLINED>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, field_name)))) {
-            return false;
-          }
-          break;
-        }
-#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-        case TYPE_MAP: {
-          if (PROTOBUF_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)(
-                  input, Raw<void>(msg, offset)))) {
-            return false;
-          }
-          break;
-        }
-        case 0: {
-          // Done.
-          input->SetLastTag(tag);
-          return true;
-        }
-        default:
-          PROTOBUF_ASSUME(false);
-      }
-    } else if (data->packed_wiretype == static_cast<unsigned char>(wire_type)) {
-      // Non-packable fields have their packed_wiretype masked with
-      // kNotPackedMask, which is impossible to match here.
-      GOOGLE_DCHECK(processing_type & kRepeatedMask);
-      GOOGLE_DCHECK_NE(processing_type, kRepeatedMask);
-      GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask);
-
-      GOOGLE_DCHECK_NE(TYPE_BYTES_INLINED | kRepeatedMask, processing_type);
-      GOOGLE_DCHECK_NE(TYPE_STRING_INLINED | kRepeatedMask, processing_type);
-
-      // Mask out kRepeatedMask bit, allowing the jump table to be smaller.
-      switch (static_cast<WireFormatLite::FieldType>(processing_type ^
-                                                     kRepeatedMask)) {
-#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD)                      \
-  case WireFormatLite::TYPE_##TYPE: {                                          \
-    RepeatedField<CPPTYPE>* values = Raw<RepeatedField<CPPTYPE>>(msg, offset); \
-    if (PROTOBUF_PREDICT_FALSE(                                                \
-            (!WireFormatLite::ReadPackedPrimitive<                             \
-                CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, values)))) {      \
-      return false;                                                            \
-    }                                                                          \
-    break;                                                                     \
-  }
-
-        HANDLE_PACKED_TYPE(INT32, int32_t, Int32)
-        HANDLE_PACKED_TYPE(INT64, int64_t, Int64)
-        HANDLE_PACKED_TYPE(SINT32, int32_t, Int32)
-        HANDLE_PACKED_TYPE(SINT64, int64_t, Int64)
-        HANDLE_PACKED_TYPE(UINT32, uint32_t, UInt32)
-        HANDLE_PACKED_TYPE(UINT64, uint64_t, UInt64)
-
-        HANDLE_PACKED_TYPE(FIXED32, uint32_t, UInt32)
-        HANDLE_PACKED_TYPE(FIXED64, uint64_t, UInt64)
-        HANDLE_PACKED_TYPE(SFIXED32, int32_t, Int32)
-        HANDLE_PACKED_TYPE(SFIXED64, int64_t, Int64)
-
-        HANDLE_PACKED_TYPE(FLOAT, float, Float)
-        HANDLE_PACKED_TYPE(DOUBLE, double, Double)
-
-        HANDLE_PACKED_TYPE(BOOL, bool, Bool)
-#undef HANDLE_PACKED_TYPE
-        case WireFormatLite::TYPE_ENUM: {
-          // To avoid unnecessarily calling MutableUnknownFields (which mutates
-          // InternalMetadata) when all inputs in the repeated series
-          // are valid, we implement our own parser rather than call
-          // WireFormat::ReadPackedEnumPreserveUnknowns.
-          uint32_t length;
-          if (PROTOBUF_PREDICT_FALSE(!input->ReadVarint32(&length))) {
-            return false;
-          }
-
-          AuxiliaryParseTableField::EnumValidator validator =
-              table.aux[field_number].enums.validator;
-          RepeatedField<int>* values = Raw<RepeatedField<int>>(msg, offset);
-
-          io::CodedInputStream::Limit limit = input->PushLimit(length);
-          while (input->BytesUntilLimit() > 0) {
-            int value;
-            if (PROTOBUF_PREDICT_FALSE(
-                    (!WireFormatLite::ReadPrimitive<
-                        int, WireFormatLite::TYPE_ENUM>(input, &value)))) {
-              return false;
-            }
-
-            if (validator == nullptr || validator(value)) {
-              values->Add(value);
-            } else {
-              // TODO(ckennelly): Consider caching here.
-              UnknownFieldHandler::Varint(msg, table, tag, value);
-            }
-          }
-          input->PopLimit(limit);
-
-          break;
-        }
-        case WireFormatLite::TYPE_STRING:
-        case WireFormatLite::TYPE_GROUP:
-        case WireFormatLite::TYPE_MESSAGE:
-        case WireFormatLite::TYPE_BYTES:
-          GOOGLE_DCHECK(false);
-          return false;
-        default:
-          PROTOBUF_ASSUME(false);
-      }
-    } else {
-      if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
-        // Must be the end of the message.
-        input->SetLastTag(tag);
-        return true;
-      }
-
-      // check for possible extensions
-      if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
-        // successfully parsed
-        continue;
-      }
-
-      // process unknown field.
-      if (PROTOBUF_PREDICT_FALSE(
-              !UnknownFieldHandler::Skip(msg, table, input, tag))) {
-        return false;
-      }
-    }
-  }
-}  // NOLINT(readability/fn_size)
-
-template <typename UnknownFieldHandler>
-bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
-                                     io::CodedInputStream* input) {
-  // The main beneficial cutoff values are 1 and 2 byte tags.
-  // Instantiate calls with the appropriate upper tag range
-  if (table.max_field_number <= (0x7F >> 3)) {
-    return MergePartialFromCodedStreamInlined<UnknownFieldHandler, 0x7F>(
-        msg, table, input);
-  } else if (table.max_field_number <= (0x3FFF >> 3)) {
-    return MergePartialFromCodedStreamInlined<UnknownFieldHandler, 0x3FFF>(
-        msg, table, input);
-  } else {
-    return MergePartialFromCodedStreamInlined<
-        UnknownFieldHandler, std::numeric_limits<uint32_t>::max()>(msg, table,
-                                                                   input);
-  }
-}
-
-}  // namespace internal
-}  // namespace protobuf
-}  // namespace google
-
-#include <google/protobuf/port_undef.inc>
-
-#endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
index 4e5c1ea..d1e15f6 100644
--- a/src/google/protobuf/generated_message_tctable_decl.h
+++ b/src/google/protobuf/generated_message_tctable_decl.h
@@ -35,11 +35,13 @@
 #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
 #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
 
+#include <array>
+#include <cstddef>
 #include <cstdint>
 #include <type_traits>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 
 // Must come last:
 #include <google/protobuf/port_def.inc>
@@ -51,17 +53,53 @@
 // Additional information about this field:
 struct TcFieldData {
   constexpr TcFieldData() : data(0) {}
-  constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint16_t offset)
-      : data(static_cast<uint64_t>(offset) << 48 |
-             static_cast<uint64_t>(hasbit_idx) << 16 | coded_tag) {}
+
+  // Fast table entry constructor:
+  constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
+                        uint16_t offset)
+      : data(uint64_t{offset} << 48 |      //
+             uint64_t{aux_idx} << 24 |     //
+             uint64_t{hasbit_idx} << 16 |  //
+             uint64_t{coded_tag}) {}
+
+  // Fields used in fast table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   :   . 16|=======| [16] coded_tag()
+  //     :   .   :   .   : 24|===|   .   : [ 8] hasbit_idx()
+  //     :   .   :   . 32|===|   :   .   : [ 8] aux_idx()
+  //     :   . 48:---.---:   .   :   .   : [16] (unused)
+  //     |=======|   .   :   .   :   .   : [16] offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
 
   template <typename TagType = uint16_t>
   TagType coded_tag() const {
     return static_cast<TagType>(data);
   }
   uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
+  uint8_t aux_idx() const { return static_cast<uint8_t>(data >> 24); }
   uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
 
+  // Fields used in mini table parsing:
+  //
+  //     Bit:
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+  //     :   .   :   .   |===============| [32] tag() (decoded)
+  //     |===============|   .   :   .   : [32] entry_offset()
+  //     +-----------+-------------------+
+  //     |63    ..     32|31     ..     0|
+  //     +---------------+---------------+
+
+  uint32_t tag() const { return static_cast<uint32_t>(data); }
+  uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
+
   uint64_t data;
 };
 
@@ -70,6 +108,12 @@
 // TailCallParseFunc is the function pointer type used in the tailcall table.
 typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
 
+namespace field_layout {
+struct Offset {
+  uint32_t off;
+};
+}  // namespace field_layout
+
 #if defined(_MSC_VER) && !defined(_WIN64)
 #pragma warning(push)
 // TcParseTableBase is intentionally overaligned on 32 bit targets.
@@ -83,14 +127,46 @@
   uint16_t extension_offset;
   uint32_t extension_range_low;
   uint32_t extension_range_high;
+  uint32_t max_field_number;
   uint8_t fast_idx_mask;
-  uint8_t reserved;
-  uint16_t num_fields;
+  uint8_t num_sequential_fields;
+  uint16_t sequential_fields_start;
+  uint16_t num_field_entries;
+
+  uint16_t num_aux_entries;
+  uint32_t aux_offset;
+
   const MessageLite* default_instance;
 
   // Handler for fields which are not handled by table dispatch.
   TailCallParseFunc fallback;
 
+  // This constructor exactly follows the field layout, so it's technically
+  // not necessary.  However, it makes it much much easier to add or re-arrange
+  // fields, because it can be overloaded with an additional constructor,
+  // temporarily allowing both old and new protocol buffer headers to be
+  // compiled.
+  constexpr TcParseTableBase(
+      uint16_t has_bits_offset, uint16_t extension_offset,
+      uint32_t extension_range_low, uint32_t extension_range_high,
+      uint32_t max_field_number, uint8_t fast_idx_mask,
+      uint8_t num_sequential_fields, uint16_t sequential_fields_start,
+      uint16_t num_field_entries, uint16_t num_aux_entries, uint32_t aux_offset,
+      const MessageLite* default_instance, TailCallParseFunc fallback)
+      : has_bits_offset(has_bits_offset),
+        extension_offset(extension_offset),
+        extension_range_low(extension_range_low),
+        extension_range_high(extension_range_high),
+        max_field_number(max_field_number),
+        fast_idx_mask(fast_idx_mask),
+        num_sequential_fields(num_sequential_fields),
+        sequential_fields_start(sequential_fields_start),
+        num_field_entries(num_field_entries),
+        num_aux_entries(num_aux_entries),
+        aux_offset(aux_offset),
+        default_instance(default_instance),
+        fallback(fallback) {}
+
   // Table entry for fast-path tailcall dispatch handling.
   struct FastFieldEntry {
     // Target function for dispatch:
@@ -102,6 +178,64 @@
   const FastFieldEntry* fast_entry(size_t idx) const {
     return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
   }
+
+  // Returns a begin/end iterator (pointer) for the field numbers array.
+  // The field numbers are a parallel array to the `FieldEntry` array. Note that
+  // not all numbers may be valid fields; in these cases, the corresponding
+  // field entry will have a field kind of `field_layout::kFkNone`.
+  const uint32_t* field_numbers_begin() const {
+    return reinterpret_cast<const uint32_t*>(
+        fast_entry((fast_idx_mask >> 3) + 1));
+  }
+  const uint32_t* field_numbers_end() const {
+    return field_numbers_begin() + num_field_entries;
+  }
+
+  // Field entry for all fields.
+  struct FieldEntry {
+    uint32_t offset;     // offset in the message object
+    int32_t has_idx;     // has-bit index
+    uint16_t aux_idx;    // index for `field_aux`.
+    uint16_t type_card;  // `FieldType` and `Cardinality` (see _impl.h)
+  };
+
+  // Returns a begin iterator (pointer) to the start of the field entries array.
+  const FieldEntry* field_entries_begin() const {
+    return reinterpret_cast<const FieldEntry*>(field_numbers_end());
+  }
+
+  // Auxiliary entries for field types that need extra information.
+  union FieldAux {
+    constexpr FieldAux() : message_default(nullptr) {}
+    constexpr FieldAux(bool (*enum_validator)(int))
+        : enum_validator(enum_validator) {}
+    constexpr FieldAux(field_layout::Offset off) : offset(off.off) {}
+    constexpr FieldAux(int16_t range_start, uint16_t range_length)
+        : enum_range{range_start, range_length} {}
+    constexpr FieldAux(const MessageLite* msg) : message_default(msg) {}
+    bool (*enum_validator)(int);
+    struct {
+      int16_t start;    // minimum enum number (if it fits)
+      uint16_t length;  // length of range (i.e., max = start + length - 1)
+    } enum_range;
+    uint32_t offset;
+    const MessageLite* message_default;
+  };
+  const FieldAux* field_aux(uint32_t idx) const {
+    return reinterpret_cast<const FieldAux*>(reinterpret_cast<uintptr_t>(this) +
+                                             aux_offset) +
+           idx;
+  }
+  const FieldAux* field_aux(const FieldEntry* entry) const {
+    return field_aux(entry->aux_idx);
+  }
+
+  // Field name data
+  const char* name_data() const {
+    return reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(this) +
+                                         aux_offset +
+                                         num_aux_entries * sizeof(FieldAux));
+  }
 };
 
 #if defined(_MSC_VER) && !defined(_WIN64)
@@ -109,9 +243,12 @@
 #endif
 
 static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
+              "Fast field entry is too big.");
+static_assert(sizeof(TcParseTableBase::FieldEntry) <= 16,
               "Field entry is too big.");
 
-template <size_t kFastTableSizeLog2>
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries = 0,
+          size_t kNumFieldAux = 0, size_t kNameTableSize = 0>
 struct TcParseTable {
   TcParseTableBase header;
 
@@ -119,15 +256,49 @@
   //
   // Fields are indexed by the lowest bits of their field number. The field
   // number is masked to fit inside the table. Note that the parsing logic
-  // generally calls `TailCallParseTableBase::table()` instead of accessing
+  // generally calls `TailCallParseTableBase::fast_entry()` instead of accessing
   // this field directly.
-  TcParseTableBase::FastFieldEntry entries[(1 << kFastTableSizeLog2)];
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+
+  // Entries for all fields:
+  std::array<uint32_t, kNumFieldEntries> field_numbers;
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<TcParseTableBase::FieldAux, kNumFieldAux> aux_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no aux entries, there will be no array.
+// In C++, arrays cannot have length 0, but (C++11) std::array<T, 0> is valid.
+// However, different implementations have different sizeof(std::array<T, 0>).
+// Skipping the member makes offset computations portable.
+template <size_t kFastTableSizeLog2, size_t kNumFieldEntries,
+          size_t kNameTableSize>
+struct TcParseTable<kFastTableSizeLog2, kNumFieldEntries, 0, kNameTableSize> {
+  TcParseTableBase header;
+  std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
+      fast_entries;
+  std::array<uint32_t, kNumFieldEntries> field_numbers;
+  std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
+  std::array<char, kNameTableSize> field_names;
+};
+
+// Partial specialization: if there are no fields at all, then we can save space
+// by skipping the field numbers and entries.
+template <size_t kNameTableSize>
+struct TcParseTable<0, 0, 0, kNameTableSize> {
+  TcParseTableBase header;
+  // N.B.: the fast entries are sized by log2, so 2**0 fields = 1 entry.
+  // The fast parsing loop will always use this entry, so it must be present.
+  std::array<TcParseTableBase::FastFieldEntry, 1> fast_entries;
+  std::array<char, kNameTableSize> field_names;
 };
 
 static_assert(std::is_standard_layout<TcParseTable<1>>::value,
               "TcParseTable must be standard layout.");
 
-static_assert(offsetof(TcParseTable<1>, entries) == sizeof(TcParseTableBase),
+static_assert(offsetof(TcParseTable<1>, fast_entries) ==
+                  sizeof(TcParseTableBase),
               "Table entries must be laid out after TcParseTableBase.");
 
 }  // namespace internal
diff --git a/src/google/protobuf/generated_message_tctable_full.cc b/src/google/protobuf/generated_message_tctable_full.cc
index 44dcddc..b77bb8d 100644
--- a/src/google/protobuf/generated_message_tctable_full.cc
+++ b/src/google/protobuf/generated_message_tctable_full.cc
@@ -30,10 +30,10 @@
 
 #include <cstdint>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_tctable_impl.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/unknown_field_set.h>
 
 // clang-format off
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index 3f2b1ca..1b67d83 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -34,12 +34,12 @@
 #include <cstdint>
 #include <type_traits>
 
-#include <google/protobuf/parse_context.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_tctable_decl.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/metadata_lite.h>
-#include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
 // Must come last:
@@ -53,6 +53,189 @@
 
 namespace internal {
 
+// Field layout enums.
+//
+// Structural information about fields is packed into a 16-bit value. The enum
+// types below represent bitwise fields, along with their respective widths,
+// shifts, and masks.
+//
+//     Bit:
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//     :  .  :  .  :  .  :  .  :  .  :  .  : 3|========| [3] FieldType
+//     :     :     :     :     :     : 5|=====|  :     : [2] FieldCardinality
+//     :  .  :  .  :  .  :  . 8|========|  :  .  :  .  : [3] FieldRep
+//     :     :     :   10|=====|     :     :     :     : [2] TransformValidation
+//     :  .  :  .12|=====|  .  :  .  :  .  :  .  :  .  : [2] FormatDiscriminator
+//     +-----------------------+-----------------------+
+//     |15        ..          8|7         ..          0|
+//     +-----------------------+-----------------------+
+//
+namespace field_layout {
+// clang-format off
+
+// Field kind (3 bits):
+// These values broadly represent a wire type and an in-memory storage class.
+enum FieldKind : uint16_t {
+  kFkShift = 0,
+  kFkBits = 3,
+  kFkMask = ((1 << kFkBits) - 1) << kFkShift,
+
+  kFkNone = 0,
+  kFkVarint,        // WT=0     rep=8,32,64 bits
+  kFkPackedVarint,  // WT=2     rep=8,32,64 bits
+  kFkFixed,         // WT=1,5   rep=32,64 bits
+  kFkPackedFixed,   // WT=2     rep=32,64 bits
+  kFkString,        // WT=2     rep=various
+  kFkMessage,       // WT=2,3,4 rep=MessageLite*
+  // Maps are a special case of Message, but use different parsing logic.
+  kFkMap,           // WT=2     rep=Map(Lite)<various, various>
+};
+
+static_assert(kFkMap < (1 << kFkBits), "too many types");
+
+// Cardinality (2 bits):
+// These values determine how many values a field can have and its presence.
+// Packed fields are represented in FieldType.
+enum Cardinality : uint16_t {
+  kFcShift    = kFkShift + kFkBits,
+  kFcBits     = 2,
+  kFcMask     = ((1 << kFcBits) - 1) << kFcShift,
+
+  kFcSingular = 0,
+  kFcOptional = 1 << kFcShift,
+  kFcRepeated = 2 << kFcShift,
+  kFcOneof    = 3 << kFcShift,
+};
+
+// Field representation (3 bits):
+// These values are the specific refinements of storage classes in FieldType.
+enum FieldRep : uint16_t {
+  kRepShift    = kFcShift + kFcBits,
+  kRepBits     = 3,
+  kRepMask     = ((1 << kRepBits) - 1) << kRepShift,
+
+  // Numeric types (used for optional and repeated fields):
+  kRep8Bits    = 0,
+  kRep32Bits   = 2 << kRepShift,
+  kRep64Bits   = 3 << kRepShift,
+  // String types:
+  kRepAString  = 0,               // ArenaStringPtr
+  kRepIString  = 1 << kRepShift,  // InlinedString
+  kRepCord     = 2 << kRepShift,  // absl::Cord
+  kRepSPiece   = 3 << kRepShift,  // StringPieceField
+  kRepSString  = 4 << kRepShift,  // std::string*
+  // Message types (WT=2 unless otherwise noted):
+  kRepMessage  = 0,               // MessageLite*
+  kRepGroup    = 1 << kRepShift,  // MessageLite* (WT=3,4)
+  kRepLazy     = 2 << kRepShift,  // LazyField*
+  kRepIWeak    = 3 << kRepShift,  // ImplicitWeak
+};
+
+// Transform/validation (2 bits):
+// These values determine transforms or validation to/from wire format.
+enum TransformValidation : uint16_t {
+  kTvShift     = kRepShift + kRepBits,
+  kTvBits      = 2,
+  kTvMask      = ((1 << kTvBits) - 1) << kTvShift,
+
+  // Varint fields:
+  kTvZigZag    = 1 << kTvShift,
+  kTvEnum      = 2 << kTvShift,  // validate using generated _IsValid()
+  kTvRange     = 3 << kTvShift,  // validate using FieldAux::enum_range
+  // String fields:
+  kTvUtf8Debug = 1 << kTvShift,  // proto2
+  kTvUtf8      = 2 << kTvShift,  // proto3
+};
+
+static_assert((kTvEnum & kTvRange) != 0,
+              "enum validation types must share a bit");
+static_assert((kTvEnum & kTvRange & kTvZigZag) == 0,
+              "zigzag encoding is not enum validation");
+
+// Format discriminators (2 bits):
+enum FormatDiscriminator : uint16_t {
+  kFmtShift      = kTvShift + kTvBits,
+  kFmtBits       = 2,
+  kFmtMask       = ((1 << kFmtBits) - 1) << kFmtShift,
+
+  // Numeric:
+  kFmtUnsigned   = 1 << kFmtShift,  // fixed, varint
+  kFmtSigned     = 2 << kFmtShift,  // fixed, varint
+  kFmtFloating   = 3 << kFmtShift,  // fixed
+  kFmtEnum       = 3 << kFmtShift,  // varint
+  // Strings:
+  kFmtUtf8       = 1 << kFmtShift,  // string (proto3, enforce_utf8=true)
+  kFmtUtf8Escape = 2 << kFmtShift,  // string (proto2, enforce_utf8=false)
+  // Bytes:
+  kFmtArray      = 1 << kFmtShift,  // bytes
+  // Messages:
+  kFmtShow       = 1 << kFmtShift,  // message, map
+};
+
+// Update this assertion (and comments above) when adding or removing bits:
+static_assert(kFmtShift + kFmtBits == 12, "number of bits changed");
+
+// This assertion should not change unless the storage width changes:
+static_assert(kFmtShift + kFmtBits <= 16, "too many bits");
+
+// Convenience aliases (16 bits, with format):
+enum FieldType : uint16_t {
+  // Numeric types:
+  kBool            = kFkVarint | kRep8Bits,
+
+  kFixed32         = kFkFixed  | kRep32Bits | kFmtUnsigned,
+  kUInt32          = kFkVarint | kRep32Bits | kFmtUnsigned,
+  kSFixed32        = kFkFixed  | kRep32Bits | kFmtSigned,
+  kInt32           = kFkVarint | kRep32Bits | kFmtSigned,
+  kSInt32          = kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kFloat           = kFkFixed  | kRep32Bits | kFmtFloating,
+  kEnum            = kFkVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kEnumRange       = kFkVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kOpenEnum        = kFkVarint | kRep32Bits | kFmtEnum,
+
+  kFixed64         = kFkFixed  | kRep64Bits | kFmtUnsigned,
+  kUInt64          = kFkVarint | kRep64Bits | kFmtUnsigned,
+  kSFixed64        = kFkFixed  | kRep64Bits | kFmtSigned,
+  kInt64           = kFkVarint | kRep64Bits | kFmtSigned,
+  kSInt64          = kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kDouble          = kFkFixed  | kRep64Bits | kFmtFloating,
+
+  kPackedBool      = kFkPackedVarint | kRep8Bits,
+
+  kPackedFixed32   = kFkPackedFixed  | kRep32Bits | kFmtUnsigned,
+  kPackedUInt32    = kFkPackedVarint | kRep32Bits | kFmtUnsigned,
+  kPackedSFixed32  = kFkPackedFixed  | kRep32Bits | kFmtSigned,
+  kPackedInt32     = kFkPackedVarint | kRep32Bits | kFmtSigned,
+  kPackedSInt32    = kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag,
+  kPackedFloat     = kFkPackedFixed  | kRep32Bits | kFmtFloating,
+  kPackedEnum      = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvEnum,
+  kPackedEnumRange = kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvRange,
+  kPackedOpenEnum  = kFkPackedVarint | kRep32Bits | kFmtEnum,
+
+  kPackedFixed64   = kFkPackedFixed  | kRep64Bits | kFmtUnsigned,
+  kPackedUInt64    = kFkPackedVarint | kRep64Bits | kFmtUnsigned,
+  kPackedSFixed64  = kFkPackedFixed  | kRep64Bits | kFmtSigned,
+  kPackedInt64     = kFkPackedVarint | kRep64Bits | kFmtSigned,
+  kPackedSInt64    = kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag,
+  kPackedDouble    = kFkPackedFixed  | kRep64Bits | kFmtFloating,
+
+  // String types:
+  kBytes           = kFkString | kFmtArray,
+  kRawString       = kFkString | kFmtUtf8  | kTvUtf8Debug,
+  kUtf8String      = kFkString | kFmtUtf8  | kTvUtf8,
+
+  // Message types:
+  kMessage         = kFkMessage,
+
+  // Map types:
+  kMap             = kFkMap,
+};
+
+// clang-format on
+}  // namespace field_layout
+
 // PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
 // defined in port_def.inc.
 //
@@ -63,36 +246,6 @@
 // PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
 #define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
 
-// PROTOBUF_TC_PARSE_* decide which function is used to parse message-typed
-// fields. The guard macros are defined in port_def.inc.
-#if PROTOBUF_TC_STATIC_PARSE_SINGULAR1
-#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1
-#else
-#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \
-  ::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint8_t>
-#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR1
-
-#if PROTOBUF_TC_STATIC_PARSE_SINGULAR2
-#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2
-#else
-#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \
-  ::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint16_t>
-#endif  // PROTOBUF_TC_STATIC_PARSE_SINGULAR2
-
-#if PROTOBUF_TC_STATIC_PARSE_REPEATED1
-#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1
-#else
-#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \
-  ::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint8_t>
-#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED1
-
-#if PROTOBUF_TC_STATIC_PARSE_REPEATED2
-#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2
-#else
-#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \
-  ::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint16_t>
-#endif  // PROTOBUF_TC_STATIC_PARSE_REPEATED2
-
 #ifndef NDEBUG
 template <size_t align>
 #ifndef _MSC_VER
@@ -107,7 +260,7 @@
 #endif
 
 // TcParser implements most of the parsing logic for tailcall tables.
-class TcParser final {
+class PROTOBUF_EXPORT TcParser final {
  public:
   static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
   static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
@@ -137,9 +290,9 @@
     PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
   }
 
-  static const char* ParseLoop(MessageLite* msg, const char* ptr,
-                               ParseContext* ctx,
-                               const TcParseTableBase* table) {
+  PROTOBUF_NOINLINE static const char* ParseLoop(
+      MessageLite* msg, const char* ptr, ParseContext* ctx,
+      const TcParseTableBase* table) {
     ScopedArenaSwap saved(msg, ctx);
     const uint32_t has_bits_offset = table->has_bits_offset;
     while (!ctx->Done(&ptr)) {
@@ -152,60 +305,99 @@
     return ptr;
   }
 
-  template <typename FieldType, typename TagType>
-  PROTOBUF_NOINLINE static const char* SingularParseMessage(
-      PROTOBUF_TC_PARAM_DECL) {
-    if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
-    }
-    ptr += sizeof(TagType);
-    hasbits |= (uint64_t{1} << data.hasbit_idx());
-    auto& field = RefAt<FieldType*>(msg, data.offset());
-    if (field == nullptr) {
-      auto arena = ctx->data().arena;
-      if (Arena::is_arena_constructable<FieldType>::value) {
-        field = Arena::CreateMessage<FieldType>(arena);
-      } else {
-        field = Arena::Create<FieldType>(arena);
-      }
-    }
-    SyncHasbits(msg, hasbits, table);
-    return ctx->ParseMessage(field, ptr);
-  }
+  // Functions referenced by generated fast tables (numeric types):
+  //   F: fixed      V: varint     Z: zigzag
+  //   8/32/64: storage type width (bits)
+  //   S: singular   R: repeated   P: packed
+  //   1/2: tag length (bytes)
 
-  template <typename FieldType, typename TagType>
-  PROTOBUF_NOINLINE static const char* RepeatedParseMessage(
-      PROTOBUF_TC_PARAM_DECL) {
-    if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
-    }
-    ptr += sizeof(TagType);
-    auto& field = RefAt<RepeatedPtrField<FieldType>>(msg, data.offset());
-    SyncHasbits(msg, hasbits, table);
-    ptr = ctx->ParseMessage(field.Add(), ptr);
-    return ptr;
-  }
+  // Fixed:
+  static const char* FastF32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastF64P2(PROTOBUF_TC_PARAM_DECL);
 
-  template <typename LayoutType, typename TagType>
-  static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
-  template <typename LayoutType, typename TagType>
-  static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
-  template <typename LayoutType, typename TagType>
-  static const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
+  // Varint:
+  static const char* FastV8S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV8P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastV64P2(PROTOBUF_TC_PARAM_DECL);
 
-  enum VarintDecode { kNoConversion = 0, kZigZag = 1 };
-  template <typename FieldType, typename TagType, VarintDecode zigzag>
-  static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
-  template <typename FieldType, typename TagType, VarintDecode zigzag>
-  static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
-  template <typename FieldType, typename TagType, VarintDecode zigzag>
-  static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
+  // Varint (with zigzag):
+  static const char* FastZ32S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ32P2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64S2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64R2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
 
-  enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
-  template <typename TagType, Utf8Type utf8>
-  static const char* SingularString(PROTOBUF_TC_PARAM_DECL);
-  template <typename TagType, Utf8Type utf8>
-  static const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
+  // Functions referenced by generated fast tables (closed enum):
+  //   E: closed enum (N.B.: open enums use V32, above)
+  //   r: enum range  v: enum validator (_IsValid function)
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastErS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastErR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastEvR2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (string types):
+  //   B: bytes      S: string     U: UTF-8 string
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastBS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastBR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastSR2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastUR2(PROTOBUF_TC_PARAM_DECL);
+
+  // Functions referenced by generated fast tables (message types):
+  //   M: message
+  //   S: singular   R: repeated
+  //   1/2: tag length (bytes)
+  static const char* FastMS1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMS2(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR1(PROTOBUF_TC_PARAM_DECL);
+  static const char* FastMR2(PROTOBUF_TC_PARAM_DECL);
 
   template <typename T>
   static inline T& RefAt(void* x, size_t offset) {
@@ -219,6 +411,19 @@
     return *target;
   }
 
+  template <typename T>
+  static inline const T& RefAt(const void* x, size_t offset) {
+    const T* target =
+        reinterpret_cast<const T*>(static_cast<const char*>(x) + offset);
+#ifndef NDEBUG
+    if (PROTOBUF_PREDICT_FALSE(
+            reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
+      AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
+    }
+#endif
+    return *target;
+  }
+
   static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
       MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
     const uint32_t has_bits_offset = table->has_bits_offset;
@@ -229,7 +434,25 @@
     }
   }
 
- protected:
+  // Mini parsing:
+  //
+  // This function parses a field from incoming data based on metadata stored in
+  // the message definition. If the field is not defined in the message, it is
+  // stored in either the ExtensionSet (if applicable) or the UnknownFieldSet.
+  //
+  // NOTE: Currently, this function only calls the table-level fallback
+  // function, so it should only be called as the fallback from fast table
+  // parsing.
+  static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+
+ private:
+  friend class GeneratedTcTableLiteTest;
+
+  template <typename TagType>
+  static inline const char* SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType>
+  static inline const char* RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL);
+
   static inline PROTOBUF_ALWAYS_INLINE const char* ToParseLoop(
       PROTOBUF_TC_PARAM_DECL) {
     (void)data;
@@ -247,6 +470,8 @@
     return nullptr;
   }
 
+  static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
+
   class ScopedArenaSwap final {
    public:
     ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
@@ -267,14 +492,12 @@
   if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
 
     SyncHasbits(msg, hasbits, table);
-    uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
     CHK_(ptr);
+    uint32_t tag = data.tag();
     if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
       ctx->SetLastTag(tag);
       return ptr;
     }
-    (void)data;
     uint32_t num = tag >> 3;
     if (table->extension_range_low <= num &&
         num <= table->extension_range_high) {
@@ -288,10 +511,67 @@
         ptr, ctx);
 #undef CHK_
   }
-};
 
-// Declare helper functions:
-#include <google/protobuf/generated_message_tctable_impl.inc>
+  // Note: `inline` is needed on template function declarations below to avoid
+  // -Wattributes diagnostic in GCC.
+
+  // Implementations for fast fixed field parsing functions:
+  template <typename LayoutType, typename TagType>
+  static inline const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  template <typename LayoutType, typename TagType>
+  static inline const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast varint field parsing functions:
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  template <typename FieldType, typename TagType, bool zigzag = false>
+  static inline const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast enum field parsing functions:
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, uint16_t xform_val>
+  static inline const char* RepeatedEnum(PROTOBUF_TC_PARAM_DECL);
+
+  // Implementations for fast string field parsing functions:
+  enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* SingularString(PROTOBUF_TC_PARAM_DECL);
+  template <typename TagType, Utf8Type utf8>
+  static inline const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
+
+  // Mini field lookup:
+  static const TcParseTableBase::FieldEntry* FindFieldEntry(
+      const TcParseTableBase* table, uint32_t field_num);
+  static StringPiece MessageName(const TcParseTableBase* table);
+  static StringPiece FieldName(const TcParseTableBase* table,
+                                     const TcParseTableBase::FieldEntry*);
+  static bool ChangeOneof(const TcParseTableBase* table,
+                          const TcParseTableBase::FieldEntry& entry,
+                          uint32_t field_num, ParseContext* ctx,
+                          MessageLite* msg);
+
+  // For FindFieldEntry tests:
+  friend class FindFieldEntryTest;
+  static constexpr const uint32_t kMtSmallScanSize = 4;
+
+  // Mini parsing:
+  static const char* MpVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedVarint(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpPackedFixed(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedString(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL);
+  static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
+};
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/generated_message_tctable_impl.inc b/src/google/protobuf/generated_message_tctable_impl.inc
deleted file mode 100644
index a6831b5..0000000
--- a/src/google/protobuf/generated_message_tctable_impl.inc
+++ /dev/null
@@ -1,92 +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.
-
-// clang-format off
-#ifdef PROTOBUF_TCT_SOURCE
-#define PROTOBUF_TCT_EXTERN
-#else
-#define PROTOBUF_TCT_EXTERN extern
-#endif
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
-#undef PROTOBUF_TCT_EXTERN
-// clang-format on
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index 4350929..a31d8f4 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -29,12 +29,13 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <cstdint>
+#include <numeric>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_tctable_decl.h>
 #include <google/protobuf/generated_message_tctable_impl.h>
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
 // clang-format off
@@ -45,6 +46,8 @@
 namespace protobuf {
 namespace internal {
 
+using FieldEntry = TcParseTableBase::FieldEntry;
+
 #ifndef NDEBUG
 template void AlignFail<4>(uintptr_t);
 template void AlignFail<8>(uintptr_t);
@@ -54,6 +57,142 @@
   return GenericFallbackImpl<MessageLite, std::string>(PROTOBUF_TC_PARAM_PASS);
 }
 
+// Returns the address of the field for `tag` in the table's field entries.
+// Returns nullptr if the field was not found.
+const TcParseTableBase::FieldEntry* TcParser::FindFieldEntry(
+    const TcParseTableBase* table, uint32_t field_num) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+
+  // Most messages have fields numbered sequentially. If the decoded tag is
+  // within that range, we can look up the field by index.
+  const uint32_t sequential_start = table->sequential_fields_start;
+  uint32_t adjusted_field_num = field_num - sequential_start;
+  const uint32_t num_sequential = table->num_sequential_fields;
+  if (PROTOBUF_PREDICT_TRUE(adjusted_field_num < num_sequential)) {
+    return field_entries + adjusted_field_num;
+  }
+
+  // Check if this field is larger than the max in the table. This is often an
+  // extension.
+  if (field_num > table->max_field_number) {
+    return nullptr;
+  }
+
+  // Otherwise, scan the next few field numbers, skipping the first
+  // `num_sequential` entries.
+  const uint32_t* const field_num_begin = table->field_numbers_begin();
+  const uint32_t small_scan_limit =
+      std::min(num_sequential + kMtSmallScanSize,
+               static_cast<uint32_t>(table->num_field_entries));
+  for (uint32_t i = num_sequential; i < small_scan_limit; ++i) {
+    if (field_num <= field_num_begin[i]) {
+      if (PROTOBUF_PREDICT_FALSE(field_num != field_num_begin[i])) {
+        // Field number mismatch.
+        return nullptr;
+      }
+      return field_entries + i;
+    }
+  }
+
+  // Finally, look up with binary search.
+  const uint32_t* const field_num_end = table->field_numbers_end();
+  auto it = std::lower_bound(field_num_begin + small_scan_limit, field_num_end,
+                             field_num);
+  if (it == field_num_end) {
+    // The only reason for binary search failing is if there was nothing to
+    // search.
+    GOOGLE_DCHECK_EQ(field_num_begin + small_scan_limit, field_num_end) << field_num;
+    return nullptr;
+  }
+  if (PROTOBUF_PREDICT_FALSE(*it != field_num)) {
+    // Field number mismatch.
+    return nullptr;
+  }
+  return field_entries + (it - field_num_begin);
+}
+
+// Field names are stored in a format of:
+//
+// 1) A table of name sizes, one byte each, from 1 to 255 per name.
+//    `entries` is the size of this first table.
+// 1a) padding bytes, so the table of name sizes is a multiple of
+//     eight bytes in length. They are zero.
+//
+// 2) All the names, concatenated, with neither separation nor termination.
+//
+// This is designed to be compact but not particularly fast to retrieve.
+// In particular, it takes O(n) to retrieve the name of the n'th field,
+// which is usually fine because most protos have fewer than 10 fields.
+static StringPiece FindName(const char* name_data, size_t entries,
+                                  size_t index) {
+  // The compiler unrolls these... if this isn't fast enough,
+  // there's an AVX version at https://godbolt.org/z/eojrjqzfr
+  // ARM-compatible version at https://godbolt.org/z/n5YT5Ee85
+
+  // The field name sizes are padded up to a multiple of 8, so we
+  // must pad them here.
+  size_t num_sizes = (entries + 7) & -8;
+  auto* uint8s = reinterpret_cast<const uint8_t*>(name_data);
+  size_t pos = std::accumulate(uint8s, uint8s + index, num_sizes);
+  size_t size = name_data[index];
+  auto* start = &name_data[pos];
+  return {start, size};
+}
+
+StringPiece TcParser::MessageName(const TcParseTableBase* table) {
+  return FindName(table->name_data(), table->num_field_entries + 1, 0);
+}
+
+StringPiece TcParser::FieldName(const TcParseTableBase* table,
+                                      const FieldEntry* field_entry) {
+  const FieldEntry* const field_entries = table->field_entries_begin();
+  auto field_index = static_cast<size_t>(field_entry - field_entries);
+  return FindName(table->name_data(), table->num_field_entries + 1,
+                  field_index + 1);
+}
+
+const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
+  uint32_t tag;
+  ptr = ReadTag(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+
+  auto* entry = FindFieldEntry(table, tag >> 3);
+  if (entry == nullptr) {
+    data.data = tag;
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // The handler may need the tag and the entry to resolve fallback logic. Both
+  // of these are 32 bits, so pack them into (the 64-bit) `data`. Since we can't
+  // pack the entry pointer itself, just pack its offset from `table`.
+  uint64_t entry_offset = reinterpret_cast<const char*>(entry) -
+                          reinterpret_cast<const char*>(table);
+  data.data = entry_offset << 32 | tag;
+
+  using field_layout::FieldKind;
+  auto field_type = entry->type_card & FieldKind::kFkMask;
+  switch (field_type) {
+    case FieldKind::kFkNone:
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkVarint:
+      PROTOBUF_MUSTTAIL return MpVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedVarint:
+      PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkFixed:
+      PROTOBUF_MUSTTAIL return MpFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkPackedFixed:
+      PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkString:
+      PROTOBUF_MUSTTAIL return MpString(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMessage:
+      PROTOBUF_MUSTTAIL return MpMessage(PROTOBUF_TC_PARAM_PASS);
+    case FieldKind::kFkMap:
+      PROTOBUF_MUSTTAIL return MpMap(PROTOBUF_TC_PARAM_PASS);
+    default:
+      return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+}
+
 namespace {
 
 // Offset returns the address `offset` bytes after `base`.
@@ -72,13 +211,72 @@
 }  // namespace
 
 //////////////////////////////////////////////////////////////////////////////
+// Message fields
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename TagType>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::SingularParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  auto& field = RefAt<MessageLite*>(msg, data.offset());
+  if (field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(data.aux_idx())->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  SyncHasbits(msg, hasbits, table);
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::FastMS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularParseMessageAuxImpl<uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType>
+inline PROTOBUF_ALWAYS_INLINE
+const char* TcParser::RepeatedParseMessageAuxImpl(PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  ptr += sizeof(TagType);
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(data.aux_idx())->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, data.offset());
+  MessageLite* submsg =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  return ctx->ParseMessage(submsg, ptr);
+}
+
+const char* TcParser::FastMR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastMR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedParseMessageAuxImpl<uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
 // Fixed fields
 //////////////////////////////////////////////////////////////////////////////
 
 template <typename LayoutType, typename TagType>
-const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL) {
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
   hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -87,8 +285,26 @@
   PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
 }
 
+const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
 template <typename LayoutType, typename TagType>
-const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedFixed(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Check if the field can be parsed as packed repeated:
     constexpr WireFormatLite::WireType fallback_wt =
@@ -98,7 +314,7 @@
     if (data.coded_tag<TagType>() == 0) {
       return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
@@ -118,18 +334,40 @@
   return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
 }
 
+const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// Note: some versions of GCC will fail with error "function not inlinable" if
+// corecursive functions are both marked with PROTOBUF_ALWAYS_INLINE (Clang
+// accepts this). We can still apply the attribute to one of the two functions,
+// just not both (so we do mark the Repeated variant as always inlined). This
+// also applies to PackedVarint, below.
 template <typename LayoutType, typename TagType>
 const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Try parsing as non-packed repeated:
     constexpr WireFormatLite::WireType fallback_wt =
         sizeof(LayoutType) == 4 ? WireFormatLite::WIRETYPE_FIXED32
-                                : WireFormatLite::WIRETYPE_FIXED64;
+        : WireFormatLite::WIRETYPE_FIXED64;
     InvertPacked<fallback_wt>(data);
     if (data.coded_tag<TagType>() == 0) {
       return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
     }
   }
   ptr += sizeof(TagType);
@@ -143,6 +381,23 @@
                               static_cast<RepeatedField<LayoutType>*>(&field));
 }
 
+const char* TcParser::FastF32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastF64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedFixed<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // Varint fields
 //////////////////////////////////////////////////////////////////////////////
@@ -276,30 +531,37 @@
   }
 }
 
-template <typename FieldType,
-          TcParser::VarintDecode = TcParser::VarintDecode::kNoConversion>
-FieldType ZigZagDecodeHelper(uint64_t value) {
+template <typename FieldType, bool zigzag = false>
+inline FieldType ZigZagDecodeHelper(uint64_t value) {
   return static_cast<FieldType>(value);
 }
 
 template <>
-int32_t ZigZagDecodeHelper<int32_t, TcParser::VarintDecode::kZigZag>(
-    uint64_t value) {
+inline int32_t ZigZagDecodeHelper<int32_t, true>(uint64_t value) {
   return WireFormatLite::ZigZagDecode32(value);
 }
 
 template <>
-int64_t ZigZagDecodeHelper<int64_t, TcParser::VarintDecode::kZigZag>(
-    uint64_t value) {
+inline int64_t ZigZagDecodeHelper<int64_t, true>(uint64_t value) {
   return WireFormatLite::ZigZagDecode64(value);
 }
 
+bool EnumIsValidAux(int32_t val, uint16_t xform_val,
+                    TcParseTableBase::FieldAux aux) {
+  if (xform_val == field_layout::kTvRange) {
+    auto lo = aux.enum_range.start;
+    return lo <= val && val < (lo + aux.enum_range.length);
+  }
+  return aux.enum_validator(val);
+}
+
 }  // namespace
 
-template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
-const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL) {
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);  // Consume tag
   hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -313,15 +575,58 @@
   PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
 }
 
-template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
-PROTOBUF_NOINLINE const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL) {
+const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64S2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename FieldType, typename TagType, bool zigzag>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     // Try parsing as non-packed repeated:
     InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
     if (data.coded_tag<TagType>() == 0) {
       return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
     }
   }
   auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
@@ -341,14 +646,57 @@
   return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
 }
 
-template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
-PROTOBUF_NOINLINE const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
+const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<bool, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64R2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+// See comment on PackedFixed for why this is not PROTOBUF_ALWAYS_INLINE.
+template <typename FieldType, typename TagType, bool zigzag>
+const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
     InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
     if (data.coded_tag<TagType>() == 0) {
       return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
     } else {
-      return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
     }
   }
   ptr += sizeof(TagType);
@@ -371,12 +719,171 @@
   });
 }
 
+const char* TcParser::FastV8P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint8_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV8P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<bool, uint16_t>(PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint32_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint8_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastV64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<uint64_t, uint16_t>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastZ32P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ32P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int32_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint8_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastZ64P2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return PackedVarint<int64_t, uint16_t, true>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Enum fields
+//////////////////////////////////////////////////////////////////////////////
+
+PROTOBUF_NOINLINE const char* TcParser::FastUnknownEnumFallback(
+    PROTOBUF_TC_PARAM_DECL) {
+  (void)msg;
+  (void)ctx;
+  (void)hasbits;
+
+  // If we know we want to put this field directly into the unknown field set,
+  // then we can skip the call to MiniParse and directly call table->fallback.
+  // However, we first have to update `data` to contain the decoded tag.
+  uint32_t tag;
+  ptr = ReadTag(ptr, &tag);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  data.data = tag;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+  }
+  const char* ptr2 = ptr;  // Save for unknown enum case
+  ptr += sizeof(TagType);  // Consume tag
+  uint64_t tmp;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  if (PROTOBUF_PREDICT_FALSE(
+          !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+    ptr = ptr2;
+    PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  hasbits |= (uint64_t{1} << data.hasbit_idx());
+  RefAt<int32_t>(msg, data.offset()) = tmp;
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+template <typename TagType, uint16_t xform_val>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedEnum(
+    PROTOBUF_TC_PARAM_DECL) {
+  if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+    InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
+    if (data.coded_tag<TagType>() == 0) {
+      // Packed parsing is handled by generated fallback.
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    } else {
+      PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
+  auto expected_tag = UnalignedLoad<TagType>(ptr);
+  const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
+  do {
+    const char* ptr2 = ptr;  // save for unknown enum case
+    ptr += sizeof(TagType);
+    uint64_t tmp;
+    ptr = ParseVarint(ptr, &tmp);
+    if (ptr == nullptr) {
+      return Error(PROTOBUF_TC_PARAM_PASS);
+    }
+    if (PROTOBUF_PREDICT_FALSE(
+            !EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
+      // We can avoid duplicate work in MiniParse by directly calling
+      // table->fallback.
+      ptr = ptr2;
+      PROTOBUF_MUSTTAIL return FastUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    field.Add(static_cast<int32_t>(tmp));
+    if (!ctx->DataAvailable(ptr)) {
+      break;
+    }
+  } while (UnalignedLoad<TagType>(ptr) == expected_tag);
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::FastErR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastErR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvRange>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint8_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastEvR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedEnum<uint16_t, field_layout::kTvEnum>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // String/bytes fields
 //////////////////////////////////////////////////////////////////////////////
 
 // Defined in wire_format_lite.cc
-void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
                        bool emit_stacktrace);
 
 namespace {
@@ -393,9 +900,10 @@
 }  // namespace
 
 template <typename TagType, TcParser::Utf8Type utf8>
-const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL) {
+PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
   }
   ptr += sizeof(TagType);
   hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -417,16 +925,42 @@
       if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) {
         return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
       }
-      PrintUTF8ErrorLog("unknown", "parsing", false);
+      PrintUTF8ErrorLog("", "unknown", "parsing", false);
       return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
                            : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
   }
 }
 
+const char* TcParser::FastBS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUS2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return SingularString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
 template <typename TagType, TcParser::Utf8Type utf8>
-const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL) {
+PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
+    PROTOBUF_TC_PARAM_DECL) {
   if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
-    return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
   }
   auto expected_tag = UnalignedLoad<TagType>(ptr);
   auto& field = RefAt<RepeatedPtrField<std::string>>(msg, data.offset());
@@ -439,7 +973,7 @@
     }
     if (utf8 != kNoUtf8) {
       if (PROTOBUF_PREDICT_FALSE(!IsStructurallyValidUTF8(*str))) {
-        PrintUTF8ErrorLog("unknown", "parsing", false);
+        PrintUTF8ErrorLog("", "unknown", "parsing", false);
         if (utf8 == kUtf8) return Error(PROTOBUF_TC_PARAM_PASS);
       }
     }
@@ -448,8 +982,615 @@
   return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
 }
 
-#define PROTOBUF_TCT_SOURCE
-#include <google/protobuf/generated_message_tctable_impl.inc>
+const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastBR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kNoUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastSR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8ValidateOnly>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR1(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint8_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+const char* TcParser::FastUR2(PROTOBUF_TC_PARAM_DECL) {
+  PROTOBUF_MUSTTAIL return RepeatedString<uint16_t, kUtf8>(
+      PROTOBUF_TC_PARAM_PASS);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Mini parsing
+//////////////////////////////////////////////////////////////////////////////
+
+namespace {
+inline void SetHas(const TcParseTableBase* table, const FieldEntry& entry,
+                   MessageLite* msg, uint64_t& hasbits) {
+  int32_t has_idx = entry.has_idx;
+  if (has_idx < 32) {
+    hasbits |= uint64_t{1} << has_idx;
+  } else {
+    auto* hasblocks = &TcParser::RefAt<uint32_t>(msg, table->has_bits_offset);
+#if defined(__x86_64__) && defined(__GNUC__)
+    asm("bts %1, %0\n" : "+m"(*hasblocks) : "r"(has_idx));
+#else
+    auto& hasblock = hasblocks[has_idx / 32];
+    hasblock |= uint32_t{1} << (has_idx % 32);
+#endif
+  }
+}
+}  // namespace
+
+// Destroys any existing oneof union member (if necessary). Returns true if the
+// caller is responsible for initializing the object, or false if the field
+// already has the desired case.
+bool TcParser::ChangeOneof(const TcParseTableBase* table,
+                           const TcParseTableBase::FieldEntry& entry,
+                           uint32_t field_num, ParseContext* ctx,
+                           MessageLite* msg) {
+  // The _oneof_case_ array offset is stored in the first aux entry.
+  uint32_t oneof_case_offset = table->field_aux(0u)->offset;
+  // The _oneof_case_ array index is stored in the has-bit index.
+  uint32_t* oneof_case =
+      &TcParser::RefAt<uint32_t>(msg, oneof_case_offset) + entry.has_idx;
+  uint32_t current_case = *oneof_case;
+  *oneof_case = field_num;
+
+  if (current_case == 0) {
+    // If the member is empty, we don't have anything to clear. Caller is
+    // responsible for creating a new member object.
+    return true;
+  }
+  if (current_case == field_num) {
+    // If the member is already active, then it should be merged. We're done.
+    return false;
+  }
+  // Look up the value that is already stored, and dispose of it if necessary.
+  const FieldEntry* current_entry = FindFieldEntry(table, current_case);
+  uint16_t current_kind = current_entry->type_card & field_layout::kFkMask;
+  uint16_t current_rep = current_entry->type_card & field_layout::kRepMask;
+  if (current_kind == field_layout::kFkString) {
+    Arena* arena = ctx->data().arena;
+    switch (current_rep) {
+      case field_layout::kRepAString: {
+        auto& field = RefAt<ArenaStringPtr>(msg, current_entry->offset);
+        field.Destroy(ArenaStringPtr::EmptyDefault{}, arena);
+        break;
+      }
+      case field_layout::kRepSString:
+      case field_layout::kRepIString:
+      default:
+        GOOGLE_LOG(DFATAL) << "string rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        return true;
+    }
+  } else if (current_kind == field_layout::kFkMessage) {
+    switch (current_rep) {
+      case field_layout::kRepMessage:
+      case field_layout::kRepGroup:
+      case field_layout::kRepIWeak: {
+        auto& field = RefAt<MessageLite*>(msg, current_entry->offset);
+        if (!ctx->data().arena) {
+          delete field;
+        }
+        break;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "message rep not handled: "
+                    << (current_rep >> field_layout::kRepShift);
+        break;
+    }
+  }
+  return true;
+}
+
+const char* TcParser::MpFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing (wiretype fallback is handled there):
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for mismatched wiretype:
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+  }
+  // Set the field present:
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (card == field_layout::kFcOneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  // Copy the value:
+  if (rep == field_layout::kRep64Bits) {
+    std::memcpy(Offset(msg, entry.offset), ptr, sizeof(uint64_t));
+    ptr += sizeof(uint64_t);
+  } else {
+    std::memcpy(Offset(msg, entry.offset), ptr, sizeof(uint32_t));
+    ptr += sizeof(uint32_t);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t type_card = entry.type_card;
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED64) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint64_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      std::memcpy(field.Add(), ptr, size);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    if (decoded_wiretype != WireFormatLite::WIRETYPE_FIXED32) {
+      PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+    }
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    constexpr auto size = sizeof(uint32_t);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      ptr = ptr2;
+      std::memcpy(field.Add(), ptr, size);
+      ptr += size;
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedFixed(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  int size = ReadSize(&ptr);
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep32Bits));
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    ptr = ctx->ReadPackedFixed(ptr, size, &field);
+  }
+
+  if (ptr == nullptr) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if ((data.tag() & 7) != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  // Parse the value:
+  const char* ptr2 = ptr;  // save for unknown enum case
+  uint64_t tmp;
+  ptr = ParseVarint(ptr, &tmp);
+  if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+
+  // Transform and/or validate the value
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode64(tmp);
+    }
+  } else if (rep == field_layout::kRep32Bits) {
+    if (is_validated_enum) {
+      if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+        ptr = ptr2;
+        PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+      }
+    } else if (is_zigzag) {
+      tmp = WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
+    }
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  if (rep == field_layout::kRep64Bits) {
+    RefAt<uint64_t>(msg, entry.offset) = tmp;
+  } else if (rep == field_layout::kRep32Bits) {
+    RefAt<uint32_t>(msg, entry.offset) = static_cast<uint32_t>(tmp);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    RefAt<bool>(msg, entry.offset) = static_cast<bool>(tmp);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  auto decoded_wiretype = decoded_tag & 7;
+
+  // Check for packed repeated fallback:
+  if (decoded_wiretype == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpPackedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_VARINT) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto& field = RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else if (rep == field_layout::kRep32Bits) {
+    auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      if (is_validated_enum) {
+        if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
+          ptr = ptr2;
+          PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+        }
+      } else if (is_zigzag) {
+        tmp = WireFormatLite::ZigZagDecode32(tmp);
+      }
+      field.Add(tmp);
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto& field = RefAt<RepeatedField<bool>>(msg, entry.offset);
+    const char* ptr2 = ptr;
+    uint32_t next_tag;
+    do {
+      uint64_t tmp;
+      ptr = ParseVarint(ptr2, &tmp);
+      if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+      field.Add(static_cast<bool>(tmp));
+      if (!ctx->DataAvailable(ptr)) break;
+      ptr2 = ReadTag(ptr, &next_tag);
+    } while (next_tag == decoded_tag);
+  }
+
+  PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  auto type_card = entry.type_card;
+  auto decoded_wiretype = data.tag() & 7;
+
+  // Check for non-packed repeated fallback:
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return MpRepeatedVarint(PROTOBUF_TC_PARAM_PASS);
+  }
+  uint16_t xform_val = (type_card & field_layout::kTvMask);
+  const bool is_zigzag = xform_val == field_layout::kTvZigZag;
+  const bool is_validated_enum = xform_val & field_layout::kTvEnum;
+  if (is_validated_enum) {
+    // TODO(b/206890171): handle enums
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Since ctx->ReadPackedFixed does not use TailCall<> or Return<>, sync any
+  // pending hasbits now:
+  SyncHasbits(msg, hasbits, table);
+
+  uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRep64Bits) {
+    auto* field = &RefAt<RepeatedField<uint64_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode64(value) : value);
+    });
+  } else if (rep == field_layout::kRep32Bits) {
+    auto* field = &RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(ptr, [field, is_zigzag](uint64_t value) {
+      field->Add(is_zigzag ? WireFormatLite::ZigZagDecode32(
+                                 static_cast<uint32_t>(value))
+                           : value);
+    });
+  } else {
+    GOOGLE_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
+    auto* field = &RefAt<RepeatedField<bool>>(msg, entry.offset);
+    return ctx->ReadPackedVarint(
+        ptr, [field](uint64_t value) { field->Add(value); });
+  }
+
+  return Error(PROTOBUF_TC_PARAM_PASS);
+}
+
+namespace {
+
+inline bool MpVerifyUtf8(StringPiece wire_bytes, const FieldEntry& entry,
+                         uint16_t xform_val) {
+  if (xform_val == field_layout::kTvUtf8) {
+    return VerifyUTF8(wire_bytes, "unknown");
+  }
+#ifndef NDEBUG
+  if (xform_val == field_layout::kTvUtf8Debug) {
+    VerifyUTF8(wire_bytes, "unknown");
+  }
+#endif  // NDEBUG
+  return true;
+}
+
+}  // namespace
+
+const char* TcParser::MpString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+  const uint32_t decoded_wiretype = data.tag() & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedString(PROTOBUF_TC_PARAM_PASS);
+  }
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+
+  // TODO(b/209516305): handle UTF-8 fields once field names are available.
+  if (
+#ifdef NDEBUG
+      xform_val == field_layout::kTvUtf8
+#else
+      xform_val != 0
+#endif
+  ) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  if (rep == field_layout::kRepIString) {
+    // TODO(b/198211897): support InilnedStringField.
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  // Mark the field as present:
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+
+  bool is_valid = false;
+  Arena* arena = ctx->data().arena;
+  switch (rep) {
+    case field_layout::kRepAString: {
+      const std::string* default_value =
+          RefAt<ArenaStringPtr>(table->default_instance, entry.offset)
+              .tagged_ptr_.Get();
+      auto& field = RefAt<ArenaStringPtr>(msg, entry.offset);
+      if (need_init) field.InitDefault();
+      if (arena) {
+        ptr = ctx->ReadArenaString(ptr, &field, arena);
+      } else {
+        std::string* str = field.MutableNoCopy(default_value, nullptr);
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+      }
+      if (!ptr) break;
+      is_valid = MpVerifyUtf8(field.Get(), entry, xform_val);
+      break;
+    }
+
+    case field_layout::kRepIString:
+      break;  // note: skipped above
+  }
+
+  if (ptr == nullptr || !is_valid) {
+    return Error(PROTOBUF_TC_PARAM_PASS);
+  }
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpRepeatedString(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint32_t decoded_tag = data.tag();
+  const uint32_t decoded_wiretype = decoded_tag & 7;
+
+  if (decoded_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const uint16_t rep = type_card & field_layout::kRepMask;
+  const uint16_t xform_val = type_card & field_layout::kTvMask;
+
+  // TODO(b/209516305): handle UTF-8 fields once field names are available.
+  if (
+#ifdef NDEBUG
+      xform_val == field_layout::kTvUtf8
+#else
+      xform_val != 0
+#endif
+  ) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  switch (rep) {
+    case field_layout::kRepSString: {
+      auto& field = RefAt<RepeatedPtrField<std::string>>(msg, entry.offset);
+      const char* ptr2 = ptr;
+      uint32_t next_tag;
+      do {
+        ptr = ptr2;
+        std::string* str = field.Add();
+        ptr = InlineGreedyStringParser(str, ptr, ctx);
+        if (PROTOBUF_PREDICT_FALSE(ptr == nullptr ||
+                                   !MpVerifyUtf8(*str, entry, xform_val))) {
+          return Error(PROTOBUF_TC_PARAM_PASS);
+        }
+        if (!ctx->DataAvailable(ptr)) break;
+        ptr2 = ReadTag(ptr, &next_tag);
+      } while (next_tag == decoded_tag);
+      break;
+    }
+
+#ifndef NDEBUG
+    default:
+      GOOGLE_LOG(FATAL) << "Unsupported repeated string rep: " << rep;
+      break;
+#endif
+  }
+
+  return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+}
+
+const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  const uint16_t card = type_card & field_layout::kFcMask;
+
+  // Check for repeated parsing:
+  if (card == field_layout::kFcRepeated) {
+    PROTOBUF_MUSTTAIL return MpRepeatedMessage(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Check for wire type mismatch:
+  // TODO(b/210762816): support groups.
+  if ((data.tag() & 7) != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Lazy and implicit weak fields are handled by generated code:
+  // TODO(b/210762816): support these.
+  if ((type_card & field_layout::kRepMask) != field_layout::kRepMessage) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  const bool is_oneof = card == field_layout::kFcOneof;
+  bool need_init = false;
+  if (card == field_layout::kFcOptional) {
+    SetHas(table, entry, msg, hasbits);
+  } else if (is_oneof) {
+    need_init = ChangeOneof(table, entry, data.tag() >> 3, ctx, msg);
+  }
+  MessageLite*& field = RefAt<MessageLite*>(msg, entry.offset);
+  if (need_init || field == nullptr) {
+    const MessageLite* default_instance =
+        table->field_aux(&entry)->message_default;
+    field = default_instance->New(ctx->data().arena);
+  }
+  SyncHasbits(msg, hasbits, table);
+  return ctx->ParseMessage(field, ptr);
+}
+
+const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  const uint16_t type_card = entry.type_card;
+  GOOGLE_DCHECK_EQ(type_card & field_layout::kFcMask,
+            static_cast<uint16_t>(field_layout::kFcRepeated));
+
+  // Check for wire type mismatch:
+  // TODO(b/210762816): support groups.
+  if ((data.tag() & 7) != WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+  // Implicit weak fields are handled by generated code:
+  // TODO(b/210762816): support these.
+  if ((type_card & field_layout::kRepMask) != field_layout::kRepMessage) {
+    PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+  }
+
+  SyncHasbits(msg, hasbits, table);
+  const MessageLite* default_instance =
+      table->field_aux(&entry)->message_default;
+  auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
+  MessageLite* value =
+      field.Add<GenericTypeHandler<MessageLite>>(default_instance);
+  return ctx->ParseMessage(value, ptr);
+}
+
+const char* TcParser::MpMap(PROTOBUF_TC_PARAM_DECL) {
+  const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+  (void)entry;
+  PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+}
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc
new file mode 100644
index 0000000..1738a84
--- /dev/null
+++ b/src/google/protobuf/generated_message_tctable_lite_test.cc
@@ -0,0 +1,537 @@
+// 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 <cstddef>
+
+#include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+
+using ::testing::Eq;
+using ::testing::Not;
+
+MATCHER_P2(IsEntryForFieldNum, table, field_num,
+           StrCat(negation ? "isn't " : "",
+                        "the field entry for field number ", field_num)) {
+  if (arg == nullptr) {
+    *result_listener << "which is nullptr";
+    return false;
+  }
+  // Use the entry's index to compare field numbers.
+  size_t index = static_cast<const TcParseTableBase::FieldEntry*>(arg) -
+                 &table->field_entries[0];
+  uint32_t actual_field_num = table->field_numbers[index];
+  if (actual_field_num != field_num) {
+    *result_listener << "which is the entry for " << actual_field_num;
+    return false;
+  }
+  return true;
+}
+
+TEST(IsEntryForFieldNumTest, Matcher) {
+  // clang-format off
+  TcParseTable<0, 3, 0, 0> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          0,           // max_field_number
+          0, 0,        // fast_idx_mask, num_sequential_fields
+          0, 0,        // sequential_fields_start, num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          nullptr,     // fallback function
+      }};
+  // clang-format on
+  table.field_numbers = {1, 2, 3};
+
+  EXPECT_THAT(&table.field_entries[0], IsEntryForFieldNum(&table, 1));
+  EXPECT_THAT(&table.field_entries[2], IsEntryForFieldNum(&table, 3));
+  EXPECT_THAT(&table.field_entries[1], Not(IsEntryForFieldNum(&table, 3)));
+
+  EXPECT_THAT(nullptr, Not(IsEntryForFieldNum(&table, 1)));
+}
+
+}  // namespace
+
+class FindFieldEntryTest : public ::testing::Test {
+ protected:
+  // Calls the private `FindFieldEntry` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize>
+  const TcParseTableBase::FieldEntry* FindFieldEntry(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize>& table,
+      uint32_t tag) {
+    return TcParser::FindFieldEntry(&table.header, tag);
+  }
+
+  // Calls the private `FieldName` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize>
+  StringPiece FieldName(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize>& table,
+      const TcParseTableBase::FieldEntry* entry) {
+    return TcParser::FieldName(&table.header, entry);
+  }
+
+  // Calls the private `MessageName` function.
+  template <size_t kFastTableSizeLog2, size_t kNumEntries, size_t kNumFieldAux,
+            size_t kNameTableSize>
+  StringPiece MessageName(
+      const TcParseTable<kFastTableSizeLog2, kNumEntries, kNumFieldAux,
+                         kNameTableSize>& table) {
+    return TcParser::MessageName(&table.header);
+  }
+
+  // Returns the number of fields scanned during a small scan.
+  static constexpr int small_scan_size() { return TcParser::kMtSmallScanSize; }
+};
+
+TEST_F(FindFieldEntryTest, SequentialFieldRange) {
+  // Look up fields that are within the range of `num_sequential_fields`.
+  // clang-format off
+  TcParseTable<0, 5, 0, 0> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          111,         // max_field_number
+          0, 4,        // fast_idx_mask, num_sequential_fields
+          2, 5,        // sequential_fields_start, num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_numbers:
+      {{2, 3, 4, 5, 111}},
+  };
+  // clang-format on
+
+  for (int i : table.field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i), IsEntryForFieldNum(&table, i));
+  }
+  for (int i : {0, 1, 6, 7, 110, 112, 500000000}) {
+    GOOGLE_LOG(WARNING) << "Field " << i;
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, SmallScanRange) {
+  // Look up fields past `num_sequential_fields`, but before binary search.
+  ASSERT_THAT(small_scan_size(), Eq(4)) << "test needs to be updated";
+  // clang-format off
+  TcParseTable<0, 6, 0, 0> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          111,         // max_field_number
+          0, 1,        // fast_idx_mask, num_sequential_fields
+          1, 6,        // sequential_fields_start, num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_numbers:
+      {{// Sequential entries:
+        1,
+        // Small scan range:
+        3, 4, 5, 7,
+        // Binary search range:
+        111}},
+  };
+  // clang-format on
+
+  for (int i : table.field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i), IsEntryForFieldNum(&table, i));
+  }
+  for (int i : {0, 2, 6, 8, 9, 110, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, BinarySearchRange) {
+  // Fields after the sequential and small-scan ranges are looked up using
+  // binary search.
+  ASSERT_THAT(small_scan_size(), Eq(4)) << "test needs to be updated";
+
+  // clang-format off
+  TcParseTable<0, 10, 0, 0> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          70,          // max_field_number
+          0, 1,        // fast_idx_mask, num_sequential_fields
+          1, 10,       // sequential_fields_start, num_field_entries
+          0, 0,        // num_aux_entries, aux_offset,
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_numbers:
+      {{// Sequential entries:
+        1,
+        // Small scan range:
+        3, 4, 5, 6,
+        // Binary search range:
+        8, 9, 11, 12, 70}},
+  };
+  // clang-format on
+  for (int i : table.field_numbers) {
+    EXPECT_THAT(FindFieldEntry(table, i), IsEntryForFieldNum(&table, i));
+  }
+  for (int i : {0, 2, 7, 10, 13, 69, 71, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, OutOfRange) {
+  // Look up tags that are larger than the maximum in the message.
+  // clang-format off
+  TcParseTable<0, 3, 0, 15> table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          3,           // max_field_number
+          0, 3,        // fast_idx_mask, num_sequential_fields
+          1, 3,        // sequential_fields_start, num_field_entries
+          0,           // num_aux_entries
+          offsetof(decltype(table), field_names),  // no aux_entries
+          nullptr,     // default instance
+          {},          // fallback function
+      },
+      {},  // fast_entries
+      // field_numbers:
+      {{1, 2, 3}},
+    {},  // "mini" table
+    // auxiliary entries (none in this test)
+    {{  // name lengths
+        "\0\1\2\3\0\0\0\0"
+          // names
+        "1"
+        "02"
+        "003"}},
+  };
+  // clang-format on
+
+  for (int field_num : table.field_numbers) {
+    auto* entry = FindFieldEntry(table, field_num);
+    EXPECT_THAT(entry, IsEntryForFieldNum(&table, field_num));
+
+    StringPiece name = FieldName(table, entry);
+    EXPECT_EQ(name.length(), field_num);
+    while (name[0] == '0') name.remove_prefix(1);  // strip leading zeores
+    EXPECT_EQ(name, StrCat(field_num));
+  }
+  for (int field_num : {0, 4, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, field_num), Eq(nullptr));
+  }
+}
+
+TEST_F(FindFieldEntryTest, EmptyMessage) {
+  // Ensure that tables with no fields are handled correctly.
+  using TableType = TcParseTable<0, 0, 0, 20>;
+  // clang-format off
+  TableType table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          0,           // max_field_number
+          0, 0,        // fast_idx_mask, num_sequential_fields
+          0, 0,        // sequential_fields_start, num_field_entries
+          0,           // num_aux_entries
+          offsetof(TableType, field_names),
+          nullptr,     // default instance
+          nullptr,     // fallback function
+      },
+      {},  // fast_entries
+      {{
+          "\13\0\0\0\0\0\0\0"
+          "MessageName"
+      }},
+  };
+  // clang-format on
+
+  for (int i : {0, 4, 112, 500000000}) {
+    EXPECT_THAT(FindFieldEntry(table, i), Eq(nullptr));
+  }
+  EXPECT_THAT(MessageName(table), Eq("MessageName"));
+}
+
+TEST_F(FindFieldEntryTest, BigMessage) {
+  // Make a monster with lots of field numbers
+  // clang-format off
+  const TcParseTable<5, 134, 5, 2176> test_all_types_table = {
+      // header:
+      {
+          0, 0, 0, 0,  // has_bits_offset, extensions
+          418, 248,    // max_field_number, fast_idx_mask
+          14, 1,       // num_sequential_fields, sequential_fields_start
+          135,         // num_field_entries
+          5,           // num_aux_entries
+          offsetof(decltype(test_all_types_table), aux_entries),
+          nullptr,     // default instance
+          nullptr,     // fallback function
+      },
+      {{
+          // tail-call table
+      }},
+      {{// field numbers
+        1,   2,   3,   4,   5,   6,   7,   8,   9,  10,
+       11,  12,  13,  14,  15,  18,  19,  21,  22,  24,
+       25,  27,  31,  32,  33,  34,  35,  36,  37,  38,
+       39,  40,  41,  42,  43,  44,  45,  48,  49,  51,
+       52,  54,  55,  56,  57,  58,  59,  60,  61,  62,
+       63,  64,  65,  66,  67,  68,  69,  70,  71,  72,
+       73,  74,  75,  76,  77,  78,  79,  80,  81,  82,
+       83,  84,  85,  86,  87,  88,  89,  90,  91,  92,
+       93,  94,  95,  96,  97,  98,  99, 100, 101, 102,
+      111, 112, 113, 114, 115, 116, 117, 118, 119, 201,
+      241, 242, 243, 244, 245, 246, 247, 248, 249, 250,
+      251, 252, 253, 254, 255, 321, 322, 401, 402, 403,
+      404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
+      414, 415, 416, 417}},
+    {{
+        // "mini" table
+    }},
+    {{  // auxiliary entries (not used in this test)
+        {-1, 4},
+        {-1, 4},
+        {-1, 4},
+        {-1, 4},
+        {-1, 4},
+      }}, {{  // name lengths
+        "\1"  // message name
+        "\16\16\17\17\17\17\20\20\21\21\16\17\15\17\16\27\30\24\25\25"
+        "\15\21\16\16\17\17\17\17\20\20\21\21\16\17\15\17\16\27\30\24"
+        "\25\25\15\17\17\21\21\21\21\23\23\25\25\17\20\15\21\20\31\32"
+        "\26\27\14\14\15\15\15\15\16\16\17\17\14\15\13\22\16\16\17\17"
+        "\17\17\20\20\21\21\16\17\15\24\14\24\14\13\12\14\13\14\12\4"
+        "\15\15\16\16\16\16\17\17\20\20\15\16\14\16\15\25\25\12\13\14"
+        "\15\13\15\12\12\13\14\14\14\16\16\15\15\16\0"
+          // names
+        "M"
+        "optional_int32"
+        "optional_int64"
+        "optional_uint32"
+        "optional_uint64"
+        "optional_sint32"
+        "optional_sint64"
+        "optional_fixed32"
+        "optional_fixed64"
+        "optional_sfixed32"
+        "optional_sfixed64"
+        "optional_float"
+        "optional_double"
+        "optional_bool"
+        "optional_string"
+        "optional_bytes"
+        "optional_nested_message"
+        "optional_foreign_message"
+        "optional_nested_enum"
+        "optional_foreign_enum"
+        "optional_string_piece"
+        "optional_cord"
+        "recursive_message"
+        "repeated_int32"
+        "repeated_int64"
+        "repeated_uint32"
+        "repeated_uint64"
+        "repeated_sint32"
+        "repeated_sint64"
+        "repeated_fixed32"
+        "repeated_fixed64"
+        "repeated_sfixed32"
+        "repeated_sfixed64"
+        "repeated_float"
+        "repeated_double"
+        "repeated_bool"
+        "repeated_string"
+        "repeated_bytes"
+        "repeated_nested_message"
+        "repeated_foreign_message"
+        "repeated_nested_enum"
+        "repeated_foreign_enum"
+        "repeated_string_piece"
+        "repeated_cord"
+        "map_int32_int32"
+        "map_int64_int64"
+        "map_uint32_uint32"
+        "map_uint64_uint64"
+        "map_sint32_sint32"
+        "map_sint64_sint64"
+        "map_fixed32_fixed32"
+        "map_fixed64_fixed64"
+        "map_sfixed32_sfixed32"
+        "map_sfixed64_sfixed64"
+        "map_int32_float"
+        "map_int32_double"
+        "map_bool_bool"
+        "map_string_string"
+        "map_string_bytes"
+        "map_string_nested_message"
+        "map_string_foreign_message"
+        "map_string_nested_enum"
+        "map_string_foreign_enum"
+        "packed_int32"
+        "packed_int64"
+        "packed_uint32"
+        "packed_uint64"
+        "packed_sint32"
+        "packed_sint64"
+        "packed_fixed32"
+        "packed_fixed64"
+        "packed_sfixed32"
+        "packed_sfixed64"
+        "packed_float"
+        "packed_double"
+        "packed_bool"
+        "packed_nested_enum"
+        "unpacked_int32"
+        "unpacked_int64"
+        "unpacked_uint32"
+        "unpacked_uint64"
+        "unpacked_sint32"
+        "unpacked_sint64"
+        "unpacked_fixed32"
+        "unpacked_fixed64"
+        "unpacked_sfixed32"
+        "unpacked_sfixed64"
+        "unpacked_float"
+        "unpacked_double"
+        "unpacked_bool"
+        "unpacked_nested_enum"
+        "oneof_uint32"
+        "oneof_nested_message"
+        "oneof_string"
+        "oneof_bytes"
+        "oneof_bool"
+        "oneof_uint64"
+        "oneof_float"
+        "oneof_double"
+        "oneof_enum"
+        "data"
+        "default_int32"
+        "default_int64"
+        "default_uint32"
+        "default_uint64"
+        "default_sint32"
+        "default_sint64"
+        "default_fixed32"
+        "default_fixed64"
+        "default_sfixed32"
+        "default_sfixed64"
+        "default_float"
+        "default_double"
+        "default_bool"
+        "default_string"
+        "default_bytes"
+        "optional_lazy_message"
+        "repeated_lazy_message"
+        "fieldname1"
+        "field_name2"
+        "_field_name3"
+        "field__name4_"
+        "field0name5"
+        "field_0_name6"
+        "fieldName7"
+        "FieldName8"
+        "field_Name9"
+        "Field_Name10"
+        "FIELD_NAME11"
+        "FIELD_name12"
+        "__field_name13"
+        "__Field_name14"
+        "field__name15"
+        "field__Name16"
+        "field_name17__"
+    }},
+  };
+  // clang-format on
+  EXPECT_THAT(MessageName(test_all_types_table), Eq("M"));
+  for (int field_num :
+       {1, 12, 31, 42, 57, 68, 79, 90, 101, 119, 249, 402, 412}) {
+    auto* entry = FindFieldEntry(test_all_types_table, field_num);
+    StringPiece name = FieldName(test_all_types_table, entry);
+    switch (field_num) {
+      case 1:
+        EXPECT_THAT(name, Eq("optional_int32"));
+        break;
+      case 12:
+        EXPECT_THAT(name, Eq("optional_double"));
+        break;
+      case 31:
+        EXPECT_THAT(name, Eq("repeated_int32"));
+        break;
+      case 42:
+        EXPECT_THAT(name, Eq("repeated_double"));
+        break;
+      case 57:
+        EXPECT_THAT(name, Eq("map_int64_int64"));
+        break;
+      case 68:
+        EXPECT_THAT(name, Eq("map_bool_bool"));
+        break;
+      case 79:
+        EXPECT_THAT(name, Eq("packed_sint32"));
+        break;
+      case 90:
+        EXPECT_THAT(name, Eq("unpacked_int64"));
+        break;
+      case 101:
+        EXPECT_THAT(name, Eq("unpacked_bool"));
+        break;
+      case 119:
+        EXPECT_THAT(name, Eq("oneof_enum"));
+        break;
+      case 249:
+        EXPECT_THAT(name, Eq("default_sfixed32"));
+        break;
+      case 402:
+        EXPECT_THAT(name, Eq("field_name2"));
+        break;
+      case 412:
+        EXPECT_THAT(name, Eq("FIELD_name12"));
+        break;
+    }
+  }
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 32a57d3..78d13f9 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -42,7 +42,6 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/extension_set.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/repeated_field.h>
@@ -66,7 +65,7 @@
 }
 
 PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
-    PROTOBUF_ATTRIBUTE_INIT_PRIORITY ExplicitlyConstructed<std::string>
+    PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString
         fixed_address_empty_string{};  // NOLINT
 
 
@@ -87,7 +86,7 @@
 // Force the initialization of the empty string.
 // Normally, registration would do it, but we don't have any guarantee that
 // there is any object with reflection.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static std::true_type init_empty_string =
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 static std::true_type init_empty_string =
     (InitProtobufDefaultsSlow(), std::true_type{});
 
 size_t StringSpaceUsedExcludingSelfLong(const std::string& str) {
@@ -253,11 +252,6 @@
 struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
     : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
 
-
-template <>
-struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
-    : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
-
 // We want to serialize to both CodedOutputStream and directly into byte arrays
 // without duplicating the code. In fact we might want extra output channels in
 // the future.
@@ -313,133 +307,6 @@
   output->ptr += o.ByteCount();
 }
 
-// Helper to branch to fast path if possible
-void SerializeMessageDispatch(const MessageLite& msg,
-                              const FieldMetadata* field_table, int num_fields,
-                              int32_t /*cached_size*/,
-                              io::CodedOutputStream* output) {
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
-  SerializeInternal(base, field_table, num_fields, output);
-}
-
-// Helper to branch to fast path if possible
-void SerializeMessageDispatch(const MessageLite& msg,
-                              const FieldMetadata* field_table, int num_fields,
-                              int32_t /*cached_size*/, ArrayOutput* output) {
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
-  output->ptr = SerializeInternalToArray(base, field_table, num_fields,
-                                         output->is_deterministic, output->ptr);
-}
-
-// Serializing messages is special as it's not a primitive type and needs an
-// explicit overload for each output type.
-template <typename O>
-void SerializeMessageTo(const MessageLite* msg, const void* table_ptr,
-                        O* output) {
-  const SerializationTable* table =
-      static_cast<const SerializationTable*>(table_ptr);
-  if (!table) {
-    // Proto1
-    WriteLengthTo(msg->GetCachedSize(), output);
-    SerializeMessageNoTable(msg, output);
-    return;
-  }
-  const FieldMetadata* field_table = table->field_table;
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
-  int cached_size =
-      *reinterpret_cast<const int32_t*>(base + field_table->offset);
-  WriteLengthTo(cached_size, output);
-  int num_fields = table->num_fields - 1;
-  SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
-                           output);
-}
-
-// Almost the same as above only it doesn't output the length field.
-template <typename O>
-void SerializeGroupTo(const MessageLite* msg, const void* table_ptr,
-                      O* output) {
-  const SerializationTable* table =
-      static_cast<const SerializationTable*>(table_ptr);
-  if (!table) {
-    // Proto1
-    SerializeMessageNoTable(msg, output);
-    return;
-  }
-  const FieldMetadata* field_table = table->field_table;
-  const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
-  int cached_size =
-      *reinterpret_cast<const int32_t*>(base + field_table->offset);
-  int num_fields = table->num_fields - 1;
-  SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
-                           output);
-}
-
-template <int type>
-struct SingularFieldHelper {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    WriteTagTo(md.tag, output);
-    SerializeTo<type>(field, output);
-  }
-};
-
-template <>
-struct SingularFieldHelper<WireFormatLite::TYPE_STRING> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    WriteTagTo(md.tag, output);
-    SerializeTo<WireFormatLite::TYPE_STRING>(&Get<ArenaStringPtr>(field).Get(),
-                                             output);
-  }
-};
-
-template <>
-struct SingularFieldHelper<WireFormatLite::TYPE_BYTES>
-    : SingularFieldHelper<WireFormatLite::TYPE_STRING> {};
-
-template <>
-struct SingularFieldHelper<WireFormatLite::TYPE_GROUP> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    WriteTagTo(md.tag, output);
-    SerializeGroupTo(Get<const MessageLite*>(field),
-                     static_cast<const SerializationTable*>(md.ptr), output);
-    WriteTagTo(md.tag + 1, output);
-  }
-};
-
-template <>
-struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    WriteTagTo(md.tag, output);
-    SerializeMessageTo(Get<const MessageLite*>(field),
-                       static_cast<const SerializationTable*>(md.ptr), output);
-  }
-};
-
-template <>
-struct SingularFieldHelper<FieldMetadata::kInlinedType> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    WriteTagTo(md.tag, output);
-    SerializeTo<FieldMetadata::kInlinedType>(&Get<std::string>(field), output);
-  }
-};
-
-template <int type>
-struct RepeatedFieldHelper {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    typedef typename PrimitiveTypeHelper<type>::Type T;
-    const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
-    for (int i = 0; i < array.size(); i++) {
-      WriteTagTo(md.tag, output);
-      SerializeTo<type>(&array[i], output);
-    }
-  }
-};
-
 // We need to use a helper class to get access to the private members
 class AccessorHelper {
  public:
@@ -449,118 +316,6 @@
   }
 };
 
-template <>
-struct RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    const internal::RepeatedPtrFieldBase& array =
-        Get<internal::RepeatedPtrFieldBase>(field);
-    for (int i = 0; i < AccessorHelper::Size(array); i++) {
-      WriteTagTo(md.tag, output);
-      SerializeTo<WireFormatLite::TYPE_STRING>(AccessorHelper::Get(array, i),
-                                               output);
-    }
-  }
-};
-
-template <>
-struct RepeatedFieldHelper<WireFormatLite::TYPE_BYTES>
-    : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
-
-template <>
-struct RepeatedFieldHelper<WireFormatLite::TYPE_GROUP> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    const internal::RepeatedPtrFieldBase& array =
-        Get<internal::RepeatedPtrFieldBase>(field);
-    for (int i = 0; i < AccessorHelper::Size(array); i++) {
-      WriteTagTo(md.tag, output);
-      SerializeGroupTo(
-          static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
-          static_cast<const SerializationTable*>(md.ptr), output);
-      WriteTagTo(md.tag + 1, output);
-    }
-  }
-};
-
-template <>
-struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    const internal::RepeatedPtrFieldBase& array =
-        Get<internal::RepeatedPtrFieldBase>(field);
-    for (int i = 0; i < AccessorHelper::Size(array); i++) {
-      WriteTagTo(md.tag, output);
-      SerializeMessageTo(
-          static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
-          md.ptr, output);
-    }
-  }
-};
-
-
-template <>
-struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
-    : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
-
-template <int type>
-struct PackedFieldHelper {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    typedef typename PrimitiveTypeHelper<type>::Type T;
-    const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
-    if (array.empty()) return;
-    WriteTagTo(md.tag, output);
-    int cached_size =
-        Get<int>(static_cast<const uint8_t*>(field) + sizeof(RepeatedField<T>));
-    WriteLengthTo(cached_size, output);
-    for (int i = 0; i < array.size(); i++) {
-      SerializeTo<type>(&array[i], output);
-    }
-  }
-};
-
-template <>
-struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
-  template <typename O>
-  static void Serialize(const void* /*field*/, const FieldMetadata& md,
-                        O* /*output*/) {
-    GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
-               << md.type;
-  }
-};
-
-template <>
-struct PackedFieldHelper<WireFormatLite::TYPE_BYTES>
-    : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
-template <>
-struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
-    : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
-template <>
-struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
-    : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
-template <>
-struct PackedFieldHelper<FieldMetadata::kInlinedType>
-    : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
-
-template <int type>
-struct OneOfFieldHelper {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    SingularFieldHelper<type>::Serialize(field, md, output);
-  }
-};
-
-
-template <>
-struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
-  template <typename O>
-  static void Serialize(const void* field, const FieldMetadata& md, O* output) {
-    SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
-        Get<const std::string*>(field), md, output);
-  }
-};
-
 void SerializeNotImplemented(int field) {
   GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
 }
@@ -569,11 +324,6 @@
 #define SERIALIZE_TABLE_OP(type, type_class) \
   ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
 
-int FieldMetadata::CalculateType(int type,
-                                 FieldMetadata::FieldTypeClass type_class) {
-  return SERIALIZE_TABLE_OP(type, type_class);
-}
-
 template <int type>
 bool IsNull(const void* ptr) {
   return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
@@ -600,125 +350,6 @@
   return Get<const MessageLite*>(ptr) == nullptr;
 }
 
-
-template <>
-bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
-  return static_cast<const std::string*>(ptr)->empty();
-}
-
-#define SERIALIZERS_FOR_TYPE(type)                                            \
-  case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence):                    \
-    if (!IsPresent(base, field_metadata.has_offset)) continue;                \
-    SingularFieldHelper<type>::Serialize(ptr, field_metadata, output);        \
-    break;                                                                    \
-  case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence):                  \
-    if (IsNull<type>(ptr)) continue;                                          \
-    SingularFieldHelper<type>::Serialize(ptr, field_metadata, output);        \
-    break;                                                                    \
-  case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated):                    \
-    RepeatedFieldHelper<type>::Serialize(ptr, field_metadata, output);        \
-    break;                                                                    \
-  case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked):                      \
-    PackedFieldHelper<type>::Serialize(ptr, field_metadata, output);          \
-    break;                                                                    \
-  case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf):                       \
-    if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \
-      continue;                                                               \
-    OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output);           \
-    break
-
-void SerializeInternal(const uint8_t* base,
-                       const FieldMetadata* field_metadata_table,
-                       int32_t num_fields, io::CodedOutputStream* output) {
-  SpecialSerializer func = nullptr;
-  for (int i = 0; i < num_fields; i++) {
-    const FieldMetadata& field_metadata = field_metadata_table[i];
-    const uint8_t* ptr = base + field_metadata.offset;
-    switch (field_metadata.type) {
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
-      SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
-
-      // Special cases
-      case FieldMetadata::kSpecial:
-        func = reinterpret_cast<SpecialSerializer>(
-            const_cast<void*>(field_metadata.ptr));
-        func(base, field_metadata.offset, field_metadata.tag,
-             field_metadata.has_offset, output);
-        break;
-      default:
-        // __builtin_unreachable()
-        SerializeNotImplemented(field_metadata.type);
-    }
-  }
-}
-
-uint8_t* SerializeInternalToArray(const uint8_t* base,
-                                  const FieldMetadata* field_metadata_table,
-                                  int32_t num_fields, bool is_deterministic,
-                                  uint8_t* buffer) {
-  ArrayOutput array_output = {buffer, is_deterministic};
-  ArrayOutput* output = &array_output;
-  SpecialSerializer func = nullptr;
-  for (int i = 0; i < num_fields; i++) {
-    const FieldMetadata& field_metadata = field_metadata_table[i];
-    const uint8_t* ptr = base + field_metadata.offset;
-    switch (field_metadata.type) {
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
-      SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
-      SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
-      // Special cases
-      case FieldMetadata::kSpecial: {
-        io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
-        io::CodedOutputStream output_stream(&array_stream);
-        output_stream.SetSerializationDeterministic(is_deterministic);
-        func = reinterpret_cast<SpecialSerializer>(
-            const_cast<void*>(field_metadata.ptr));
-        func(base, field_metadata.offset, field_metadata.tag,
-             field_metadata.has_offset, &output_stream);
-        array_output.ptr += output_stream.ByteCount();
-      } break;
-      default:
-        // __builtin_unreachable()
-        SerializeNotImplemented(field_metadata.type);
-    }
-  }
-  return array_output.ptr;
-}
-#undef SERIALIZERS_FOR_TYPE
-
 void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
                          uint32_t offset, uint32_t tag, uint32_t has_offset,
                          io::CodedOutputStream* output) {
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 336234c..71d15cd 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -46,17 +46,18 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>  // Add direct dep on port for pb.cc
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/any.h>
 #include <google/protobuf/has_bits.h>
 #include <google/protobuf/implicit_weak_message.h>
 #include <google/protobuf/message_lite.h>
-#include <google/protobuf/stubs/once.h>  // Add direct dep on port for pb.cc
-#include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/casts.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
diff --git a/src/google/protobuf/has_bits.h b/src/google/protobuf/has_bits.h
index acbca68..f8a4587 100644
--- a/src/google/protobuf/has_bits.h
+++ b/src/google/protobuf/has_bits.h
@@ -34,6 +34,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
index 528cf95..27ed6b6 100644
--- a/src/google/protobuf/implicit_weak_message.cc
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -30,34 +30,39 @@
 
 #include <google/protobuf/implicit_weak_message.h>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
+PROTOBUF_PRAGMA_INIT_SEG
+
 namespace google {
 namespace protobuf {
 namespace internal {
 
 const char* ImplicitWeakMessage::_InternalParse(const char* ptr,
                                                 ParseContext* ctx) {
-  return ctx->AppendString(ptr, &data_);
+  return ctx->AppendString(ptr, data_);
 }
 
-ExplicitlyConstructed<ImplicitWeakMessage>
+struct ImplicitWeakMessageDefaultType {
+  constexpr ImplicitWeakMessageDefaultType()
+      : instance(ConstantInitialized{}) {}
+  ~ImplicitWeakMessageDefaultType() {}
+  union {
+    ImplicitWeakMessage instance;
+  };
+};
+
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ImplicitWeakMessageDefaultType
     implicit_weak_message_default_instance;
-internal::once_flag implicit_weak_message_once_init_;
-
-void InitImplicitWeakMessageDefaultInstance() {
-  implicit_weak_message_default_instance.DefaultConstruct();
-}
 
 const ImplicitWeakMessage* ImplicitWeakMessage::default_instance() {
-  internal::call_once(implicit_weak_message_once_init_,
-                      InitImplicitWeakMessageDefaultInstance);
-  return &implicit_weak_message_default_instance.get();
+  return reinterpret_cast<ImplicitWeakMessage*>(
+      &implicit_weak_message_default_instance);
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
index 5db8b9c..b894ab4 100644
--- a/src/google/protobuf/implicit_weak_message.h
+++ b/src/google/protobuf/implicit_weak_message.h
@@ -42,6 +42,7 @@
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 // This file is logically internal-only and should only be used by protobuf
@@ -56,8 +57,17 @@
 // message type does not get linked into the binary.
 class PROTOBUF_EXPORT ImplicitWeakMessage : public MessageLite {
  public:
-  ImplicitWeakMessage() {}
-  explicit ImplicitWeakMessage(Arena* arena) : MessageLite(arena) {}
+  ImplicitWeakMessage() : data_(new std::string) {}
+  explicit constexpr ImplicitWeakMessage(ConstantInitialized)
+      : data_(nullptr) {}
+  explicit ImplicitWeakMessage(Arena* arena)
+      : MessageLite(arena), data_(new std::string) {}
+
+  ~ImplicitWeakMessage() override {
+    // data_ will be null in the default instance, but we can safely call delete
+    // here because the default instance will never be destroyed.
+    delete data_;
+  }
 
   static const ImplicitWeakMessage* default_instance();
 
@@ -67,33 +77,50 @@
     return Arena::CreateMessage<ImplicitWeakMessage>(arena);
   }
 
-  void Clear() override { data_.clear(); }
+  void Clear() override { data_->clear(); }
 
   bool IsInitialized() const override { return true; }
 
   void CheckTypeAndMergeFrom(const MessageLite& other) override {
-    data_.append(static_cast<const ImplicitWeakMessage&>(other).data_);
+    const std::string* other_data =
+        static_cast<const ImplicitWeakMessage&>(other).data_;
+    if (other_data != nullptr) {
+      data_->append(*other_data);
+    }
   }
 
   const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
 
-  size_t ByteSizeLong() const override { return data_.size(); }
+  size_t ByteSizeLong() const override {
+    return data_ == nullptr ? 0 : data_->size();
+  }
 
   uint8_t* _InternalSerialize(uint8_t* target,
                               io::EpsCopyOutputStream* stream) const final {
-    return stream->WriteRaw(data_.data(), static_cast<int>(data_.size()),
+    if (data_ == nullptr) {
+      return target;
+    }
+    return stream->WriteRaw(data_->data(), static_cast<int>(data_->size()),
                             target);
   }
 
-  int GetCachedSize() const override { return static_cast<int>(data_.size()); }
+  int GetCachedSize() const override {
+    return data_ == nullptr ? 0 : static_cast<int>(data_->size());
+  }
 
   typedef void InternalArenaConstructable_;
 
  private:
-  std::string data_;
+  // This std::string is allocated on the heap, but we use a raw pointer so that
+  // the default instance can be constant-initialized. In the const methods, we
+  // have to handle the possibility of data_ being null.
+  std::string* data_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImplicitWeakMessage);
 };
 
+struct ImplicitWeakMessageDefaultType;
+extern ImplicitWeakMessageDefaultType implicit_weak_message_default_instance;
+
 // A type handler for use with implicit weak repeated message fields.
 template <typename ImplicitWeakType>
 class ImplicitWeakTypeHandler {
diff --git a/src/google/protobuf/inlined_string_field.cc b/src/google/protobuf/inlined_string_field.cc
index 0d16869..f60fb91 100644
--- a/src/google/protobuf/inlined_string_field.cc
+++ b/src/google/protobuf/inlined_string_field.cc
@@ -30,11 +30,11 @@
 
 #include <google/protobuf/inlined_string_field.h>
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 
 // clang-format off
 #include <google/protobuf/port_def.inc>
@@ -48,40 +48,48 @@
 std::string* InlinedStringField::Mutable(const LazyString& /*default_value*/,
                                          Arena* arena, bool donated,
                                          uint32_t* donating_states,
-                                         uint32_t mask) {
+                                         uint32_t mask, MessageLite* msg) {
   if (arena == nullptr || !donated) {
     return UnsafeMutablePointer();
   }
-  return MutableSlow(arena, donated, donating_states, mask);
+  return MutableSlow(arena, donated, donating_states, mask, msg);
 }
 
 std::string* InlinedStringField::Mutable(ArenaStringPtr::EmptyDefault,
                                          Arena* arena, bool donated,
                                          uint32_t* donating_states,
-                                         uint32_t mask) {
+                                         uint32_t mask, MessageLite* msg) {
   if (arena == nullptr || !donated) {
     return UnsafeMutablePointer();
   }
-  return MutableSlow(arena, donated, donating_states, mask);
+  return MutableSlow(arena, donated, donating_states, mask, msg);
 }
 
 std::string* InlinedStringField::MutableSlow(::google::protobuf::Arena* arena,
                                              bool donated,
                                              uint32_t* donating_states,
-                                             uint32_t mask) {
+                                             uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
   return UnsafeMutablePointer();
 }
 
 void InlinedStringField::SetAllocated(const std::string* default_value,
                                       std::string* value, Arena* arena,
                                       bool donated, uint32_t* donating_states,
-                                      uint32_t mask) {
+                                      uint32_t mask, MessageLite* msg) {
+  (void)mask;
+  (void)msg;
   SetAllocatedNoArena(default_value, value);
 }
 
 void InlinedStringField::Set(const std::string* default_value,
                              std::string&& value, Arena* arena, bool donated,
-                             uint32_t* donating_states, uint32_t mask) {
+                             uint32_t* donating_states, uint32_t mask,
+                             MessageLite* msg) {
+  (void)donating_states;
+  (void)mask;
+  (void)msg;
   SetNoArena(default_value, std::move(value));
 }
 
diff --git a/src/google/protobuf/inlined_string_field.h b/src/google/protobuf/inlined_string_field.h
index e4ab359..69ba493 100644
--- a/src/google/protobuf/inlined_string_field.h
+++ b/src/google/protobuf/inlined_string_field.h
@@ -36,10 +36,10 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/arenastring.h>
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
 
 // Must be included last.
 #include <google/protobuf/port_def.inc>
@@ -132,7 +132,7 @@
   // This method never changes the `donating_states`.
   void Set(const std::string* default_value, ConstStringParam value,
            Arena* arena, bool donated, uint32_t* /*donating_states*/,
-           uint32_t /*mask*/) {
+           uint32_t /*mask*/, MessageLite* /*msg*/) {
     (void)arena;
     (void)donated;
     SetNoArena(default_value, value);
@@ -141,43 +141,46 @@
   // Rvalue Set. If this field is donated, this method will undonate this field
   // by mutating the `donating_states` according to `mask`.
   void Set(const std::string* default_value, std::string&& value, Arena* arena,
-           bool donated, uint32_t* donating_states, uint32_t mask);
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg);
 
   template <typename FirstParam>
   void Set(FirstParam p1, const char* str, ::google::protobuf::Arena* arena, bool donated,
-           uint32_t* donating_states, uint32_t mask) {
-    Set(p1, ConstStringParam(str), arena, donated, donating_states, mask);
+           uint32_t* donating_states, uint32_t mask, MessageLite* msg) {
+    Set(p1, ConstStringParam(str), arena, donated, donating_states, mask, msg);
   }
 
   template <typename FirstParam>
   void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
-           bool donated, uint32_t* donating_states, uint32_t mask) {
+           bool donated, uint32_t* donating_states, uint32_t mask,
+           MessageLite* msg) {
     ConstStringParam sp{str, size};  // for string_view and `const string &`
-    Set(p1, sp, arena, donated, donating_states, mask);
+    Set(p1, sp, arena, donated, donating_states, mask, msg);
   }
 
   template <typename FirstParam, typename RefWrappedType>
   void Set(FirstParam p1,
            std::reference_wrapper<RefWrappedType> const_string_ref,
            ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
-           uint32_t mask) {
-    Set(p1, const_string_ref.get(), arena, donated, donating_states, mask);
+           uint32_t mask, MessageLite* msg) {
+    Set(p1, const_string_ref.get(), arena, donated, donating_states, mask, msg);
   }
 
   template <typename FirstParam, typename SecondParam>
   void SetBytes(FirstParam p1, SecondParam&& p2, ::google::protobuf::Arena* arena,
-                bool donated, uint32_t* donating_states, uint32_t mask) {
+                bool donated, uint32_t* donating_states, uint32_t mask,
+                MessageLite* msg) {
     Set(p1, static_cast<SecondParam&&>(p2), arena, donated, donating_states,
-        mask);
+        mask, msg);
   }
 
   template <typename FirstParam>
   void SetBytes(FirstParam p1, const void* str, size_t size,
                 ::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
-                uint32_t mask) {
+                uint32_t mask, MessageLite* msg) {
     // Must work whether ConstStringParam is string_view or `const string &`
     ConstStringParam sp{static_cast<const char*>(str), size};
-    Set(p1, sp, arena, donated, donating_states, mask);
+    Set(p1, sp, arena, donated, donating_states, mask, msg);
   }
 
   PROTOBUF_NDEBUG_INLINE void SetNoArena(const std::string* default_value,
@@ -194,9 +197,11 @@
   // `donating_states` according to `mask`, and copies the content of the
   // original string to the returning string.
   std::string* Mutable(const LazyString& default_value, Arena* arena,
-                       bool donated, uint32_t* donating_states, uint32_t mask);
+                       bool donated, uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg);
   std::string* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
-                       uint32_t* donating_states, uint32_t mask);
+                       uint32_t* donating_states, uint32_t mask,
+                       MessageLite* msg);
 
   // Release returns a std::string* instance that is heap-allocated and is not
   // Own()'d by any arena. If the field is not set, this returns nullptr. The
@@ -216,20 +221,19 @@
   // `donating_states` according to `mask`.
   void SetAllocated(const std::string* default_value, std::string* value,
                     Arena* arena, bool donated, uint32_t* donating_states,
-                    uint32_t mask);
+                    uint32_t mask, MessageLite* msg);
 
   void SetAllocatedNoArena(const std::string* default_value,
                            std::string* value);
 
-  // When one of `this` and `from` is donated and the other is not donated, this
-  // method will undonate the donated one and swap the two heap-allocated
-  // strings.
-  PROTOBUF_NDEBUG_INLINE void Swap(InlinedStringField* from,
-                                   const std::string* default_value,
-                                   Arena* arena, bool donated,
-                                   bool from_donated, uint32_t* donating_states,
-                                   uint32_t* from_donating_states,
-                                   uint32_t mask);
+  // Arena-safety semantics: this is guarded by the logic in
+  // Swap()/UnsafeArenaSwap() at the message level, so this method is
+  // 'unsafe' if called directly.
+  inline PROTOBUF_NDEBUG_INLINE static void InternalSwap(
+      InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+      MessageLite* lhs_msg,  //
+      InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+      MessageLite* rhs_msg);
 
   // Frees storage (if not on an arena).
   PROTOBUF_NDEBUG_INLINE void Destroy(const std::string* default_value,
@@ -264,7 +268,8 @@
 
   // InlinedStringField doesn't have things like the `default_value` pointer in
   // ArenaStringPtr.
-  bool IsDefault(const std::string* /*default_value*/) const { return false; }
+  static constexpr bool IsDefault()  { return false; }
+  static constexpr bool IsDefault(const std::string*) { return false; }
 
  private:
   void Destruct() { get_mutable()->~basic_string(); }
@@ -275,7 +280,8 @@
   alignas(std::string) char value_[sizeof(std::string)];
 
   std::string* MutableSlow(::google::protobuf::Arena* arena, bool donated,
-                           uint32_t* donating_states, uint32_t mask);
+                           uint32_t* donating_states, uint32_t mask,
+                           MessageLite* msg);
 
 
   // When constructed in an Arena, we want our destructor to be skipped.
@@ -297,12 +303,8 @@
   new (get_mutable()) std::string(default_value);
 }
 
-inline InlinedStringField::InlinedStringField(Arena* arena) {
-  Init();
-  if (arena != nullptr) {
-    arena->OwnDestructor(get_mutable());
-  }
-}
+
+inline InlinedStringField::InlinedStringField(Arena* /*arena*/) { Init(); }
 
 inline const std::string& InlinedStringField::GetNoArena() const {
   return *get_const();
@@ -343,27 +345,28 @@
   get_mutable()->assign(std::move(value));
 }
 
-inline void InlinedStringField::Swap(
-    InlinedStringField* from, const std::string* /*default_value*/,
-    Arena* arena, bool donated, bool from_donated, uint32_t* donating_states,
-    uint32_t* from_donating_states, uint32_t mask) {
-#ifdef GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  // If one is donated and the other is not, undonate the donated one.
-  if (donated && !from_donated) {
-    MutableSlow(arena, donated, donating_states, mask);
-  } else if (!donated && from_donated) {
-    from->MutableSlow(arena, from_donated, from_donating_states, mask);
+// Caller should make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
+inline PROTOBUF_NDEBUG_INLINE void InlinedStringField::InternalSwap(
+    InlinedStringField* lhs, Arena* lhs_arena, bool lhs_arena_dtor_registered,
+    MessageLite* lhs_msg,  //
+    InlinedStringField* rhs, Arena* rhs_arena, bool rhs_arena_dtor_registered,
+    MessageLite* rhs_msg) {
+#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
+  lhs->get_mutable()->swap(*rhs->get_mutable());
+  if (!lhs_arena_dtor_registered && rhs_arena_dtor_registered) {
+    lhs_msg->OnDemandRegisterArenaDtor(lhs_arena);
+  } else if (lhs_arena_dtor_registered && !rhs_arena_dtor_registered) {
+    rhs_msg->OnDemandRegisterArenaDtor(rhs_arena);
   }
-  // Then, swap the two undonated strings.
 #else
-  (void)arena;
-  (void)donated;
-  (void)from_donated;
-  (void)donating_states;
-  (void)from_donating_states;
-  (void)mask;
+  (void)lhs_arena;
+  (void)rhs_arena;
+  (void)lhs_arena_dtor_registered;
+  (void)rhs_arena_dtor_registered;
+  (void)lhs_msg;
+  (void)rhs_msg;
+  lhs->get_mutable()->swap(*rhs->get_mutable());
 #endif
-  get_mutable()->swap(*from->get_mutable());
 }
 
 inline std::string* InlinedStringField::MutableNoArenaNoDefault(
diff --git a/src/google/protobuf/inlined_string_field_unittest.cc b/src/google/protobuf/inlined_string_field_unittest.cc
index 52affbd..90c1412 100644
--- a/src/google/protobuf/inlined_string_field_unittest.cc
+++ b/src/google/protobuf/inlined_string_field_unittest.cc
@@ -52,235 +52,7 @@
 using internal::ArenaStringPtr;
 using internal::InlinedStringField;
 
-static std::string WrapString(const char* value) { return value; }
-
 namespace {
-
-const uint32 kMask = ~0x00000001u;
-const uint32 kMask1 = ~0x00000004u;
-const uint32 kMask2 = ~0x00000020u;
-
-TEST(InlinedStringFieldTest, SetOnHeap) {
-  InlinedStringField field;
-  uint32 donating_states = 0;
-  const std::string kDefaultValue = "default";
-  field.Set(&kDefaultValue, WrapString("Test short"), nullptr, false,
-            &donating_states, kMask);
-  EXPECT_EQ(std::string("Test short"), field.Get());
-  field.Set(&kDefaultValue, WrapString("Test long long long long value"),
-            nullptr, false, &donating_states, kMask);
-  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
-}
-
-TEST(InlinedStringFieldTest, SetRvalueOnHeap) {
-  InlinedStringField field;
-  uint32 donating_states = 0;
-  std::string string_moved = "Moved long long long long string 1";
-  field.Set(nullptr, std::move(string_moved), nullptr, false, &donating_states,
-            kMask);
-  EXPECT_EQ("Moved long long long long string 1", field.Get());
-  EXPECT_EQ(donating_states & ~kMask1, 0);
-}
-
-TEST(InlinedStringFieldTest, UnsafeMutablePointerThenRelease) {
-  InlinedStringField field;
-  const std::string kDefaultValue = "default";
-  std::string* mut = field.UnsafeMutablePointer();
-  // The address of inlined string doesn't change behind the scene.
-  EXPECT_EQ(mut, field.UnsafeMutablePointer());
-  EXPECT_EQ(mut, &field.Get());
-  EXPECT_EQ(std::string(""), *mut);
-  *mut = "Test long long long long value";  // ensure string allocates
-  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
-
-  std::string* released = field.ReleaseNonDefaultNoArena(&kDefaultValue);
-  EXPECT_EQ("Test long long long long value", *released);
-  // Default value is ignored.
-  EXPECT_EQ("", field.Get());
-  delete released;
-}
-
-// When donating mechanism is enabled:
-// - Initially, the string is donated.
-// - After lvalue Set: the string is still donated.
-// - After Mutable: the string is undonated. The data buffer of the string is a
-// new buffer on the heap.
-TEST(InlinedStringFieldTest, ArenaSetThenMutable) {
-  Arena arena;
-  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  uint32 donating_states = ~0u;
-  const std::string kDefaultValue = "default";
-  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
-                   /*donated=*/true, &donating_states, kMask1);
-  EXPECT_EQ(std::string("Test short"), field_arena->Get());
-  field_arena->Set(&kDefaultValue, "Test long long long long value", &arena,
-                   /*donated=*/(donating_states & ~kMask1) != 0,
-                   &donating_states, kMask1);
-  EXPECT_EQ(std::string("Test long long long long value"), field_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_NE(donating_states & ~kMask1, 0);  // donate.
-#endif
-
-  const std::string* old_string = &field_arena->Get();
-  const char* old_data = old_string->data();
-  (void)old_data;
-  std::string* mut = field_arena->Mutable(
-      ArenaStringPtr::EmptyDefault{}, &arena,
-      /*donated=*/(donating_states & ~kMask1) != 0, &donating_states, kMask1);
-  EXPECT_EQ(old_string, mut);
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask1, 0);
-  EXPECT_NE(old_data, mut->data());  // The data buffer of the mutated string is
-                                     // a new buffer on the heap.
-#endif
-  *mut = "Test an even longer long long long long value";
-  EXPECT_EQ(std::string("Test an even longer long long long long value"),
-            field_arena->Get());
-  EXPECT_EQ(&field_arena->Get(), mut);
-}
-
-// Release doesn't change the donating state.
-// When donating mechanism is enabled:
-// - Initially, the string is donated.
-// - Then lvalue Set: the string is still donated.
-// - Then Release: the string is cleared, and still donated.
-// - Then Mutable: the string is undonated.
-// - Then Release: the string is still undonated.
-TEST(InlinedStringFieldTest, ArenaRelease) {
-  Arena arena;
-  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  uint32 donating_states = ~0u;
-  const std::string kDefaultValue = "default";
-  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
-                   /*donated=*/true, &donating_states, kMask1);
-  std::string* released = field_arena->Release(
-      &kDefaultValue, &arena, /*donated=*/(donating_states & ~kMask1) != 0);
-  EXPECT_EQ("Test short", *released);
-  EXPECT_EQ("", field_arena->Get());
-  EXPECT_NE(released, &field_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_NE(donating_states & ~kMask1, 0);  // still donated.
-#endif
-  delete released;
-
-  std::string* mut = field_arena->Mutable(
-      ArenaStringPtr::EmptyDefault{}, &arena,
-      /*donated=*/(donating_states & ~kMask1) != 0u, &donating_states, kMask1);
-  *mut = "Test long long long long value";
-  std::string* released2 =
-      field_arena->Release(&kDefaultValue, &arena,
-                           /*donated=*/(donating_states & ~kMask1) != 0);
-  EXPECT_EQ("Test long long long long value", *released2);
-  EXPECT_EQ("", field_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask1, 0);  // undonated.
-#endif
-  delete released2;
-}
-
-// Rvalue Set always undoantes a donated string.
-TEST(InlinedStringFieldTest, SetRvalueArena) {
-  Arena arena;
-  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  uint32 donating_states = ~0u;
-  const std::string kDefaultValue = "default";
-
-  std::string string_moved = "Moved long long long long string 1";
-  field1_arena->Set(nullptr, std::move(string_moved), &arena, true,
-                    &donating_states, kMask1);
-  EXPECT_EQ("Moved long long long long string 1", field1_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask1, 0);  // Undonate.
-#endif
-
-  field2_arena->Set(nullptr, std::string("string 2 on heap"), &arena, true,
-                    &donating_states, kMask);
-  EXPECT_EQ("string 2 on heap", field2_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask, 0);  // Undonated.
-#endif
-}
-
-// Tests SetAllocated for non-arena string fields and arena string fields.
-TEST(InlinedStringFieldTest, SetAllocated) {
-  InlinedStringField field;
-  Arena arena;
-  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  uint32 donating_states = ~0u;
-  const std::string kDefaultValue = "default";
-
-  // The string in field is on heap.
-  field.Set(&kDefaultValue, WrapString("String on heap"), nullptr, false,
-            &donating_states, kMask);
-  auto* allocated = new std::string("Allocated string on heap");
-  field.SetAllocatedNoArena(&kDefaultValue, allocated);
-  EXPECT_EQ("Allocated string on heap", field.Get());
-
-  // The string in field1_arena is on arena (aka. donated).
-  field1_arena->Set(&kDefaultValue, WrapString("String 1 on arena"), &arena,
-                    true, &donating_states, kMask1);
-  *field1_arena->Mutable(ArenaStringPtr::EmptyDefault{}, &arena,
-                         (donating_states & ~kMask1) != 0, &donating_states,
-                         kMask1) = "Mutated string 1 is now on heap long long";
-  // After Mutable, the string is undonated.
-  allocated = new std::string("Allocated string on heap long long long");
-  field1_arena->SetAllocated(&kDefaultValue, allocated, &arena,
-                             (donating_states & ~kMask1) != 0, &donating_states,
-                             kMask1);
-  EXPECT_EQ("Allocated string on heap long long long", field1_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask1, 0);  // Still undonated.
-#endif
-
-  // The string in field2_arena is on arena (aka. donated).
-  field2_arena->Set(&kDefaultValue, WrapString("String 2 on arena long long"),
-                    &arena, true, &donating_states,
-                    kMask2);  // Still donated.
-  allocated = new std::string("Allocated string on heap long long long 2");
-  field2_arena->SetAllocated(&kDefaultValue, allocated, &arena, true,
-                             &donating_states, kMask2);
-  EXPECT_EQ("Allocated string on heap long long long 2", field2_arena->Get());
-#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
-  EXPECT_EQ(donating_states & ~kMask2, 0);  // Undonated.
-#endif
-}
-
-// Tests Swap for non-arena string fields and arena string fields.
-TEST(InlinedStringFieldTest, Swap) {
-  // Swap should only be called when the from and to are on the same arena.
-  InlinedStringField field1;
-  InlinedStringField field2;
-  uint32 donating_states = 0;
-  Arena arena;
-  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
-  uint32 donating_states_1 = ~0u;
-  uint32 donating_states_2 = ~0u;
-  const std::string kDefaultValue = "default";
-
-  const std::string& string1_heap = "String 1 on heap";
-  const std::string& string2_heap = "String 2 on heap long long long long";
-  const std::string& string1_arena = "String 1 on arena";
-  const std::string& string2_arena = "String 2 on arena long long long long";
-  field1.SetNoArena(&kDefaultValue, string1_heap);
-  field2.SetNoArena(&kDefaultValue, string2_heap);
-  field1_arena->Set(&kDefaultValue, string1_arena, &arena, true,
-                    &donating_states_1, kMask1);
-  field2_arena->Set(&kDefaultValue, string2_arena, &arena, true,
-                    &donating_states_2, kMask1);
-
-  field1.Swap(&field2, &kDefaultValue, nullptr, false, false, &donating_states,
-              &donating_states_2, kMask);
-  field1_arena->Swap(field2_arena, &kDefaultValue, &arena, true, true,
-                     &donating_states_1, &donating_states_2, kMask1);
-  EXPECT_EQ(field1.Get(), string2_heap);
-  EXPECT_EQ(field2.Get(), string1_heap);
-  EXPECT_EQ(field1_arena->Get(), string2_arena);
-  EXPECT_EQ(field2_arena->Get(), string1_arena);
-}
-
 }  // namespace
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 20977b7..aacf007 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -54,6 +54,7 @@
 #include <google/protobuf/stubs/stl_util.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -196,7 +197,7 @@
       << total_bytes_limit_
       << " bytes).  To increase the limit (or to disable these "
          "warnings), see CodedInputStream::SetTotalBytesLimit() "
-         "in third_party/protobuf/src/google/protobuf/io/coded_stream.h.";
+         "in third_party/protobuf/io/coded_stream.h.";
 }
 
 bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
@@ -704,7 +705,7 @@
 uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) {
   if (had_error_) return ptr;
   int s = Flush(ptr);
-  if (s) stream_->BackUp(s);
+  stream_->BackUp(s);
   // Reset to initial state (expecting new buffer)
   buffer_end_ = end_ = buffer_;
   return buffer_;
@@ -929,18 +930,6 @@
 std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
     false};
 
-CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* stream,
-                                     bool do_eager_refresh)
-    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
-      start_count_(stream->ByteCount()) {
-  if (do_eager_refresh) {
-    void* data;
-    int size;
-    if (!stream->Next(&data, &size) || size == 0) return;
-    cur_ = impl_.SetInitialBuffer(data, size);
-  }
-}
-
 CodedOutputStream::~CodedOutputStream() { Trim(); }
 
 
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 45963ef..1024b40 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -158,6 +158,7 @@
 #include <google/protobuf/stubs/port.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -848,6 +849,7 @@
   bool had_error_ = false;
   bool aliasing_enabled_ = false;  // See EnableAliasing().
   bool is_serialization_deterministic_;
+  bool skip_check_consistency = false;
 
   uint8_t* EnsureSpaceFallback(uint8_t* ptr);
   inline uint8_t* Next();
@@ -1067,10 +1069,18 @@
 //   delete coded_output;
 class PROTOBUF_EXPORT CodedOutputStream {
  public:
-  // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
-  explicit CodedOutputStream(ZeroCopyOutputStream* stream)
-      : CodedOutputStream(stream, true) {}
-  CodedOutputStream(ZeroCopyOutputStream* stream, bool do_eager_refresh);
+  // Creates a CodedOutputStream that writes to the given `stream`.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  explicit CodedOutputStream(Stream* stream);
+
+  // Creates a CodedOutputStream that writes to the given `stream`, and does
+  // an 'eager initialization' of the internal state if `eager_init` is true.
+  // The provided stream must publicly derive from `ZeroCopyOutputStream`.
+  template <class Stream, class = typename std::enable_if<std::is_base_of<
+                              ZeroCopyOutputStream, Stream>::value>::type>
+  CodedOutputStream(Stream* stream, bool eager_init);
 
   // Destroy the CodedOutputStream and position the underlying
   // ZeroCopyOutputStream immediately after the last byte written.
@@ -1233,7 +1243,7 @@
   // remains live until all of the data has been consumed from the stream.
   void EnableAliasing(bool enabled) { impl_.EnableAliasing(enabled); }
 
-  // Indicate to the serializer whether the user wants derministic
+  // Indicate to the serializer whether the user wants deterministic
   // serialization. The default when this is not called comes from the global
   // default, controlled by SetDefaultSerializationDeterministic.
   //
@@ -1276,6 +1286,9 @@
   EpsCopyOutputStream* EpsCopy() { return &impl_; }
 
  private:
+  template <class Stream>
+  void InitEagerly(Stream* stream);
+
   EpsCopyOutputStream impl_;
   uint8_t* cur_;
   int64_t start_count_;
@@ -1620,6 +1633,31 @@
   return SkipFallback(count, original_buffer_size);
 }
 
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  InitEagerly(stream);
+}
+
+template <class Stream, class>
+inline CodedOutputStream::CodedOutputStream(Stream* stream, bool eager_init)
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
+  if (eager_init) {
+    InitEagerly(stream);
+  }
+}
+
+template <class Stream>
+inline void CodedOutputStream::InitEagerly(Stream* stream) {
+  void* data;
+  int size;
+  if (PROTOBUF_PREDICT_TRUE(stream->Next(&data, &size) && size > 0)) {
+    cur_ = impl_.SetInitialBuffer(data, size);
+  }
+}
+
 inline uint8_t* CodedOutputStream::WriteVarint32ToArray(uint32_t value,
                                                         uint8_t* target) {
   return EpsCopyOutputStream::UnsafeVarint(value, target);
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index 671bde9..6e45d04 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -49,6 +49,7 @@
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/casts.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 
diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc
index 2f1d26f..a5284b3 100644
--- a/src/google/protobuf/io/gzip_stream.cc
+++ b/src/google/protobuf/io/gzip_stream.cc
@@ -36,6 +36,7 @@
 
 #if HAVE_ZLIB
 #include <google/protobuf/io/gzip_stream.h>
+#include <google/protobuf/port.h>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
@@ -70,7 +71,7 @@
   output_position_ = output_buffer_;
 }
 GzipInputStream::~GzipInputStream() {
-  operator delete(output_buffer_);
+  internal::SizedDelete(output_buffer_, output_buffer_length_);
   zerror_ = inflateEnd(&zcontext_);
 }
 
@@ -244,7 +245,7 @@
 
 GzipOutputStream::~GzipOutputStream() {
   Close();
-  operator delete(input_buffer_);
+  internal::SizedDelete(input_buffer_, input_buffer_length_);
 }
 
 // private
diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h
index f0283e8..5dc7aa8 100644
--- a/src/google/protobuf/io/gzip_stream.h
+++ b/src/google/protobuf/io/gzip_stream.h
@@ -49,6 +49,7 @@
 #include <google/protobuf/port.h>
 #include <zlib.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -56,7 +57,8 @@
 namespace io {
 
 // A ZeroCopyInputStream that reads compressed data through zlib
-class PROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT GzipInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   // Format key for constructor
   enum Format {
@@ -104,7 +106,8 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
 };
 
-class PROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
+class PROTOBUF_EXPORT GzipOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
  public:
   // Format key for constructor
   enum Format {
diff --git a/src/google/protobuf/io/io_win32.cc b/src/google/protobuf/io/io_win32.cc
index ed8ab19..4e81908 100644
--- a/src/google/protobuf/io/io_win32.cc
+++ b/src/google/protobuf/io/io_win32.cc
@@ -397,7 +397,8 @@
       matched = ExpandWildcardsResult::kSuccess;
       string filename;
       if (!strings::wcs_to_utf8(metadata.cFileName, &filename)) {
-        return ExpandWildcardsResult::kErrorOutputPathConversion;
+        matched = ExpandWildcardsResult::kErrorOutputPathConversion;
+        break;
       }
 
       if (dirname.empty()) {
diff --git a/src/google/protobuf/io/io_win32.h b/src/google/protobuf/io/io_win32.h
index 7d11dc2..a72b4ea 100644
--- a/src/google/protobuf/io/io_win32.h
+++ b/src/google/protobuf/io/io_win32.h
@@ -53,6 +53,8 @@
 #include <string>
 
 #include <google/protobuf/port.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 // Compilers on Windows other than MSVC (e.g. Cygwin, MinGW32) define the
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index 230960c..47bd00b 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -66,8 +66,11 @@
       annotation_collector_(annotation_collector) {}
 
 Printer::~Printer() {
-  // Only BackUp() if we have called Next() at least once and never failed.
-  if (buffer_size_ > 0 && !failed_) {
+  // Only BackUp() if we invoked Next() at least once, and we have never failed.
+  // Note that we always call `Backup`, i.e. we call BackUp(0) as some output
+  // streams have buffered output, and BackUp() serves as a flush event in such
+  // implementations.
+  if (buffer_ != nullptr && !failed_) {
     output_->BackUp(buffer_size_);
   }
 }
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index e857cf0..92a4321 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -43,6 +43,8 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h
index f7b693e..4abab7e 100644
--- a/src/google/protobuf/io/tokenizer.h
+++ b/src/google/protobuf/io/tokenizer.h
@@ -43,6 +43,8 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/io/zero_copy_stream.h b/src/google/protobuf/io/zero_copy_stream.h
index d3bd6da..e2c9737 100644
--- a/src/google/protobuf/io/zero_copy_stream.h
+++ b/src/google/protobuf/io/zero_copy_stream.h
@@ -111,9 +111,11 @@
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/port_def.inc>
 
 
+// Must be included last.
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace io {
@@ -154,6 +156,13 @@
   // buffer that goes beyond what you wanted to read, you can use BackUp()
   // to return to the point where you intended to finish.
   //
+  // This method can be called with `count = 0` to finalize (flush) any
+  // previously returned buffer. For example, a file output stream can
+  // flush buffers returned from a previous call to Next() upon such
+  // BackUp(0) invocations. ZeroCopyOutputStream callers should always
+  // invoke BackUp() after a final Next() call, even if there is no
+  // excess buffer data to be backed up to indicate a flush point.
+  //
   // Preconditions:
   // * The last method called must have been Next().
   // * count must be less than or equal to the size of the last buffer
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h
index e6ba902..a385992 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -48,6 +48,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -62,7 +63,8 @@
 // The latter will introduce an extra layer of buffering, harming performance.
 // Also, it's conceivable that FileInputStream could someday be enhanced
 // to use zero-copy file descriptors on OSs which support them.
-class PROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT FileInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   // Creates a stream that reads from the given Unix file descriptor.
   // If a block_size is given, it specifies the number of bytes that
@@ -95,7 +97,8 @@
   int64_t ByteCount() const override;
 
  private:
-  class PROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
+  class PROTOBUF_EXPORT CopyingFileInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
    public:
     CopyingFileInputStream(int file_descriptor);
     ~CopyingFileInputStream() override;
@@ -139,7 +142,8 @@
 // harming performance.  Also, it's conceivable that FileOutputStream could
 // someday be enhanced to use zero-copy file descriptors on OSs which
 // support them.
-class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
+class PROTOBUF_EXPORT FileOutputStream PROTOBUF_FUTURE_FINAL
+    : public CopyingOutputStreamAdaptor {
  public:
   // Creates a stream that writes to the given Unix file descriptor.
   // If a block_size is given, it specifies the size of the buffers
@@ -168,7 +172,8 @@
   int GetErrno() const { return copying_output_.GetErrno(); }
 
  private:
-  class PROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
+  class PROTOBUF_EXPORT CopyingFileOutputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingOutputStream {
    public:
     CopyingFileOutputStream(int file_descriptor);
     ~CopyingFileOutputStream() override;
@@ -203,7 +208,8 @@
 //
 // Note that for reading files (or anything represented by a file descriptor),
 // FileInputStream is more efficient.
-class PROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT IstreamInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   // Creates a stream that reads from the given C++ istream.
   // If a block_size is given, it specifies the number of bytes that
@@ -218,7 +224,8 @@
   int64_t ByteCount() const override;
 
  private:
-  class PROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
+  class PROTOBUF_EXPORT CopyingIstreamInputStream PROTOBUF_FUTURE_FINAL
+      : public CopyingInputStream {
    public:
     CopyingIstreamInputStream(std::istream* input);
     ~CopyingIstreamInputStream() override;
@@ -246,7 +253,8 @@
 //
 // Note that for writing files (or anything represented by a file descriptor),
 // FileOutputStream is more efficient.
-class PROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
+class PROTOBUF_EXPORT OstreamOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
  public:
   // Creates a stream that writes to the given C++ ostream.
   // If a block_size is given, it specifies the size of the buffers
@@ -261,7 +269,7 @@
   int64_t ByteCount() const override;
 
  private:
-  class PROTOBUF_EXPORT CopyingOstreamOutputStream
+  class PROTOBUF_EXPORT CopyingOstreamOutputStream PROTOBUF_FUTURE_FINAL
       : public CopyingOutputStream {
    public:
     CopyingOstreamOutputStream(std::ostream* output);
@@ -292,7 +300,8 @@
 // ConcatenatingInputStream may do odd things.  It is suggested that you do
 // not use ConcatenatingInputStream on streams that might produce read errors
 // other than end-of-stream.
-class PROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT ConcatenatingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   // All streams passed in as well as the array itself must remain valid
   // until the ConcatenatingInputStream is destroyed.
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 dc4b1e9..b3dfd84 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -124,12 +124,11 @@
 }
 
 void ArrayOutputStream::BackUp(int count) {
-  GOOGLE_CHECK_GT(last_returned_size_, 0)
-      << "BackUp() can only be called after a successful Next().";
-  GOOGLE_CHECK_LE(count, last_returned_size_);
+  GOOGLE_CHECK_LE(count, last_returned_size_)
+      << "BackUp() can not exceed the size of the last Next() call.";
   GOOGLE_CHECK_GE(count, 0);
   position_ -= count;
-  last_returned_size_ = 0;  // Don't let caller back up further.
+  last_returned_size_ -= count;
 }
 
 int64_t ArrayOutputStream::ByteCount() const { return position_; }
@@ -328,6 +327,10 @@
 }
 
 void CopyingOutputStreamAdaptor::BackUp(int count) {
+  if (count == 0) {
+    Flush();
+    return;
+  }
   GOOGLE_CHECK_GE(count, 0);
   GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
       << " BackUp() can only be called after Next().";
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 9ee3691..cbda328 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -55,6 +55,7 @@
 #include <google/protobuf/stubs/stl_util.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -64,7 +65,8 @@
 // ===================================================================
 
 // A ZeroCopyInputStream backed by an in-memory array of bytes.
-class PROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT ArrayInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   // Create an InputStream that returns the bytes pointed to by "data".
   // "data" remains the property of the caller but must remain valid until
@@ -98,7 +100,8 @@
 // ===================================================================
 
 // A ZeroCopyOutputStream backed by an in-memory array of bytes.
-class PROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
+class PROTOBUF_EXPORT ArrayOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
  public:
   // Create an OutputStream that writes to the bytes pointed to by "data".
   // "data" remains the property of the caller but must remain valid until
@@ -130,7 +133,8 @@
 // ===================================================================
 
 // A ZeroCopyOutputStream which appends bytes to a string.
-class PROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
+class PROTOBUF_EXPORT StringOutputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyOutputStream {
  public:
   // Create a StringOutputStream which appends bytes to the given string.
   // The string remains property of the caller, but it is mutated in arbitrary
@@ -346,7 +350,8 @@
 
 // A ZeroCopyInputStream which wraps some other stream and limits it to
 // a particular byte count.
-class PROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
+class PROTOBUF_EXPORT LimitingInputStream PROTOBUF_FUTURE_FINAL
+    : public ZeroCopyInputStream {
  public:
   LimitingInputStream(ZeroCopyInputStream* input, int64_t limit);
   ~LimitingInputStream() override;
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index deb5f06..d4fe499 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -617,8 +617,9 @@
     MapLiteTestUtil::SetMapFields(&message1);
     size_t size = message1.ByteSizeLong();
     data.resize(size);
-    ::google::protobuf::uint8* start = reinterpret_cast<::google::protobuf::uint8*>(::google::protobuf::string_as_array(&data));
-    ::google::protobuf::uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    ::uint8_t* start =
+        reinterpret_cast<::uint8_t*>(::google::protobuf::string_as_array(&data));
+    ::uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
     EXPECT_EQ(size, end - start);
     EXPECT_TRUE(message2.ParseFromString(data));
     MapLiteTestUtil::ExpectMapFieldsSet(message2);
@@ -877,7 +878,8 @@
     protobuf_unittest::TestOneofParsingLite message2;
     message2.mutable_oneof_submessage();
     io::CodedInputStream input_stream(
-        reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()), serialized.size());
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
     EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
     EXPECT_EQ(17, message2.oneof_int32());
   }
@@ -887,7 +889,8 @@
     protobuf_unittest::TestOneofParsingLite message2;
     message2.set_oneof_string("string");
     io::CodedInputStream input_stream(
-        reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()), serialized.size());
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
     EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
     EXPECT_EQ(17, message2.oneof_int32());
   }
@@ -897,7 +900,8 @@
     protobuf_unittest::TestOneofParsingLite message2;
     message2.set_oneof_bytes("bytes");
     io::CodedInputStream input_stream(
-        reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()), serialized.size());
+        reinterpret_cast<const ::uint8_t*>(serialized.data()),
+        serialized.size());
     EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
     EXPECT_EQ(17, message2.oneof_int32());
   }
@@ -916,7 +920,7 @@
     protobuf_unittest::TestOneofParsingLite parsed;
     for (int i = 0; i < 2; ++i) {
       io::CodedInputStream input_stream(
-          reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()),
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
           serialized.size());
       EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
       EXPECT_EQ(17, parsed.oneof_int32());
@@ -932,7 +936,7 @@
     protobuf_unittest::TestOneofParsingLite parsed;
     for (int i = 0; i < 2; ++i) {
       io::CodedInputStream input_stream(
-          reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()),
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
           serialized.size());
       EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
       EXPECT_EQ(5, parsed.oneof_submessage().optional_int32());
@@ -948,7 +952,7 @@
     protobuf_unittest::TestOneofParsingLite parsed;
     for (int i = 0; i < 2; ++i) {
       io::CodedInputStream input_stream(
-          reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()),
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
           serialized.size());
       EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
       EXPECT_EQ("string", parsed.oneof_string());
@@ -964,7 +968,7 @@
     protobuf_unittest::TestOneofParsingLite parsed;
     for (int i = 0; i < 2; ++i) {
       io::CodedInputStream input_stream(
-          reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()),
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
           serialized.size());
       EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
       EXPECT_EQ("bytes", parsed.oneof_bytes());
@@ -980,7 +984,7 @@
     protobuf_unittest::TestOneofParsingLite parsed;
     for (int i = 0; i < 2; ++i) {
       io::CodedInputStream input_stream(
-          reinterpret_cast<const ::google::protobuf::uint8*>(serialized.data()),
+          reinterpret_cast<const ::uint8_t*>(serialized.data()),
           serialized.size());
       EXPECT_TRUE(parsed.MergeFromCodedStream(&input_stream));
       EXPECT_EQ(protobuf_unittest::V2_SECOND, parsed.oneof_enum());
@@ -997,7 +1001,7 @@
   protobuf_unittest::ForeignMessageLite a;
   EXPECT_TRUE(a.ParseFromString(data));
   io::CodedInputStream input_stream(
-      reinterpret_cast<const ::google::protobuf::uint8*>(data.data()), data.size());
+      reinterpret_cast<const ::uint8_t*>(data.data()), data.size());
   EXPECT_TRUE(a.MergePartialFromCodedStream(&input_stream));
 
   std::string serialized = a.SerializeAsString();
@@ -1059,7 +1063,7 @@
     // will not encounter an end-group tag. However the parser should behave
     // like any wire format parser should.
     static const char kWireFormat[] = "\204\1";
-    io::CodedInputStream cis(reinterpret_cast<const uint8*>(kWireFormat), 2);
+    io::CodedInputStream cis(reinterpret_cast<const uint8_t*>(kWireFormat), 2);
     // The old CodedInputStream parser got an optimization (ReadTagNoLastTag)
     // for non-group messages (like TestAllTypesLite) which made it not accept
     // end-group. This is not a real big deal, but I think going forward its
@@ -1072,7 +1076,7 @@
     // This is an incomplete end-group tag. This should be a genuine parse
     // failure.
     static const char kWireFormat[] = "\214";
-    io::CodedInputStream cis(reinterpret_cast<const uint8*>(kWireFormat), 1);
+    io::CodedInputStream cis(reinterpret_cast<const uint8_t*>(kWireFormat), 1);
     // Unfortunately the old parser detects a parse error in ReadTag and returns
     // 0 (as it states 0 is an invalid tag). However 0 is not an invalid tag
     // as it can be used to terminate the stream, so this returns true.
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 0708366..09d03b8 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -37,6 +37,7 @@
 #ifndef GOOGLE_PROTOBUF_MAP_H__
 #define GOOGLE_PROTOBUF_MAP_H__
 
+
 #include <functional>
 #include <initializer_list>
 #include <iterator>
@@ -58,12 +59,14 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/generated_enum_util.h>
 #include <google/protobuf/map_type_handler.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/stubs/hash.h>
 
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -115,6 +118,11 @@
   MapAllocator(const MapAllocator<X>& allocator)  // NOLINT(runtime/explicit)
       : arena_(allocator.arena()) {}
 
+  // MapAllocator does not support alignments beyond 8. Technically we should
+  // support up to std::max_align_t, but this fails with ubsan and tcmalloc
+  // debug allocation logic which assume 8 as default alignment.
+  static_assert(alignof(value_type) <= 8, "");
+
   pointer allocate(size_type n, const void* /* hint */ = nullptr) {
     // If arena is not given, malloc needs to be called which doesn't
     // construct element object.
@@ -128,12 +136,7 @@
 
   void deallocate(pointer p, size_type n) {
     if (arena_ == nullptr) {
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
-      ::operator delete(p, n * sizeof(value_type));
-#else
-      (void)n;
-      ::operator delete(p);
-#endif
+      internal::SizedDelete(p, n * sizeof(value_type));
     }
   }
 
@@ -334,7 +337,7 @@
 // std::pair as value_type, we use this class which provides us more control of
 // its process of construction and destruction.
 template <typename Key, typename T>
-struct MapPair {
+struct PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG MapPair {
   using first_type = const Key;
   using second_type = T;
 
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
index 2aec2d4..536dec9 100644
--- a/src/google/protobuf/map_entry.h
+++ b/src/google/protobuf/map_entry.h
@@ -31,14 +31,15 @@
 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_H__
 #define GOOGLE_PROTOBUF_MAP_ENTRY_H__
 
+#include <google/protobuf/port.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/map_entry_lite.h>
 #include <google/protobuf/map_type_handler.h>
-#include <google/protobuf/port.h>
 #include <google/protobuf/reflection_ops.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -93,14 +94,12 @@
 class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
                                      kKeyFieldType, kValueFieldType> {
  public:
-  constexpr MapEntry() : _internal_metadata_() {}
+  constexpr MapEntry() {}
   explicit MapEntry(Arena* arena)
       : MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
-                     kValueFieldType>(arena),
-        _internal_metadata_(arena) {}
-  ~MapEntry() {
+                     kValueFieldType>(arena) {}
+  ~MapEntry() override {
     Message::_internal_metadata_.template Delete<UnknownFieldSet>();
-    _internal_metadata_.Delete<UnknownFieldSet>();
   }
   typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
@@ -117,8 +116,6 @@
     return size;
   }
 
-  InternalMetadata _internal_metadata_;
-
  private:
   friend class ::PROTOBUF_NAMESPACE_ID::Arena;
   template <typename C, typename K, typename V,
@@ -128,29 +125,6 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
 };
 
-// Specialization for the full runtime
-template <typename Derived, typename Key, typename Value,
-          WireFormatLite::FieldType kKeyFieldType,
-          WireFormatLite::FieldType kValueFieldType>
-struct MapEntryHelper<
-    MapEntry<Derived, Key, Value, kKeyFieldType, kValueFieldType> >
-    : MapEntryHelper<
-          MapEntryLite<Derived, Key, Value, kKeyFieldType, kValueFieldType> > {
-  explicit MapEntryHelper(const MapPair<Key, Value>& map_pair)
-      : MapEntryHelper<
-            MapEntryLite<Derived, Key, Value, kKeyFieldType, kValueFieldType> >(
-            map_pair) {}
-};
-
-template <typename Derived, typename K, typename V,
-          WireFormatLite::FieldType key, WireFormatLite::FieldType value>
-struct DeconstructMapEntry<MapEntry<Derived, K, V, key, value> > {
-  typedef K Key;
-  typedef V Value;
-  static constexpr WireFormatLite::FieldType kKeyFieldType = key;
-  static constexpr WireFormatLite::FieldType kValueFieldType = value;
-};
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 34b185b..6b08cd9 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -32,19 +32,23 @@
 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
 
 #include <assert.h>
+
+#include <algorithm>
 #include <string>
+#include <utility>
 
 #include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/map.h>
 #include <google/protobuf/map_type_handler.h>
-#include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
@@ -97,44 +101,6 @@
   }
 };
 
-// Functions for operating on a map entry.  Does not contain any representation
-// (this class is not intended to be instantiated).
-template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
-          WireFormatLite::FieldType kValueFieldType>
-struct MapEntryFuncs {
-  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
-  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
-  static const int kKeyFieldNumber = 1;
-  static const int kValueFieldNumber = 2;
-
-  static uint8_t* InternalSerialize(int field_number, const Key& key,
-                                    const Value& value, uint8_t* ptr,
-                                    io::EpsCopyOutputStream* stream) {
-    ptr = stream->EnsureSpace(ptr);
-    ptr = WireFormatLite::WriteTagToArray(
-        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
-    ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
-                                                      ptr);
-
-    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
-    return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
-  }
-
-  static size_t ByteSizeLong(const Key& key, const Value& value) {
-    // Tags for key and value will both be one byte (field numbers 1 and 2).
-    size_t inner_length =
-        2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
-    return inner_length + io::CodedOutputStream::VarintSize32(
-                              static_cast<uint32_t>(inner_length));
-  }
-
-  static int GetCachedSize(const Key& key, const Value& value) {
-    // Tags for key and value will both be one byte (field numbers 1 and 2).
-    return 2 + KeyTypeHandler::GetCachedSize(key) +
-           ValueTypeHandler::GetCachedSize(value);
-  }
-};
-
 // MapEntryImpl is used to implement parsing and serialization of map entries.
 // It uses Curious Recursive Template Pattern (CRTP) to provide the type of
 // the eventual code to the template code.
@@ -193,7 +159,7 @@
         value_(ValueTypeHandler::Constinit()),
         _has_bits_{} {}
 
-  ~MapEntryImpl() {
+  ~MapEntryImpl() override {
     if (Base::GetArenaForAllocation() != nullptr) return;
     KeyTypeHandler::DeleteNoArena(key_);
     ValueTypeHandler::DeleteNoArena(value_);
@@ -329,51 +295,6 @@
         delete entry_;
     }
 
-    // This does what the typical MergePartialFromCodedStream() is expected to
-    // do, with the additional side-effect that if successful (i.e., if true is
-    // going to be its return value) it inserts the key-value pair into map_.
-    bool MergePartialFromCodedStream(io::CodedInputStream* input) {
-      // Look for the expected thing: a key and then a value.  If it fails,
-      // invoke the enclosing class's MergePartialFromCodedStream, or return
-      // false if that would be pointless.
-      if (input->ExpectTag(kKeyTag)) {
-        if (!KeyTypeHandler::Read(input, &key_)) {
-          return false;
-        }
-        // Peek at the next byte to see if it is kValueTag.  If not, bail out.
-        const void* data;
-        int size;
-        input->GetDirectBufferPointerInline(&data, &size);
-        // We could use memcmp here, but we don't bother. The tag is one byte.
-        static_assert(kTagSize == 1, "tag size must be 1");
-        if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
-          typename Map::size_type map_size = map_->size();
-          value_ptr_ = &(*map_)[key_];
-          if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
-            // We created a new key-value pair.  Fill in the value.
-            typedef
-                typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
-            input->Skip(kTagSize);  // Skip kValueTag.
-            if (!ValueTypeHandler::Read(input,
-                                        reinterpret_cast<T>(value_ptr_))) {
-              map_->erase(key_);  // Failure! Undo insertion.
-              return false;
-            }
-            if (input->ExpectAtEnd()) return true;
-            return ReadBeyondKeyValuePair(input);
-          }
-        }
-      } else {
-        key_ = Key();
-      }
-
-      NewEntry();
-      *entry_->mutable_key() = key_;
-      const bool result = entry_->MergePartialFromCodedStream(input);
-      if (result) UseKeyAndValueFromEntry();
-      return result;
-    }
-
     const char* _InternalParse(const char* ptr, ParseContext* ctx) {
       if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
         ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
@@ -493,7 +414,7 @@
  public:
   inline Arena* GetArena() const { return Base::GetArena(); }
 
- public:  // Needed for constructing tables
+ protected:  // Needed for constructing tables
   KeyOnMemory key_;
   ValueOnMemory value_;
   uint32_t _has_bits_[1];
@@ -523,7 +444,7 @@
       SuperType;
   constexpr MapEntryLite() {}
   explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
-  ~MapEntryLite() {
+  ~MapEntryLite() override {
     MessageLite::_internal_metadata_.template Delete<std::string>();
   }
   void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
@@ -531,118 +452,106 @@
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
 };
-// The completely unprincipled and unwieldy use of template parameters in
-// the map code necessitates wrappers to make the code a little bit more
-// manageable.
-template <typename Derived>
-struct DeconstructMapEntry;
-
-template <typename T, typename K, typename V, WireFormatLite::FieldType key,
-          WireFormatLite::FieldType value>
-struct DeconstructMapEntry<MapEntryLite<T, K, V, key, value> > {
-  typedef K Key;
-  typedef V Value;
-  static const WireFormatLite::FieldType kKeyFieldType = key;
-  static const WireFormatLite::FieldType kValueFieldType = value;
-};
 
 // Helpers for deterministic serialization =============================
 
-// This struct can be used with any generic sorting algorithm.  If the Key
-// type is relatively small and easy to copy then copying Keys into an
-// array of SortItems can be beneficial.  Then all the data the sorting
-// algorithm needs to touch is in that one array.
-template <typename Key, typename PtrToKeyValuePair>
-struct SortItem {
-  SortItem() {}
-  explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {}
-
-  Key first;
-  PtrToKeyValuePair second;
+// Iterator base for MapSorterFlat and MapSorterPtr.
+template <typename storage_type>
+struct MapSorterIt {
+  storage_type* ptr;
+  MapSorterIt(storage_type* ptr) : ptr(ptr) {}
+  bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; }
+  bool operator!=(const MapSorterIt& other) const { return !(*this == other); }
+  MapSorterIt& operator++() { ++ptr; return *this; }
+  MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; }
+  MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; }
 };
 
-template <typename T>
-struct CompareByFirstField {
-  bool operator()(const T& a, const T& b) const { return a.first < b.first; }
-};
+// MapSorterFlat stores keys inline with pointers to map entries, so that
+// keys can be compared without indirection. This type is used for maps with
+// keys that are not strings.
+template <typename MapT>
+class MapSorterFlat {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = std::pair<typename MapT::key_type, const value_type*>;
 
-template <typename T>
-struct CompareByDerefFirst {
-  bool operator()(const T& a, const T& b) const { return a->first < b->first; }
-};
+  // This const_iterator dereferenes to the map entry stored in the sorting
+  // array pairs. This is the same interface as the Map::const_iterator type,
+  // and allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterFlat(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
 
-// Helper for table driven serialization
+    pointer operator->() const { return this->ptr->second; }
+    reference operator*() const { return *this->operator->(); }
+  };
 
-template <WireFormatLite::FieldType FieldType>
-struct FromHelper {
-  template <typename T>
-  static const T& From(const T& x) {
-    return x;
+  explicit MapSorterFlat(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = {entry.first, &entry};
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a.first < b.first;
+              });
   }
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
+
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
 };
 
-template <>
-struct FromHelper<WireFormatLite::TYPE_STRING> {
-  static ArenaStringPtr From(const std::string& x) {
-    ArenaStringPtr res;
-    TaggedPtr<std::string> ptr;
-    ptr.Set(const_cast<std::string*>(&x));
-    res.UnsafeSetTaggedPointer(ptr);
-    return res;
+// MapSorterPtr stores and sorts pointers to map entries. This type is used for
+// maps with keys that are strings.
+template <typename MapT>
+class MapSorterPtr {
+ public:
+  using value_type = typename MapT::value_type;
+  using storage_type = const typename MapT::value_type*;
+
+  // This const_iterator dereferenes the map entry pointer stored in the sorting
+  // array. This is the same interface as the Map::const_iterator type, and
+  // allows generated code to use the same loop body with either form:
+  //   for (const auto& entry : map) { ... }
+  //   for (const auto& entry : MapSorterPtr(map)) { ... }
+  struct const_iterator : public MapSorterIt<storage_type> {
+    using pointer = const typename MapT::value_type*;
+    using reference = const typename MapT::value_type&;
+    using MapSorterIt<storage_type>::MapSorterIt;
+
+    pointer operator->() const { return *this->ptr; }
+    reference operator*() const { return *this->operator->(); }
+  };
+
+  explicit MapSorterPtr(const MapT& m)
+      : size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
+    if (!size_) return;
+    storage_type* it = &items_[0];
+    for (const auto& entry : m) {
+      *it++ = &entry;
+    }
+    std::sort(&items_[0], &items_[size_],
+              [](const storage_type& a, const storage_type& b) {
+                return a->first < b->first;
+              });
   }
-};
-template <>
-struct FromHelper<WireFormatLite::TYPE_BYTES> {
-  static ArenaStringPtr From(const std::string& x) {
-    ArenaStringPtr res;
-    TaggedPtr<std::string> ptr;
-    ptr.Set(const_cast<std::string*>(&x));
-    res.UnsafeSetTaggedPointer(ptr);
-    return res;
-  }
-};
-template <>
-struct FromHelper<WireFormatLite::TYPE_MESSAGE> {
-  template <typename T>
-  static T* From(const T& x) {
-    return const_cast<T*>(&x);
-  }
-};
+  size_t size() const { return size_; }
+  const_iterator begin() const { return {items_.get()}; }
+  const_iterator end() const { return {items_.get() + size_}; }
 
-template <typename MapEntryType>
-struct MapEntryHelper;
-
-template <typename T, typename Key, typename Value,
-          WireFormatLite::FieldType kKeyFieldType,
-          WireFormatLite::FieldType kValueFieldType>
-struct MapEntryHelper<
-    MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType> > {
-  // Provide utilities to parse/serialize key/value.  Provide utilities to
-  // manipulate internal stored type.
-  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
-  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
-
-  // Define internal memory layout. Strings and messages are stored as
-  // pointers, while other types are stored as values.
-  typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
-  typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
-
-  explicit MapEntryHelper(const MapPair<Key, Value>& map_pair)
-      : _has_bits_(3),
-        _cached_size_(2 + KeyTypeHandler::GetCachedSize(map_pair.first) +
-                      ValueTypeHandler::GetCachedSize(map_pair.second)),
-        key_(FromHelper<kKeyFieldType>::From(map_pair.first)),
-        value_(FromHelper<kValueFieldType>::From(map_pair.second)) {}
-
-  // Purposely not following the style guide naming. These are the names
-  // the proto compiler would generate given the map entry descriptor.
-  // The proto compiler generates the offsets in this struct as if this was
-  // a regular message. This way the table driven code barely notices it's
-  // dealing with a map field.
-  uint32_t _has_bits_;     // NOLINT
-  uint32_t _cached_size_;  // NOLINT
-  KeyOnMemory key_;      // NOLINT
-  ValueOnMemory value_;  // NOLINT
+ private:
+  size_t size_;
+  std::unique_ptr<storage_type[]> items_;
 };
 
 }  // namespace internal
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index 367cc2a..ed662df 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -29,18 +29,23 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <google/protobuf/map_field.h>
-#include <google/protobuf/map_field_inl.h>
 
 #include <vector>
 
+#include <google/protobuf/map_field_inl.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
 namespace internal {
 
-MapFieldBase::~MapFieldBase() {
-  if (repeated_field_ != nullptr && arena_ == nullptr) delete repeated_field_;
+void MapFieldBase::Destruct() {
+  if (arena_ == nullptr) {
+    delete repeated_field_;
+  }
+  repeated_field_ = nullptr;
 }
 
 const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
@@ -219,13 +224,15 @@
       default_entry_(default_entry) {}
 
 DynamicMapField::~DynamicMapField() {
-  if (arena_ != nullptr) return;
-  // DynamicMapField owns map values. Need to delete them before clearing the
-  // map.
-  for (auto& kv : map_) {
-    kv.second.DeleteData();
+  if (arena_ == nullptr) {
+    // DynamicMapField owns map values. Need to delete them before clearing the
+    // map.
+    for (auto& kv : map_) {
+      kv.second.DeleteData();
+    }
+    map_.clear();
   }
-  map_.clear();
+  Destruct();
 }
 
 int DynamicMapField::size() const { return GetMap().size(); }
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 19b73ca..5bf54d4 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -35,6 +35,8 @@
 #include <functional>
 
 #include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/mutex.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/generated_message_util.h>
@@ -42,12 +44,11 @@
 #include <google/protobuf/map_field_lite.h>
 #include <google/protobuf/map_type_handler.h>
 #include <google/protobuf/message.h>
-#include <google/protobuf/stubs/mutex.h>
-#include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -59,6 +60,13 @@
 class DynamicMessage;
 class MapIterator;
 
+// Microsoft compiler complains about non-virtual destructor,
+// even when the destructor is private.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4265)
+#endif  // _MSC_VER
+
 #define TYPE_CHECK(EXPECTEDTYPE, METHOD)                                   \
   if (type() != EXPECTEDTYPE) {                                            \
     GOOGLE_LOG(FATAL) << "Protocol Buffer map usage error:\n"                     \
@@ -337,8 +345,14 @@
         state_(STATE_MODIFIED_MAP) {}
   explicit MapFieldBase(Arena* arena)
       : arena_(arena), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
-  virtual ~MapFieldBase();
 
+ protected:
+  ~MapFieldBase() {  // "protected" stops users from deleting a `MapFieldBase *`
+    GOOGLE_DCHECK(repeated_field_ == nullptr);
+  }
+  void Destruct();
+
+ public:
   // Returns reference to internal repeated field. Data written using
   // Map's api prior to calling this function is guarantted to be
   // included in repeated field.
@@ -486,7 +500,12 @@
   explicit constexpr TypeDefinedMapFieldBase(ConstantInitialized tag)
       : MapFieldBase(tag) {}
   explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {}
-  ~TypeDefinedMapFieldBase() override {}
+
+ protected:
+  ~TypeDefinedMapFieldBase() {}
+  using MapFieldBase::Destruct;
+
+ public:
   void MapBegin(MapIterator* map_iter) const override;
   void MapEnd(MapIterator* map_iter) const override;
   bool EqualIterator(const MapIterator& a, const MapIterator& b) const override;
@@ -536,10 +555,14 @@
   typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
 
  public:
-  typedef typename Derived::SuperType EntryTypeTrait;
   typedef Map<Key, T> MapType;
 
-  MapField() {}
+  MapField() : impl_() {}
+  virtual ~MapField() {}  // Destruct() must already have been called!
+  void Destruct() {
+    impl_.Destruct();
+    TypeDefinedMapFieldBase<Key, T>::Destruct();
+  }
 
   // This constructor is for constant initialized global instances.
   // It uses a linker initialized mutex, so it is not compatible with regular
@@ -579,16 +602,6 @@
   // Used in the implementation of parsing. Caller should take the ownership iff
   // arena_ is nullptr.
   EntryType* NewEntry() const { return impl_.NewEntry(); }
-  // Used in the implementation of serializing enum value type. Caller should
-  // take the ownership iff arena_ is nullptr.
-  EntryType* NewEnumEntryWrapper(const Key& key, const T t) const {
-    return impl_.NewEnumEntryWrapper(key, t);
-  }
-  // Used in the implementation of serializing other value types. Caller should
-  // take the ownership iff arena_ is nullptr.
-  EntryType* NewEntryWrapper(const Key& key, const T& t) const {
-    return impl_.NewEntryWrapper(key, t);
-  }
 
   const char* _InternalParse(const char* ptr, ParseContext* ctx) {
     return impl_._InternalParse(ptr, ctx);
@@ -645,7 +658,7 @@
  public:
   explicit DynamicMapField(const Message* default_entry);
   DynamicMapField(const Message* default_entry, Arena* arena);
-  ~DynamicMapField() override;
+  virtual ~DynamicMapField();
 
   // Implement MapFieldBase
   bool ContainsMapKey(const MapKey& map_key) const override;
@@ -918,6 +931,10 @@
 }  // namespace protobuf
 }  // namespace google
 
+#ifdef _MSC_VER
+#pragma warning(pop)  // restore warning C4265
+#endif                // _MSC_VER
+
 #include <google/protobuf/port_undef.inc>
 
 #endif  // GOOGLE_PROTOBUF_MAP_FIELD_H__
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index 255a0bc..c114453 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -32,13 +32,15 @@
 #define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
 
 #include <type_traits>
-#include <google/protobuf/parse_context.h>
+
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/map.h>
 #include <google/protobuf/map_entry_lite.h>
-#include <google/protobuf/port.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -49,6 +51,10 @@
 namespace protobuf {
 namespace internal {
 
+#ifndef NDEBUG
+void MapFieldLiteNotDestructed(void* map_field_lite);
+#endif
+
 // This class provides access to map field using generated api. It is used for
 // internal generated message implementation only. Users should never use this
 // directly.
@@ -61,12 +67,29 @@
 
  public:
   typedef Map<Key, T> MapType;
-  typedef EntryType EntryTypeTrait;
 
-  constexpr MapFieldLite() {}
-
+  constexpr MapFieldLite() : map_() {}
   explicit MapFieldLite(Arena* arena) : map_(arena) {}
 
+#ifdef NDEBUG
+  void Destruct() { map_.~Map(); }
+  ~MapFieldLite() {}
+#else
+  void Destruct() {
+    // We want to destruct the map in such a way that we can verify
+    // that we've done that, but also be sure that we've deallocated
+    // everything (as opposed to leaving an allocation behind with no
+    // data in it, as would happen if a vector was resize'd to zero.
+    // Map::Swap with an empty map accomplishes that.
+    decltype(map_) swapped_map(map_.arena());
+    map_.InternalSwap(swapped_map);
+  }
+  ~MapFieldLite() {
+    if (map_.arena() == nullptr && !map_.empty()) {
+      MapFieldLiteNotDestructed(this);
+    }
+  }
+#endif
   // Accessors
   const Map<Key, T>& GetMap() const { return map_; }
   Map<Key, T>* MutableMap() { return &map_; }
@@ -88,16 +111,6 @@
   EntryType* NewEntry() const {
     return Arena::CreateMessage<EntryType>(map_.arena());
   }
-  // Used in the implementation of serializing enum value type. Caller should
-  // take the ownership iff arena_ is nullptr.
-  EntryType* NewEnumEntryWrapper(const Key& key, const T t) const {
-    return EntryType::EnumWrap(key, t, map_.arena_);
-  }
-  // Used in the implementation of serializing other value types. Caller should
-  // take the ownership iff arena_ is nullptr.
-  EntryType* NewEntryWrapper(const Key& key, const T& t) const {
-    return EntryType::Wrap(key, t, map_.arena_);
-  }
 
   const char* _InternalParse(const char* ptr, ParseContext* ctx) {
     typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
@@ -116,7 +129,11 @@
  private:
   typedef void DestructorSkippable_;
 
-  Map<Key, T> map_;
+  // map_ is inside an anonymous union so we can explicitly control its
+  // destruction
+  union {
+    Map<Key, T> map_;
+  };
 
   friend class ::PROTOBUF_NAMESPACE_ID::Arena;
 };
@@ -175,6 +192,13 @@
       MapFieldType;
 };
 
+#ifndef NDEBUG
+inline PROTOBUF_NOINLINE void MapFieldLiteNotDestructed(void* map_field_lite) {
+  bool proper_destruct = false;
+  GOOGLE_CHECK(proper_destruct) << map_field_lite;
+}
+#endif
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index cfc08f4..846f47c 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -55,11 +55,21 @@
 
 using unittest::TestAllTypes;
 
+// ArenaHolder from map_test_util.h works fine for fields other than map
+// fields.  For map fields, the Destruct() call must be made before the
+// actual destructor is called.
+template <typename MapType>
+struct ArenaDestructor : ArenaHolder<MapType> {
+  using ArenaHolder<MapType>::ArenaHolder;
+  ~ArenaDestructor() { ArenaHolder<MapType>::get()->Destruct(); }
+};
+
 class MapFieldBaseStub : public MapFieldBase {
  public:
   typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
   MapFieldBaseStub() {}
+  virtual ~MapFieldBaseStub() { MapFieldBase::Destruct(); }
   explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
   // Get underlined repeated field without synchronizing map.
   RepeatedPtrField<Message>* InternalRepeatedField() { return repeated_field_; }
@@ -110,7 +120,7 @@
 class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {
  protected:
   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
-  typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
+  typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
                    WireFormatLite::TYPE_INT32>
       MapFieldType;
 
@@ -135,13 +145,14 @@
   }
 
   std::unique_ptr<Arena> arena_;
-  ArenaHolder<MapFieldType> map_field_;
+  ArenaDestructor<MapFieldType> map_field_;
   MapFieldBase* map_field_base_;
-  Map<int32, int32>* map_;
+  Map<int32_t, int32_t>* map_;
   const Descriptor* map_descriptor_;
   const FieldDescriptor* key_descriptor_;
   const FieldDescriptor* value_descriptor_;
-  std::map<int32, int32> initial_value_map_;  // copy of initial values inserted
+  std::map<int32_t, int32_t>
+      initial_value_map_;  // copy of initial values inserted
 };
 
 INSTANTIATE_TEST_SUITE_P(MapFieldBasePrimitiveTestInstance,
@@ -229,7 +240,7 @@
     : public testing::TestWithParam<std::tuple<State, bool>> {
  protected:
   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
-  typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
+  typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
                    WireFormatLite::TYPE_INT32>
       MapFieldType;
   MapFieldStateTest()
@@ -256,14 +267,14 @@
 
   void AddOneStillClean(MapFieldType* map_field) {
     MapFieldBase* map_field_base = map_field;
-    Map<int32, int32>* map = map_field->MutableMap();
+    Map<int32_t, int32_t>* map = map_field->MutableMap();
     (*map)[0] = 0;
     map_field_base->GetRepeatedField();
     Expect(map_field, CLEAN, 1, 1, false);
   }
 
   void MakeMapDirty(MapFieldType* map_field) {
-    Map<int32, int32>* map = map_field->MutableMap();
+    Map<int32_t, int32_t>* map = map_field->MutableMap();
     (*map)[0] = 0;
     Expect(map_field, MAP_DIRTY, 1, 0, true);
   }
@@ -273,7 +284,7 @@
     MapFieldBase* map_field_base = map_field;
     map_field_base->MutableRepeatedField();
     // We use MutableMap on impl_ because we don't want to disturb the syncing
-    Map<int32, int32>* map = map_field->impl_.MutableMap();
+    Map<int32_t, int32_t>* map = map_field->impl_.MutableMap();
     map->clear();
 
     Expect(map_field, REPEATED_DIRTY, 0, 1, false);
@@ -286,7 +297,7 @@
         reinterpret_cast<MapFieldBaseStub*>(map_field_base);
 
     // We use MutableMap on impl_ because we don't want to disturb the syncing
-    Map<int32, int32>* map = map_field->impl_.MutableMap();
+    Map<int32_t, int32_t>* map = map_field->impl_.MutableMap();
     RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
 
     switch (state) {
@@ -319,7 +330,7 @@
   }
 
   std::unique_ptr<Arena> arena_;
-  ArenaHolder<MapFieldType> map_field_;
+  ArenaDestructor<MapFieldType> map_field_;
   MapFieldBase* map_field_base_;
   State state_;
 };
@@ -348,7 +359,7 @@
 }
 
 TEST_P(MapFieldStateTest, MergeFromClean) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   AddOneStillClean(other.get());
 
   map_field_->MergeFrom(*other);
@@ -363,7 +374,7 @@
 }
 
 TEST_P(MapFieldStateTest, MergeFromMapDirty) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   MakeMapDirty(other.get());
 
   map_field_->MergeFrom(*other);
@@ -378,7 +389,7 @@
 }
 
 TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   MakeRepeatedDirty(other.get());
 
   map_field_->MergeFrom(*other);
@@ -393,7 +404,7 @@
 }
 
 TEST_P(MapFieldStateTest, SwapClean) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   AddOneStillClean(other.get());
 
   map_field_->Swap(other.get());
@@ -416,7 +427,7 @@
 }
 
 TEST_P(MapFieldStateTest, SwapMapDirty) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   MakeMapDirty(other.get());
 
   map_field_->Swap(other.get());
@@ -439,7 +450,7 @@
 }
 
 TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
-  ArenaHolder<MapFieldType> other(arena_.get());
+  ArenaDestructor<MapFieldType> other(arena_.get());
   MakeRepeatedDirty(other.get());
 
   map_field_->Swap(other.get());
@@ -506,8 +517,8 @@
 }
 
 class MyMapField
-    : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32,
-                      int32, internal::WireFormatLite::TYPE_INT32,
+    : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32_t,
+                      int32_t, internal::WireFormatLite::TYPE_INT32,
                       internal::WireFormatLite::TYPE_INT32> {
  public:
   constexpr MyMapField()
diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto
index cc00dee..7f10431 100644
--- a/src/google/protobuf/map_lite_unittest.proto
+++ b/src/google/protobuf/map_lite_unittest.proto
@@ -120,6 +120,10 @@
   required int32 a = 1;
   required int32 b = 2;
   required int32 c = 3;
+
+  extend TestAllExtensionsLite {
+    optional TestRequiredLite single = 1000;
+  }
 }
 
 message ForeignMessageArenaLite {
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index c9be28b..f7c024c 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -55,6 +55,29 @@
 namespace {
 
 
+struct AlignedAsDefault {
+  int x;
+};
+struct alignas(8) AlignedAs8 {
+  int x;
+};
+
+template <typename Aligned, bool on_arena = false>
+void MapTest_Aligned() {
+  Arena arena;
+  constexpr size_t align_mask = alignof(Aligned) - 1;
+  Map<int, Aligned> map(on_arena ? &arena : nullptr);
+  map.insert({1, Aligned{}});
+  auto it = map.find(1);
+  ASSERT_NE(it, map.end());
+  ASSERT_EQ(reinterpret_cast<intptr_t>(&it->second) & align_mask, 0);
+  map.clear();
+}
+
+TEST(MapTest, Aligned) { MapTest_Aligned<AlignedAsDefault>(); }
+TEST(MapTest, AlignedOnArena) { MapTest_Aligned<AlignedAsDefault, true>(); }
+TEST(MapTest, Aligned8) { MapTest_Aligned<AlignedAs8>(); }
+TEST(MapTest, Aligned8OnArena) { MapTest_Aligned<AlignedAs8, true>(); }
 
 
 }  // namespace
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
index ed75c6f..1f13106 100644
--- a/src/google/protobuf/map_test.inc
+++ b/src/google/protobuf/map_test.inc
@@ -48,7 +48,6 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/test_util2.h>
@@ -99,29 +98,29 @@
 class MapImplTest : public ::testing::Test {
  protected:
   MapImplTest()
-      : map_ptr_(new Map<int32, int32>()),
+      : map_ptr_(new Map<int32_t, int32_t>()),
         map_(*map_ptr_),
         const_map_(*map_ptr_) {
     EXPECT_TRUE(map_.empty());
     EXPECT_EQ(0, map_.size());
   }
 
-  void ExpectSingleElement(int32 key, int32 value) {
+  void ExpectSingleElement(int32_t key, int32_t value) {
     EXPECT_FALSE(map_.empty());
     EXPECT_EQ(1, map_.size());
     ExpectElement(key, value);
   }
 
-  void ExpectElements(const std::map<int32, int32>& map) {
+  void ExpectElements(const std::map<int32_t, int32_t>& map) {
     EXPECT_FALSE(map_.empty());
     EXPECT_EQ(map.size(), map_.size());
-    for (std::map<int32, int32>::const_iterator it = map.begin();
+    for (std::map<int32_t, int32_t>::const_iterator it = map.begin();
          it != map.end(); ++it) {
       ExpectElement(it->first, it->second);
     }
   }
 
-  void ExpectElement(int32 key, int32 value) {
+  void ExpectElement(int32_t key, int32_t value) {
     // Test map size is correct.
     EXPECT_EQ(value, map_[key]);
     EXPECT_EQ(1, map_.count(key));
@@ -129,7 +128,7 @@
 
     // Check mutable at and find work correctly.
     EXPECT_EQ(value, map_.at(key));
-    Map<int32, int32>::iterator it = map_.find(key);
+    Map<int32_t, int32_t>::iterator it = map_.find(key);
 
     // iterator dereferenceable
     EXPECT_EQ(key, (*it).first);
@@ -149,7 +148,7 @@
     EXPECT_EQ(value, map_[key]);
 
     // copy constructor
-    Map<int32, int32>::iterator it_copy = it;
+    Map<int32_t, int32_t>::iterator it_copy = it;
     EXPECT_EQ(key, it_copy->first);
     EXPECT_EQ(value, it_copy->second);
 
@@ -157,7 +156,7 @@
 
     // Check immutable at and find work correctly.
     EXPECT_EQ(value, const_map_.at(key));
-    Map<int32, int32>::const_iterator const_it = const_map_.find(key);
+    Map<int32_t, int32_t>::const_iterator const_it = const_map_.find(key);
 
     // iterator dereferenceable
     EXPECT_EQ(key, (*const_it).first);
@@ -166,20 +165,20 @@
     EXPECT_EQ(value, const_it->second);
 
     // copy constructor
-    Map<int32, int32>::const_iterator const_it_copy = const_it;
+    Map<int32_t, int32_t>::const_iterator const_it_copy = const_it;
     EXPECT_EQ(key, const_it_copy->first);
     EXPECT_EQ(value, const_it_copy->second);
   }
 
-  std::unique_ptr<Map<int32, int32> > map_ptr_;
-  Map<int32, int32>& map_;
-  const Map<int32, int32>& const_map_;
+  std::unique_ptr<Map<int32_t, int32_t>> map_ptr_;
+  Map<int32_t, int32_t>& map_;
+  const Map<int32_t, int32_t>& const_map_;
 };
 
 TEST_F(MapImplTest, OperatorBracket) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
   EXPECT_EQ(0, map_[key]);
 
@@ -247,17 +246,17 @@
 }
 
 TEST_F(MapImplTest, OperatorBracketNonExist) {
-  int32 key = 0;
-  int32 default_value = 0;
+  int32_t key = 0;
+  int32_t default_value = 0;
 
   EXPECT_EQ(default_value, map_[key]);
   ExpectSingleElement(key, default_value);
 }
 
 TEST_F(MapImplTest, MutableAt) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
   map_[key] = value1;
   ExpectSingleElement(key, value1);
@@ -326,20 +325,20 @@
     map_[i] = i;
   }
 
-  for (Map<int32, int32>::const_iterator it = map_.cbegin();
+  for (Map<int32_t, int32_t>::const_iterator it = map_.cbegin();
        it != map_.cend();) {
-    Map<int32, int32>::const_reference entry = *it++;
+    Map<int32_t, int32_t>::const_reference entry = *it++;
     EXPECT_EQ(entry.first, entry.second);
   }
 
-  for (Map<int32, int32>::const_iterator it = const_map_.begin();
+  for (Map<int32_t, int32_t>::const_iterator it = const_map_.begin();
        it != const_map_.end();) {
-    Map<int32, int32>::const_reference entry = *it++;
+    Map<int32_t, int32_t>::const_reference entry = *it++;
     EXPECT_EQ(entry.first, entry.second);
   }
 
-  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
-    Map<int32, int32>::reference entry = *it++;
+  for (Map<int32_t, int32_t>::iterator it = map_.begin(); it != map_.end();) {
+    Map<int32_t, int32_t>::reference entry = *it++;
     EXPECT_EQ(entry.first + 1, ++entry.second);
   }
 }
@@ -367,13 +366,13 @@
 }
 
 template <typename Iterator>
-static int64 median(Iterator i0, Iterator i1) {
-  std::vector<int64> v(i0, i1);
+static int64_t median(Iterator i0, Iterator i1) {
+  std::vector<int64_t> v(i0, i1);
   std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end());
   return v[v.size() / 2];
 }
 
-static int64 Now() {
+static int64_t Now() {
   return util::TimeUtil::TimestampToNanoseconds(
       util::TimeUtil::GetCurrentTime());
 }
@@ -388,14 +387,14 @@
 // avoid that, as std::unordered_map does.
 TEST_F(MapImplTest, BeginIsFast) {
   if (true) return;  // TODO(gpike): make this less flaky and re-enable it.
-  Map<int32, int32> map;
+  Map<int32_t, int32_t> map;
   const int kTestSize = 250000;
   // Create a random-looking map of size n.  Use non-negative integer keys.
-  uint32 frog = 123983;
+  uint32_t frog = 123983;
   int last_key = 0;
   int counter = 0;
   while (map.size() < kTestSize) {
-    frog *= static_cast<uint32>(k0);
+    frog *= static_cast<uint32_t>(k0);
     frog ^= frog >> 17;
     frog += counter++;
     last_key =
@@ -403,18 +402,18 @@
     GOOGLE_DCHECK_GE(last_key, 0);
     map[last_key] = last_key ^ 1;
   }
-  std::vector<int64> times;
+  std::vector<int64_t> times;
   // We're going to do map.erase(map.begin()) over and over again.  But,
   // just in case one iteration is fast compared to the granularity of
   // our time keeping, we measure kChunkSize iterations per outer-loop iter.
   const int kChunkSize = 1000;
   GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0);
   do {
-    const int64 start = Now();
+    const int64_t start = Now();
     for (int i = 0; i < kChunkSize; i++) {
       map.erase(map.begin());
     }
-    const int64 end = Now();
+    const int64_t end = Now();
     if (end > start) {
       times.push_back(end - start);
     }
@@ -423,8 +422,8 @@
     GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time";
     return;
   }
-  int64 x0 = median(times.begin(), times.begin() + 9);
-  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  int64_t x0 = median(times.begin(), times.begin() + 9);
+  int64_t x1 = median(times.begin() + times.size() - 9, times.end());
   GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1;
   // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
   // And we'll probably time out and never get here.  So, this test is
@@ -448,13 +447,13 @@
   // 1024 (or 512 or 2048 or ...) entries.  This assumes that map_ uses powers
   // of 2 for table sizes, and that it's sufficient to "flood" with respect to
   // the low bits of the output of map_.hash_function().
-  std::vector<int64> times;
+  std::vector<int64_t> times;
   std::set<int>::iterator it = s.begin();
   int count = 0;
   do {
-    const int64 start = Now();
+    const int64_t start = Now();
     map_[*it] = 0;
-    const int64 end = Now();
+    const int64_t end = Now();
     if (end > start) {
       times.push_back(end - start);
     }
@@ -462,24 +461,25 @@
     ++it;
   } while (it != s.end());
   if (times.size() < .99 * count) return;
-  int64 x0 = median(times.begin(), times.begin() + 9);
-  int64 x1 = median(times.begin() + times.size() - 9, times.end());
+  int64_t x0 = median(times.begin(), times.begin() + 9);
+  int64_t x1 = median(times.begin() + times.size() - 9, times.end());
   // x1 will greatly exceed x0 if the code we just executed took O(n^2) time.
   // But we want to allow O(n log n).  A factor of 20 should be generous enough.
   EXPECT_LE(x1, x0 * 20);
 }
 
 TEST_F(MapImplTest, CopyIteratorStressTest) {
-  std::vector<Map<int32, int32>::iterator> v;
+  std::vector<Map<int32_t, int32_t>::iterator> v;
   const int kIters = 1e5;
-  for (uint32 i = 0; i < kIters; i++) {
-    int32 key = (3 + i * (5 + i * (-8 + i * (62 + i)))) & 0x77777777;
+  for (uint32_t i = 0; i < kIters; i++) {
+    int32_t key = (3 + i * (5 + i * (-8 + i * (62 + i)))) & 0x77777777;
     map_[key] = i;
     v.push_back(map_.find(key));
   }
-  for (std::vector<Map<int32, int32>::iterator>::const_iterator it = v.begin();
+  for (std::vector<Map<int32_t, int32_t>::iterator>::const_iterator it =
+           v.begin();
        it != v.end(); it++) {
-    Map<int32, int32>::iterator i = *it;
+    Map<int32_t, int32_t>::iterator i = *it;
     ASSERT_EQ(i->first, (*it)->first);
     ASSERT_EQ(i->second, (*it)->second);
   }
@@ -554,11 +554,11 @@
   GOOGLE_CHECK_GT(n, 0);
   // Create a random-looking map of size n.  Use non-negative integer keys.
   Map<int, int> m;
-  uint32 frog = 123987 + n;
+  uint32_t frog = 123987 + n;
   int last_key = 0;
   int counter = 0;
   while (m.size() < n) {
-    frog *= static_cast<uint32>(k0);
+    frog *= static_cast<uint32_t>(k0);
     frog ^= frog >> 17;
     frog += counter++;
     last_key =
@@ -688,46 +688,46 @@
 }
 
 TEST_F(MapImplTest, InsertSingle) {
-  int32 key = 0;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key = 0;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
   // Insert a non-existed key.
-  std::pair<Map<int32, int32>::iterator, bool> result1 =
-      map_.insert(Map<int32, int32>::value_type(key, value1));
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result1 =
+      map_.insert(Map<int32_t, int32_t>::value_type(key, value1));
   ExpectSingleElement(key, value1);
 
-  Map<int32, int32>::iterator it1 = result1.first;
+  Map<int32_t, int32_t>::iterator it1 = result1.first;
   EXPECT_EQ(key, it1->first);
   EXPECT_EQ(value1, it1->second);
   EXPECT_TRUE(result1.second);
 
   // Insert an existed key.
-  std::pair<Map<int32, int32>::iterator, bool> result2 =
-      map_.insert(Map<int32, int32>::value_type(key, value2));
+  std::pair<Map<int32_t, int32_t>::iterator, bool> result2 =
+      map_.insert(Map<int32_t, int32_t>::value_type(key, value2));
   ExpectSingleElement(key, value1);
 
-  Map<int32, int32>::iterator it2 = result2.first;
+  Map<int32_t, int32_t>::iterator it2 = result2.first;
   EXPECT_TRUE(it1 == it2);
   EXPECT_FALSE(result2.second);
 }
 
 TEST_F(MapImplTest, InsertByIterator) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1a = 100;
-  int32 value1b = 101;
-  int32 value2a = 200;
-  int32 value2b = 201;
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1a = 100;
+  int32_t value1b = 101;
+  int32_t value2a = 200;
+  int32_t value2b = 201;
 
-  std::map<int32, int32> map1;
+  std::map<int32_t, int32_t> map1;
   map1[key1] = value1a;
   map1[key2] = value2a;
 
   map_.insert(map1.begin(), map1.end());
   ExpectElements(map1);
 
-  std::map<int32, int32> map2;
+  std::map<int32_t, int32_t> map2;
   map2[key1] = value1b;
   map2[key2] = value2b;
 
@@ -744,8 +744,8 @@
 }
 
 TEST_F(MapImplTest, EraseSingleByKey) {
-  int32 key = 0;
-  int32 value = 100;
+  int32_t key = 0;
+  int32_t value = 100;
 
   map_[key] = value;
   ExpectSingleElement(key, value);
@@ -789,13 +789,13 @@
 }
 
 TEST_F(MapImplTest, EraseSingleByIterator) {
-  int32 key = 0;
-  int32 value = 100;
+  int32_t key = 0;
+  int32_t value = 100;
 
   map_[key] = value;
   ExpectSingleElement(key, value);
 
-  Map<int32, int32>::iterator it = map_.find(key);
+  Map<int32_t, int32_t>::iterator it = map_.find(key);
   map_.erase(it);
   EXPECT_TRUE(map_.empty());
   EXPECT_EQ(0, map_.size());
@@ -810,7 +810,7 @@
 
   int count = 0;
 
-  for (Map<int32, int32>::iterator it = map_.begin(); it != map_.end();) {
+  for (Map<int32_t, int32_t>::iterator it = map_.begin(); it != map_.end();) {
     count++;
     if (it->first % 2 == 1) {
       map_.erase(it++);
@@ -824,12 +824,12 @@
 }
 
 TEST_F(MapImplTest, EraseByIterator) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
-  std::map<int32, int32> map;
+  std::map<int32_t, int32_t> map;
   map[key1] = value1;
   map[key2] = value2;
 
@@ -845,8 +845,8 @@
 }
 
 TEST_F(MapImplTest, Clear) {
-  int32 key = 0;
-  int32 value = 100;
+  int32_t key = 0;
+  int32_t value = 100;
 
   map_[key] = value;
   ExpectSingleElement(key, value);
@@ -859,19 +859,19 @@
   EXPECT_TRUE(map_.begin() == map_.end());
 }
 
-static void CopyConstructorHelper(Arena* arena, Map<int32, int32>* m) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
+static void CopyConstructorHelper(Arena* arena, Map<int32_t, int32_t>* m) {
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
-  std::map<int32, int32> map;
+  std::map<int32_t, int32_t> map;
   map[key1] = value1;
   map[key2] = value2;
 
   m->insert(map.begin(), map.end());
 
-  Map<int32, int32> other(*m);
+  Map<int32_t, int32_t> other(*m);
 
   EXPECT_EQ(2, other.size());
   EXPECT_EQ(value1, other.at(key1));
@@ -888,16 +888,16 @@
 }
 
 TEST_F(MapImplTest, IterConstructor) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
-  std::map<int32, int32> map;
+  std::map<int32_t, int32_t> map;
   map[key1] = value1;
   map[key2] = value2;
 
-  Map<int32, int32> new_map(map.begin(), map.end());
+  Map<int32_t, int32_t> new_map(map.begin(), map.end());
 
   EXPECT_EQ(2, new_map.size());
   EXPECT_EQ(value1, new_map.at(key1));
@@ -905,20 +905,20 @@
 }
 
 TEST_F(MapImplTest, Assigner) {
-  int32 key1 = 0;
-  int32 key2 = 1;
-  int32 value1 = 100;
-  int32 value2 = 101;
+  int32_t key1 = 0;
+  int32_t key2 = 1;
+  int32_t value1 = 100;
+  int32_t value2 = 101;
 
-  std::map<int32, int32> map;
+  std::map<int32_t, int32_t> map;
   map[key1] = value1;
   map[key2] = value2;
 
   map_.insert(map.begin(), map.end());
 
-  Map<int32, int32> other;
-  int32 key_other = 123;
-  int32 value_other = 321;
+  Map<int32_t, int32_t> other;
+  int32_t key_other = 123;
+  int32_t value_other = 321;
   other[key_other] = value_other;
   EXPECT_EQ(1, other.size());
 
@@ -938,7 +938,7 @@
 
 TEST_F(MapImplTest, Rehash) {
   const int test_size = 50;
-  std::map<int32, int32> reference_map;
+  std::map<int32_t, int32_t> reference_map;
   for (int i = 0; i < test_size; i++) {
     reference_map[i] = i;
   }
@@ -957,8 +957,8 @@
   int key = 100, key_missing = 101;
   map_[key] = 100;
 
-  std::pair<Map<int32, int32>::iterator, Map<int32, int32>::iterator> range =
-      map_.equal_range(key);
+  std::pair<Map<int32_t, int32_t>::iterator, Map<int32_t, int32_t>::iterator>
+      range = map_.equal_range(key);
   EXPECT_TRUE(map_.find(key) == range.first);
   EXPECT_TRUE(++map_.find(key) == range.second);
 
@@ -966,8 +966,8 @@
   EXPECT_TRUE(map_.end() == range.first);
   EXPECT_TRUE(map_.end() == range.second);
 
-  std::pair<Map<int32, int32>::const_iterator,
-            Map<int32, int32>::const_iterator>
+  std::pair<Map<int32_t, int32_t>::const_iterator,
+            Map<int32_t, int32_t>::const_iterator>
       const_range = const_map_.equal_range(key);
   EXPECT_TRUE(const_map_.find(key) == const_range.first);
   EXPECT_TRUE(++const_map_.find(key) == const_range.second);
@@ -979,21 +979,21 @@
 
 TEST_F(MapImplTest, ConvertToStdMap) {
   map_[100] = 101;
-  std::map<int32, int32> std_map(map_.begin(), map_.end());
+  std::map<int32_t, int32_t> std_map(map_.begin(), map_.end());
   EXPECT_EQ(1, std_map.size());
   EXPECT_EQ(101, std_map[100]);
 }
 
 TEST_F(MapImplTest, ConvertToStdVectorOfPairs) {
   map_[100] = 101;
-  std::vector<std::pair<int32, int32> > std_vec(map_.begin(), map_.end());
+  std::vector<std::pair<int32_t, int32_t>> std_vec(map_.begin(), map_.end());
   EXPECT_EQ(1, std_vec.size());
   EXPECT_EQ(100, std_vec[0].first);
   EXPECT_EQ(101, std_vec[0].second);
 }
 
 TEST_F(MapImplTest, SwapBasic) {
-  Map<int32, int32> another;
+  Map<int32_t, int32_t> another;
   map_[9398] = 41999;
   another[9398] = 41999;
   another[8070] = 42056;
@@ -1006,8 +1006,8 @@
 
 TEST_F(MapImplTest, SwapArena) {
   Arena arena1, arena2;
-  Map<int32, int32> m1(&arena1);
-  Map<int32, int32> m2(&arena2);
+  Map<int32_t, int32_t> m1(&arena1);
+  Map<int32_t, int32_t> m2(&arena2);
   map_[9398] = 41999;
   m1[9398] = 41999;
   m1[8070] = 42056;
@@ -1063,7 +1063,7 @@
 TEST_F(MapImplTest, SpaceUsed) {
   constexpr size_t kMinCap = 8;
 
-  Map<int32, int32> m;
+  Map<int32_t, int32_t> m;
   // An newly constructed map should have no space used.
   EXPECT_EQ(m.SpaceUsedExcludingSelfLong(), 0);
 
@@ -1074,26 +1074,27 @@
     if (m.size() >= capacity * kMaxLoadFactor) {
       capacity *= 2;
     }
-    EXPECT_EQ(m.SpaceUsedExcludingSelfLong(),
-              sizeof(void*) * capacity +
-                  m.size() * sizeof(std::pair<std::pair<int32, int32>, void*>));
+    EXPECT_EQ(
+        m.SpaceUsedExcludingSelfLong(),
+        sizeof(void*) * capacity +
+            m.size() * sizeof(std::pair<std::pair<int32_t, int32_t>, void*>));
   }
 
   // Test string, and non-scalar keys.
-  Map<std::string, int32> m2;
+  Map<std::string, int32_t> m2;
   std::string str = "Some arbitrarily large string";
   m2[str] = 1;
   EXPECT_EQ(m2.SpaceUsedExcludingSelfLong(),
             sizeof(void*) * kMinCap +
-                sizeof(std::pair<std::pair<std::string, int32>, void*>) +
+                sizeof(std::pair<std::pair<std::string, int32_t>, void*>) +
                 internal::StringSpaceUsedExcludingSelfLong(str));
 
   // Test messages, and non-scalar values.
-  Map<int32, TestAllTypes> m3;
+  Map<int32_t, TestAllTypes> m3;
   m3[0].set_optional_string(str);
   EXPECT_EQ(m3.SpaceUsedExcludingSelfLong(),
             sizeof(void*) * kMinCap +
-                sizeof(std::pair<std::pair<int32, TestAllTypes>, void*>) +
+                sizeof(std::pair<std::pair<int32_t, TestAllTypes>, void*>) +
                 m3[0].SpaceUsedLong() - sizeof(m3[0]));
 }
 
@@ -1102,12 +1103,12 @@
 bool MapOrderingIsRandom(int a, int b) {
   bool saw_a_first = false;
   bool saw_b_first = false;
-  std::vector<Map<int32, int32>> v(50);
+  std::vector<Map<int32_t, int32_t>> v(50);
   for (int i = 0; i < 50; ++i) {
-    Map<int32, int32>& m = v[i];
+    Map<int32_t, int32_t>& m = v[i];
     m[a] = 0;
     m[b] = 0;
-    int32 first_element = m.begin()->first;
+    int32_t first_element = m.begin()->first;
     if (first_element == a) saw_a_first = true;
     if (first_element == b) saw_b_first = true;
     if (saw_a_first && saw_b_first) {
@@ -1234,11 +1235,11 @@
   const Reflection* refl = message.GetReflection();
   const Descriptor* desc = message.GetDescriptor();
 
-  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
-  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<int32_t, int32_t>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32_t, double>* map_int32_double = message.mutable_map_int32_double();
   Map<std::string, std::string>* map_string_string =
       message.mutable_map_string_string();
-  Map<int32, ForeignMessage>* map_int32_foreign_message =
+  Map<int32_t, ForeignMessage>* map_int32_foreign_message =
       message.mutable_map_int32_foreign_message();
 
   for (int i = 0; i < 10; ++i) {
@@ -1301,14 +1302,14 @@
     {
       // Check gets through const objects.
       const Message& message_int32_int32 = mf_int32_int32.Get(i);
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_value);
       EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
 
       const Message& message_int32_double = mf_int32_double.Get(i);
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
           message_int32_double, fd_map_int32_double_key);
       double value_int32_double =
           message_int32_double.GetReflection()->GetDouble(
@@ -1325,8 +1326,9 @@
       EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
 
       const Message& message_int32_message = mf_int32_foreign_message.Get(i);
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
       const ForeignMessage& value_int32_message =
           down_cast<const ForeignMessage&>(
               message_int32_message.GetReflection()->GetMessage(
@@ -1337,14 +1339,14 @@
     {
       // Check gets through mutable objects.
       const Message& message_int32_int32 = mmf_int32_int32->Get(i);
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_value);
       EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
 
       const Message& message_int32_double = mmf_int32_double->Get(i);
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
           message_int32_double, fd_map_int32_double_key);
       double value_int32_double =
           message_int32_double.GetReflection()->GetDouble(
@@ -1361,8 +1363,9 @@
       EXPECT_EQ(value_string_string, StrFunc(Int(key_string_string), 5));
 
       const Message& message_int32_message = mmf_int32_foreign_message->Get(i);
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
       const ForeignMessage& value_int32_message =
           down_cast<const ForeignMessage&>(
               message_int32_message.GetReflection()->GetMessage(
@@ -1375,15 +1378,16 @@
   for (int i = 0; i < 10; i++) {
     {
       Message* message_int32_int32 = mmf_int32_int32->Mutable(i);
-      int32 key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
+      int32_t key_int32_int32 = message_int32_int32->GetReflection()->GetInt32(
           *message_int32_int32, fd_map_int32_in32_key);
       message_int32_int32->GetReflection()->SetInt32(message_int32_int32,
                                                      fd_map_int32_in32_value,
                                                      Func(key_int32_int32, -1));
 
       Message* message_int32_double = mmf_int32_double->Mutable(i);
-      int32 key_int32_double = message_int32_double->GetReflection()->GetInt32(
-          *message_int32_double, fd_map_int32_double_key);
+      int32_t key_int32_double =
+          message_int32_double->GetReflection()->GetInt32(
+              *message_int32_double, fd_map_int32_double_key);
       message_int32_double->GetReflection()->SetDouble(
           message_int32_double, fd_map_int32_double_value,
           Func(key_int32_double, -2));
@@ -1397,7 +1401,7 @@
           StrFunc(Int(key_string_string), -5));
 
       Message* message_int32_message = mmf_int32_foreign_message->Mutable(i);
-      int32 key_int32_message =
+      int32_t key_int32_message =
           message_int32_message->GetReflection()->GetInt32(
               *message_int32_message, fd_map_int32_foreign_message_key);
       ForeignMessage* value_int32_message = down_cast<ForeignMessage*>(
@@ -1421,11 +1425,11 @@
   const Reflection* refl = message.GetReflection();
   const Descriptor* desc = message.GetDescriptor();
 
-  Map<int32, int32>* map_int32_int32 = message.mutable_map_int32_int32();
-  Map<int32, double>* map_int32_double = message.mutable_map_int32_double();
+  Map<int32_t, int32_t>* map_int32_int32 = message.mutable_map_int32_int32();
+  Map<int32_t, double>* map_int32_double = message.mutable_map_int32_double();
   Map<std::string, std::string>* map_string_string =
       message.mutable_map_string_string();
-  Map<int32, ForeignMessage>* map_int32_foreign_message =
+  Map<int32_t, ForeignMessage>* map_int32_foreign_message =
       message.mutable_map_int32_foreign_message();
 
   for (int i = 0; i < 10; ++i) {
@@ -1525,15 +1529,15 @@
       // Check gets through const objects.
       const Message& message_int32_int32 =
           mf_int32_int32.Get(i, entry_int32_int32.get());
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_value);
       EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
 
       const Message& message_int32_double =
           mf_int32_double.Get(i, entry_int32_double.get());
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
           message_int32_double, fd_map_int32_double_key);
       double value_int32_double =
           message_int32_double.GetReflection()->GetDouble(
@@ -1552,8 +1556,9 @@
 
       const Message& message_int32_message =
           mf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
       const ForeignMessage& value_int32_message =
           down_cast<const ForeignMessage&>(
               message_int32_message.GetReflection()->GetMessage(
@@ -1565,15 +1570,15 @@
       // Check gets through mutable objects.
       const Message& message_int32_int32 =
           mmf_int32_int32.Get(i, entry_int32_int32.get());
-      int32 key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t key_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_key);
-      int32 value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
+      int32_t value_int32_int32 = message_int32_int32.GetReflection()->GetInt32(
           message_int32_int32, fd_map_int32_in32_value);
       EXPECT_EQ(value_int32_int32, Func(key_int32_int32, 1));
 
       const Message& message_int32_double =
           mmf_int32_double.Get(i, entry_int32_double.get());
-      int32 key_int32_double = message_int32_double.GetReflection()->GetInt32(
+      int32_t key_int32_double = message_int32_double.GetReflection()->GetInt32(
           message_int32_double, fd_map_int32_double_key);
       double value_int32_double =
           message_int32_double.GetReflection()->GetDouble(
@@ -1592,8 +1597,9 @@
 
       const Message& message_int32_message =
           mmf_int32_foreign_message.Get(i, entry_int32_foreign_message.get());
-      int32 key_int32_message = message_int32_message.GetReflection()->GetInt32(
-          message_int32_message, fd_map_int32_foreign_message_key);
+      int32_t key_int32_message =
+          message_int32_message.GetReflection()->GetInt32(
+              message_int32_message, fd_map_int32_foreign_message_key);
       const ForeignMessage& value_int32_message =
           down_cast<const ForeignMessage&>(
               message_int32_message.GetReflection()->GetMessage(
@@ -1654,19 +1660,20 @@
   // Test iterators.
   {
     int index = 0;
-    std::unordered_map<int32, int32> result;
+    std::unordered_map<int32_t, int32_t> result;
     for (RepeatedFieldRef<Message>::iterator it = mf_int32_int32.begin();
          it != mf_int32_int32.end(); ++it) {
       const Message& message = *it;
-      int32 key =
+      int32_t key =
           message.GetReflection()->GetInt32(message, fd_map_int32_in32_key);
-      int32 value =
+      int32_t value =
           message.GetReflection()->GetInt32(message, fd_map_int32_in32_value);
       result[key] = value;
       ++index;
     }
     EXPECT_EQ(10, index);
-    for (std::unordered_map<int32, int32>::const_iterator it = result.begin();
+    for (std::unordered_map<int32_t, int32_t>::const_iterator it =
+             result.begin();
          it != result.end(); ++it) {
       EXPECT_EQ(message.map_int32_int32().at(it->first), it->second);
     }
@@ -1674,11 +1681,11 @@
 
   {
     int index = 0;
-    std::unordered_map<int32, double> result;
+    std::unordered_map<int32_t, double> result;
     for (RepeatedFieldRef<Message>::iterator it = mf_int32_double.begin();
          it != mf_int32_double.end(); ++it) {
       const Message& message = *it;
-      int32 key =
+      int32_t key =
           message.GetReflection()->GetInt32(message, fd_map_int32_double_key);
       double value = message.GetReflection()->GetDouble(
           message, fd_map_int32_double_value);
@@ -1686,7 +1693,8 @@
       ++index;
     }
     EXPECT_EQ(10, index);
-    for (std::unordered_map<int32, double>::const_iterator it = result.begin();
+    for (std::unordered_map<int32_t, double>::const_iterator it =
+             result.begin();
          it != result.end(); ++it) {
       EXPECT_EQ(message.map_int32_double().at(it->first), it->second);
     }
@@ -1715,12 +1723,12 @@
 
   {
     int index = 0;
-    std::map<int32, ForeignMessage> result;
+    std::map<int32_t, ForeignMessage> result;
     for (RepeatedFieldRef<Message>::iterator it =
              mf_int32_foreign_message.begin();
          it != mf_int32_foreign_message.end(); ++it) {
       const Message& message = *it;
-      int32 key = message.GetReflection()->GetInt32(
+      int32_t key = message.GetReflection()->GetInt32(
           message, fd_map_int32_foreign_message_key);
       const ForeignMessage& sub_message =
           down_cast<const ForeignMessage&>(message.GetReflection()->GetMessage(
@@ -1729,7 +1737,7 @@
       ++index;
     }
     EXPECT_EQ(10, index);
-    for (std::map<int32, ForeignMessage>::const_iterator it = result.begin();
+    for (std::map<int32_t, ForeignMessage>::const_iterator it = result.begin();
          it != result.end(); ++it) {
       EXPECT_EQ(message.map_int32_foreign_message().at(it->first).c(),
                 it->second.c());
@@ -1805,19 +1813,19 @@
   // Test MutableRepeatedFieldRef::SwapElements()
   {
     const Message& message0a = mmf_int32_int32.Get(0, entry_int32_int32.get());
-    int32 int32_value0a =
+    int32_t int32_value0a =
         message0a.GetReflection()->GetInt32(message0a, fd_map_int32_in32_value);
     const Message& message9a = mmf_int32_int32.Get(9, entry_int32_int32.get());
-    int32 int32_value9a =
+    int32_t int32_value9a =
         message9a.GetReflection()->GetInt32(message9a, fd_map_int32_in32_value);
 
     mmf_int32_int32.SwapElements(0, 9);
 
     const Message& message0b = mmf_int32_int32.Get(0, entry_int32_int32.get());
-    int32 int32_value0b =
+    int32_t int32_value0b =
         message0b.GetReflection()->GetInt32(message0b, fd_map_int32_in32_value);
     const Message& message9b = mmf_int32_int32.Get(9, entry_int32_int32.get());
-    int32 int32_value9b =
+    int32_t int32_value9b =
         message9b.GetReflection()->GetInt32(message9b, fd_map_int32_in32_value);
 
     EXPECT_EQ(int32_value9a, int32_value0b);
@@ -1880,13 +1888,13 @@
     const ForeignMessage& sub_message0a =
         down_cast<const ForeignMessage&>(message0a.GetReflection()->GetMessage(
             message0a, fd_map_int32_foreign_message_value));
-    int32 int32_value0a = sub_message0a.c();
+    int32_t int32_value0a = sub_message0a.c();
     const Message& message9a =
         mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
     const ForeignMessage& sub_message9a =
         down_cast<const ForeignMessage&>(message9a.GetReflection()->GetMessage(
             message9a, fd_map_int32_foreign_message_value));
-    int32 int32_value9a = sub_message9a.c();
+    int32_t int32_value9a = sub_message9a.c();
 
     mmf_int32_foreign_message.SwapElements(0, 9);
 
@@ -1895,13 +1903,13 @@
     const ForeignMessage& sub_message0b =
         down_cast<const ForeignMessage&>(message0b.GetReflection()->GetMessage(
             message0b, fd_map_int32_foreign_message_value));
-    int32 int32_value0b = sub_message0b.c();
+    int32_t int32_value0b = sub_message0b.c();
     const Message& message9b =
         mmf_int32_foreign_message.Get(9, entry_int32_foreign_message.get());
     const ForeignMessage& sub_message9b =
         down_cast<const ForeignMessage&>(message9b.GetReflection()->GetMessage(
             message9b, fd_map_int32_foreign_message_value));
-    int32 int32_value9b = sub_message9b.c();
+    int32_t int32_value9b = sub_message9b.c();
 
     EXPECT_EQ(int32_value9a, int32_value0b);
     EXPECT_EQ(int32_value0a, int32_value9b);
@@ -2037,8 +2045,7 @@
     Message* entry2 = reflection->AddMessage(message.get(), field);
 
     const Reflection* entry_reflection = entry1->GetReflection();
-    const FieldDescriptor* key_field =
-        entry1->GetDescriptor()->map_key();
+    const FieldDescriptor* key_field = entry1->GetDescriptor()->map_key();
     entry_reflection->SetInt32(entry1, key_field, 1);
     entry_reflection->SetInt32(entry2, key_field, 1);
 
@@ -2058,8 +2065,7 @@
     Message* entry2 = reflection->AddMessage(&message, field);
 
     const Reflection* entry_reflection = entry1->GetReflection();
-    const FieldDescriptor* key_field =
-        entry1->GetDescriptor()->map_key();
+    const FieldDescriptor* key_field = entry1->GetDescriptor()->map_key();
     entry_reflection->SetInt32(entry1, key_field, 1);
     entry_reflection->SetInt32(entry2, key_field, 1);
 
@@ -2079,7 +2085,7 @@
 }
 
 class MyMapEntry
-    : public internal::MapEntry<MyMapEntry, ::google::protobuf::int32, ::google::protobuf::int32,
+    : public internal::MapEntry<MyMapEntry, ::int32_t, ::int32_t,
                                 internal::WireFormatLite::TYPE_INT32,
                                 internal::WireFormatLite::TYPE_INT32> {
  public:
@@ -2091,7 +2097,7 @@
 };
 
 class MyMapEntryLite
-    : public internal::MapEntryLite<MyMapEntryLite, ::google::protobuf::int32, ::google::protobuf::int32,
+    : public internal::MapEntryLite<MyMapEntryLite, ::int32_t, ::int32_t,
                                     internal::WireFormatLite::TYPE_INT32,
                                     internal::WireFormatLite::TYPE_INT32> {
  public:
@@ -2405,8 +2411,8 @@
   MapTestUtil::SetMapFields(&message1);
   size_t size = message1.ByteSizeLong();
   data.resize(size);
-  uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data));
-  uint8* end = message1.SerializeWithCachedSizesToArray(start);
+  uint8_t* start = reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&data));
+  uint8_t* end = message1.SerializeWithCachedSizesToArray(start);
   EXPECT_EQ(size, end - start);
   EXPECT_TRUE(message2.ParseFromString(data));
   MapTestUtil::ExpectMapFieldsSet(message2);
@@ -2699,7 +2705,7 @@
   // The exact value will depend on internal state, like collisions,
   // so we can't predict it. But we can predict a lower bound.
   size_t lower_bound =
-      initial + kNumValues * (space_used_message + sizeof(int32) +
+      initial + kNumValues * (space_used_message + sizeof(int32_t) +
                               /* Node::next */ sizeof(void*) +
                               /* table entry */ sizeof(void*));
 
@@ -2950,8 +2956,7 @@
   const FieldDescriptor* map_field =
       UNITTEST::TestMessageMap::descriptor()->FindFieldByName(
           "map_int32_message");
-  const FieldDescriptor* value =
-      map_field->message_type()->map_value();
+  const FieldDescriptor* value = map_field->message_type()->map_value();
 
   Message* entry_message =
       message.GetReflection()->AddMessage(&message, map_field);
@@ -2970,10 +2975,8 @@
   UNITTEST::TestMap message;
   const FieldDescriptor* map_field =
       UNITTEST::TestMap::descriptor()->FindFieldByName("map_int32_int32");
-  const FieldDescriptor* key =
-      map_field->message_type()->map_key();
-  const FieldDescriptor* value =
-      map_field->message_type()->map_value();
+  const FieldDescriptor* key = map_field->message_type()->map_key();
+  const FieldDescriptor* value = map_field->message_type()->map_value();
 
   Message* entry_message1 =
       message.GetReflection()->AddMessage(&message, map_field);
@@ -3035,7 +3038,7 @@
   MapFieldInDynamicMessageTest()
       : pool_(DescriptorPool::generated_pool()), factory_(pool_) {}
 
-  virtual void SetUp() {
+  void SetUp() override {
     map_descriptor_ = pool_->FindMessageTypeByName(
         std::string(UNITTEST_PACKAGE_NAME) + ".TestMap");
     recursive_map_descriptor_ = pool_->FindMessageTypeByName(
@@ -3497,8 +3500,8 @@
 }
 
 // Helper for MapSerializationTest.  Return a 7-bit ASCII string.
-static std::string ConstructKey(uint64 n) {
-  std::string s(n % static_cast<uint64>(9), '\0');
+static std::string ConstructKey(uint64_t n) {
+  std::string s(n % static_cast<uint64_t>(9), '\0');
   if (s.empty()) {
     return StrCat(n);
   } else {
@@ -3516,13 +3519,13 @@
   UNITTEST::TestIntIntMap inner;
   (*inner.mutable_m())[0] = (*inner.mutable_m())[10] =
       (*inner.mutable_m())[-200] = 0;
-  uint64 frog = 9;
-  const uint64 multiplier = 0xa29cd16f;
+  uint64_t frog = 9;
+  const uint64_t multiplier = 0xa29cd16f;
   for (int i = 0; i < kIters; i++) {
-    const int32 i32 = static_cast<int32>(frog & 0xffffffff);
-    const uint32 u32 = static_cast<uint32>(i32) * 91919;
-    const int64 i64 = static_cast<int64>(frog);
-    const uint64 u64 = frog * static_cast<uint64>(187321);
+    const int32_t i32 = static_cast<int32_t>(frog & 0xffffffff);
+    const uint32_t u32 = static_cast<uint32_t>(i32) * 91919;
+    const int64_t i64 = static_cast<int64_t>(frog);
+    const uint64_t u64 = frog * static_cast<uint64_t>(187321);
     const bool b = i32 > 0;
     const std::string s = ConstructKey(frog);
     (*inner.mutable_m())[i] = i32;
@@ -3534,8 +3537,9 @@
     (*t.mutable_m_uint64())[u64] = (*t.mutable_m_fixed64())[u64] = inner;
     (*t.mutable_m_bool())[b] = inner;
     (*t.mutable_m_string())[s] = inner;
-    (*t.mutable_m_string())[s + std::string(1 << (u32 % static_cast<uint32>(9)),
-                                            b)] = inner;
+    (*t.mutable_m_string())[s + std::string(
+                                    1 << (u32 % static_cast<uint32_t>(9)), b)] =
+        inner;
     inner.mutable_m()->erase(i);
     frog = frog * multiplier + i;
     frog ^= (frog >> 41);
@@ -3569,6 +3573,7 @@
   // randomly-chosen hash function.
   const int kAttempts = 10;
   for (int i = 0; i < kAttempts; i++) {
+    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
     UNITTEST::TestSubmessageMaps q(p);
     ASSERT_EQ(DeterministicSerialization(q), DeterministicSerialization(p));
   }
@@ -3649,7 +3654,8 @@
   (*source.mutable_map_int32_int32())[1] = 1;
 
   // Get iterator.
-  Map<int32, int32>::iterator iter = source.mutable_map_int32_int32()->find(1);
+  Map<int32_t, int32_t>::iterator iter =
+      source.mutable_map_int32_int32()->find(1);
 
   // Serialize message to text format, which will invalidate the previous
   // iterator previously.
@@ -3695,8 +3701,7 @@
 
   // Modify map via the iterator (invalidated in previous implementation.).
   const Reflection* map_entry_reflection = iter->GetReflection();
-  const FieldDescriptor* value_field_desc =
-      iter->GetDescriptor()->map_value();
+  const FieldDescriptor* value_field_desc = iter->GetDescriptor()->map_value();
   map_entry_reflection->SetInt32(&(*iter), value_field_desc, 2);
   GOOGLE_LOG(INFO) << iter->DebugString();
 
@@ -3831,13 +3836,13 @@
 }
 
 TEST(MoveTest, MoveConstructorWorks) {
-  Map<int32, TestAllTypes> original_map;
+  Map<int32_t, TestAllTypes> original_map;
   original_map[42].mutable_optional_nested_message()->set_bb(42);
   original_map[43].mutable_optional_nested_message()->set_bb(43);
   const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
   const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
 
-  Map<int32, TestAllTypes> moved_to_map(std::move(original_map));
+  Map<int32_t, TestAllTypes> moved_to_map(std::move(original_map));
   EXPECT_TRUE(original_map.empty());
   EXPECT_EQ(2, moved_to_map.size());
   EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
@@ -3849,13 +3854,13 @@
 }
 
 TEST(MoveTest, MoveAssignmentWorks) {
-  Map<int32, TestAllTypes> original_map;
+  Map<int32_t, TestAllTypes> original_map;
   original_map[42].mutable_optional_nested_message()->set_bb(42);
   original_map[43].mutable_optional_nested_message()->set_bb(43);
   const auto* nested_msg42_ptr = &original_map[42].optional_nested_message();
   const auto* nested_msg43_ptr = &original_map[43].optional_nested_message();
 
-  Map<int32, TestAllTypes> moved_to_map = std::move(original_map);
+  Map<int32_t, TestAllTypes> moved_to_map = std::move(original_map);
   EXPECT_TRUE(original_map.empty());
   EXPECT_EQ(2, moved_to_map.size());
   EXPECT_EQ(42, moved_to_map[42].optional_nested_message().bb());
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 2857342..d79efb4 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -31,9 +31,10 @@
 #ifndef GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
 #define GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
 
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
 
 #ifdef SWIG
@@ -322,7 +323,8 @@
     int field, const MapEntryAccessorType& value, uint8_t* ptr,
     io::EpsCopyOutputStream* stream) {
   ptr = stream->EnsureSpace(ptr);
-  return WireFormatLite::InternalWriteMessage(field, value, ptr, stream);
+  return WireFormatLite::InternalWriteMessage(
+      field, value, value.GetCachedSize(), ptr, stream);
 }
 
 #define WRITE_METHOD(FieldType, DeclaredType)                     \
@@ -684,6 +686,48 @@
 PRIMITIVE_HANDLER_FUNCTIONS(BOOL)
 #undef PRIMITIVE_HANDLER_FUNCTIONS
 
+// Functions for operating on a map entry using type handlers.
+//
+// Does not contain any representation (this class is not intended to be
+// instantiated).
+template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
+          WireFormatLite::FieldType kValueFieldType>
+struct MapEntryFuncs {
+  typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
+  typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
+  enum : int {
+    kKeyFieldNumber = 1,
+    kValueFieldNumber = 2
+  };
+
+  static uint8_t* InternalSerialize(int field_number, const Key& key,
+                                    const Value& value, uint8_t* ptr,
+                                    io::EpsCopyOutputStream* stream) {
+    ptr = stream->EnsureSpace(ptr);
+    ptr = WireFormatLite::WriteTagToArray(
+        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
+    ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
+                                                      ptr);
+
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
+  }
+
+  static size_t ByteSizeLong(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    size_t inner_length =
+        2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
+    return inner_length + io::CodedOutputStream::VarintSize32(
+                              static_cast<uint32_t>(inner_length));
+  }
+
+  static int GetCachedSize(const Key& key, const Value& value) {
+    // Tags for key and value will both be one byte (field numbers 1 and 2).
+    return 2 + KeyTypeHandler::GetCachedSize(key) +
+           ValueTypeHandler::GetCachedSize(value);
+  }
+};
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 7e50ef1..cff2165 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -41,25 +41,26 @@
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/parse_context.h>
-#include <google/protobuf/reflection_internal.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/reflection_internal.h>
 #include <google/protobuf/reflection_ops.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/hash.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index a086945..e470c7d 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -110,6 +110,7 @@
 #ifndef GOOGLE_PROTOBUF_MESSAGE_H__
 #define GOOGLE_PROTOBUF_MESSAGE_H__
 
+
 #include <iosfwd>
 #include <string>
 #include <type_traits>
@@ -118,16 +119,18 @@
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_reflection.h>
 #include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/map.h>  // TODO(b/211442718): cleanup
 #include <google/protobuf/message_lite.h>
-#include <google/protobuf/port.h>
 
 
 #define GOOGLE_PROTOBUF_HAS_ONEOF
 #define GOOGLE_PROTOBUF_HAS_ARENAS
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -145,7 +148,6 @@
 // Defined in other files.
 class AssignDescriptorsHelper;
 class DynamicMessageFactory;
-class DynamicMessageReflectionHelper;
 class GeneratedMessageReflectionTestHelper;
 class MapKey;
 class MapValueConstRef;
@@ -1040,7 +1042,6 @@
   friend class ::PROTOBUF_NAMESPACE_ID::MessageLayoutInspector;
   friend class ::PROTOBUF_NAMESPACE_ID::AssignDescriptorsHelper;
   friend class DynamicMessageFactory;
-  friend class DynamicMessageReflectionHelper;
   friend class GeneratedMessageReflectionTestHelper;
   friend class python::MapReflectionFriend;
   friend class python::MessageReflectionFriend;
@@ -1144,7 +1145,7 @@
   const internal::ExtensionSet& GetExtensionSet(const Message& message) const;
   internal::ExtensionSet* MutableExtensionSet(Message* message) const;
 
-  inline const internal::InternalMetadata& GetInternalMetadata(
+  const internal::InternalMetadata& GetInternalMetadata(
       const Message& message) const;
 
   internal::InternalMetadata* MutableInternalMetadata(Message* message) const;
@@ -1163,6 +1164,8 @@
   inline uint32_t* MutableInlinedStringDonatedArray(Message* message) const;
   inline bool IsInlinedStringDonated(const Message& message,
                                      const FieldDescriptor* field) const;
+  inline void SwapInlinedStringDonated(Message* lhs, Message* rhs,
+                                       const FieldDescriptor* field) const;
 
   // Shallow-swap fields listed in fields vector of two messages. It is the
   // caller's responsibility to make sure shallow swap is safe.
@@ -1375,11 +1378,11 @@
 // Call this function to ensure that this message's reflection is linked into
 // the binary:
 //
-//   google::protobuf::LinkMessageReflection<FooMessage>();
+//   google::protobuf::LinkMessageReflection<pkg::FooMessage>();
 //
 // This will ensure that the following lookup will succeed:
 //
-//   DescriptorPool::generated_pool()->FindMessageTypeByName("FooMessage");
+//   DescriptorPool::generated_pool()->FindMessageTypeByName("pkg.FooMessage");
 //
 // As a side-effect, it will also guarantee that anything else from the same
 // .proto file will also be available for lookup in the generated pool.
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index b4f8d40..df614b9 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -48,13 +48,13 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/repeated_field.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/stl_util.h>
 #include <google/protobuf/stubs/mutex.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -506,9 +506,8 @@
 
 namespace internal {
 
-template <>
-MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
-    const MessageLite* prototype, Arena* arena) {
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype,
+                                    Arena* arena) {
   return prototype->New(arena);
 }
 template <>
@@ -522,6 +521,19 @@
   *to = from;
 }
 
+// Non-inline implementations of InternalMetadata routines
+#if defined(NDEBUG) || defined(_MSC_VER)
+// for opt and MSVC builds, the destructor is defined in the header.
+#else
+// This is moved out of the header because the GOOGLE_DCHECK produces a lot of code.
+InternalMetadata::~InternalMetadata() {
+  if (HasMessageOwnedArenaTag()) {
+    GOOGLE_DCHECK(!HasUnknownFieldsTag());
+    delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
+  }
+}
+#endif
+
 // Non-inline variants of std::string specializations for
 // various InternalMetadata routines.
 template <>
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 5e6fbdb..903fb1a 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -39,6 +39,7 @@
 #ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
 #define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
 
+
 #include <climits>
 #include <string>
 
@@ -46,12 +47,12 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/explicitly_constructed.h>
-#include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/stubs/strutil.h>
-
+#include <google/protobuf/explicitly_constructed.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/stubs/hash.h>  // TODO(b/211442718): cleanup
 
 // clang-format off
 #include <google/protobuf/port_def.inc>
@@ -130,8 +131,9 @@
 }
 
 // Default empty string object. Don't use this directly. Instead, call
-// GetEmptyString() to get the reference.
-PROTOBUF_EXPORT extern ExplicitlyConstructed<std::string>
+// GetEmptyString() to get the reference. This empty string is aligned with a
+// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr.
+PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
     fixed_address_empty_string;
 
 
@@ -187,8 +189,8 @@
   // if arena is a nullptr.
   virtual MessageLite* New(Arena* arena) const = 0;
 
-  // Same as GetOwningArena.
-  Arena* GetArena() const { return GetOwningArena(); }
+  // Returns user-owned arena; nullptr if it's message owned.
+  Arena* GetArena() const { return _internal_metadata_.user_arena(); }
 
   // Clear all fields of the message and set them to their default values.
   // Clear() avoids freeing memory, assuming that any memory allocated
@@ -422,6 +424,8 @@
     return nullptr;
   }
 
+  virtual void OnDemandRegisterArenaDtor(Arena* /*arena*/) {}
+
  protected:
   template <typename T>
   static T* CreateMaybeMessage(Arena* arena) {
@@ -472,9 +476,6 @@
   }
 
  private:
-  // TODO(gerbens) make this a pure abstract function
-  virtual const void* InternalGetTable() const { return nullptr; }
-
   friend class FastReflectionMessageMutator;
   friend class FastReflectionStringSetter;
   friend class Message;
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
index f57fc8e..141b4e0 100644
--- a/src/google/protobuf/message_unittest.inc
+++ b/src/google/protobuf/message_unittest.inc
@@ -264,6 +264,29 @@
                   UNITTEST_PACKAGE_NAME)));
 }
 
+TEST(MESSAGE_TEST_NAME, MergeFromUninitialized) {
+  UNITTEST::TestNestedRequiredForeign o, p, q;
+  UNITTEST::TestNestedRequiredForeign* child = o.mutable_child();
+  constexpr int kDepth = 2;
+  for (int i = 0; i < kDepth; i++) {
+    child->set_dummy(i);
+    child = child->mutable_child();
+  }
+  UNITTEST::TestRequiredForeign* payload = child->mutable_payload();
+  payload->mutable_optional_message()->set_a(1);
+  payload->mutable_optional_message()->set_dummy2(100);
+  payload->mutable_optional_message()->set_dummy4(200);
+  ASSERT_TRUE(p.ParsePartialFromString(o.SerializePartialAsString()));
+
+  GOOGLE_LOG(ERROR) << "seongkim: copy 1";
+  q.mutable_child()->set_dummy(500);
+  q = p;
+  GOOGLE_LOG(ERROR) << "seongkim: copy 1 done";
+  q.ParsePartialFromString(q.SerializePartialAsString());
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(q, o.SerializePartialAsString()));
+  EXPECT_TRUE(TestUtil::EqualsToSerialized(q, p.SerializePartialAsString()));
+}
+
 TEST(MESSAGE_TEST_NAME, ParseFailsIfSubmessageTruncated) {
   UNITTEST::NestedTestAllTypes o, p;
   constexpr int kDepth = 5;
@@ -349,6 +372,142 @@
   EXPECT_FALSE(p.ParseFromString(serialized));
 }
 
+TEST(MESSAGE_TEST_NAME, UninitializedAndMalformed) {
+  UNITTEST::TestRequiredForeign o, p1, p2;
+  o.mutable_optional_message()->set_a(-1);
+
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  std::string serialized;
+  EXPECT_TRUE(o.SerializePartialToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p1.ParsePartialFromString(serialized));
+  EXPECT_FALSE(p1.IsInitialized());
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p2.ParseFromString(serialized));
+  EXPECT_FALSE(p2.IsInitialized());
+}
+
+inline UNITTEST::NestedTestAllTypes InitNestedProto(int depth) {
+  UNITTEST::NestedTestAllTypes p;
+  auto* child = p.mutable_child();
+  for (int i = 0; i < depth; i++) {
+    child->mutable_payload()->set_optional_int32(i);
+    child = child->mutable_child();
+  }
+  // -1 becomes \xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1
+  child->mutable_payload()->set_optional_int32(-1);
+  return p;
+}
+
+// Parsing proto must not access beyond the bound.
+TEST(MESSAGE_TEST_NAME, ParseStrictlyBoundedStream) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 2;
+  o = InitNestedProto(kDepth);
+  TestUtil::SetAllFields(o.mutable_child()->mutable_payload());
+  o.mutable_child()->mutable_child()->mutable_payload()->set_optional_string(
+      std::string(1024, 'a'));
+
+  std::string data;
+  EXPECT_TRUE(o.SerializeToString(&data));
+
+  TestUtil::BoundedArrayInputStream stream(data.data(), data.size());
+  EXPECT_TRUE(p.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+  TestUtil::ExpectAllFieldsSet(p.child().payload());
+}
+
+TEST(MESSAGE_TEST_NAME, SuccessAfterParsingFailure) {
+  UNITTEST::NestedTestAllTypes o, p, q;
+  constexpr int kDepth = 5;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should parse correctly.
+  EXPECT_TRUE(p.ParseFromString(serialized));
+
+  // Overwriting the last byte to 0xFF results in malformed wire.
+  serialized[serialized.size() - 1] = 0xFF;
+  EXPECT_FALSE(p.ParseFromString(serialized));
+
+  // Subsequent serialization should be parsed correctly.
+  EXPECT_TRUE(q.ParseFromString(p.SerializeAsString()));
+}
+
+TEST(MESSAGE_TEST_NAME, ExceedRecursionLimit) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Recursion level deeper than the default.
+  EXPECT_FALSE(p.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME, SupportCustomRecursionLimitRead) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should pass with custom limit + reads.
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(kDepth + 10);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+
+  EXPECT_EQ(p.child().payload().optional_int32(), 0);
+  EXPECT_EQ(p.child().child().payload().optional_int32(), 1);
+
+  // Verify p serializes successfully (survives VerifyConsistency).
+  std::string result;
+  EXPECT_TRUE(p.SerializeToString(&result));
+}
+
+TEST(MESSAGE_TEST_NAME, SupportCustomRecursionLimitWrite) {
+  UNITTEST::NestedTestAllTypes o, p;
+  const int kDepth = io::CodedInputStream::GetDefaultRecursionLimit() + 10;
+  o = InitNestedProto(kDepth);
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  // Should pass with custom limit + writes.
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(kDepth + 10);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+
+  EXPECT_EQ(p.mutable_child()->mutable_payload()->optional_int32(), 0);
+  EXPECT_EQ(
+      p.mutable_child()->mutable_child()->mutable_payload()->optional_int32(),
+      1);
+}
+
+// While deep recursion is never guaranteed, this test aims to catch potential
+// issues with very deep recursion.
+TEST(MESSAGE_TEST_NAME, SupportDeepRecursionLimit) {
+  UNITTEST::NestedTestAllTypes o, p;
+  constexpr int kDepth = 1000;
+  auto* child = o.mutable_child();
+  for (int i = 0; i < kDepth; i++) {
+    child = child->mutable_child();
+  }
+  child->mutable_payload()->set_optional_int32(100);
+
+  std::string serialized;
+  EXPECT_TRUE(o.SerializeToString(&serialized));
+
+  io::ArrayInputStream raw_input(serialized.data(), serialized.size());
+  io::CodedInputStream input(&raw_input);
+  input.SetRecursionLimit(1100);
+  EXPECT_TRUE(p.ParseFromCodedStream(&input));
+}
+
 TEST(MESSAGE_TEST_NAME, Swap) {
   UNITTEST::NestedTestAllTypes o;
   constexpr int kDepth = 5;
@@ -485,7 +644,7 @@
   std::string data_;
   size_t count_;     // The number of strings that haven't been consumed.
   size_t position_;  // Position in the std::string for the next read.
-  int64 total_byte_count_;
+  int64_t total_byte_count_;
 };
 }  // namespace
 
@@ -513,6 +672,8 @@
 }
 
 TEST(MESSAGE_TEST_NAME, TestParseMessagesOver2G) {
+  constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
+
   // Create a message with a large std::string field.
   std::string value = std::string(64 * 1024 * 1024, 'x');
   UNITTEST::TestAllTypes message;
diff --git a/src/google/protobuf/metadata_lite.h b/src/google/protobuf/metadata_lite.h
index e6ecfb7..d6cf87f 100644
--- a/src/google/protobuf/metadata_lite.h
+++ b/src/google/protobuf/metadata_lite.h
@@ -36,6 +36,7 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -69,11 +70,15 @@
     GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
   }
 
+#if defined(NDEBUG) || defined(_MSC_VER)
   ~InternalMetadata() {
     if (HasMessageOwnedArenaTag()) {
-      delete arena();
+      delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
     }
   }
+#else
+  ~InternalMetadata();
+#endif
 
   template <typename T>
   void Delete() {
@@ -83,10 +88,31 @@
     }
   }
 
+  // DeleteReturnArena will delete the unknown fields only if they weren't
+  // allocated on an arena.  Then it updates the flags so that if you call
+  // have_unknown_fields(), it will return false.  Finally, it returns the
+  // current value of arena().  It is designed to be used as part of a
+  // Message class's destructor call, so that when control eventually gets
+  // to ~InternalMetadata(), we don't need to check for have_unknown_fields()
+  // again.
+  template <typename T>
+  Arena* DeleteReturnArena() {
+    if (have_unknown_fields()) {
+      return DeleteOutOfLineHelper<T>();
+    } else {
+      return PtrValue<Arena>();
+    }
+  }
+
   PROTOBUF_NDEBUG_INLINE Arena* owning_arena() const {
     return HasMessageOwnedArenaTag() ? nullptr : arena();
   }
 
+  PROTOBUF_NDEBUG_INLINE Arena* user_arena() const {
+    Arena* a = arena();
+    return a && !a->IsMessageOwned() ? a : nullptr;
+  }
+
   PROTOBUF_NDEBUG_INLINE Arena* arena() const {
     if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
       return PtrValue<ContainerBase>()->arena;
@@ -187,9 +213,18 @@
   };
 
   template <typename T>
-  PROTOBUF_NOINLINE void DeleteOutOfLineHelper() {
-    if (arena() == nullptr) {
+  PROTOBUF_NOINLINE Arena* DeleteOutOfLineHelper() {
+    if (auto* a = arena()) {
+      // Subtle: we want to preserve the message-owned arena flag, while at the
+      // same time replacing the pointer to Container<T> with a pointer to the
+      // arena.
+      intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
+      ptr_ = reinterpret_cast<intptr_t>(a) | message_owned_arena_tag;
+      return a;
+    } else {
       delete PtrValue<Container<T>>();
+      ptr_ = 0;
+      return nullptr;
     }
   }
 
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index 1aec2ae..da42e87 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -36,9 +36,10 @@
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
-#include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format_lite.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -388,12 +389,13 @@
 }
 
 // Defined in wire_format_lite.cc
-void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
                        bool emit_stacktrace);
 
 bool VerifyUTF8(StringPiece str, const char* field_name) {
   if (!IsStructurallyValidUTF8(str)) {
-    PrintUTF8ErrorLog(field_name, "parsing", false);
+    PrintUTF8ErrorLog("", field_name, "parsing", false);
     return false;
   }
   return true;
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index 80d5b01..c00048d 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -38,15 +38,16 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/implicit_weak_message.h>
 #include <google/protobuf/inlined_string_field.h>
 #include <google/protobuf/metadata_lite.h>
-#include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/stubs/strutil.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 
@@ -197,6 +198,7 @@
     return ptr > limit_end_ &&
            (next_chunk_ == nullptr || ptr - buffer_end_ > limit_);
   }
+  bool AliasingEnabled() const { return aliasing_ != kNoAliasing; }
   int BytesUntilLimit(const char* ptr) const {
     return limit_ + static_cast<int>(buffer_end_ - ptr);
   }
@@ -370,6 +372,9 @@
   friend class ImplicitWeakMessage;
 };
 
+using LazyEagerVerifyFnType = const char* (*)(const char* ptr,
+                                              ParseContext* ctx);
+
 // ParseContext holds all data that is global to the entire parse. Most
 // importantly it contains the input stream, but also recursion depth and also
 // stores the end group tag, in case a parser ended on a endgroup, to verify
@@ -399,6 +404,18 @@
 
   const char* ParseMessage(MessageLite* msg, const char* ptr);
 
+  // Spawns a child parsing context that inherits key properties. New context
+  // inherits the following:
+  // --depth_, data_, check_required_fields_, lazy_parse_mode_
+  // The spanwed context always disables aliasing (different input).
+  template <typename... T>
+  ParseContext Spawn(const char** start, T&&... args) {
+    ParseContext spawned(depth_, false, start, std::forward<T>(args)...);
+    // Transfer key context states.
+    spawned.data_ = data_;
+    return spawned;
+  }
+
   // This overload supports those few cases where ParseMessage is called
   // on a class that is not actually a proto message.
   // TODO(jorg): Eliminate this use case.
diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h
index 4c09eb1..3201d45 100644
--- a/src/google/protobuf/port.h
+++ b/src/google/protobuf/port.h
@@ -36,5 +36,29 @@
 #ifndef GOOGLE_PROTOBUF_PORT_H__
 #define GOOGLE_PROTOBUF_PORT_H__
 
+#include <cstddef>
+#include <new>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+inline void SizedDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete(p, size);
+#else
+  ::operator delete(p);
+#endif
+}
+inline void SizedArrayDelete(void* p, size_t size) {
+#if defined(__cpp_sized_deallocation)
+  ::operator delete[](p, size);
+#else
+  ::operator delete[](p);
+#endif
+}
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 
 #endif  // GOOGLE_PROTOBUF_PORT_H__
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index dca2dad..ae1cc59 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -148,7 +148,11 @@
 // Future versions of protobuf will include breaking changes to some APIs.
 // This macro can be set to enable these API changes ahead of time, so that
 // user code can be updated before upgrading versions of protobuf.
+// PROTOBUF_FUTURE_FINAL is used on classes that are historically not marked as
+// final, but that may be marked final in future (breaking) releases.
 // #define PROTOBUF_FUTURE_BREAKING_CHANGES 1
+// #define PROTOBUF_FUTURE_FINAL final
+#define PROTOBUF_FUTURE_FINAL
 
 #ifdef PROTOBUF_VERSION
 #error PROTOBUF_VERSION was previously defined
@@ -364,11 +368,19 @@
 #error PROTOBUF_RTTI was previously defined
 #endif
 #if defined(GOOGLE_PROTOBUF_NO_RTTI) && GOOGLE_PROTOBUF_NO_RTTI
+// A user-provided definition GOOGLE_PROTOBUF_NO_RTTI=1 disables RTTI.
 #define PROTOBUF_RTTI 0
-#elif __has_feature(cxx_rtti)
+#elif defined(__cpp_rtti)
+// https://en.cppreference.com/w/cpp/feature_test
 #define PROTOBUF_RTTI 1
-#elif defined(__cxx_rtti)
-// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros#C.2B.2B98
+#elif __has_feature(cxx_rtti)
+// https://clang.llvm.org/docs/LanguageExtensions.html#c-rtti
+#define PROTOBUF_RTTI 1
+#elif defined(__GXX_RTTI)
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+#define PROTOBUF_RTTI 1
+#elif defined(_CPPRTTI)
+// https://docs.microsoft.com/en-us/cpp/build/reference/gr-enable-run-time-type-information
 #define PROTOBUF_RTTI 1
 #else
 #define PROTOBUF_RTTI 0
@@ -461,7 +473,7 @@
 #ifdef PROTOBUF_NODISCARD
 #error PROTOBUF_NODISCARD was previously defined
 #endif
-#if __has_cpp_attribute(nodiscard)
+#if __has_cpp_attribute(nodiscard) && PROTOBUF_CPLUSPLUS_MIN(201703L)
 #define PROTOBUF_NODISCARD [[nodiscard]]
 #elif __has_attribute(warn_unused_result) || PROTOBUF_GNUC_MIN(4, 8)
 #define PROTOBUF_NODISCARD __attribute__((warn_unused_result))
@@ -469,6 +481,13 @@
 #define PROTOBUF_NODISCARD
 #endif
 
+// Enable all stable experiments if this flag is set.  This allows us to group
+// all of these experiments under a single build flag, which can be enabled in
+// the protobuf.stable-experiments TAP project.
+#ifdef PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+#define PROTOBUF_FORCE_MESSAGE_OWNED_ARENA
+#endif  // !PROTOBUF_ENABLE_STABLE_EXPERIMENTS
+
 #ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
 #error PROTOBUF_FORCE_COPY_IN_RELEASE was previously defined
 #endif
@@ -576,14 +595,18 @@
 #ifdef PROTOBUF_CONSTINIT
 #error PROTOBUF_CONSTINIT was previously defined
 #endif
-#if defined(__cpp_constinit) && !PROTOBUF_GNUC_MIN(3, 0) && !defined(_MSC_VER)
-// Our use of constinit does not yet work with GCC:
-// https://github.com/protocolbuffers/protobuf/issues/8310
-// Does not work yet with Visual Studio 2019 Update 16.10
+#if defined(__cpp_constinit)
 #define PROTOBUF_CONSTINIT constinit
-#elif !defined(_MSC_VER) && \
-    __has_cpp_attribute(clang::require_constant_initialization)
+// Some older Clang versions incorrectly raise an error about
+// constant-initializing weak default instance pointers. Versions 12.0 and
+// higher seem to work, except that XCode 12.5.1 shows the error even though it
+// uses Clang 12.0.5.
+#elif __has_cpp_attribute(clang::require_constant_initialization) && \
+    ((defined(__APPLE__) && __clang_major__ >= 13) ||                \
+     (!defined(__APPLE__) && __clang_major__ >= 12))
 #define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
+#elif PROTOBUF_GNUC_MIN(12, 0)
+#define PROTOBUF_CONSTINIT __constinit
 #else
 #define PROTOBUF_CONSTINIT
 #endif
@@ -600,20 +623,43 @@
 #define PROTOBUF_ATTRIBUTE_NO_DESTROY
 #endif
 
+// Force clang to always emit complete debug info for a type.
+// Clang uses constructor homing to determine when to emit debug info for a
+// type. If the constructor of a type is never used, which can happen in some
+// cases where member variables are constructed in place for optimization
+// purposes (see b/208803175 for an example), the type will have incomplete
+// debug info unless this attribute is used.
+#ifdef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#error PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG was previously defined
+#endif
+#if __has_cpp_attribute(clang::standalone_debug)
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG [[clang::standalone_debug]]
+#else
+#define PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#endif
+
 // Protobuf extensions and reflection require registration of the protos linked
 // in the binary. Not until everything is registered does the runtime have a
 // complete view on all protos. When code is using reflection or extensions
 // in between registration calls this can lead to surprising behavior. By
 // having the registration run first we mitigate this scenario.
-// Highest priority is 101. We use 102 to allow code that really wants to
-// higher priority to still beat us.
-#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY
-#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY was previously defined
+// Highest priority is 101. We use 102 for registration, to allow code that
+// really wants to higher priority to still beat us. Some initialization happens
+// at higher priority, though, since it is needed before registration.
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 was previously defined
 #endif
-#if PROTOBUF_GNUC_MIN(3, 0) && (!defined(__APPLE__) || defined(__clang__)) && !((defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)))
-#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY __attribute__((init_priority((102))))
+#ifdef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+#error PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 was previously defined
+#endif
+#if PROTOBUF_GNUC_MIN(3, 0) && (!defined(__APPLE__) || defined(__clang__)) && \
+    !((defined(sun) || defined(__sun)) &&                                     \
+      (defined(__SVR4) || defined(__svr4__)))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 __attribute__((init_priority((101))))
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 __attribute__((init_priority((102))))
 #else
-#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#define PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
 #endif
 
 #ifdef PROTOBUF_PRAGMA_INIT_SEG
@@ -681,19 +727,6 @@
 #endif
 #if defined(PROTOBUF_EXPERIMENTAL_USE_TAIL_CALL_TABLE_PARSER)
 #define PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED 1
-// Selectively use static member functions instead of templates:
-#ifndef PROTOBUF_TC_STATIC_PARSE_SINGULAR1
-#  define PROTOBUF_TC_STATIC_PARSE_SINGULAR1 1
-#endif
-#ifndef PROTOBUF_TC_STATIC_PARSE_SINGULAR2
-#  define PROTOBUF_TC_STATIC_PARSE_SINGULAR2 0
-#endif
-#ifndef PROTOBUF_TC_STATIC_PARSE_REPEATED1
-#  define PROTOBUF_TC_STATIC_PARSE_REPEATED1 0
-#endif
-#ifndef PROTOBUF_TC_STATIC_PARSE_REPEATED2
-#  define PROTOBUF_TC_STATIC_PARSE_REPEATED2 0
-#endif
 #endif
 
 #define PROTOBUF_TC_PARAM_DECL                                 \
@@ -714,6 +747,8 @@
 #define PROTOBUF_UNUSED
 #endif
 
+// ThreadSafeArenaz is turned off completely in opensource builds.
+
 // Windows declares several inconvenient macro names.  We #undef them and then
 // restore them in port_undef.inc.
 #ifdef _MSC_VER
@@ -759,12 +794,25 @@
 #undef SERVICE_DISABLED
 #pragma push_macro("SEVERITY_ERROR")
 #undef SEVERITY_ERROR
+#pragma push_macro("STATUS_PENDING")
+#undef STATUS_PENDING
 #pragma push_macro("STRICT")
 #undef STRICT
 #pragma push_macro("timezone")
 #undef timezone
 #endif  // _MSC_VER
 
+#ifdef __APPLE__
+// Inconvenient macro names from usr/include/math.h in some macOS SDKs.
+#pragma push_macro("DOMAIN")
+#undef DOMAIN
+// Inconvenient macro names from /usr/include/mach/boolean.h in some macOS SDKs.
+#pragma push_macro("TRUE")
+#undef TRUE
+#pragma push_macro("FALSE")
+#undef FALSE
+#endif  // __APPLE__
+
 #if defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)
 // Don't let Objective-C Macros interfere with proto identifiers with the same
 // name.
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index ccc5daf..664c936 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -76,22 +76,21 @@
 #undef PROTOBUF_EXPORT_TEMPLATE_DEFINE
 #undef PROTOBUF_ALIGNAS
 #undef PROTOBUF_FINAL
+#undef PROTOBUF_FUTURE_FINAL
 #undef PROTOBUF_THREAD_LOCAL
 #undef PROTOBUF_MESSAGE_OWNED_ARENA_EXPERIMENT
 #undef PROTOBUF_CONSTINIT
 #undef PROTOBUF_ATTRIBUTE_WEAK
 #undef PROTOBUF_HAVE_ATTRIBUTE_WEAK
 #undef PROTOBUF_ATTRIBUTE_NO_DESTROY
-#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY
+#undef PROTOBUF_ATTRIBUTE_STANDALONE_DEBUG
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY1
+#undef PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
 #undef PROTOBUF_PRAGMA_INIT_SEG
 #undef PROTOBUF_ASAN
 #undef PROTOBUF_MSAN
 #undef PROTOBUF_TSAN
 #undef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED
-#undef PROTOBUF_TC_STATIC_PARSE_SINGULAR1
-#undef PROTOBUF_TC_STATIC_PARSE_SINGULAR2
-#undef PROTOBUF_TC_STATIC_PARSE_REPEATED1
-#undef PROTOBUF_TC_STATIC_PARSE_REPEATED2
 #undef PROTOBUF_TC_PARAM_DECL
 #undef PROTOBUF_EXCLUSIVE_LOCKS_REQUIRED
 #undef PROTOBUF_LOCKS_EXCLUDED
@@ -126,9 +125,16 @@
 #pragma pop_macro("SERVICE_DISABLED")
 #pragma pop_macro("SEVERITY_ERROR")
 #pragma pop_macro("STRICT")
+#pragma pop_macro("STATUS_PENDING")
 #pragma pop_macro("timezone")
 #endif
 
+#ifdef __APPLE__
+#pragma pop_macro("DOMAIN")
+#pragma pop_macro("TRUE")
+#pragma pop_macro("FALSE")
+#endif  // __APPLE__
+
 #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
 #pragma pop_macro("DEBUG")
 #endif // defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
index 498ab71..7b75a43 100644
--- a/src/google/protobuf/reflection.h
+++ b/src/google/protobuf/reflection.h
@@ -33,6 +33,7 @@
 #ifndef GOOGLE_PROTOBUF_REFLECTION_H__
 #define GOOGLE_PROTOBUF_REFLECTION_H__
 
+
 #include <memory>
 
 #include <google/protobuf/message.h>
@@ -42,6 +43,7 @@
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index 8f0cfb9..b267672 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -38,12 +38,13 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/unknown_field_set.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -182,7 +183,9 @@
     reflection->ClearField(message, field);
   }
 
-  reflection->MutableUnknownFields(message)->Clear();
+  if (reflection->GetInternalMetadata(*message).have_unknown_fields()) {
+    reflection->MutableUnknownFields(message)->Clear();
+  }
 }
 
 bool ReflectionOps::IsInitialized(const Message& message, bool check_fields,
diff --git a/src/google/protobuf/reflection_ops.h b/src/google/protobuf/reflection_ops.h
index fb98714..0a45702 100644
--- a/src/google/protobuf/reflection_ops.h
+++ b/src/google/protobuf/reflection_ops.h
@@ -45,6 +45,7 @@
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc
index 8c4da21..0ae6974 100644
--- a/src/google/protobuf/reflection_ops_unittest.cc
+++ b/src/google/protobuf/reflection_ops_unittest.cc
@@ -110,7 +110,7 @@
 
   // This tests concatenating.
   message2.add_repeated_int32(message.repeated_int32(1));
-  int32 i = message.repeated_int32(0);
+  int32_t i = message.repeated_int32(0);
   message.clear_repeated_int32();
   message.add_repeated_int32(i);
 
@@ -143,7 +143,7 @@
   message2.AddExtension(
       unittest::repeated_int32_extension,
       message.GetExtension(unittest::repeated_int32_extension, 1));
-  int32 i = message.GetExtension(unittest::repeated_int32_extension, 0);
+  int32_t i = message.GetExtension(unittest::repeated_int32_extension, 0);
   message.ClearExtension(unittest::repeated_int32_extension);
   message.AddExtension(unittest::repeated_int32_extension, i);
 
@@ -516,7 +516,7 @@
     unittest::TestAllTypes message;
     auto* arena_message = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
     TestUtil::SetAllFields(arena_message);
-    const uint64 initial_arena_size = arena.SpaceUsed();
+    const uint64_t initial_arena_size = arena.SpaceUsed();
 
     GenericSwap(&message, arena_message);
 
@@ -529,7 +529,7 @@
     unittest::TestAllTypes message;
     auto* arena_message = Arena::CreateMessage<unittest::TestAllTypes>(&arena);
     TestUtil::SetAllFields(arena_message);
-    const uint64 initial_arena_size = arena.SpaceUsed();
+    const uint64_t initial_arena_size = arena.SpaceUsed();
 
     GenericSwap(arena_message, &message);
 
diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc
index 28a7bd3..3070b14 100644
--- a/src/google/protobuf/repeated_field.cc
+++ b/src/google/protobuf/repeated_field.cc
@@ -39,6 +39,7 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 3f362f9..c230a0f 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -39,32 +39,25 @@
 // particularly different from STL vector as it manages ownership of the
 // pointers that it contains.
 //
-// Typically, clients should not need to access RepeatedField objects directly,
-// but should instead use the accessor functions generated automatically by the
-// protocol compiler.
-//
 // This header covers RepeatedField.
 
 #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
 #define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
 
-#include <utility>
-#ifdef _MSC_VER
-// This is required for min/max on VS2013 only.
-#include <algorithm>
-#endif
 
+#include <algorithm>
 #include <iterator>
 #include <limits>
 #include <string>
 #include <type_traits>
+#include <utility>
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/repeated_ptr_field.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_ptr_field.h>
 
 
 // Must be included last.
@@ -81,9 +74,18 @@
 
 namespace internal {
 
-// kRepeatedFieldLowerClampLimit is the smallest size that will be allocated
-// when growing a repeated field.
-constexpr int kRepeatedFieldLowerClampLimit = 4;
+template <typename T, int kRepHeaderSize>
+constexpr int RepeatedFieldLowerClampLimit() {
+  // The header is padded to be at least `sizeof(T)` when it would be smaller
+  // otherwise.
+  static_assert(sizeof(T) <= kRepHeaderSize, "");
+  // We want to pad the minimum size to be a power of two bytes, including the
+  // header.
+  // The first allocation is kRepHeaderSize bytes worth of elements for a total
+  // of 2*kRepHeaderSize bytes.
+  // For an 8-byte header, we allocate 8 bool, 2 ints, or 1 int64.
+  return kRepHeaderSize / sizeof(T);
+}
 
 // kRepeatedFieldUpperClampLimit is the lowest signed integer value that
 // overflows when multiplied by 2 (which is undefined behavior). Sizes above
@@ -120,7 +122,6 @@
 
 // Swaps two blocks of memory of size kSize:
 //  template <int kSize> void memswap(char* p, char* q);
-
 template <int kSize>
 inline typename std::enable_if<(kSize == 0), void>::type memswap(char*, char*) {
 }
@@ -192,20 +193,20 @@
 
   void Set(int index, const Element& value);
   void Add(const Element& value);
-  // Appends a new element and return a pointer to it.
+  // Appends a new element and returns a pointer to it.
   // The new element is uninitialized if |Element| is a POD type.
   Element* Add();
-  // Append elements in the range [begin, end) after reserving
+  // Appends elements in the range [begin, end) after reserving
   // the appropriate number of elements.
   template <typename Iter>
   void Add(Iter begin, Iter end);
 
-  // Remove the last element in the array.
+  // Removes the last element in the array.
   void RemoveLast();
 
-  // Extract elements with indices in "[start .. start+num-1]".
-  // Copy them into "elements[0 .. num-1]" if "elements" is not nullptr.
-  // Caution: implementation also moves elements with indices [start+num ..].
+  // Extracts elements with indices in "[start .. start+num-1]".
+  // Copies them into "elements[0 .. num-1]" if "elements" is not nullptr.
+  // Caution: also moves elements with indices [start+num ..].
   // Calling this routine inside a loop can cause quadratic behavior.
   void ExtractSubrange(int start, int num, Element* elements);
 
@@ -217,11 +218,11 @@
   template <typename Iter>
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
 
-  // Reserve space to expand the field to at least the given size.  If the
+  // Reserves space to expand the field to at least the given size.  If the
   // array is grown, it will always be at least doubled in size.
   void Reserve(int new_size);
 
-  // Resize the RepeatedField to a new, smaller size.  This is O(1).
+  // Resizes the RepeatedField to a new, smaller size.  This is O(1).
   void Truncate(int new_size);
 
   void AddAlreadyReserved(const Element& value);
@@ -242,17 +243,17 @@
   Element* mutable_data();
   const Element* data() const;
 
-  // Swap entire contents with "other". If they are separate arenas then, copies
-  // data between each other.
+  // Swaps entire contents with "other". If they are separate arenas then,
+  // copies data between each other.
   void Swap(RepeatedField* other);
 
-  // Swap entire contents with "other". Should be called only if the caller can
+  // Swaps entire contents with "other". Should be called only if the caller can
   // guarantee that both repeated fields are on the same arena or are on the
   // heap. Swapping between different arenas is disallowed and caught by a
   // GOOGLE_DCHECK (see API docs for details).
   void UnsafeArenaSwap(RepeatedField* other);
 
-  // Swap two elements.
+  // Swaps two elements.
   void SwapElements(int index1, int index2);
 
   // STL-like iterator support
@@ -308,10 +309,9 @@
   // 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.
+  // Gets the Arena on which this RepeatedField stores its elements.
   inline Arena* GetArena() const {
-    return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
-                              : rep()->arena;
+    return GetOwningArena();
   }
 
   // For internal use only.
@@ -320,6 +320,14 @@
   inline void InternalSwap(RepeatedField* other);
 
  private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  // Gets the Arena on which this RepeatedField stores its elements.
+  inline Arena* GetOwningArena() const {
+    return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
+                              : rep()->arena;
+  }
+
   static constexpr int kInitialSize = 0;
   // A note on the representation here (see also comment below for
   // RepeatedPtrFieldBase's struct Rep):
@@ -333,21 +341,24 @@
   // RepeatedField class to avoid costly cache misses due to the indirection.
   int current_size_;
   int total_size_;
+  // Pad the Rep after arena allow for power-of-two byte sizes when
+  // sizeof(Element) > sizeof(Arena*). eg for 16-byte objects.
+  static constexpr size_t kRepHeaderSize =
+      sizeof(Arena*) < sizeof(Element) ? sizeof(Element) : sizeof(Arena*);
   struct Rep {
     Arena* arena;
-    // Here we declare a huge array as a way of approximating C's "flexible
-    // array member" feature without relying on undefined behavior.
-    Element elements[(std::numeric_limits<int>::max() - 2 * sizeof(Arena*)) /
-                     sizeof(Element)];
+    Element* elements() {
+      return reinterpret_cast<Element*>(reinterpret_cast<char*>(this) +
+                                        kRepHeaderSize);
+    }
   };
-  static constexpr size_t kRepHeaderSize = offsetof(Rep, elements);
 
   // If total_size_ == 0 this points to an Arena otherwise it points to the
   // elements member of a Rep struct. Using this invariant allows the storage of
   // the arena pointer without an extra allocation in the constructor.
   void* arena_or_elements_;
 
-  // Return pointer to elements array.
+  // Returns a pointer to elements array.
   // pre-condition: the array must have been allocated.
   Element* elements() const {
     GOOGLE_DCHECK_GT(total_size_, 0);
@@ -355,48 +366,48 @@
     return unsafe_elements();
   }
 
-  // Return pointer to elements array if it exists otherwise either null or
-  // a invalid pointer is returned. This only happens for empty repeated fields,
-  // where you can't dereference this pointer anyway (it's empty).
+  // Returns a pointer to elements array if it exists; otherwise either null or
+  // an invalid pointer is returned. This only happens for empty repeated
+  // fields, where you can't dereference this pointer anyway (it's empty).
   Element* unsafe_elements() const {
     return static_cast<Element*>(arena_or_elements_);
   }
 
-  // Return pointer to the Rep struct.
+  // Returns a pointer to the Rep struct.
   // pre-condition: the Rep must have been allocated, ie elements() is safe.
   Rep* rep() const {
-    char* addr = reinterpret_cast<char*>(elements()) - offsetof(Rep, elements);
-    return reinterpret_cast<Rep*>(addr);
+    return reinterpret_cast<Rep*>(reinterpret_cast<char*>(elements()) -
+                                  kRepHeaderSize);
   }
 
   friend class Arena;
   typedef void InternalArenaConstructable_;
 
-  // Move the contents of |from| into |to|, possibly clobbering |from| in the
+  // Moves the contents of |from| into |to|, possibly clobbering |from| in the
   // process.  For primitive types this is just a memcpy(), but it could be
   // specialized for non-primitive types to, say, swap each element instead.
   void MoveArray(Element* to, Element* from, int size);
 
-  // Copy the elements of |from| into |to|.
+  // Copies the elements of |from| into |to|.
   void CopyArray(Element* to, const Element* from, int size);
 
   // Internal helper to delete all elements and deallocate the storage.
-  void InternalDeallocate(Rep* rep, int size) {
+  void InternalDeallocate(Rep* rep, int size, bool in_destructor) {
     if (rep != nullptr) {
-      Element* e = &rep->elements[0];
+      Element* e = &rep->elements()[0];
       if (!std::is_trivial<Element>::value) {
-        Element* limit = &rep->elements[size];
+        Element* limit = &rep->elements()[size];
         for (; e < limit; e++) {
           e->~Element();
         }
       }
+      const size_t bytes = size * sizeof(*e) + kRepHeaderSize;
       if (rep->arena == nullptr) {
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
-        const size_t bytes = size * sizeof(*e) + kRepHeaderSize;
-        ::operator delete(static_cast<void*>(rep), bytes);
-#else
-        ::operator delete(static_cast<void*>(rep));
-#endif
+        internal::SizedDelete(rep, bytes);
+      } else if (!in_destructor) {
+        // If we are in the destructor, we might be being destroyed as part of
+        // the arena teardown. We can't try and return blocks to the arena then.
+        rep->arena->ReturnArrayMemory(rep, bytes);
       }
     }
   }
@@ -419,7 +430,7 @@
   // largely the presence of the fallback path disturbs the compilers mem-to-reg
   // analysis.
   //
-  // This class takes ownership of a repeated field for the duration of it's
+  // This class takes ownership of a repeated field for the duration of its
   // lifetime. The repeated field should not be accessed during this time, ie.
   // only access through this class is allowed. This class should always be a
   // function local stack variable. Intended use
@@ -432,13 +443,13 @@
   //   }
   // }
   //
-  // Typically due to the fact adder is a local stack variable. The compiler
-  // will be successful in mem-to-reg transformation and the machine code will
-  // be loop: cmp %size, %capacity jae fallback mov dword ptr [%buffer + %size *
-  // 4], %val inc %size jmp loop
+  // Typically, due to the fact that adder is a local stack variable, the
+  // compiler will be successful in mem-to-reg transformation and the machine
+  // code will be loop: cmp %size, %capacity jae fallback mov dword ptr [%buffer
+  // + %size * 4], %val inc %size jmp loop
   //
   // The first version executes at 7 cycles per iteration while the second
-  // version near 1 or 2 cycles.
+  // version executes at only 1 or 2 cycles.
   template <int = 0, bool = std::is_trivial<Element>::value>
   class FastAdderImpl {
    public:
@@ -531,13 +542,13 @@
 template <typename Element>
 RepeatedField<Element>::~RepeatedField() {
 #ifndef NDEBUG
-  // Try to trigger segfault / asan failure in non-opt builds. If arena_
+  // Try to trigger segfault / asan failure in non-opt builds if arena_
   // lifetime has ended before the destructor.
   auto arena = GetArena();
   if (arena) (void)arena->SpaceAllocated();
 #endif
   if (total_size_ > 0) {
-    InternalDeallocate(rep(), total_size_);
+    InternalDeallocate(rep(), total_size_, true);
   }
 }
 
@@ -886,18 +897,23 @@
 //     new_size > total_size &&
 //     (total_size == 0 ||
 //      total_size >= kRepeatedFieldLowerClampLimit)
+template <typename T, int kRepHeaderSize>
 inline int CalculateReserveSize(int total_size, int new_size) {
-  if (new_size < kRepeatedFieldLowerClampLimit) {
+  constexpr int lower_limit = RepeatedFieldLowerClampLimit<T, kRepHeaderSize>();
+  if (new_size < lower_limit) {
     // Clamp to smallest allowed size.
-    return kRepeatedFieldLowerClampLimit;
+    return lower_limit;
   }
-  if (total_size < kRepeatedFieldUpperClampLimit) {
-    return std::max(total_size * 2, new_size);
-  } else {
-    // Clamp to largest allowed size.
-    GOOGLE_DCHECK_GT(new_size, kRepeatedFieldUpperClampLimit);
+  constexpr int kMaxSizeBeforeClamp =
+      (std::numeric_limits<int>::max() - kRepHeaderSize) / 2;
+  if (PROTOBUF_PREDICT_FALSE(total_size > kMaxSizeBeforeClamp)) {
     return std::numeric_limits<int>::max();
   }
+  // We want to double the number of bytes, not the number of elements, to try
+  // to stay within power-of-two allocations.
+  // The allocation has kRepHeaderSize + sizeof(T) * capacity.
+  int doubled_size = 2 * total_size + kRepHeaderSize / sizeof(T);
+  return std::max(doubled_size, new_size);
 }
 }  // namespace internal
 
@@ -909,7 +925,10 @@
   Rep* old_rep = total_size_ > 0 ? rep() : nullptr;
   Rep* new_rep;
   Arena* arena = GetArena();
-  new_size = internal::CalculateReserveSize(total_size_, new_size);
+
+  new_size = internal::CalculateReserveSize<Element, kRepHeaderSize>(
+      total_size_, new_size);
+
   GOOGLE_DCHECK_LE(
       static_cast<size_t>(new_size),
       (std::numeric_limits<size_t>::max() - kRepHeaderSize) / sizeof(Element))
@@ -928,7 +947,7 @@
   //     total_size_ == 0 ||
   //     total_size_ >= internal::kMinRepeatedFieldAllocationSize
   total_size_ = new_size;
-  arena_or_elements_ = new_rep->elements;
+  arena_or_elements_ = new_rep->elements();
   // Invoke placement-new on newly allocated elements. We shouldn't have to do
   // this, since Element is supposed to be POD, but a previous version of this
   // code allocated storage with "new Element[size]" and some code uses
@@ -944,11 +963,11 @@
     new (e) Element;
   }
   if (current_size_ > 0) {
-    MoveArray(&elements()[0], old_rep->elements, current_size_);
+    MoveArray(&elements()[0], old_rep->elements(), current_size_);
   }
 
   // Likewise, we need to invoke destructors on the old array.
-  InternalDeallocate(old_rep, old_total_size);
+  InternalDeallocate(old_rep, old_total_size, false);
 
 }
 
diff --git a/src/google/protobuf/repeated_field_reflection_unittest.cc b/src/google/protobuf/repeated_field_reflection_unittest.cc
index 63b2349..e472fa4 100644
--- a/src/google/protobuf/repeated_field_reflection_unittest.cc
+++ b/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -34,7 +34,6 @@
 // This test proto2 methods on a proto2 layout.
 
 #include <google/protobuf/stubs/casts.h>
-#include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/dynamic_message.h>
@@ -77,14 +76,14 @@
       desc->FindFieldByName("repeated_foreign_message");
 
   // Get RepeatedField objects for all fields of interest.
-  const RepeatedField<int32>& rf_int32 =
-      refl->GetRepeatedField<int32>(message, fd_repeated_int32);
+  const RepeatedField<int32_t>& rf_int32 =
+      refl->GetRepeatedField<int32_t>(message, fd_repeated_int32);
   const RepeatedField<double>& rf_double =
       refl->GetRepeatedField<double>(message, fd_repeated_double);
 
   // Get mutable RepeatedField objects for all fields of interest.
-  RepeatedField<int32>* mrf_int32 =
-      refl->MutableRepeatedField<int32>(&message, fd_repeated_int32);
+  RepeatedField<int32_t>* mrf_int32 =
+      refl->MutableRepeatedField<int32_t>(&message, fd_repeated_int32);
   RepeatedField<double>* mrf_double =
       refl->MutableRepeatedField<double>(&message, fd_repeated_double);
 
@@ -142,7 +141,7 @@
   // Make sure types are checked correctly at runtime.
   const FieldDescriptor* fd_optional_int32 =
       desc->FindFieldByName("optional_int32");
-  EXPECT_DEATH(refl->GetRepeatedField<int32>(message, fd_optional_int32),
+  EXPECT_DEATH(refl->GetRepeatedField<int32_t>(message, fd_optional_int32),
                "requires a repeated field");
   EXPECT_DEATH(refl->GetRepeatedField<double>(message, fd_repeated_int32),
                "not the right type");
@@ -167,12 +166,13 @@
       desc->file()->FindExtensionByName("repeated_int64_extension");
   GOOGLE_CHECK(fd_repeated_int64_extension != nullptr);
 
-  const RepeatedField<int64>& rf_int64_extension =
-      refl->GetRepeatedField<int64>(extended_message,
-                                    fd_repeated_int64_extension);
+  const RepeatedField<int64_t>& rf_int64_extension =
+      refl->GetRepeatedField<int64_t>(extended_message,
+                                      fd_repeated_int64_extension);
 
-  RepeatedField<int64>* mrf_int64_extension = refl->MutableRepeatedField<int64>(
-      &extended_message, fd_repeated_int64_extension);
+  RepeatedField<int64_t>* mrf_int64_extension =
+      refl->MutableRepeatedField<int64_t>(&extended_message,
+                                          fd_repeated_int64_extension);
 
   for (int i = 0; i < 10; ++i) {
     EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
@@ -234,8 +234,8 @@
       desc->FindFieldByName("repeated_foreign_message");
 
   // Get RepeatedFieldRef objects for all fields of interest.
-  const RepeatedFieldRef<int32> rf_int32 =
-      refl->GetRepeatedFieldRef<int32>(message, fd_repeated_int32);
+  const RepeatedFieldRef<int32_t> rf_int32 =
+      refl->GetRepeatedFieldRef<int32_t>(message, fd_repeated_int32);
   const RepeatedFieldRef<double> rf_double =
       refl->GetRepeatedFieldRef<double>(message, fd_repeated_double);
   const RepeatedFieldRef<std::string> rf_string =
@@ -247,8 +247,8 @@
       refl->GetRepeatedFieldRef<Message>(message, fd_repeated_foreign_message);
 
   // Get MutableRepeatedFieldRef objects for all fields of interest.
-  const MutableRepeatedFieldRef<int32> mrf_int32 =
-      refl->GetMutableRepeatedFieldRef<int32>(&message, fd_repeated_int32);
+  const MutableRepeatedFieldRef<int32_t> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&message, fd_repeated_int32);
   const MutableRepeatedFieldRef<double> mrf_double =
       refl->GetMutableRepeatedFieldRef<double>(&message, fd_repeated_double);
   const MutableRepeatedFieldRef<std::string> mrf_string =
@@ -425,7 +425,7 @@
   // Make sure types are checked correctly at runtime.
   const FieldDescriptor* fd_optional_int32 =
       desc->FindFieldByName("optional_int32");
-  EXPECT_DEATH(refl->GetRepeatedFieldRef<int32>(message, fd_optional_int32),
+  EXPECT_DEATH(refl->GetRepeatedFieldRef<int32_t>(message, fd_optional_int32),
                "");
   EXPECT_DEATH(refl->GetRepeatedFieldRef<double>(message, fd_repeated_int32),
                "");
@@ -453,11 +453,11 @@
   const MutableRepeatedFieldRef<TestAllTypes::NestedEnum> mutable_enum_ref =
       refl->GetMutableRepeatedFieldRef<TestAllTypes::NestedEnum>(
           &message, fd_repeated_nested_enum);
-  const RepeatedFieldRef<int32> int32_ref =
-      refl->GetRepeatedFieldRef<int32>(message, fd_repeated_nested_enum);
-  const MutableRepeatedFieldRef<int32> mutable_int32_ref =
-      refl->GetMutableRepeatedFieldRef<int32>(&message,
-                                              fd_repeated_nested_enum);
+  const RepeatedFieldRef<int32_t> int32_ref =
+      refl->GetRepeatedFieldRef<int32_t>(message, fd_repeated_nested_enum);
+  const MutableRepeatedFieldRef<int32_t> mutable_int32_ref =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&message,
+                                                fd_repeated_nested_enum);
 
   EXPECT_EQ(message.repeated_nested_enum_size(), enum_ref.size());
   EXPECT_EQ(message.repeated_nested_enum_size(), mutable_enum_ref.size());
@@ -540,13 +540,13 @@
       desc->file()->FindExtensionByName("repeated_int64_extension");
   GOOGLE_CHECK(fd_repeated_int64_extension != nullptr);
 
-  const RepeatedFieldRef<int64> rf_int64_extension =
-      refl->GetRepeatedFieldRef<int64>(extended_message,
-                                       fd_repeated_int64_extension);
+  const RepeatedFieldRef<int64_t> rf_int64_extension =
+      refl->GetRepeatedFieldRef<int64_t>(extended_message,
+                                         fd_repeated_int64_extension);
 
-  const MutableRepeatedFieldRef<int64> mrf_int64_extension =
-      refl->GetMutableRepeatedFieldRef<int64>(&extended_message,
-                                              fd_repeated_int64_extension);
+  const MutableRepeatedFieldRef<int64_t> mrf_int64_extension =
+      refl->GetMutableRepeatedFieldRef<int64_t>(&extended_message,
+                                                fd_repeated_int64_extension);
 
   for (int i = 0; i < 10; ++i) {
     EXPECT_EQ(Func(i, 1), rf_int64_extension.Get(i));
@@ -594,8 +594,8 @@
       desc->FindFieldByName("repeated_nested_enum");
 
   // Get MutableRepeatedFieldRef objects for all fields of interest.
-  const MutableRepeatedFieldRef<int32> mrf_int32 =
-      refl->GetMutableRepeatedFieldRef<int32>(&m0, fd_repeated_int32);
+  const MutableRepeatedFieldRef<int32_t> mrf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(&m0, fd_repeated_int32);
   const MutableRepeatedFieldRef<double> mrf_double =
       refl->GetMutableRepeatedFieldRef<double>(&m0, fd_repeated_double);
   const MutableRepeatedFieldRef<std::string> mrf_string =
@@ -608,7 +608,7 @@
           &m0, fd_repeated_nested_enum);
 
   // Test MutableRepeatedRef::CopyFrom
-  mrf_int32.CopyFrom(refl->GetRepeatedFieldRef<int32>(m1, fd_repeated_int32));
+  mrf_int32.CopyFrom(refl->GetRepeatedFieldRef<int32_t>(m1, fd_repeated_int32));
   mrf_double.CopyFrom(
       refl->GetRepeatedFieldRef<double>(m1, fd_repeated_double));
   mrf_string.CopyFrom(
@@ -626,7 +626,8 @@
   }
 
   // Test MutableRepeatedRef::MergeFrom
-  mrf_int32.MergeFrom(refl->GetRepeatedFieldRef<int32>(m2, fd_repeated_int32));
+  mrf_int32.MergeFrom(
+      refl->GetRepeatedFieldRef<int32_t>(m2, fd_repeated_int32));
   mrf_double.MergeFrom(
       refl->GetRepeatedFieldRef<double>(m2, fd_repeated_double));
   mrf_string.MergeFrom(
@@ -646,7 +647,7 @@
   // Test MutableRepeatedRef::Swap
   // Swap between m0 and m2.
   mrf_int32.Swap(
-      refl->GetMutableRepeatedFieldRef<int32>(&m2, fd_repeated_int32));
+      refl->GetMutableRepeatedFieldRef<int32_t>(&m2, fd_repeated_int32));
   mrf_double.Swap(
       refl->GetMutableRepeatedFieldRef<double>(&m2, fd_repeated_double));
   mrf_string.Swap(
@@ -694,9 +695,9 @@
   std::unique_ptr<Message> dynamic_message(factory.GetPrototype(desc)->New());
   const Reflection* refl = dynamic_message->GetReflection();
 
-  MutableRepeatedFieldRef<int32> rf_int32 =
-      refl->GetMutableRepeatedFieldRef<int32>(dynamic_message.get(),
-                                              fd_repeated_int32);
+  MutableRepeatedFieldRef<int32_t> rf_int32 =
+      refl->GetMutableRepeatedFieldRef<int32_t>(dynamic_message.get(),
+                                                fd_repeated_int32);
   rf_int32.Add(1234);
   EXPECT_EQ(1, refl->FieldSize(*dynamic_message, fd_repeated_int32));
   EXPECT_EQ(1234,
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 297baee..1856414 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -43,6 +43,7 @@
 #include <limits>
 #include <list>
 #include <sstream>
+#include <string>
 #include <type_traits>
 #include <vector>
 
@@ -63,7 +64,10 @@
 namespace {
 
 using ::protobuf_unittest::TestAllTypes;
+using ::testing::AllOf;
 using ::testing::ElementsAre;
+using ::testing::Ge;
+using ::testing::Le;
 
 TEST(RepeatedField, ConstInit) {
   PROTOBUF_CONSTINIT static RepeatedField<int> field{};  // NOLINT
@@ -123,7 +127,10 @@
   EXPECT_TRUE(field.empty());
   EXPECT_EQ(field.size(), 0);
   // Additional bytes are for 'struct Rep' header.
-  int expected_usage = 4 * sizeof(int) + sizeof(Arena*);
+  int expected_usage =
+      (sizeof(Arena*) > sizeof(int) ? sizeof(Arena*) / sizeof(int) : 3) *
+          sizeof(int) +
+      sizeof(Arena*);
   EXPECT_GE(field.SpaceUsedExcludingSelf(), expected_usage);
 }
 
@@ -148,6 +155,85 @@
   EXPECT_GE(field.SpaceUsedExcludingSelf(), expected_usage);
 }
 
+template <typename Rep>
+void CheckAllocationSizes(bool is_ptr) {
+  using T = typename Rep::value_type;
+  // Use a large initial block to make the checks below easier to predict.
+  std::string buf(1 << 20, 0);
+
+  Arena arena(&buf[0], buf.size());
+  auto* rep = Arena::CreateMessage<Rep>(&arena);
+  size_t prev = arena.SpaceUsed();
+
+  for (int i = 0; i < 100; ++i) {
+    rep->Add(T{});
+    if (sizeof(void*) == 8) {
+      // For RepeatedPtrField we also allocate the T in the arena.
+      // Subtract those from the count.
+      size_t new_used = arena.SpaceUsed() - (is_ptr ? sizeof(T) * (i + 1) : 0);
+      size_t last_alloc = new_used - prev;
+      prev = new_used;
+
+      // When we actually allocated something, check the size.
+      if (last_alloc != 0) {
+        // Must be `>= 16`, as expected by the Arena.
+        ASSERT_GE(last_alloc, 16);
+        // Must be of a power of two.
+        size_t log2 = Bits::Log2FloorNonZero64(last_alloc);
+        ASSERT_EQ((1 << log2), last_alloc);
+      }
+
+      // The byte size must be a multiple of 8.
+      ASSERT_EQ(rep->Capacity() * sizeof(T) % 8, 0);
+    }
+  }
+}
+
+TEST(RepeatedField, ArenaAllocationSizesMatchExpectedValues) {
+  // RepeatedField guarantees that in 64-bit mode we never allocate anything
+  // smaller than 16 bytes from an arena.
+  // This is important to avoid a branch in the reallocation path.
+  // This is also important because allocating anything less would be wasting
+  // memory.
+  // If the allocation size is wrong, ReturnArrayMemory will GOOGLE_DCHECK.
+  CheckAllocationSizes<RepeatedField<bool>>(false);
+  CheckAllocationSizes<RepeatedField<uint8_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint16_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint32_t>>(false);
+  CheckAllocationSizes<RepeatedField<uint64_t>>(false);
+  CheckAllocationSizes<RepeatedField<std::pair<uint64_t, uint64_t>>>(false);
+}
+
+template <typename Rep>
+void CheckNaturalGrowthOnArenasReuseBlocks(bool is_ptr) {
+  Arena arena;
+  std::vector<Rep*> values;
+  using T = typename Rep::value_type;
+
+  static constexpr int kNumFields = 100;
+  static constexpr int kNumElems = 1000;
+  for (int i = 0; i < kNumFields; ++i) {
+    values.push_back(Arena::CreateMessage<Rep>(&arena));
+    auto& field = *values.back();
+    for (int j = 0; j < kNumElems; ++j) {
+      field.Add(T{});
+    }
+  }
+
+  size_t used_bytes_if_reusing =
+      values.size() * values[0]->Capacity() * (is_ptr ? sizeof(T*) : sizeof(T));
+  // Use a 2% slack for other overhead.
+  // If we were not reusing the blocks, the actual value would be ~2x the
+  // expected.
+  EXPECT_THAT(
+      arena.SpaceUsed() - (is_ptr ? sizeof(T) * kNumElems * kNumFields : 0),
+      AllOf(Ge(used_bytes_if_reusing), Le(1.02 * used_bytes_if_reusing)));
+}
+
+TEST(RepeatedField, NaturalGrowthOnArenasReuseBlocks) {
+  CheckNaturalGrowthOnArenasReuseBlocks<RepeatedField<int>>(false);
+}
+
 // Test swapping between various types of RepeatedFields.
 TEST(RepeatedField, SwapSmallSmall) {
   RepeatedField<int> field1;
@@ -287,16 +373,38 @@
 }
 
 TEST(RepeatedField, ReserveLowerClamp) {
-  const int clamped_value = internal::CalculateReserveSize(0, 1);
-  EXPECT_EQ(internal::kRepeatedFieldLowerClampLimit, clamped_value);
-  EXPECT_EQ(clamped_value, internal::CalculateReserveSize(clamped_value, 2));
+  int clamped_value = internal::CalculateReserveSize<bool, sizeof(void*)>(0, 1);
+  EXPECT_GE(clamped_value, 8 / sizeof(bool));
+  EXPECT_EQ((internal::RepeatedFieldLowerClampLimit<bool, sizeof(void*)>()),
+            clamped_value);
+  // EXPECT_EQ(clamped_value, (internal::CalculateReserveSize<bool,
+  // sizeof(void*)>( clamped_value, 2)));
+
+  clamped_value = internal::CalculateReserveSize<int, sizeof(void*)>(0, 1);
+  EXPECT_GE(clamped_value, 8 / sizeof(int));
+  EXPECT_EQ((internal::RepeatedFieldLowerClampLimit<int, sizeof(void*)>()),
+            clamped_value);
+  // EXPECT_EQ(clamped_value, (internal::CalculateReserveSize<int,
+  // sizeof(void*)>( clamped_value, 2)));
 }
 
 TEST(RepeatedField, ReserveGrowth) {
   // Make sure the field capacity doubles in size on repeated reservation.
-  for (int size = internal::kRepeatedFieldLowerClampLimit, i = 0; i < 4;
-       ++i, size *= 2) {
-    EXPECT_EQ(size * 2, internal::CalculateReserveSize(size, size + 1));
+  for (int size = internal::RepeatedFieldLowerClampLimit<int, sizeof(void*)>(),
+           i = 0;
+       i < 4; ++i) {
+    int next =
+        sizeof(Arena*) >= sizeof(int)
+            ?
+            // for small enough elements, we double number of total bytes
+            ((2 * (size * sizeof(int) + sizeof(Arena*))) - sizeof(Arena*)) /
+                sizeof(int)
+            :
+            // we just double the number of elements if too large size.
+            size * 2;
+    EXPECT_EQ(next, (internal::CalculateReserveSize<int, sizeof(void*)>(
+                        size, size + 1)));
+    size = next;
   }
 }
 
@@ -306,22 +414,24 @@
   const int new_size = old_size * 3 + 1;
 
   // Reserving more than 2x current capacity should grow directly to that size.
-  EXPECT_EQ(new_size, internal::CalculateReserveSize(old_size, new_size));
+  EXPECT_EQ(new_size, (internal::CalculateReserveSize<int, sizeof(void*)>(
+                          old_size, new_size)));
 }
 
 TEST(RepeatedField, ReserveHuge) {
   // Largest value that does not clamp to the large limit:
-  constexpr int non_clamping_limit = std::numeric_limits<int>::max() / 2;
+  constexpr int non_clamping_limit =
+      (std::numeric_limits<int>::max() - sizeof(Arena*)) / 2;
   ASSERT_LT(2 * non_clamping_limit, std::numeric_limits<int>::max());
-  EXPECT_LT(internal::CalculateReserveSize(non_clamping_limit,
-                                           non_clamping_limit + 1),
+  EXPECT_LT((internal::CalculateReserveSize<int, sizeof(void*)>(
+                non_clamping_limit, non_clamping_limit + 1)),
             std::numeric_limits<int>::max());
 
   // Smallest size that *will* clamp to the upper limit:
   constexpr int min_clamping_size = std::numeric_limits<int>::max() / 2 + 1;
-  EXPECT_EQ(
-      internal::CalculateReserveSize(min_clamping_size, min_clamping_size + 1),
-      std::numeric_limits<int>::max());
+  EXPECT_EQ((internal::CalculateReserveSize<int, sizeof(void*)>(
+                min_clamping_size, min_clamping_size + 1)),
+            std::numeric_limits<int>::max());
 
 #ifdef PROTOBUF_TEST_ALLOW_LARGE_ALLOC
   // The rest of this test may allocate several GB of memory, so it is only
@@ -797,12 +907,12 @@
     for (int num = 0; num <= sz; ++num) {
       for (int start = 0; start < sz - num; ++start) {
         // Create RepeatedField with sz elements having values 0 through sz-1.
-        RepeatedField<int32> field;
+        RepeatedField<int32_t> field;
         for (int i = 0; i < sz; ++i) field.Add(i);
         EXPECT_EQ(field.size(), sz);
 
         // Create a catcher array and call ExtractSubrange.
-        int32 catcher[10];
+        int32_t catcher[10];
         for (int i = 0; i < 10; ++i) catcher[i] = -1;
         field.ExtractSubrange(start, num, catcher);
 
@@ -962,6 +1072,14 @@
   EXPECT_GE(field.SpaceUsedExcludingSelf(), min_expected_usage);
 }
 
+TEST(RepeatedPtrField, ArenaAllocationSizesMatchExpectedValues) {
+  CheckAllocationSizes<RepeatedPtrField<std::string>>(true);
+}
+
+TEST(RepeatedPtrField, NaturalGrowthOnArenasReuseBlocks) {
+  CheckNaturalGrowthOnArenasReuseBlocks<RepeatedPtrField<std::string>>(true);
+}
+
 TEST(RepeatedPtrField, AddAndAssignRanges) {
   RepeatedPtrField<std::string> field;
 
@@ -1585,7 +1703,7 @@
 // Iterator tests stolen from net/proto/proto-array_unittest.
 class RepeatedFieldIteratorTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     for (int i = 0; i < 3; ++i) {
       proto_array_.Add(i);
     }
@@ -1635,7 +1753,7 @@
 
 class RepeatedPtrFieldIteratorTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     proto_array_.Add()->assign("foo");
     proto_array_.Add()->assign("bar");
     proto_array_.Add()->assign("baz");
@@ -1711,6 +1829,23 @@
   EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
 }
 
+TEST_F(RepeatedPtrFieldIteratorTest, RandomAccessConst) {
+  RepeatedPtrField<std::string>::const_iterator iter = proto_array_.cbegin();
+  RepeatedPtrField<std::string>::const_iterator iter2 = iter;
+  ++iter2;
+  ++iter2;
+  EXPECT_TRUE(iter + 2 == iter2);
+  EXPECT_TRUE(iter == iter2 - 2);
+  EXPECT_EQ("baz", iter[2]);
+  EXPECT_EQ("baz", *(iter + 2));
+  EXPECT_EQ(3, proto_array_.cend() - proto_array_.cbegin());
+}
+
+TEST_F(RepeatedPtrFieldIteratorTest, DifferenceConstConversion) {
+  EXPECT_EQ(3, proto_array_.end() - proto_array_.cbegin());
+  EXPECT_EQ(3, proto_array_.cend() - proto_array_.begin());
+}
+
 TEST_F(RepeatedPtrFieldIteratorTest, Comparable) {
   RepeatedPtrField<std::string>::const_iterator iter = proto_array_.begin();
   RepeatedPtrField<std::string>::const_iterator iter2 = iter + 1;
@@ -1724,6 +1859,22 @@
   EXPECT_TRUE(iter >= iter);
 }
 
+TEST_F(RepeatedPtrFieldIteratorTest, ComparableConstConversion) {
+  RepeatedPtrField<std::string>::iterator iter = proto_array_.begin();
+  RepeatedPtrField<std::string>::const_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter == proto_array_.cbegin());
+  EXPECT_TRUE(proto_array_.cbegin() == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter2 != iter);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
 // Uninitialized iterator does not point to any of the RepeatedPtrField.
 TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) {
   RepeatedPtrField<std::string>::iterator iter;
@@ -1762,7 +1913,7 @@
 
 class RepeatedPtrFieldPtrsIteratorTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     proto_array_.Add()->assign("foo");
     proto_array_.Add()->assign("bar");
     proto_array_.Add()->assign("baz");
@@ -1835,6 +1986,13 @@
   EXPECT_EQ(3, const_proto_array_->end() - const_proto_array_->begin());
 }
 
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, DifferenceConstConversion) {
+  EXPECT_EQ(3,
+            proto_array_.pointer_end() - const_proto_array_->pointer_begin());
+  EXPECT_EQ(3,
+            const_proto_array_->pointer_end() - proto_array_.pointer_begin());
+}
+
 TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
   RepeatedPtrField<std::string>::pointer_iterator iter =
       proto_array_.pointer_begin();
@@ -1863,6 +2021,23 @@
   EXPECT_TRUE(iter >= iter);
 }
 
+TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparableConstConversion) {
+  RepeatedPtrField<std::string>::pointer_iterator iter =
+      proto_array_.pointer_begin();
+  RepeatedPtrField<std::string>::const_pointer_iterator iter2 = iter + 1;
+  EXPECT_TRUE(iter == iter);
+  EXPECT_TRUE(iter == const_proto_array_->pointer_begin());
+  EXPECT_TRUE(const_proto_array_->pointer_begin() == iter);
+  EXPECT_TRUE(iter != iter2);
+  EXPECT_TRUE(iter2 != iter);
+  EXPECT_TRUE(iter < iter2);
+  EXPECT_TRUE(iter <= iter2);
+  EXPECT_TRUE(iter <= iter);
+  EXPECT_TRUE(iter2 > iter);
+  EXPECT_TRUE(iter2 >= iter);
+  EXPECT_TRUE(iter >= iter);
+}
+
 // Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs.
 // Dereferencing an uninitialized iterator crashes the process.
 TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
@@ -1980,7 +2155,7 @@
   std::vector<Nested*> nested_ptrs;
   TestAllTypes protobuffer;
 
-  virtual void SetUp() {
+  void SetUp() override {
     fibonacci.push_back(1);
     fibonacci.push_back(1);
     fibonacci.push_back(2);
@@ -2023,7 +2198,7 @@
                   protobuffer.mutable_repeated_nested_message()));
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     for (auto ptr : nested_ptrs) {
       delete ptr;
     }
@@ -2160,7 +2335,7 @@
 }
 
 TEST_F(RepeatedFieldInsertionIteratorsTest, MoveProtos) {
-  auto make_nested = [](int32 x) {
+  auto make_nested = [](int32_t x) {
     Nested ret;
     ret.set_bb(x);
     return ret;
diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc
index 0f0b3e2..6c322d1 100644
--- a/src/google/protobuf/repeated_ptr_field.cc
+++ b/src/google/protobuf/repeated_ptr_field.cc
@@ -32,14 +32,15 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#include <google/protobuf/repeated_field.h>
-
 #include <algorithm>
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -56,8 +57,8 @@
   }
   Rep* old_rep = rep_;
   Arena* arena = GetArena();
-  new_size = std::max(internal::kRepeatedFieldLowerClampLimit,
-                      std::max(total_size_ * 2, new_size));
+  new_size = internal::CalculateReserveSize<void*, kRepHeaderSize>(total_size_,
+                                                                   new_size);
   GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
            static_cast<int64_t>(
                (std::numeric_limits<size_t>::max() - kRepHeaderSize) /
@@ -69,25 +70,24 @@
   } else {
     rep_ = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
   }
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
   const int old_total_size = total_size_;
-#endif
   total_size_ = new_size;
-  if (old_rep && old_rep->allocated_size > 0) {
-    memcpy(rep_->elements, old_rep->elements,
-           old_rep->allocated_size * sizeof(rep_->elements[0]));
+  if (old_rep) {
+    if (old_rep->allocated_size > 0) {
+      memcpy(rep_->elements, old_rep->elements,
+             old_rep->allocated_size * sizeof(rep_->elements[0]));
+    }
     rep_->allocated_size = old_rep->allocated_size;
-  } else {
-    rep_->allocated_size = 0;
-  }
-  if (arena == nullptr) {
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
+
     const size_t old_size =
         old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize;
-    ::operator delete(static_cast<void*>(old_rep), old_size);
-#else
-    ::operator delete(static_cast<void*>(old_rep));
-#endif
+    if (arena == nullptr) {
+      internal::SizedDelete(old_rep, old_size);
+    } else {
+      arena_->ReturnArrayMemory(old_rep, old_size);
+    }
+  } else {
+    rep_->allocated_size = 0;
   }
   return &rep_->elements[current_size_];
 }
@@ -106,14 +106,9 @@
   for (int i = 0; i < n; i++) {
     delete static_cast<MessageLite*>(elements[i]);
   }
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
   const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
-  ::operator delete(static_cast<void*>(rep_), size);
+  internal::SizedDelete(rep_, size);
   rep_ = nullptr;
-#else
-  ::operator delete(static_cast<void*>(rep_));
-  rep_ = nullptr;
-#endif
 }
 
 void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) {
diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h
index 3c813a9..c2b0237 100644
--- a/src/google/protobuf/repeated_ptr_field.h
+++ b/src/google/protobuf/repeated_ptr_field.h
@@ -39,16 +39,15 @@
 // particularly different from STL vector as it manages ownership of the
 // pointers that it contains.
 //
-// Typically, clients should not need to access RepeatedField objects directly,
-// but should instead use the accessor functions generated automatically by the
-// protocol compiler.
-//
 // This header covers RepeatedPtrField.
 
+// IWYU pragma: private, include "net/proto2/public/repeated_field.h"
+
 #ifndef GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
 #define GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__
 
 #include <utility>
+
 #ifdef _MSC_VER
 // This is required for min/max on VS2013 only.
 #include <algorithm>
@@ -62,8 +61,8 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
 
 
 // Must be included last.
@@ -166,8 +165,14 @@
 //   };
 class PROTOBUF_EXPORT RepeatedPtrFieldBase {
  protected:
-  constexpr RepeatedPtrFieldBase();
-  explicit RepeatedPtrFieldBase(Arena* arena);
+  constexpr RepeatedPtrFieldBase()
+      : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {}
+  explicit RepeatedPtrFieldBase(Arena* arena)
+      : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {}
+
+  RepeatedPtrFieldBase(const RepeatedPtrFieldBase&) = delete;
+  RepeatedPtrFieldBase& operator=(const RepeatedPtrFieldBase&) = delete;
+
   ~RepeatedPtrFieldBase() {
 #ifndef NDEBUG
     // Try to trigger segfault / asan failure in non-opt builds. If arena_
@@ -176,27 +181,84 @@
 #endif
   }
 
-  // Must be called from destructor.
-  template <typename TypeHandler>
-  void Destroy();
-  bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; }
-  void DestroyProtos();
-
-  bool empty() const;
-  int size() const;
+  bool empty() const { return current_size_ == 0; }
+  int size() const { return current_size_; }
+  int Capacity() const { return total_size_; }
 
   template <typename TypeHandler>
-  const typename TypeHandler::Type& at(int index) const;
-  template <typename TypeHandler>
-  typename TypeHandler::Type& at(int index);
+  const typename TypeHandler::Type& at(int index) const {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
 
   template <typename TypeHandler>
-  typename TypeHandler::Type* Mutable(int index);
+  typename TypeHandler::Type& at(int index) {
+    GOOGLE_CHECK_GE(index, 0);
+    GOOGLE_CHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
+
   template <typename TypeHandler>
-  void Delete(int index);
+  typename TypeHandler::Type* Mutable(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return cast<TypeHandler>(rep_->elements[index]);
+  }
+
   template <typename TypeHandler>
   typename TypeHandler::Type* Add(
-      typename TypeHandler::Type* prototype = nullptr);
+      const typename TypeHandler::Type* prototype = nullptr) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    }
+    typename TypeHandler::Type* result =
+        TypeHandler::NewFromPrototype(prototype, arena_);
+    return reinterpret_cast<typename TypeHandler::Type*>(
+        AddOutOfLineHelper(result));
+  }
+
+  template <
+      typename TypeHandler,
+      typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
+  inline void Add(typename TypeHandler::Type&& value) {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      *cast<TypeHandler>(rep_->elements[current_size_++]) = std::move(value);
+      return;
+    }
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    ++rep_->allocated_size;
+    typename TypeHandler::Type* result =
+        TypeHandler::New(arena_, std::move(value));
+    rep_->elements[current_size_++] = result;
+  }
+
+  template <typename TypeHandler>
+  void Delete(int index) {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
+  }
+
+  // Must be called from destructor.
+  template <typename TypeHandler>
+  void Destroy() {
+    if (rep_ != nullptr && arena_ == nullptr) {
+      int n = rep_->allocated_size;
+      void* const* elements = rep_->elements;
+      for (int i = 0; i < n; i++) {
+        TypeHandler::Delete(cast<TypeHandler>(elements[i]), nullptr);
+      }
+      const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
+      internal::SizedDelete(rep_, size);
+    }
+    rep_ = nullptr;
+  }
+
+  bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; }
+  void DestroyProtos();  // implemented in the cc file
 
  public:
   // The next few methods are public so that they can be called from generated
@@ -204,7 +266,11 @@
   // application code.
 
   template <typename TypeHandler>
-  const typename TypeHandler::Type& Get(int index) const;
+  const typename TypeHandler::Type& Get(int index) const {
+    GOOGLE_DCHECK_GE(index, 0);
+    GOOGLE_DCHECK_LT(index, current_size_);
+    return *cast<TypeHandler>(rep_->elements[index]);
+  }
 
   // Creates and adds an element using the given prototype, without introducing
   // a link-time dependency on the concrete message type. This method is used to
@@ -213,29 +279,61 @@
   MessageLite* AddWeak(const MessageLite* prototype);
 
   template <typename TypeHandler>
-  void Clear();
+  void Clear() {
+    const int n = current_size_;
+    GOOGLE_DCHECK_GE(n, 0);
+    if (n > 0) {
+      void* const* elements = rep_->elements;
+      int i = 0;
+      do {
+        TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
+      } while (i < n);
+      current_size_ = 0;
+    }
+  }
 
   template <typename TypeHandler>
-  void MergeFrom(const RepeatedPtrFieldBase& other);
+  void MergeFrom(const RepeatedPtrFieldBase& other) {
+    // To avoid unnecessary code duplication and reduce binary size, we use a
+    // layered approach to implementing MergeFrom(). The toplevel method is
+    // templated, so we get a small thunk per concrete message type in the
+    // binary. This calls a shared implementation with most of the logic,
+    // passing a function pointer to another type-specific piece of code that
+    // calls the object-allocate and merge handlers.
+    GOOGLE_DCHECK_NE(&other, this);
+    if (other.current_size_ == 0) return;
+    MergeFromInternal(other,
+                      &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
+  }
 
-  inline void InternalSwap(RepeatedPtrFieldBase*);
+  inline void InternalSwap(RepeatedPtrFieldBase* rhs) {
+    GOOGLE_DCHECK(this != rhs);
+
+    // Swap all fields at once.
+    auto temp = std::make_tuple(rhs->arena_, rhs->current_size_,
+                                rhs->total_size_, rhs->rep_);
+    std::tie(rhs->arena_, rhs->current_size_, rhs->total_size_, rhs->rep_) =
+        std::make_tuple(arena_, current_size_, total_size_, rep_);
+    std::tie(arena_, current_size_, total_size_, rep_) = temp;
+  }
 
  protected:
-  template <
-      typename TypeHandler,
-      typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
-  void Add(typename TypeHandler::Type&& value);
+  template <typename TypeHandler>
+  void RemoveLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
+  }
 
   template <typename TypeHandler>
-  void RemoveLast();
-  template <typename TypeHandler>
-  void CopyFrom(const RepeatedPtrFieldBase& other);
+  void CopyFrom(const RepeatedPtrFieldBase& other) {
+    if (&other == this) return;
+    RepeatedPtrFieldBase::Clear<TypeHandler>();
+    RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
+  }
 
-  void CloseGap(int start, int num);
+  void CloseGap(int start, int num);  // implemented in the cc file
 
-  void Reserve(int new_size);
-
-  int Capacity() const;
+  void Reserve(int new_size);  // implemented in the cc file
 
   template <typename TypeHandler>
   static inline typename TypeHandler::Type* copy(
@@ -246,27 +344,69 @@
   }
 
   // Used for constructing iterators.
-  void* const* raw_data() const;
-  void** raw_mutable_data() const;
+  void* const* raw_data() const { return rep_ ? rep_->elements : nullptr; }
+  void** raw_mutable_data() const {
+    return rep_ ? const_cast<void**>(rep_->elements) : nullptr;
+  }
 
   template <typename TypeHandler>
-  typename TypeHandler::Type** mutable_data();
-  template <typename TypeHandler>
-  const typename TypeHandler::Type* const* data() const;
+  typename TypeHandler::Type** mutable_data() {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
+  }
 
   template <typename TypeHandler>
-  PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other);
-
-  void SwapElements(int index1, int index2);
+  const typename TypeHandler::Type* const* data() const {
+    // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
+    //   method entirely.
+    return reinterpret_cast<const typename TypeHandler::Type* const*>(
+        raw_data());
+  }
 
   template <typename TypeHandler>
-  size_t SpaceUsedExcludingSelfLong() const;
+  PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetArena() != nullptr && GetArena() == other->GetArena())
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    if (GetArena() == other->GetArena())
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+    {
+      InternalSwap(other);
+    } else {
+      SwapFallback<TypeHandler>(other);
+    }
+  }
+
+  void SwapElements(int index1, int index2) {
+    using std::swap;  // enable ADL with fallback
+    swap(rep_->elements[index1], rep_->elements[index2]);
+  }
+
+  template <typename TypeHandler>
+  size_t SpaceUsedExcludingSelfLong() const {
+    size_t allocated_bytes = static_cast<size_t>(total_size_) * sizeof(void*);
+    if (rep_ != nullptr) {
+      for (int i = 0; i < rep_->allocated_size; ++i) {
+        allocated_bytes +=
+            TypeHandler::SpaceUsedLong(*cast<TypeHandler>(rep_->elements[i]));
+      }
+      allocated_bytes += kRepHeaderSize;
+    }
+    return allocated_bytes;
+  }
 
   // Advanced memory management --------------------------------------
 
   // Like Add(), but if there are no cleared objects to use, returns nullptr.
   template <typename TypeHandler>
-  typename TypeHandler::Type* AddFromCleared();
+  typename TypeHandler::Type* AddFromCleared() {
+    if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
+      return cast<TypeHandler>(rep_->elements[current_size_++]);
+    } else {
+      return nullptr;
+    }
+  }
 
   template <typename TypeHandler>
   void AddAllocated(typename TypeHandler::Type* value) {
@@ -275,7 +415,31 @@
   }
 
   template <typename TypeHandler>
-  void UnsafeArenaAddAllocated(typename TypeHandler::Type* value);
+  void UnsafeArenaAddAllocated(typename TypeHandler::Type* value) {
+    // Make room for the new pointer.
+    if (!rep_ || current_size_ == total_size_) {
+      // The array is completely full with no cleared objects, so grow it.
+      Reserve(total_size_ + 1);
+      ++rep_->allocated_size;
+    } else if (rep_->allocated_size == total_size_) {
+      // There is no more space in the pointer array because it contains some
+      // cleared objects awaiting reuse.  We don't want to grow the array in
+      // this case because otherwise a loop calling AddAllocated() followed by
+      // Clear() would leak memory.
+      TypeHandler::Delete(cast<TypeHandler>(rep_->elements[current_size_]),
+                          arena_);
+    } else if (current_size_ < rep_->allocated_size) {
+      // We have some cleared objects.  We don't care about their order, so we
+      // can just move the first one to the end to make space.
+      rep_->elements[rep_->allocated_size] = rep_->elements[current_size_];
+      ++rep_->allocated_size;
+    } else {
+      // There are no cleared objects.
+      ++rep_->allocated_size;
+    }
+
+    rep_->elements[current_size_++] = value;
+  }
 
   template <typename TypeHandler>
   PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() {
@@ -283,51 +447,187 @@
     return ReleaseLastInternal<TypeHandler>(t);
   }
 
-  // Releases last element and returns it, but does not do out-of-arena copy.
-  // And just returns the raw pointer to the contained element in the arena.
+  // Releases and returns the last element, but does not do out-of-arena copy.
+  // Instead, just returns the raw pointer to the contained element in the
+  // arena.
   template <typename TypeHandler>
-  typename TypeHandler::Type* UnsafeArenaReleaseLast();
+  typename TypeHandler::Type* UnsafeArenaReleaseLast() {
+    GOOGLE_DCHECK_GT(current_size_, 0);
+    typename TypeHandler::Type* result =
+        cast<TypeHandler>(rep_->elements[--current_size_]);
+    --rep_->allocated_size;
+    if (current_size_ < rep_->allocated_size) {
+      // There are cleared elements on the end; replace the removed element
+      // with the last allocated element.
+      rep_->elements[current_size_] = rep_->elements[rep_->allocated_size];
+    }
+    return result;
+  }
 
-  int ClearedCount() const;
-  template <typename TypeHandler>
-  void AddCleared(typename TypeHandler::Type* value);
-  template <typename TypeHandler>
-  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared();
+  int ClearedCount() const {
+    return rep_ ? (rep_->allocated_size - current_size_) : 0;
+  }
 
   template <typename TypeHandler>
-  void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type);
-  template <typename TypeHandler>
-  void AddAllocatedInternal(typename TypeHandler::Type* value, std::false_type);
+  void AddCleared(typename TypeHandler::Type* value) {
+    GOOGLE_DCHECK(GetArena() == nullptr) << "AddCleared() can only be used on a "
+                                     "RepeatedPtrField not on an arena.";
+    GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr)
+        << "AddCleared() can only accept values not on an arena.";
+    if (!rep_ || rep_->allocated_size == total_size_) {
+      Reserve(total_size_ + 1);
+    }
+    rep_->elements[rep_->allocated_size++] = value;
+  }
 
   template <typename TypeHandler>
+  PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared() {
+    GOOGLE_DCHECK(GetArena() == nullptr)
+        << "ReleaseCleared() can only be used on a RepeatedPtrField not on "
+        << "an arena.";
+    GOOGLE_DCHECK(GetArena() == nullptr);
+    GOOGLE_DCHECK(rep_ != nullptr);
+    GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_);
+    return cast<TypeHandler>(rep_->elements[--rep_->allocated_size]);
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type) {
+    // AddAllocated version that implements arena-safe copying behavior.
+    Arena* element_arena =
+        reinterpret_cast<Arena*>(TypeHandler::GetOwningArena(value));
+    Arena* arena = GetArena();
+    if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      rep_->allocated_size = rep_->allocated_size + 1;
+    } else {
+      AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena);
+    }
+  }
+
+  template <typename TypeHandler>
+  void AddAllocatedInternal(
+      // AddAllocated version that does not implement arena-safe copying
+      // behavior.
+      typename TypeHandler::Type* value, std::false_type) {
+    if (rep_ && rep_->allocated_size < total_size_) {
+      // Fast path: underlying arena representation (tagged pointer) is equal to
+      // our arena pointer, and we can add to array without resizing it (at
+      // least one slot that is not allocated).
+      void** elems = rep_->elements;
+      if (current_size_ < rep_->allocated_size) {
+        // Make space at [current] by moving first allocated element to end of
+        // allocated list.
+        elems[rep_->allocated_size] = elems[current_size_];
+      }
+      elems[current_size_] = value;
+      current_size_ = current_size_ + 1;
+      ++rep_->allocated_size;
+    } else {
+      UnsafeArenaAddAllocated<TypeHandler>(value);
+    }
+  }
+
+  // Slowpath handles all cases, copying if necessary.
+  template <typename TypeHandler>
   PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy(
-      typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena);
-  template <typename TypeHandler>
-  PROTOBUF_NOINLINE void AddAllocatedSlowWithoutCopy(
-      typename TypeHandler::Type* value);
+      // Pass value_arena and my_arena to avoid duplicate virtual call (value)
+      // or load (mine).
+      typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
+    // Ensure that either the value is in the same arena, or if not, we do the
+    // appropriate thing: Own() it (if it's on heap and we're in an arena) or
+    // copy it to our arena/heap (otherwise).
+    if (my_arena != nullptr && value_arena == nullptr) {
+      my_arena->Own(value);
+    } else if (my_arena != value_arena) {
+      typename TypeHandler::Type* new_value =
+          TypeHandler::NewFromPrototype(value, my_arena);
+      TypeHandler::Merge(*value, new_value);
+      TypeHandler::Delete(value, value_arena);
+      value = new_value;
+    }
+
+    UnsafeArenaAddAllocated<TypeHandler>(value);
+  }
 
   template <typename TypeHandler>
-  typename TypeHandler::Type* ReleaseLastInternal(std::true_type);
-  template <typename TypeHandler>
-  typename TypeHandler::Type* ReleaseLastInternal(std::false_type);
+  typename TypeHandler::Type* ReleaseLastInternal(std::true_type) {
+    // ReleaseLast() for types that implement merge/copy behavior.
+    // First, release an element.
+    typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
+    // Now perform a copy if we're on an arena.
+    Arena* arena = GetArena();
+
+    typename TypeHandler::Type* new_result;
+#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = copy<TypeHandler>(result);
+    if (arena == nullptr) delete result;
+#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
+    new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
+#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
+    return new_result;
+  }
 
   template <typename TypeHandler>
-  PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other);
+  typename TypeHandler::Type* ReleaseLastInternal(std::false_type) {
+    // ReleaseLast() for types that *do not* implement merge/copy behavior --
+    // this is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if
+    // we're on an arena, since the user really should implement the copy
+    // operation in this case.
+    GOOGLE_DCHECK(GetArena() == nullptr)
+        << "ReleaseLast() called on a RepeatedPtrField that is on an arena, "
+        << "with a type that does not implement MergeFrom. This is unsafe; "
+        << "please implement MergeFrom for your type.";
+    return UnsafeArenaReleaseLast<TypeHandler>();
+  }
+
+  template <typename TypeHandler>
+  PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other) {
+#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(GetArena() == nullptr || other->GetArena() != GetArena());
+#else   // PROTOBUF_FORCE_COPY_IN_SWAP
+    GOOGLE_DCHECK(other->GetArena() != GetArena());
+#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
+
+    // Copy semantics in this case. We try to improve efficiency by placing the
+    // temporary on |other|'s arena so that messages are copied twice rather
+    // than three times.
+    RepeatedPtrFieldBase temp(other->GetArena());
+    temp.MergeFrom<TypeHandler>(*this);
+    this->Clear<TypeHandler>();
+    this->MergeFrom<TypeHandler>(*other);
+    other->InternalSwap(&temp);
+    temp.Destroy<TypeHandler>();  // Frees rep_ if `other` had no arena.
+  }
 
   inline Arena* GetArena() const { return arena_; }
 
  private:
+  template <typename T> friend class Arena::InternalHelper;
+
+  inline Arena* GetOwningArena() const { return arena_; }
+
   static constexpr int kInitialSize = 0;
   // A few notes on internal representation:
   //
   // We use an indirected approach, with struct Rep, to keep
   // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support
-  // was added, namely, 3 8-byte machine words on x86-64. An instance of Rep is
+  // was added; namely, 3 8-byte machine words on x86-64. An instance of Rep is
   // allocated only when the repeated field is non-empty, and it is a
   // dynamically-sized struct (the header is directly followed by elements[]).
   // We place arena_ and current_size_ directly in the object to avoid cache
   // misses due to the indirection, because these fields are checked frequently.
-  // Placing all fields directly in the RepeatedPtrFieldBase instance costs
+  // Placing all fields directly in the RepeatedPtrFieldBase instance would cost
   // significant performance for memory-sensitive workloads.
   Arena* arena_;
   int current_size_;
@@ -356,20 +656,55 @@
   void MergeFromInternal(const RepeatedPtrFieldBase& other,
                          void (RepeatedPtrFieldBase::*inner_loop)(void**,
                                                                   void**, int,
-                                                                  int));
+                                                                  int)) {
+    // Note: wrapper has already guaranteed that other.rep_ != nullptr here.
+    int other_size = other.current_size_;
+    void** other_elements = other.rep_->elements;
+    void** new_elements = InternalExtend(other_size);
+    int allocated_elems = rep_->allocated_size - current_size_;
+    (this->*inner_loop)(new_elements, other_elements, other_size,
+                        allocated_elems);
+    current_size_ += other_size;
+    if (rep_->allocated_size < current_size_) {
+      rep_->allocated_size = current_size_;
+    }
+  }
 
+  // Merges other_elems to our_elems.
   template <typename TypeHandler>
   PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems,
                                             void** other_elems, int length,
-                                            int already_allocated);
+                                            int already_allocated) {
+    if (already_allocated < length) {
+      Arena* arena = GetArena();
+      typename TypeHandler::Type* elem_prototype =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[0]);
+      for (int i = already_allocated; i < length; i++) {
+        // Allocate a new empty element that we'll merge into below
+        typename TypeHandler::Type* new_elem =
+            TypeHandler::NewFromPrototype(elem_prototype, arena);
+        our_elems[i] = new_elem;
+      }
+    }
+    // Main loop that does the actual merging
+    for (int i = 0; i < length; i++) {
+      // Already allocated: use existing element.
+      typename TypeHandler::Type* other_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
+      typename TypeHandler::Type* new_elem =
+          reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
+      TypeHandler::Merge(*other_elem, new_elem);
+    }
+  }
 
-  // Internal helper: extend array space if necessary to contain |extend_amount|
-  // more elements, and return a pointer to the element immediately following
-  // the old list of elements.  This interface factors out common behavior from
-  // Reserve() and MergeFrom() to reduce code size. |extend_amount| must be > 0.
+  // Internal helper: extends array space if necessary to contain
+  // |extend_amount| more elements, and returns a pointer to the element
+  // immediately following the old list of elements.  This interface factors out
+  // common behavior from Reserve() and MergeFrom() to reduce code size.
+  // |extend_amount| must be > 0.
   void** InternalExtend(int extend_amount);
 
-  // Internal helper for Add: add "obj" as the next element in the
+  // Internal helper for Add: adds "obj" as the next element in the
   // array, including potentially resizing the array with Reserve if
   // needed
   void* AddOutOfLineHelper(void* obj);
@@ -399,8 +734,7 @@
   friend class AccessorHelper;
   template <typename T>
   friend struct google::protobuf::WeakRepeatedPtrField;
-
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
+  friend class internal::TcParser;  // TODO(jorg): Remove this friend.
 };
 
 template <typename GenericType>
@@ -416,7 +750,9 @@
     return Arena::Create<GenericType>(arena, std::move(value));
   }
   static inline GenericType* NewFromPrototype(const GenericType* prototype,
-                                              Arena* arena = nullptr);
+                                              Arena* arena = nullptr) {
+    return New(arena);
+  }
   static inline void Delete(GenericType* value, Arena* arena) {
     if (arena == nullptr) {
       delete value;
@@ -427,38 +763,37 @@
   }
 
   static inline void Clear(GenericType* value) { value->Clear(); }
-  PROTOBUF_NOINLINE
   static void Merge(const GenericType& from, GenericType* to);
   static inline size_t SpaceUsedLong(const GenericType& value) {
     return value.SpaceUsedLong();
   }
 };
 
-template <typename GenericType>
-GenericType* GenericTypeHandler<GenericType>::NewFromPrototype(
-    const GenericType* /* prototype */, Arena* arena) {
-  return New(arena);
-}
-template <typename GenericType>
-void GenericTypeHandler<GenericType>::Merge(const GenericType& from,
-                                            GenericType* to) {
-  to->MergeFrom(from);
-}
+// NewFromPrototypeHelper() is not defined inline here, as we will need to do a
+// virtual function dispatch anyways to go from Message* to call New/Merge. (The
+// additional helper is needed as a workaround for MSVC.)
+MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena);
 
-// NewFromPrototype() and Merge() are not defined inline here, as we will need
-// to do a virtual function dispatch anyways to go from Message* to call
-// New/Merge.
 template <>
-MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
-    const MessageLite* prototype, Arena* arena);
+inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, Arena* arena) {
+  return NewFromPrototypeHelper(prototype, arena);
+}
 template <>
 inline Arena* GenericTypeHandler<MessageLite>::GetOwningArena(
     MessageLite* value) {
   return value->GetOwningArena();
 }
+
+template <typename GenericType>
+PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
+    const GenericType& from, GenericType* to) {
+  to->MergeFrom(from);
+}
 template <>
 void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
                                             MessageLite* to);
+
 template <>
 inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
   value->clear();
@@ -549,12 +884,12 @@
   const Element& at(int index) const;
   Element& at(int index);
 
-  // Remove the last element in the array.
+  // Removes the last element in the array.
   // Ownership of the element is retained by the array.
   void RemoveLast();
 
-  // Delete elements with indices in the range [start .. start+num-1].
-  // Caution: implementation moves all elements with indices [start+num .. ].
+  // Deletes elements with indices in the range [start .. start+num-1].
+  // Caution: moves all elements with indices [start+num .. ].
   // Calling this routine inside a loop can cause quadratic behavior.
   void DeleteSubrange(int start, int num);
 
@@ -566,7 +901,7 @@
   template <typename Iter>
   PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end);
 
-  // Reserve space to expand the field to at least the given size.  This only
+  // Reserves space to expand the field to at least the given size.  This only
   // resizes the pointer array; it doesn't allocate any objects.  If the
   // array is grown, it will always be at least doubled in size.
   void Reserve(int new_size);
@@ -575,20 +910,24 @@
 
   // Gets the underlying array.  This pointer is possibly invalidated by
   // any add or remove operation.
+  //
+  // This API is deprecated. Instead of directly working with element array,
+  // use APIs in repeated_field_util.h; e.g. sorting, etc.
+  PROTOBUF_DEPRECATED_MSG("Use APIs in repeated_field_util.h")
   Element** mutable_data();
   const Element* const* data() const;
 
-  // Swap entire contents with "other". If they are on separate arenas, then
+  // Swaps entire contents with "other". If they are on separate arenas, then
   // copies data.
   void Swap(RepeatedPtrField* other);
 
-  // Swap entire contents with "other". Caller should guarantee that either both
-  // fields are on the same arena or both are on the heap. Swapping between
+  // Swaps entire contents with "other". Caller should guarantee that either
+  // both fields are on the same arena or both are on the heap. Swapping between
   // different arenas with this function is disallowed and is caught via
   // GOOGLE_DCHECK.
   void UnsafeArenaSwap(RepeatedPtrField* other);
 
-  // Swap two elements.
+  // Swaps two elements.
   void SwapElements(int index1, int index2);
 
   // STL-like iterator support
@@ -645,7 +984,7 @@
   // When hardcore memory management becomes necessary -- as it sometimes
   // does here at Google -- the following methods may be useful.
 
-  // Add an already-allocated object, passing ownership to the
+  // Adds an already-allocated object, passing ownership to the
   // RepeatedPtrField.
   //
   // Note that some special behavior occurs with respect to arenas:
@@ -658,7 +997,7 @@
   //   this at runtime, so User Beware.
   void AddAllocated(Element* value);
 
-  // Remove the last element and return it, passing ownership to the caller.
+  // Removes and returns the last element, passing ownership to the caller.
   // Requires:  size() > 0
   //
   // If this RepeatedPtrField is on an arena, an object copy is required to pass
@@ -666,7 +1005,7 @@
   // UnsafeArenaReleaseLast() if this behavior is undesired.
   PROTOBUF_NODISCARD Element* ReleaseLast();
 
-  // Add an already-allocated object, skipping arena-ownership checks. The user
+  // Adds an already-allocated object, skipping arena-ownership checks. The user
   // must guarantee that the given object is in the same arena as this
   // RepeatedPtrField.
   // It is also useful in legacy code that uses temporary ownership to avoid
@@ -677,16 +1016,16 @@
   //   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
   // If you put temp_field on the arena this fails, because the ownership
   // transfers to the arena at the "AddAllocated" call and is not released
-  // anymore causing a double delete. UnsafeArenaAddAllocated prevents this.
+  // anymore, causing a double delete. UnsafeArenaAddAllocated prevents this.
   void UnsafeArenaAddAllocated(Element* value);
 
-  // Remove the last element and return it.  Unlike ReleaseLast, the returned
-  // pointer is always to the original object.  This may be in an arena, and
-  // therefore have the arena's lifetime.
+  // Removes and returns the last element.  Unlike ReleaseLast, the returned
+  // pointer is always to the original object.  This may be in an arena, in
+  // which case it would have the arena's lifetime.
   // Requires: current_size_ > 0
   Element* UnsafeArenaReleaseLast();
 
-  // Extract elements with indices in the range "[start .. start+num-1]".
+  // Extracts elements with indices in the range "[start .. start+num-1]".
   // The caller assumes ownership of the extracted elements and is responsible
   // for deleting them when they are no longer needed.
   // If "elements" is non-nullptr, then pointers to the extracted elements
@@ -717,22 +1056,21 @@
   // Hardcore programs may choose to manipulate these cleared objects
   // to better optimize memory management using the following routines.
 
-  // Get the number of cleared objects that are currently being kept
+  // Gets the number of cleared objects that are currently being kept
   // around for reuse.
   int ClearedCount() const;
 #ifndef PROTOBUF_FUTURE_BREAKING_CHANGES
-  // Add an element to the pool of cleared objects, passing ownership to
+  // Adds an element to the pool of cleared objects, passing ownership to
   // the RepeatedPtrField.  The element must be cleared prior to calling
   // this method.
   //
-  // This method cannot be called when the repeated field is on an arena or when
-  // |value| is; both cases will trigger a GOOGLE_DCHECK-failure.
+  // This method cannot be called when either the repeated field or |value| is
+  // on an arena; both cases will trigger a GOOGLE_DCHECK-failure.
   void AddCleared(Element* value);
-  // Remove a single element from the cleared pool and return it, passing
+  // Removes and returns a single element from the cleared pool, passing
   // ownership to the caller.  The element is guaranteed to be cleared.
   // Requires:  ClearedCount() > 0
   //
-  //
   // This method cannot be called when the repeated field is on an arena; doing
   // so will trigger a GOOGLE_DCHECK-failure.
   PROTOBUF_NODISCARD Element* ReleaseCleared();
@@ -785,446 +1123,6 @@
 
 };
 
-// implementation ====================================================
-
-namespace internal {
-
-constexpr RepeatedPtrFieldBase::RepeatedPtrFieldBase()
-    : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {}
-
-inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(Arena* arena)
-    : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {}
-
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::Destroy() {
-  if (rep_ != nullptr && arena_ == nullptr) {
-    int n = rep_->allocated_size;
-    void* const* elements = rep_->elements;
-    for (int i = 0; i < n; i++) {
-      TypeHandler::Delete(cast<TypeHandler>(elements[i]), nullptr);
-    }
-#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
-    const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
-    ::operator delete(static_cast<void*>(rep_), size);
-#else
-    ::operator delete(static_cast<void*>(rep_));
-#endif
-  }
-  rep_ = nullptr;
-}
-
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
-#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
-  if (GetArena() != nullptr && GetArena() == other->GetArena()) {
-#else   // PROTOBUF_FORCE_COPY_IN_SWAP
-  if (GetArena() == other->GetArena()) {
-#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
-    InternalSwap(other);
-  } else {
-    SwapFallback<TypeHandler>(other);
-  }
-}
-
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) {
-#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
-  GOOGLE_DCHECK(GetArena() == nullptr || other->GetArena() != GetArena());
-#else   // PROTOBUF_FORCE_COPY_IN_SWAP
-  GOOGLE_DCHECK(other->GetArena() != GetArena());
-#endif  // !PROTOBUF_FORCE_COPY_IN_SWAP
-
-  // Copy semantics in this case. We try to improve efficiency by placing the
-  // temporary on |other|'s arena so that messages are copied twice rather than
-  // three times.
-  RepeatedPtrFieldBase temp(other->GetArena());
-  temp.MergeFrom<TypeHandler>(*this);
-  this->Clear<TypeHandler>();
-  this->MergeFrom<TypeHandler>(*other);
-  other->InternalSwap(&temp);
-  temp.Destroy<TypeHandler>();  // Frees rep_ if `other` had no arena.
-}
-
-inline bool RepeatedPtrFieldBase::empty() const { return current_size_ == 0; }
-
-inline int RepeatedPtrFieldBase::size() const { return current_size_; }
-
-template <typename TypeHandler>
-inline const typename TypeHandler::Type& RepeatedPtrFieldBase::Get(
-    int index) const {
-  GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, current_size_);
-  return *cast<TypeHandler>(rep_->elements[index]);
-}
-
-template <typename TypeHandler>
-inline const typename TypeHandler::Type& RepeatedPtrFieldBase::at(
-    int index) const {
-  GOOGLE_CHECK_GE(index, 0);
-  GOOGLE_CHECK_LT(index, current_size_);
-  return *cast<TypeHandler>(rep_->elements[index]);
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type& RepeatedPtrFieldBase::at(int index) {
-  GOOGLE_CHECK_GE(index, 0);
-  GOOGLE_CHECK_LT(index, current_size_);
-  return *cast<TypeHandler>(rep_->elements[index]);
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::Mutable(int index) {
-  GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, current_size_);
-  return cast<TypeHandler>(rep_->elements[index]);
-}
-
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::Delete(int index) {
-  GOOGLE_DCHECK_GE(index, 0);
-  GOOGLE_DCHECK_LT(index, current_size_);
-  TypeHandler::Delete(cast<TypeHandler>(rep_->elements[index]), arena_);
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add(
-    typename TypeHandler::Type* prototype) {
-  if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
-    return cast<TypeHandler>(rep_->elements[current_size_++]);
-  }
-  typename TypeHandler::Type* result =
-      TypeHandler::NewFromPrototype(prototype, arena_);
-  return reinterpret_cast<typename TypeHandler::Type*>(
-      AddOutOfLineHelper(result));
-}
-
-template <typename TypeHandler,
-          typename std::enable_if<TypeHandler::Movable::value>::type*>
-inline void RepeatedPtrFieldBase::Add(typename TypeHandler::Type&& value) {
-  if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
-    *cast<TypeHandler>(rep_->elements[current_size_++]) = std::move(value);
-    return;
-  }
-  if (!rep_ || rep_->allocated_size == total_size_) {
-    Reserve(total_size_ + 1);
-  }
-  ++rep_->allocated_size;
-  typename TypeHandler::Type* result =
-      TypeHandler::New(arena_, std::move(value));
-  rep_->elements[current_size_++] = result;
-}
-
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::RemoveLast() {
-  GOOGLE_DCHECK_GT(current_size_, 0);
-  TypeHandler::Clear(cast<TypeHandler>(rep_->elements[--current_size_]));
-}
-
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::Clear() {
-  const int n = current_size_;
-  GOOGLE_DCHECK_GE(n, 0);
-  if (n > 0) {
-    void* const* elements = rep_->elements;
-    int i = 0;
-    do {
-      TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
-    } while (i < n);
-    current_size_ = 0;
-  }
-}
-
-// To avoid unnecessary code duplication and reduce binary size, we use a
-// layered approach to implementing MergeFrom(). The toplevel method is
-// templated, so we get a small thunk per concrete message type in the binary.
-// This calls a shared implementation with most of the logic, passing a function
-// pointer to another type-specific piece of code that calls the object-allocate
-// and merge handlers.
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) {
-  GOOGLE_DCHECK_NE(&other, this);
-  if (other.current_size_ == 0) return;
-  MergeFromInternal(other,
-                    &RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
-}
-
-inline void RepeatedPtrFieldBase::MergeFromInternal(
-    const RepeatedPtrFieldBase& other,
-    void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)) {
-  // Note: wrapper has already guaranteed that other.rep_ != nullptr here.
-  int other_size = other.current_size_;
-  void** other_elements = other.rep_->elements;
-  void** new_elements = InternalExtend(other_size);
-  int allocated_elems = rep_->allocated_size - current_size_;
-  (this->*inner_loop)(new_elements, other_elements, other_size,
-                      allocated_elems);
-  current_size_ += other_size;
-  if (rep_->allocated_size < current_size_) {
-    rep_->allocated_size = current_size_;
-  }
-}
-
-// Merges other_elems to our_elems.
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::MergeFromInnerLoop(void** our_elems,
-                                              void** other_elems, int length,
-                                              int already_allocated) {
-  if (already_allocated < length) {
-    Arena* arena = GetArena();
-    typename TypeHandler::Type* elem_prototype =
-        reinterpret_cast<typename TypeHandler::Type*>(other_elems[0]);
-    for (int i = already_allocated; i < length; i++) {
-      // Allocate a new empty element that we'll merge into below
-      typename TypeHandler::Type* new_elem =
-          TypeHandler::NewFromPrototype(elem_prototype, arena);
-      our_elems[i] = new_elem;
-    }
-  }
-  // Main loop that does the actual merging
-  for (int i = 0; i < length; i++) {
-    // Already allocated: use existing element.
-    typename TypeHandler::Type* other_elem =
-        reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
-    typename TypeHandler::Type* new_elem =
-        reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
-    TypeHandler::Merge(*other_elem, new_elem);
-  }
-}
-
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) {
-  if (&other == this) return;
-  RepeatedPtrFieldBase::Clear<TypeHandler>();
-  RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
-}
-
-inline int RepeatedPtrFieldBase::Capacity() const { return total_size_; }
-
-inline void* const* RepeatedPtrFieldBase::raw_data() const {
-  return rep_ ? rep_->elements : nullptr;
-}
-
-inline void** RepeatedPtrFieldBase::raw_mutable_data() const {
-  return rep_ ? const_cast<void**>(rep_->elements) : nullptr;
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() {
-  // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
-  //   method entirely.
-  return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
-}
-
-template <typename TypeHandler>
-inline const typename TypeHandler::Type* const* RepeatedPtrFieldBase::data()
-    const {
-  // TODO(kenton):  Breaks C++ aliasing rules.  We should probably remove this
-  //   method entirely.
-  return reinterpret_cast<const typename TypeHandler::Type* const*>(raw_data());
-}
-
-inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) {
-  using std::swap;  // enable ADL with fallback
-  swap(rep_->elements[index1], rep_->elements[index2]);
-}
-
-template <typename TypeHandler>
-inline size_t RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() const {
-  size_t allocated_bytes = static_cast<size_t>(total_size_) * sizeof(void*);
-  if (rep_ != nullptr) {
-    for (int i = 0; i < rep_->allocated_size; ++i) {
-      allocated_bytes +=
-          TypeHandler::SpaceUsedLong(*cast<TypeHandler>(rep_->elements[i]));
-    }
-    allocated_bytes += kRepHeaderSize;
-  }
-  return allocated_bytes;
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() {
-  if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
-    return cast<TypeHandler>(rep_->elements[current_size_++]);
-  } else {
-    return nullptr;
-  }
-}
-
-// AddAllocated version that implements arena-safe copying behavior.
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::AddAllocatedInternal(
-    typename TypeHandler::Type* value, std::true_type) {
-  Arena* element_arena =
-      reinterpret_cast<Arena*>(TypeHandler::GetOwningArena(value));
-  Arena* arena = GetArena();
-  if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) {
-    // Fast path: underlying arena representation (tagged pointer) is equal to
-    // our arena pointer, and we can add to array without resizing it (at least
-    // one slot that is not allocated).
-    void** elems = rep_->elements;
-    if (current_size_ < rep_->allocated_size) {
-      // Make space at [current] by moving first allocated element to end of
-      // allocated list.
-      elems[rep_->allocated_size] = elems[current_size_];
-    }
-    elems[current_size_] = value;
-    current_size_ = current_size_ + 1;
-    rep_->allocated_size = rep_->allocated_size + 1;
-  } else {
-    AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena);
-  }
-}
-
-// Slowpath handles all cases, copying if necessary.
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::AddAllocatedSlowWithCopy(
-    // Pass value_arena and my_arena to avoid duplicate virtual call (value) or
-    // load (mine).
-    typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
-  // Ensure that either the value is in the same arena, or if not, we do the
-  // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy
-  // it to our arena/heap (otherwise).
-  if (my_arena != nullptr && value_arena == nullptr) {
-    my_arena->Own(value);
-  } else if (my_arena != value_arena) {
-    typename TypeHandler::Type* new_value =
-        TypeHandler::NewFromPrototype(value, my_arena);
-    TypeHandler::Merge(*value, new_value);
-    TypeHandler::Delete(value, value_arena);
-    value = new_value;
-  }
-
-  UnsafeArenaAddAllocated<TypeHandler>(value);
-}
-
-// AddAllocated version that does not implement arena-safe copying behavior.
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::AddAllocatedInternal(
-    typename TypeHandler::Type* value, std::false_type) {
-  if (rep_ && rep_->allocated_size < total_size_) {
-    // Fast path: underlying arena representation (tagged pointer) is equal to
-    // our arena pointer, and we can add to array without resizing it (at least
-    // one slot that is not allocated).
-    void** elems = rep_->elements;
-    if (current_size_ < rep_->allocated_size) {
-      // Make space at [current] by moving first allocated element to end of
-      // allocated list.
-      elems[rep_->allocated_size] = elems[current_size_];
-    }
-    elems[current_size_] = value;
-    current_size_ = current_size_ + 1;
-    ++rep_->allocated_size;
-  } else {
-    UnsafeArenaAddAllocated<TypeHandler>(value);
-  }
-}
-
-template <typename TypeHandler>
-void RepeatedPtrFieldBase::UnsafeArenaAddAllocated(
-    typename TypeHandler::Type* value) {
-  // Make room for the new pointer.
-  if (!rep_ || current_size_ == total_size_) {
-    // The array is completely full with no cleared objects, so grow it.
-    Reserve(total_size_ + 1);
-    ++rep_->allocated_size;
-  } else if (rep_->allocated_size == total_size_) {
-    // There is no more space in the pointer array because it contains some
-    // cleared objects awaiting reuse.  We don't want to grow the array in this
-    // case because otherwise a loop calling AddAllocated() followed by Clear()
-    // would leak memory.
-    TypeHandler::Delete(cast<TypeHandler>(rep_->elements[current_size_]),
-                        arena_);
-  } else if (current_size_ < rep_->allocated_size) {
-    // We have some cleared objects.  We don't care about their order, so we
-    // can just move the first one to the end to make space.
-    rep_->elements[rep_->allocated_size] = rep_->elements[current_size_];
-    ++rep_->allocated_size;
-  } else {
-    // There are no cleared objects.
-    ++rep_->allocated_size;
-  }
-
-  rep_->elements[current_size_++] = value;
-}
-
-// ReleaseLast() for types that implement merge/copy behavior.
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal(
-    std::true_type) {
-  // First, release an element.
-  typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
-  // Now perform a copy if we're on an arena.
-  Arena* arena = GetArena();
-
-  typename TypeHandler::Type* new_result;
-#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
-  new_result = copy<TypeHandler>(result);
-  if (arena == nullptr) delete result;
-#else   // PROTOBUF_FORCE_COPY_IN_RELEASE
-  new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
-#endif  // !PROTOBUF_FORCE_COPY_IN_RELEASE
-  return new_result;
-}
-
-// ReleaseLast() for types that *do not* implement merge/copy behavior -- this
-// is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if we're on
-// an arena, since the user really should implement the copy operation in this
-// case.
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal(
-    std::false_type) {
-  GOOGLE_DCHECK(GetArena() == nullptr)
-      << "ReleaseLast() called on a RepeatedPtrField that is on an arena, "
-      << "with a type that does not implement MergeFrom. This is unsafe; "
-      << "please implement MergeFrom for your type.";
-  return UnsafeArenaReleaseLast<TypeHandler>();
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type*
-RepeatedPtrFieldBase::UnsafeArenaReleaseLast() {
-  GOOGLE_DCHECK_GT(current_size_, 0);
-  typename TypeHandler::Type* result =
-      cast<TypeHandler>(rep_->elements[--current_size_]);
-  --rep_->allocated_size;
-  if (current_size_ < rep_->allocated_size) {
-    // There are cleared elements on the end; replace the removed element
-    // with the last allocated element.
-    rep_->elements[current_size_] = rep_->elements[rep_->allocated_size];
-  }
-  return result;
-}
-
-inline int RepeatedPtrFieldBase::ClearedCount() const {
-  return rep_ ? (rep_->allocated_size - current_size_) : 0;
-}
-
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::AddCleared(
-    typename TypeHandler::Type* value) {
-  GOOGLE_DCHECK(GetArena() == nullptr)
-      << "AddCleared() can only be used on a RepeatedPtrField not on an arena.";
-  GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr)
-      << "AddCleared() can only accept values not on an arena.";
-  if (!rep_ || rep_->allocated_size == total_size_) {
-    Reserve(total_size_ + 1);
-  }
-  rep_->elements[rep_->allocated_size++] = value;
-}
-
-template <typename TypeHandler>
-inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
-  GOOGLE_DCHECK(GetArena() == nullptr)
-      << "ReleaseCleared() can only be used on a RepeatedPtrField not on "
-      << "an arena.";
-  GOOGLE_DCHECK(GetArena() == nullptr);
-  GOOGLE_DCHECK(rep_ != nullptr);
-  GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_);
-  return cast<TypeHandler>(rep_->elements[--rep_->allocated_size]);
-}
-
-}  // namespace internal
-
 // -------------------------------------------------------------------
 
 template <typename Element>
@@ -1626,16 +1524,13 @@
   RepeatedPtrIterator() : it_(nullptr) {}
   explicit RepeatedPtrIterator(void* const* it) : it_(it) {}
 
-  // Allow "upcasting" from RepeatedPtrIterator<T**> to
+  // Allows "upcasting" from RepeatedPtrIterator<T**> to
   // RepeatedPtrIterator<const T*const*>.
-  template <typename OtherElement>
+  template <typename OtherElement,
+            typename std::enable_if<std::is_convertible<
+                OtherElement*, pointer>::value>::type* = nullptr>
   RepeatedPtrIterator(const RepeatedPtrIterator<OtherElement>& other)
-      : it_(other.it_) {
-    // Force a compiler error if the other type is not convertible to ours.
-    if (false) {
-      static_cast<void>([](OtherElement* from) -> Element* { return from; });
-    }
-  }
+      : it_(other.it_) {}
 
   // dereferenceable
   reference operator*() const { return *reinterpret_cast<Element*>(*it_); }
@@ -1654,20 +1549,26 @@
   iterator operator--(int) { return iterator(it_--); }
 
   // equality_comparable
-  bool operator==(const nonconst_iterator& x) const { return it_ == x.it_; }
-  bool operator==(const const_iterator& x) const { return it_ == x.it_; }
-  bool operator!=(const nonconst_iterator& x) const { return it_ != x.it_; }
-  bool operator!=(const const_iterator& x) const { return it_ != x.it_; }
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
 
   // less_than_comparable
-  bool operator<(const nonconst_iterator& x) const { return it_ < x.it_; }
-  bool operator<(const const_iterator& x) const { return it_ < x.it_; }
-  bool operator<=(const nonconst_iterator& x) const { return it_ <= x.it_; }
-  bool operator<=(const const_iterator& x) const { return it_ <= x.it_; }
-  bool operator>(const nonconst_iterator& x) const { return it_ > x.it_; }
-  bool operator>(const const_iterator& x) const { return it_ > x.it_; }
-  bool operator>=(const nonconst_iterator& x) const { return it_ >= x.it_; }
-  bool operator>=(const const_iterator& x) const { return it_ >= x.it_; }
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
 
   // addable, subtractable
   iterator& operator+=(difference_type d) {
@@ -1695,7 +1596,9 @@
   reference operator[](difference_type d) const { return *(*this + d); }
 
   // random access iterator
-  difference_type operator-(const iterator& x) const { return it_ - x.it_; }
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
 
  private:
   template <typename OtherElement>
@@ -1705,7 +1608,7 @@
   void* const* it_;
 };
 
-// Provide an iterator that operates on pointers to the underlying objects
+// Provides an iterator that operates on pointers to the underlying objects
 // rather than the objects themselves as RepeatedPtrIterator does.
 // Consider using this when working with stl algorithms that change
 // the array.
@@ -1725,6 +1628,17 @@
   RepeatedPtrOverPtrsIterator() : it_(nullptr) {}
   explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
 
+  // Allows "upcasting" from RepeatedPtrOverPtrsIterator<T**> to
+  // RepeatedPtrOverPtrsIterator<const T*const*>.
+  template <
+      typename OtherElement, typename OtherVoidPtr,
+      typename std::enable_if<
+          std::is_convertible<OtherElement*, pointer>::value &&
+          std::is_convertible<OtherVoidPtr*, VoidPtr>::value>::type* = nullptr>
+  RepeatedPtrOverPtrsIterator(
+      const RepeatedPtrOverPtrsIterator<OtherElement, OtherVoidPtr>& other)
+      : it_(other.it_) {}
+
   // dereferenceable
   reference operator*() const { return *reinterpret_cast<Element*>(it_); }
   pointer operator->() const { return &(operator*()); }
@@ -1742,14 +1656,26 @@
   iterator operator--(int) { return iterator(it_--); }
 
   // equality_comparable
-  bool operator==(const iterator& x) const { return it_ == x.it_; }
-  bool operator!=(const iterator& x) const { return it_ != x.it_; }
+  friend bool operator==(const iterator& x, const iterator& y) {
+    return x.it_ == y.it_;
+  }
+  friend bool operator!=(const iterator& x, const iterator& y) {
+    return x.it_ != y.it_;
+  }
 
   // less_than_comparable
-  bool operator<(const iterator& x) const { return it_ < x.it_; }
-  bool operator<=(const iterator& x) const { return it_ <= x.it_; }
-  bool operator>(const iterator& x) const { return it_ > x.it_; }
-  bool operator>=(const iterator& x) const { return it_ >= x.it_; }
+  friend bool operator<(const iterator& x, const iterator& y) {
+    return x.it_ < y.it_;
+  }
+  friend bool operator<=(const iterator& x, const iterator& y) {
+    return x.it_ <= y.it_;
+  }
+  friend bool operator>(const iterator& x, const iterator& y) {
+    return x.it_ > y.it_;
+  }
+  friend bool operator>=(const iterator& x, const iterator& y) {
+    return x.it_ >= y.it_;
+  }
 
   // addable, subtractable
   iterator& operator+=(difference_type d) {
@@ -1777,27 +1703,18 @@
   reference operator[](difference_type d) const { return *(*this + d); }
 
   // random access iterator
-  difference_type operator-(const iterator& x) const { return it_ - x.it_; }
+  friend difference_type operator-(iterator it1, iterator it2) {
+    return it1.it_ - it2.it_;
+  }
 
  private:
-  template <typename OtherElement>
-  friend class RepeatedPtrIterator;
+  template <typename OtherElement, typename OtherVoidPtr>
+  friend class RepeatedPtrOverPtrsIterator;
 
   // The internal iterator.
   VoidPtr* it_;
 };
 
-void RepeatedPtrFieldBase::InternalSwap(RepeatedPtrFieldBase* rhs) {
-  GOOGLE_DCHECK(this != rhs);
-
-  // Swap all fields at once.
-  auto temp = std::make_tuple(rhs->arena_, rhs->current_size_, rhs->total_size_,
-                              rhs->rep_);
-  std::tie(rhs->arena_, rhs->current_size_, rhs->total_size_, rhs->rep_) =
-      std::make_tuple(arena_, current_size_, total_size_, rep_);
-  std::tie(arena_, current_size_, total_size_, rep_) = temp;
-}
-
 }  // namespace internal
 
 template <typename Element>
@@ -2000,9 +1917,9 @@
 //   temp_field.UnsafeArenaAddAllocated(new T);
 //   ... // Do something with temp_field
 //   temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr);
-// If you put temp_field on the arena this fails, because the ownership
-// transfers to the arena at the "AddAllocated" call and is not released anymore
-// causing a double delete. Using UnsafeArenaAddAllocated prevents this.
+// Putting temp_field on the arena fails because the ownership transfers to the
+// arena at the "AddAllocated" call and is not released anymore causing a
+// double delete. This function uses UnsafeArenaAddAllocated to prevent this.
 template <typename T>
 internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator<T>
 UnsafeArenaAllocatedRepeatedPtrFieldBackInserter(
diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h
index b18a803..d288eb5 100644
--- a/src/google/protobuf/service.h
+++ b/src/google/protobuf/service.h
@@ -100,6 +100,7 @@
 #ifndef GOOGLE_PROTOBUF_SERVICE_H__
 #define GOOGLE_PROTOBUF_SERVICE_H__
 
+
 #include <string>
 #include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
@@ -108,6 +109,7 @@
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 4edb90b..ec691b1 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -16,23 +16,27 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr SourceContext::SourceContext(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : file_name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){}
 struct SourceContextDefaultTypeInternal {
   constexpr SourceContextDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~SourceContextDefaultTypeInternal() {}
   union {
     SourceContext _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT SourceContextDefaultTypeInternal _SourceContext_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 SourceContextDefaultTypeInternal _SourceContext_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -43,12 +47,12 @@
   ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::SourceContext, file_name_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceContext)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_SourceContext_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -59,19 +63,21 @@
   "tobuf/types/known/sourcecontextpb\242\002\003GPB\252"
   "\002\036Google.Protobuf.WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
-  false, false, 240, descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto, "google/protobuf/source_context.proto", 
-  &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+    false, false, 240, descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    "google/protobuf/source_context.proto",
+    &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fsource_5fcontext_2eproto(&descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fsource_5fcontext_2eproto(&descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -84,15 +90,12 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.SourceContext)
 }
 SourceContext::SourceContext(const SourceContext& from)
   : ::PROTOBUF_NAMESPACE_ID::Message() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  file_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  file_name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -104,7 +107,7 @@
 }
 
 inline void SourceContext::SharedCtor() {
-file_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+file_name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -112,9 +115,11 @@
 
 SourceContext::~SourceContext() {
   // @@protoc_insertion_point(destructor:google.protobuf.SourceContext)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void SourceContext::SharedDtor() {
@@ -122,12 +127,6 @@
   file_name_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void SourceContext::ArenaDtor(void* object) {
-  SourceContext* _this = reinterpret_cast< SourceContext* >(object);
-  (void)_this;
-}
-void SourceContext::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void SourceContext::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -142,19 +141,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* SourceContext::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* SourceContext::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string file_name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_file_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.SourceContext.file_name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.SourceContext.file_name"));
         } else
           goto handle_unusual;
         continue;
@@ -198,7 +197,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceContext)
@@ -272,7 +271,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata SourceContext::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_getter, &descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[0]);
 }
@@ -280,7 +279,8 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceContext* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceContext >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::SourceContext*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::SourceContext >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::SourceContext >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index 28af27d..036406f 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto;
@@ -172,9 +163,6 @@
   protected:
   explicit SourceContext(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -269,7 +257,7 @@
   file_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), file_name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (file_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (file_name_.IsDefault()) {
     file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index f90e213..69933f2 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -16,58 +16,62 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Struct_FieldsEntry_DoNotUse::Struct_FieldsEntry_DoNotUse(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized){}
+    ::_pbi::ConstantInitialized){}
 struct Struct_FieldsEntry_DoNotUseDefaultTypeInternal {
   constexpr Struct_FieldsEntry_DoNotUseDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~Struct_FieldsEntry_DoNotUseDefaultTypeInternal() {}
   union {
     Struct_FieldsEntry_DoNotUse _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Struct_FieldsEntry_DoNotUseDefaultTypeInternal _Struct_FieldsEntry_DoNotUse_default_instance_;
 constexpr Struct::Struct(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : fields_(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}){}
 struct StructDefaultTypeInternal {
   constexpr StructDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~StructDefaultTypeInternal() {}
   union {
     Struct _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT StructDefaultTypeInternal _Struct_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StructDefaultTypeInternal _Struct_default_instance_;
 constexpr Value::Value(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : _oneof_case_{}{}
 struct ValueDefaultTypeInternal {
   constexpr ValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ValueDefaultTypeInternal() {}
   union {
     Value _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ValueDefaultTypeInternal _Value_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ValueDefaultTypeInternal _Value_default_instance_;
 constexpr ListValue::ListValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : values_(){}
 struct ListValueDefaultTypeInternal {
   constexpr ListValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~ListValueDefaultTypeInternal() {}
   union {
     ListValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ListValueDefaultTypeInternal _ListValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ListValueDefaultTypeInternal _ListValue_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
-static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse, _has_bits_),
@@ -93,12 +97,12 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, _oneof_case_[0]),
   ~0u,  // no _weak_field_map_
   ~0u,  // no _inlined_string_donated_
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
-  ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
+  ::_pbi::kInvalidFieldOffsetTag,
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Value, kind_),
   ~0u,  // no _has_bits_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, _internal_metadata_),
@@ -108,18 +112,18 @@
   ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::ListValue, values_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, 8, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse)},
   { 10, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Struct)},
   { 17, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Value)},
   { 30, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::ListValue)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Struct_FieldsEntry_DoNotUse_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Value_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Struct_FieldsEntry_DoNotUse_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_ListValue_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -140,19 +144,21 @@
   "rotobuf/types/known/structpb\370\001\001\242\002\003GPB\252\002\036"
   "Google.Protobuf.WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fstruct_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
-  false, false, 638, descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto, "google/protobuf/struct.proto", 
-  &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once, nullptr, 0, 4,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fstruct_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto, file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fstruct_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+    false, false, 638, descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
+    "google/protobuf/struct.proto",
+    &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once, nullptr, 0, 4,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fstruct_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fstruct_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fstruct_2eproto(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fstruct_2eproto(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* NullValue_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fstruct_2eproto);
@@ -177,7 +183,7 @@
   MergeFromInternal(other);
 }
 ::PROTOBUF_NAMESPACE_ID::Metadata Struct_FieldsEntry_DoNotUse::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fstruct_2eproto[0]);
 }
@@ -193,8 +199,8 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   fields_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
+  if (arena != nullptr && !is_message_owned) {
+    arena->OwnCustomDestructor(this, &Struct::ArenaDtor);
   }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Struct)
 }
@@ -210,24 +216,22 @@
 
 Struct::~Struct() {
   // @@protoc_insertion_point(destructor:google.protobuf.Struct)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    ArenaDtor(this);
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Struct::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
+  fields_.Destruct();
 }
 
 void Struct::ArenaDtor(void* object) {
   Struct* _this = reinterpret_cast< Struct* >(object);
-  (void)_this;
-  _this->fields_. ~MapField();
-}
-inline void Struct::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena) {
-  if (arena != nullptr) {
-    arena->OwnCustomDestructor(this, &Struct::ArenaDtor);
-  }
+  _this->fields_.Destruct();
 }
 void Struct::SetCachedSize(int size) const {
   _cached_size_.Set(size);
@@ -243,11 +247,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Struct::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Struct::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // map<string, .google.protobuf.Value> fields = 1;
       case 1:
@@ -293,48 +297,32 @@
 
   // map<string, .google.protobuf.Value> fields = 1;
   if (!this->_internal_fields().empty()) {
-    typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::const_pointer
-        ConstPtr;
-    typedef ConstPtr SortItem;
-    typedef ::PROTOBUF_NAMESPACE_ID::internal::CompareByDerefFirst<SortItem> Less;
-    struct Utf8Check {
-      static void Check(ConstPtr p) {
-        (void)p;
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-          p->first.data(), static_cast<int>(p->first.length()),
-          ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-          "google.protobuf.Struct.FieldsEntry.key");
-      }
+    using MapType = ::_pb::Map<std::string, ::PROTOBUF_NAMESPACE_ID::Value>;
+    using WireHelper = Struct_FieldsEntry_DoNotUse::Funcs;
+    const auto& map_field = this->_internal_fields();
+    auto check_utf8 = [](const MapType::value_type& entry) {
+      (void)entry;
+      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+        entry.first.data(), static_cast<int>(entry.first.length()),
+        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
+        "google.protobuf.Struct.FieldsEntry.key");
     };
 
-    if (stream->IsSerializationDeterministic() &&
-        this->_internal_fields().size() > 1) {
-      ::std::unique_ptr<SortItem[]> items(
-          new SortItem[this->_internal_fields().size()]);
-      typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::size_type size_type;
-      size_type n = 0;
-      for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::const_iterator
-          it = this->_internal_fields().begin();
-          it != this->_internal_fields().end(); ++it, ++n) {
-        items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);
-      }
-      ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
-      for (size_type i = 0; i < n; i++) {
-        target = Struct_FieldsEntry_DoNotUse::Funcs::InternalSerialize(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, target, stream);
-        Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
+    if (stream->IsSerializationDeterministic() && map_field.size() > 1) {
+      for (const auto& entry : ::_pbi::MapSorterPtr<MapType>(map_field)) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
       }
     } else {
-      for (::PROTOBUF_NAMESPACE_ID::Map< std::string, ::PROTOBUF_NAMESPACE_ID::Value >::const_iterator
-          it = this->_internal_fields().begin();
-          it != this->_internal_fields().end(); ++it) {
-        target = Struct_FieldsEntry_DoNotUse::Funcs::InternalSerialize(1, it->first, it->second, target, stream);
-        Utf8Check::Check(&(*it));
+      for (const auto& entry : map_field) {
+        target = WireHelper::InternalSerialize(1, entry.first, entry.second, target, stream);
+        check_utf8(entry);
       }
     }
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Struct)
@@ -402,7 +390,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Struct::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fstruct_2eproto[1]);
 }
@@ -457,9 +445,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Value)
 }
 Value::Value(const Value& from)
@@ -504,9 +489,11 @@
 
 Value::~Value() {
   // @@protoc_insertion_point(destructor:google.protobuf.Value)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Value::SharedDtor() {
@@ -516,12 +503,6 @@
   }
 }
 
-void Value::ArenaDtor(void* object) {
-  Value* _this = reinterpret_cast< Value* >(object);
-  (void)_this;
-}
-void Value::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Value::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -575,11 +556,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // .google.protobuf.NullValue null_value = 1;
       case 1:
@@ -602,9 +583,9 @@
       case 3:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
           auto str = _internal_mutable_string_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Value.string_value"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Value.string_value"));
         } else
           goto handle_unusual;
         continue;
@@ -664,14 +645,14 @@
   // .google.protobuf.NullValue null_value = 1;
   if (_internal_has_null_value()) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       1, this->_internal_null_value(), target);
   }
 
   // double number_value = 2;
   if (_internal_has_number_value()) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(2, this->_internal_number_value(), target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(2, this->_internal_number_value(), target);
   }
 
   // string string_value = 3;
@@ -687,27 +668,25 @@
   // bool bool_value = 4;
   if (_internal_has_bool_value()) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(4, this->_internal_bool_value(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(4, this->_internal_bool_value(), target);
   }
 
   // .google.protobuf.Struct struct_value = 5;
   if (_internal_has_struct_value()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        5, _Internal::struct_value(this), target, stream);
+      InternalWriteMessage(5, _Internal::struct_value(this),
+        _Internal::struct_value(this).GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.ListValue list_value = 6;
   if (_internal_has_list_value()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        6, _Internal::list_value(this), target, stream);
+      InternalWriteMessage(6, _Internal::list_value(this),
+        _Internal::list_value(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
@@ -726,7 +705,7 @@
     // .google.protobuf.NullValue null_value = 1;
     case kNullValue: {
       total_size += 1 +
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_null_value());
+        ::_pbi::WireFormatLite::EnumSize(this->_internal_null_value());
       break;
     }
     // double number_value = 2;
@@ -837,7 +816,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Value::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fstruct_2eproto[2]);
 }
@@ -853,9 +832,6 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   values_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.ListValue)
 }
 ListValue::ListValue(const ListValue& from)
@@ -870,21 +846,17 @@
 
 ListValue::~ListValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.ListValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void ListValue::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void ListValue::ArenaDtor(void* object) {
-  ListValue* _this = reinterpret_cast< ListValue* >(object);
-  (void)_this;
-}
-void ListValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void ListValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -899,11 +871,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* ListValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* ListValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // repeated .google.protobuf.Value values = 1;
       case 1:
@@ -948,15 +920,15 @@
   (void) cached_has_bits;
 
   // repeated .google.protobuf.Value values = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_values_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_values_size()); i < n; i++) {
+    const auto& repfield = this->_internal_values(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(1, this->_internal_values(i), target, stream);
+        InternalWriteMessage(1, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
@@ -1022,7 +994,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata ListValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fstruct_2eproto_getter, &descriptor_table_google_2fprotobuf_2fstruct_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fstruct_2eproto[3]);
 }
@@ -1030,16 +1002,20 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct_FieldsEntry_DoNotUse >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Struct*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Struct >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Struct >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Value* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Value >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Value >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Value >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ListValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::ListValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::ListValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::ListValue >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 8ac5cdb..eaf82b2 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -46,14 +45,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fstruct_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[4]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto;
@@ -126,6 +117,7 @@
   static bool ValidateValue(void*) { return true; }
   using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
   ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
+  friend struct ::TableStruct_google_2fprotobuf_2fstruct_2eproto;
 };
 
 // -------------------------------------------------------------------
@@ -239,7 +231,6 @@
                        bool is_message_owned = false);
   private:
   static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -406,9 +397,6 @@
   protected:
   explicit Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -663,9 +651,6 @@
   protected:
   explicit ListValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -856,7 +841,7 @@
   if (!_internal_has_string_value()) {
     clear_kind();
     set_has_string_value();
-    kind_.string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+    kind_.string_value_.InitDefault();
   }
   kind_.string_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
   // @@protoc_insertion_point(field_set:google.protobuf.Value.string_value)
@@ -876,7 +861,7 @@
   if (!_internal_has_string_value()) {
     clear_kind();
     set_has_string_value();
-    kind_.string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+    kind_.string_value_.InitDefault();
   }
   kind_.string_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation());
 }
@@ -884,7 +869,7 @@
   if (!_internal_has_string_value()) {
     clear_kind();
     set_has_string_value();
-    kind_.string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+    kind_.string_value_.InitDefault();
   }
   return kind_.string_value_.Mutable(
       ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation());
@@ -904,11 +889,7 @@
   }
   if (string_value != nullptr) {
     set_has_string_value();
-    kind_.string_value_.UnsafeSetDefault(string_value);
-    ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaForAllocation();
-    if (arena != nullptr) {
-      arena->Own(string_value);
-    }
+    kind_.string_value_.InitAllocated(string_value, GetArenaForAllocation());
   }
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.string_value)
 }
@@ -973,7 +954,7 @@
   // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value)
   if (_internal_has_struct_value()) {
     clear_has_kind();
-      ::PROTOBUF_NAMESPACE_ID::Struct* temp = kind_.struct_value_;
+    ::PROTOBUF_NAMESPACE_ID::Struct* temp = kind_.struct_value_;
     if (GetArenaForAllocation() != nullptr) {
       temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
     }
@@ -1047,7 +1028,7 @@
   // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value)
   if (_internal_has_list_value()) {
     clear_has_kind();
-      ::PROTOBUF_NAMESPACE_ID::ListValue* temp = kind_.list_value_;
+    ::PROTOBUF_NAMESPACE_ID::ListValue* temp = kind_.list_value_;
     if (GetArenaForAllocation() != nullptr) {
       temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
     }
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index 6bead9a..7c84cac 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -1405,7 +1405,7 @@
   // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
   // where 0x10000 is the smallest hex number that is as wide as the user
   // asked for.
-  uint64 mask = ((static_cast<uint64>(1) << (width - 1) * 4)) | value;
+  uint64 mask = (static_cast<uint64>(1) << ((width - 1) * 4)) | value;
   static const char hexdigits[] = "0123456789abcdef";
   do {
     *--writer = hexdigits[value & 0xF];
diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto
index 39fc123..c7b9c48 100644
--- a/src/google/protobuf/test_messages_proto2.proto
+++ b/src/google/protobuf/test_messages_proto2.proto
@@ -209,6 +209,7 @@
   optional double default_double = 252 [ default = 7e22];
   optional bool default_bool = 253 [ default = true];
   optional string default_string = 254 [ default = "Rosebud"];
+  optional bytes default_bytes = 255 [ default = "joshua"];
 
   // Test field-name-to-JSON-name convention.
   // (protobuf says names can be any valid C/C++ identifier.)
@@ -290,3 +291,7 @@
     kTrue = 1;
   }
 }
+
+message OneStringProto2 {
+  optional string data = 1;
+}
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index 3ec3aa7..738490e 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -44,6 +44,7 @@
 #undef UNITTEST
 #undef UNITTEST_IMPORT
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/test_util2.h b/src/google/protobuf/test_util2.h
index f12addb..e3f53a9 100644
--- a/src/google/protobuf/test_util2.h
+++ b/src/google/protobuf/test_util2.h
@@ -35,6 +35,8 @@
 
 #include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/testing/googletest.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 
 namespace google {
 namespace protobuf {
@@ -75,6 +77,28 @@
   return util::MessageDifferencer::Equals(message, other);
 }
 
+// Wraps io::ArrayInputStream while checking against bound. When a blocking
+// stream is used with bounded length, proto parsing must not access beyond the
+// bound. Otherwise, it can result in unintended block, then deadlock.
+class BoundedArrayInputStream : public io::ZeroCopyInputStream {
+ public:
+  BoundedArrayInputStream(const void* data, int size)
+      : stream_(data, size), bound_(size) {}
+  ~BoundedArrayInputStream() override {}
+
+  bool Next(const void** data, int* size) override {
+    GOOGLE_CHECK_LT(stream_.ByteCount(), bound_);
+    return stream_.Next(data, size);
+  }
+  void BackUp(int count) override { stream_.BackUp(count); }
+  bool Skip(int count) override { return stream_.Skip(count); }
+  int64_t ByteCount() const override { return stream_.ByteCount(); }
+
+ private:
+  io::ArrayInputStream stream_;
+  int bound_;
+};
+
 }  // namespace TestUtil
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 8b20d76..880b16d 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -44,22 +44,21 @@
 #include <limits>
 #include <vector>
 
-#include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/any.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/tokenizer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/any.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/stubs/strutil.h>
-#include <google/protobuf/io/strtod.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 
@@ -276,6 +275,7 @@
         allow_partial_(allow_partial),
         initial_recursion_limit_(recursion_limit),
         recursion_limit_(recursion_limit),
+        had_silent_marker_(false),
         had_errors_(false) {
     // For backwards-compatibility with proto1, we need to allow the 'f' suffix
     // for floats.
@@ -429,10 +429,11 @@
       std::string prefix_and_full_type_name =
           StrCat(prefix, full_type_name);
       DO(ConsumeBeforeWhitespace("]"));
-      TryConsumeWhitespace(prefix_and_full_type_name, "Any");
+      TryConsumeWhitespace();
       // ':' is optional between message labels and values.
-      TryConsumeBeforeWhitespace(":");
-      TryConsumeWhitespace(prefix_and_full_type_name, "Any");
+      if (TryConsumeBeforeWhitespace(":")) {
+        TryConsumeWhitespace();
+      }
       std::string serialized_value;
       const Descriptor* value_descriptor =
           finder_ ? finder_->FindAnyType(*message, prefix, full_type_name)
@@ -462,7 +463,7 @@
       // Extension.
       DO(ConsumeFullTypeName(&field_name));
       DO(ConsumeBeforeWhitespace("]"));
-      TryConsumeWhitespace(message->GetTypeName(), "Extension");
+      TryConsumeWhitespace();
 
       field = finder_ ? finder_->FindExtension(message, field_name)
                       : DefaultFinderFindExtension(message, field_name);
@@ -482,7 +483,7 @@
       }
     } else {
       DO(ConsumeIdentifierBeforeWhitespace(&field_name));
-      TryConsumeWhitespace(message->GetTypeName(), "Normal");
+      TryConsumeWhitespace();
 
       int32_t field_number;
       if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
@@ -551,7 +552,7 @@
       // If there is no ":" or there is a "{" or "<" after ":", this field has
       // to be a message or the input is ill-formed.
       if (TryConsumeBeforeWhitespace(":")) {
-        TryConsumeWhitespace(message->GetTypeName(), "Unknown/Reserved");
+        TryConsumeWhitespace();
         if (!LookingAt("{") && !LookingAt("<")) {
           return SkipFieldValue();
         }
@@ -587,7 +588,9 @@
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       // ':' is optional here.
       bool consumed_semicolon = TryConsumeBeforeWhitespace(":");
-      TryConsumeWhitespace(message->GetTypeName(), "Normal");
+      if (consumed_semicolon) {
+        TryConsumeWhitespace();
+      }
       if (consumed_semicolon && field->options().weak() &&
           LookingAtType(io::Tokenizer::TYPE_STRING)) {
         // we are getting a bytes string for a weak field.
@@ -602,7 +605,7 @@
     } else {
       // ':' is required here.
       DO(ConsumeBeforeWhitespace(":"));
-      TryConsumeWhitespace(message->GetTypeName(), "Normal");
+      TryConsumeWhitespace();
     }
 
     if (field->is_repeated() && TryConsume("[")) {
@@ -653,15 +656,15 @@
 
   // Skips the next field including the field's name and value.
   bool SkipField() {
+    std::string field_name;
     if (TryConsume("[")) {
       // Extension name or type URL.
-      DO(ConsumeTypeUrlOrFullTypeName());
+      DO(ConsumeTypeUrlOrFullTypeName(&field_name));
       DO(ConsumeBeforeWhitespace("]"));
     } else {
-      std::string field_name;
       DO(ConsumeIdentifierBeforeWhitespace(&field_name));
     }
-    TryConsumeWhitespace("Unknown/Reserved", "n/a");
+    TryConsumeWhitespace();
 
     // Try to guess the type of this field.
     // If this field is not a message, there should be a ":" between the
@@ -670,7 +673,7 @@
     // If there is no ":" or there is a "{" or "<" after ":", this field has
     // to be a message or the input is ill-formed.
     if (TryConsumeBeforeWhitespace(":")) {
-      TryConsumeWhitespace("Unknown/Reserved", "n/a");
+      TryConsumeWhitespace();
       if (!LookingAt("{") && !LookingAt("<")) {
         DO(SkipFieldValue());
       } else {
@@ -1018,11 +1021,21 @@
     return true;
   }
 
-  bool ConsumeTypeUrlOrFullTypeName() {
-    std::string discarded;
-    DO(ConsumeIdentifier(&discarded));
-    while (TryConsume(".") || TryConsume("/")) {
-      DO(ConsumeIdentifier(&discarded));
+  bool ConsumeTypeUrlOrFullTypeName(std::string* name) {
+    DO(ConsumeIdentifier(name));
+    while (true) {
+      std::string connector;
+      if (TryConsume(".")) {
+        connector = ".";
+      } else if (TryConsume("/")) {
+        connector = "/";
+      } else {
+        break;
+      }
+      std::string part;
+      DO(ConsumeIdentifier(&part));
+      *name += connector;
+      *name += part;
     }
     return true;
   }
@@ -1264,13 +1277,15 @@
     return result;
   }
 
-  bool TryConsumeWhitespace(const std::string& message_type,
-                            const char* field_type) {
+  bool TryConsumeWhitespace() {
+    had_silent_marker_ = false;
     if (LookingAtType(io::Tokenizer::TYPE_WHITESPACE)) {
+      if (tokenizer_.current().text == " " DEBUG_STRING_SILENT_MARKER) {
+        had_silent_marker_ = true;
+      }
       tokenizer_.Next();
       return true;
     }
-
     return false;
   }
 
@@ -1311,6 +1326,7 @@
   const bool allow_partial_;
   const int initial_recursion_limit_;
   int recursion_limit_;
+  bool had_silent_marker_;
   bool had_errors_;
 };
 
@@ -1342,10 +1358,10 @@
         indent_level_(initial_indent_level),
         initial_indent_level_(initial_indent_level) {}
 
-  ~TextGenerator() {
+  ~TextGenerator() override {
     // Only BackUp() if we're sure we've successfully called Next() at least
     // once.
-    if (!failed_ && buffer_size_ > 0) {
+    if (!failed_) {
       output_->BackUp(buffer_size_);
     }
   }
@@ -1640,7 +1656,6 @@
   return Merge(&input_stream, output);
 }
 
-
 bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
                                         Message* output,
                                         ParserImpl* parser_impl) {
@@ -1689,7 +1704,6 @@
   return Parser().MergeFromString(input, output);
 }
 
-
 #undef DO
 
 // ===========================================================================
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index f2c8dc3..8640493 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -38,17 +38,19 @@
 #ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
 #define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
 
+
 #include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/port.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message_lite.h>
-#include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 1da753b..32a33d8 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -63,6 +63,7 @@
 #include <google/protobuf/stubs/substitute.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -456,7 +457,7 @@
 // A printer that appends 'u' to all unsigned int32.
 class CustomUInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
-  virtual std::string PrintUInt32(uint32 val) const {
+  std::string PrintUInt32(uint32_t val) const override {
     return StrCat(FieldValuePrinter::PrintUInt32(val), "u");
   }
 };
@@ -480,7 +481,7 @@
 
 class CustomInt32FieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
-  virtual std::string PrintInt32(int32 val) const {
+  std::string PrintInt32(int32_t val) const override {
     return StrCat("value-is(", FieldValuePrinter::PrintInt32(val), ")");
   }
 };
@@ -531,14 +532,14 @@
 
 class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
-  virtual std::string PrintInt32(int32 v) const {
+  std::string PrintInt32(int32_t v) const override {
     return StrCat(FieldValuePrinter::PrintInt32(v), "  # x",
                         strings::Hex(v));
   }
 
-  virtual std::string PrintMessageStart(const Message& message, int field_index,
-                                        int field_count,
-                                        bool single_line_mode) const {
+  std::string PrintMessageStart(const Message& message, int field_index,
+                                int field_count,
+                                bool single_line_mode) const override {
     if (single_line_mode) {
       return " { ";
     }
@@ -629,9 +630,9 @@
 
 class CustomMultilineCommentPrinter : public TextFormat::FieldValuePrinter {
  public:
-  virtual std::string PrintMessageStart(const Message& message, int field_index,
-                                        int field_count,
-                                        bool single_line_comment) const {
+  std::string PrintMessageStart(const Message& message, int field_index,
+                                int field_count,
+                                bool single_line_comment) const override {
     return StrCat(" {  # 1\n", "  # 2\n");
   }
 };
@@ -1433,17 +1434,17 @@
   class MockErrorCollector : public io::ErrorCollector {
    public:
     MockErrorCollector() {}
-    ~MockErrorCollector() {}
+    ~MockErrorCollector() override {}
 
     std::string text_;
 
     // implements ErrorCollector -------------------------------------
-    void AddError(int line, int column, const std::string& message) {
+    void AddError(int line, int column, const std::string& message) override {
       strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line + 1, column + 1,
                                 message);
     }
 
-    void AddWarning(int line, int column, const std::string& message) {
+    void AddWarning(int line, int column, const std::string& message) override {
       AddError(line, column, "WARNING:" + message);
     }
   };
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 71361e3..c6bfd7b 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -16,24 +16,28 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Timestamp::Timestamp(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : seconds_(int64_t{0})
   , nanos_(0){}
 struct TimestampDefaultTypeInternal {
   constexpr TimestampDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~TimestampDefaultTypeInternal() {}
   union {
     Timestamp _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT TimestampDefaultTypeInternal _Timestamp_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TimestampDefaultTypeInternal _Timestamp_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -45,12 +49,12 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, seconds_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Timestamp, nanos_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Timestamp)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Timestamp_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Timestamp_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -61,19 +65,21 @@
   "tobuf/types/known/timestamppb\370\001\001\242\002\003GPB\252\002"
   "\036Google.Protobuf.WellKnownTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
-  false, false, 239, descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto, "google/protobuf/timestamp.proto", 
-  &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once, nullptr, 0, 1,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+    false, false, 239, descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
+    "google/protobuf/timestamp.proto",
+    &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once, nullptr, 0, 1,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftimestamp_2eproto(&descriptor_table_google_2fprotobuf_2ftimestamp_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftimestamp_2eproto(&descriptor_table_google_2fprotobuf_2ftimestamp_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -86,9 +92,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Timestamp)
 }
 Timestamp::Timestamp(const Timestamp& from)
@@ -109,21 +112,17 @@
 
 Timestamp::~Timestamp() {
   // @@protoc_insertion_point(destructor:google.protobuf.Timestamp)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Timestamp::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void Timestamp::ArenaDtor(void* object) {
-  Timestamp* _this = reinterpret_cast< Timestamp* >(object);
-  (void)_this;
-}
-void Timestamp::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Timestamp::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -140,11 +139,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Timestamp::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Timestamp::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // int64 seconds = 1;
       case 1:
@@ -194,17 +193,17 @@
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_seconds(), target);
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_nanos(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Timestamp)
@@ -221,12 +220,12 @@
 
   // int64 seconds = 1;
   if (this->_internal_seconds() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_seconds());
   }
 
   // int32 nanos = 2;
   if (this->_internal_nanos() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_nanos());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -283,7 +282,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Timestamp::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftimestamp_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[0]);
 }
@@ -291,7 +290,8 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Timestamp* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Timestamp >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Timestamp*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Timestamp >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Timestamp >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index cf66335..41545fc 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftimestamp_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto;
@@ -172,9 +163,6 @@
   protected:
   explicit Timestamp(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 88fa46c..8c61d1b 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -16,9 +16,13 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr Type::Type(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : fields_()
   , oneofs_()
   , options_()
@@ -28,15 +32,15 @@
 {}
 struct TypeDefaultTypeInternal {
   constexpr TypeDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~TypeDefaultTypeInternal() {}
   union {
     Type _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT TypeDefaultTypeInternal _Type_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 TypeDefaultTypeInternal _Type_default_instance_;
 constexpr Field::Field(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : options_()
   , name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , type_url_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -51,15 +55,15 @@
   , packed_(false){}
 struct FieldDefaultTypeInternal {
   constexpr FieldDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FieldDefaultTypeInternal() {}
   union {
     Field _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FieldDefaultTypeInternal _Field_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FieldDefaultTypeInternal _Field_default_instance_;
 constexpr Enum::Enum(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : enumvalue_()
   , options_()
   , name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
@@ -68,44 +72,44 @@
 {}
 struct EnumDefaultTypeInternal {
   constexpr EnumDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumDefaultTypeInternal() {}
   union {
     Enum _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumDefaultTypeInternal _Enum_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumDefaultTypeInternal _Enum_default_instance_;
 constexpr EnumValue::EnumValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : options_()
   , name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , number_(0){}
 struct EnumValueDefaultTypeInternal {
   constexpr EnumValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~EnumValueDefaultTypeInternal() {}
   union {
     EnumValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT EnumValueDefaultTypeInternal _EnumValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 EnumValueDefaultTypeInternal _EnumValue_default_instance_;
 constexpr Option::Option(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : name_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string)
   , value_(nullptr){}
 struct OptionDefaultTypeInternal {
   constexpr OptionDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~OptionDefaultTypeInternal() {}
   union {
     Option _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT OptionDefaultTypeInternal _Option_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 OptionDefaultTypeInternal _Option_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
-static const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
+static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2ftype_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -165,7 +169,7 @@
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, name_),
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Option, value_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Type)},
   { 12, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Field)},
   { 28, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Enum)},
@@ -173,12 +177,12 @@
   { 48, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Option)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Type_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Field_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Enum_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_EnumValue_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Option_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_Type_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Field_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Enum_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_EnumValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Option_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -223,23 +227,25 @@
   "buf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google"
   ".Protobuf.WellKnownTypesb\006proto3"
   ;
-static const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable*const descriptor_table_google_2fprotobuf_2ftype_2eproto_deps[2] = {
+static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2ftype_2eproto_deps[2] = {
   &::descriptor_table_google_2fprotobuf_2fany_2eproto,
   &::descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto,
 };
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2ftype_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
-  false, false, 1592, descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto, "google/protobuf/type.proto", 
-  &descriptor_table_google_2fprotobuf_2ftype_2eproto_once, descriptor_table_google_2fprotobuf_2ftype_2eproto_deps, 2, 5,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftype_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2ftype_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2ftype_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+    false, false, 1592, descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
+    "google/protobuf/type.proto",
+    &descriptor_table_google_2fprotobuf_2ftype_2eproto_once, descriptor_table_google_2fprotobuf_2ftype_2eproto_deps, 2, 5,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2ftype_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2ftype_2eproto, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2ftype_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2ftype_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2ftype_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftype_2eproto(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2ftype_2eproto(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Field_Kind_descriptor() {
   ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2ftype_2eproto);
@@ -360,9 +366,6 @@
   oneofs_(arena),
   options_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Type)
 }
 Type::Type(const Type& from)
@@ -371,7 +374,7 @@
       oneofs_(from.oneofs_),
       options_(from.options_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -389,7 +392,7 @@
 }
 
 inline void Type::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -401,9 +404,11 @@
 
 Type::~Type() {
   // @@protoc_insertion_point(destructor:google.protobuf.Type)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Type::SharedDtor() {
@@ -412,12 +417,6 @@
   if (this != internal_default_instance()) delete source_context_;
 }
 
-void Type::ArenaDtor(void* object) {
-  Type* _this = reinterpret_cast< Type* >(object);
-  (void)_this;
-}
-void Type::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Type::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -440,19 +439,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Type::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Type::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Type.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.name"));
         } else
           goto handle_unusual;
         continue;
@@ -476,9 +475,9 @@
           do {
             ptr += 1;
             auto str = _internal_add_oneofs();
-            ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-            CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Type.oneofs"));
+            ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
             CHK_(ptr);
+            CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.oneofs"));
             if (!ctx->DataAvailable(ptr)) break;
           } while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
         } else
@@ -554,11 +553,11 @@
   }
 
   // repeated .google.protobuf.Field fields = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_fields_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_fields_size()); i < n; i++) {
+    const auto& repfield = this->_internal_fields(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_fields(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated string oneofs = 3;
@@ -572,30 +571,29 @@
   }
 
   // repeated .google.protobuf.Option options = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(4, this->_internal_options(i), target, stream);
+        InternalWriteMessage(4, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.SourceContext source_context = 5;
   if (this->_internal_has_source_context()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        5, _Internal::source_context(this), target, stream);
+      InternalWriteMessage(5, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 6;
   if (this->_internal_syntax() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       6, this->_internal_syntax(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type)
@@ -649,7 +647,7 @@
   // .google.protobuf.Syntax syntax = 6;
   if (this->_internal_syntax() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -722,7 +720,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Type::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftype_2eproto[0]);
 }
@@ -738,16 +736,13 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   options_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Field)
 }
 Field::Field(const Field& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       options_(from.options_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -755,7 +750,7 @@
     name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(), 
       GetArenaForAllocation());
   }
-  type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  type_url_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -763,7 +758,7 @@
     type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_type_url(), 
       GetArenaForAllocation());
   }
-  json_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  json_name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -771,7 +766,7 @@
     json_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_json_name(), 
       GetArenaForAllocation());
   }
-  default_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  default_value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -786,19 +781,19 @@
 }
 
 inline void Field::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+type_url_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-json_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+json_name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
-default_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+default_value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -810,9 +805,11 @@
 
 Field::~Field() {
   // @@protoc_insertion_point(destructor:google.protobuf.Field)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Field::SharedDtor() {
@@ -823,12 +820,6 @@
   default_value_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void Field::ArenaDtor(void* object) {
-  Field* _this = reinterpret_cast< Field* >(object);
-  (void)_this;
-}
-void Field::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Field::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -850,11 +841,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Field::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Field::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // .google.protobuf.Field.Kind kind = 1;
       case 1:
@@ -886,9 +877,9 @@
       case 4:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.name"));
         } else
           goto handle_unusual;
         continue;
@@ -896,9 +887,9 @@
       case 6:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 50)) {
           auto str = _internal_mutable_type_url();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.type_url"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.type_url"));
         } else
           goto handle_unusual;
         continue;
@@ -935,9 +926,9 @@
       case 10:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 82)) {
           auto str = _internal_mutable_json_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.json_name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.json_name"));
         } else
           goto handle_unusual;
         continue;
@@ -945,9 +936,9 @@
       case 11:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 90)) {
           auto str = _internal_mutable_default_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Field.default_value"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Field.default_value"));
         } else
           goto handle_unusual;
         continue;
@@ -983,21 +974,21 @@
   // .google.protobuf.Field.Kind kind = 1;
   if (this->_internal_kind() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       1, this->_internal_kind(), target);
   }
 
   // .google.protobuf.Field.Cardinality cardinality = 2;
   if (this->_internal_cardinality() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       2, this->_internal_cardinality(), target);
   }
 
   // int32 number = 3;
   if (this->_internal_number() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(3, this->_internal_number(), target);
   }
 
   // string name = 4;
@@ -1023,21 +1014,21 @@
   // int32 oneof_index = 7;
   if (this->_internal_oneof_index() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(7, this->_internal_oneof_index(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(7, this->_internal_oneof_index(), target);
   }
 
   // bool packed = 8;
   if (this->_internal_packed() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(8, this->_internal_packed(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(8, this->_internal_packed(), target);
   }
 
   // repeated .google.protobuf.Option options = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(9, this->_internal_options(i), target, stream);
+        InternalWriteMessage(9, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // string json_name = 10;
@@ -1061,7 +1052,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
@@ -1114,23 +1105,23 @@
   // .google.protobuf.Field.Kind kind = 1;
   if (this->_internal_kind() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_kind());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_kind());
   }
 
   // .google.protobuf.Field.Cardinality cardinality = 2;
   if (this->_internal_cardinality() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_cardinality());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_cardinality());
   }
 
   // int32 number = 3;
   if (this->_internal_number() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
   }
 
   // int32 oneof_index = 7;
   if (this->_internal_oneof_index() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_oneof_index());
   }
 
   // bool packed = 8;
@@ -1237,7 +1228,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Field::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftype_2eproto[1]);
 }
@@ -1265,9 +1256,6 @@
   enumvalue_(arena),
   options_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Enum)
 }
 Enum::Enum(const Enum& from)
@@ -1275,7 +1263,7 @@
       enumvalue_(from.enumvalue_),
       options_(from.options_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1293,7 +1281,7 @@
 }
 
 inline void Enum::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1305,9 +1293,11 @@
 
 Enum::~Enum() {
   // @@protoc_insertion_point(destructor:google.protobuf.Enum)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Enum::SharedDtor() {
@@ -1316,12 +1306,6 @@
   if (this != internal_default_instance()) delete source_context_;
 }
 
-void Enum::ArenaDtor(void* object) {
-  Enum* _this = reinterpret_cast< Enum* >(object);
-  (void)_this;
-}
-void Enum::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Enum::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1343,19 +1327,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Enum::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Enum::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Enum.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Enum.name"));
         } else
           goto handle_unusual;
         continue;
@@ -1442,38 +1426,37 @@
   }
 
   // repeated .google.protobuf.EnumValue enumvalue = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_enumvalue_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_enumvalue_size()); i < n; i++) {
+    const auto& repfield = this->_internal_enumvalue(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(2, this->_internal_enumvalue(i), target, stream);
+        InternalWriteMessage(2, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(3, this->_internal_options(i), target, stream);
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.SourceContext source_context = 4;
   if (this->_internal_has_source_context()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        4, _Internal::source_context(this), target, stream);
+      InternalWriteMessage(4, _Internal::source_context(this),
+        _Internal::source_context(this).GetCachedSize(), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 5;
   if (this->_internal_syntax() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
+    target = ::_pbi::WireFormatLite::WriteEnumToArray(
       5, this->_internal_syntax(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum)
@@ -1519,7 +1502,7 @@
   // .google.protobuf.Syntax syntax = 5;
   if (this->_internal_syntax() != 0) {
     total_size += 1 +
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->_internal_syntax());
+      ::_pbi::WireFormatLite::EnumSize(this->_internal_syntax());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -1590,7 +1573,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Enum::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftype_2eproto[2]);
 }
@@ -1606,16 +1589,13 @@
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned),
   options_(arena) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.EnumValue)
 }
 EnumValue::EnumValue(const EnumValue& from)
   : ::PROTOBUF_NAMESPACE_ID::Message(),
       options_(from.options_) {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1628,7 +1608,7 @@
 }
 
 inline void EnumValue::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1637,9 +1617,11 @@
 
 EnumValue::~EnumValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.EnumValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void EnumValue::SharedDtor() {
@@ -1647,12 +1629,6 @@
   name_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void EnumValue::ArenaDtor(void* object) {
-  EnumValue* _this = reinterpret_cast< EnumValue* >(object);
-  (void)_this;
-}
-void EnumValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void EnumValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1669,19 +1645,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* EnumValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* EnumValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.EnumValue.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.EnumValue.name"));
         } else
           goto handle_unusual;
         continue;
@@ -1748,19 +1724,19 @@
   // int32 number = 2;
   if (this->_internal_number() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(2, this->_internal_number(), target);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->_internal_options_size()); i < n; i++) {
-    target = stream->EnsureSpace(target);
+  for (unsigned i = 0,
+      n = static_cast<unsigned>(this->_internal_options_size()); i < n; i++) {
+    const auto& repfield = this->_internal_options(i);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(3, this->_internal_options(i), target, stream);
+        InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
@@ -1791,7 +1767,7 @@
 
   // int32 number = 2;
   if (this->_internal_number() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_number());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_number());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -1852,7 +1828,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata EnumValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftype_2eproto[3]);
 }
@@ -1878,15 +1854,12 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Option)
 }
 Option::Option(const Option& from)
   : ::PROTOBUF_NAMESPACE_ID::Message() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  name_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1903,7 +1876,7 @@
 }
 
 inline void Option::SharedCtor() {
-name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+name_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1912,9 +1885,11 @@
 
 Option::~Option() {
   // @@protoc_insertion_point(destructor:google.protobuf.Option)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Option::SharedDtor() {
@@ -1923,12 +1898,6 @@
   if (this != internal_default_instance()) delete value_;
 }
 
-void Option::ArenaDtor(void* object) {
-  Option* _this = reinterpret_cast< Option* >(object);
-  (void)_this;
-}
-void Option::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Option::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1947,19 +1916,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Option::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Option::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string name = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_name();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.Option.name"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Option.name"));
         } else
           goto handle_unusual;
         continue;
@@ -2012,14 +1981,13 @@
 
   // .google.protobuf.Any value = 2;
   if (this->_internal_has_value()) {
-    target = stream->EnsureSpace(target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessage(
-        2, _Internal::value(this), target, stream);
+      InternalWriteMessage(2, _Internal::value(this),
+        _Internal::value(this).GetCachedSize(), target, stream);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
@@ -2104,7 +2072,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Option::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2ftype_2eproto_getter, &descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
       file_level_metadata_google_2fprotobuf_2ftype_2eproto[4]);
 }
@@ -2112,19 +2080,24 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Type* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Type >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Type*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Type >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Type >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Field* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Field >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Field*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Field >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Field >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Enum* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Enum >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Enum*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Enum >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Enum >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::EnumValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::EnumValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::EnumValue >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Option* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Option >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Option*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Option >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Option >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index cf5943c..9913ed1 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -45,14 +44,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ftype_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[5]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto;
@@ -285,9 +276,6 @@
   protected:
   explicit Type(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -533,9 +521,6 @@
   protected:
   explicit Field(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -905,9 +890,6 @@
   protected:
   explicit Enum(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1127,9 +1109,6 @@
   protected:
   explicit EnumValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1309,9 +1288,6 @@
   protected:
   explicit Option(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1426,7 +1402,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1802,7 +1778,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1853,7 +1829,7 @@
   type_url_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), type_url,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (type_url_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (type_url_.IsDefault()) {
     type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1984,7 +1960,7 @@
   json_name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), json_name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (json_name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (json_name_.IsDefault()) {
     json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2035,7 +2011,7 @@
   default_value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), default_value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (default_value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (default_value_.IsDefault()) {
     default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2090,7 +2066,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2331,7 +2307,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -2446,7 +2422,7 @@
   name_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), name,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (name_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (name_.IsDefault()) {
     name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 7dda924..1f1f128 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -187,6 +187,8 @@
   optional NestedTestAllTypes child = 1;
   optional TestAllTypes payload = 2;
   repeated NestedTestAllTypes repeated_child = 3;
+  optional NestedTestAllTypes lazy_child = 4 [lazy=true];
+  optional TestAllTypes eager_child = 5 [lazy=false];
 }
 
 message TestDeprecatedFields {
@@ -370,6 +372,33 @@
   optional TestAllExtensions optional_extension = 3;
 }
 
+// Emulates wireformat data of TestChildExtension with dynamic extension
+// (DynamicExtension).
+message TestChildExtensionData {
+  message NestedTestAllExtensionsData {
+    message NestedDynamicExtensions {
+      optional int32 a = 1;
+      optional int32 b = 2;
+    }
+    optional NestedDynamicExtensions dynamic = 409707008;
+  }
+  optional string a = 1;
+  optional string b = 2;
+  optional NestedTestAllExtensionsData optional_extension = 3;
+}
+
+message TestNestedChildExtension {
+  optional int32 a = 1;
+  optional TestChildExtension child = 2;
+}
+
+// Emulates wireformat data of TestNestedChildExtension with dynamic extension
+// (DynamicExtension).
+message TestNestedChildExtensionData {
+  optional int32 a = 1;
+  optional TestChildExtensionData child = 2;
+}
+
 // We have separate messages for testing required fields because it's
 // annoying to have to fill in required fields in TestProto in order to
 // do anything with it.  Note that we don't need to test every type of
@@ -418,6 +447,9 @@
   optional int32 dummy32 = 32;
 
   required int32 c = 33;
+
+  // Add an optional child message to make this non-trivial for go/pdlazy.
+  optional ForeignMessage optional_foreign = 34;
 }
 
 message TestRequiredForeign {
@@ -432,6 +464,12 @@
   required TestRequired required_message = 3;
 }
 
+message TestNestedRequiredForeign {
+  optional TestNestedRequiredForeign child = 1;
+  optional TestRequiredForeign payload = 2;
+  optional int32 dummy = 3;
+}
+
 // Test that we can use NestedMessage from outside TestAllTypes.
 message TestForeignNested {
   optional TestAllTypes.NestedMessage foreign_nested = 1;
@@ -519,7 +557,10 @@
 message TestLazyMessage {
   optional TestAllTypes sub_message = 1 [lazy=true];
 }
-
+message TestEagerMaybeLazy {
+  optional TestAllTypes message_foo = 1;
+  optional TestAllTypes message_bar = 2;
+}
 // Needed for a Python test.
 message TestNestedMessageHasBits {
   message NestedMessage {
@@ -685,6 +726,41 @@
   repeated bytes data = 1;
 }
 
+message ManyOptionalString {
+  optional string str1 = 1;
+  optional string str2 = 2;
+  optional string str3 = 3;
+  optional string str4 = 4;
+  optional string str5 = 5;
+  optional string str6 = 6;
+  optional string str7 = 7;
+  optional string str8 = 8;
+  optional string str9 = 9;
+  optional string str10 = 10;
+  optional string str11 = 11;
+  optional string str12 = 12;
+  optional string str13 = 13;
+  optional string str14 = 14;
+  optional string str15 = 15;
+  optional string str16 = 16;
+  optional string str17 = 17;
+  optional string str18 = 18;
+  optional string str19 = 19;
+  optional string str20 = 20;
+  optional string str21 = 21;
+  optional string str22 = 22;
+  optional string str23 = 23;
+  optional string str24 = 24;
+  optional string str25 = 25;
+  optional string str26 = 26;
+  optional string str27 = 27;
+  optional string str28 = 28;
+  optional string str29 = 29;
+  optional string str30 = 30;
+  optional string str31 = 31;
+  optional string str32 = 32;
+}
+
 // Test int32, uint32, int64, uint64, and bool are all compatible
 message Int32Message {
   optional int32 data = 1;
@@ -943,6 +1019,12 @@
   }
 }
 
+// Test that the correct exception is thrown by parseFrom in a corner case
+// involving merging, extensions, and required fields.
+message TestMergeException {
+  optional TestAllExtensions all_extensions = 1;
+}
+
 message TestCommentInjectionMessage {
   // */ <- This should not close the generated doc comment
   optional string a = 1 [default="*/ <- Neither should this."];
@@ -1023,6 +1105,37 @@
   optional int32 test_extension_inside_table_extension = 5;
 }
 
+// NOTE(b/202996544): Intentionally nested to mirror go/glep.
+message TestNestedGroupExtensionOuter {
+  optional group Layer1OptionalGroup = 1 {
+    repeated group Layer2RepeatedGroup = 2 {
+      extensions 3
+        // NOTE: extension metadata is not supported due to targets such as
+        // `//third_party/protobuf_legacy_opensource/src:shell_scripts_test`,
+        // eee https://screenshot.googleplex.com/Axz2QD8nxjdpyFF
+        //[metadata = {
+        // NOTE: can't write type there due to some clever build gen code at
+        // http://google3/net/proto2/internal/BUILD;l=1247;rcl=411090862
+        // type: "protobuf_unittest.TestNestedGroupExtensionInnerExtension",
+        // name: "inner",
+        // }]
+        ;
+      optional string another_field = 6;
+    }
+    repeated group Layer2AnotherOptionalRepeatedGroup = 4 {
+      optional string but_why_tho = 5;
+    }
+  }
+}
+
+message TestNestedGroupExtensionInnerExtension {
+  optional string inner_name= 1;
+}
+
+extend TestNestedGroupExtensionOuter.Layer1OptionalGroup.Layer2RepeatedGroup {
+  optional TestNestedGroupExtensionInnerExtension inner = 3;
+}
+
 enum VeryLargeEnum {
   ENUM_LABEL_DEFAULT = 0;
   ENUM_LABEL_1 = 1;
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
index 92282a6..e2730ac 100644
--- a/src/google/protobuf/unittest_lite.proto
+++ b/src/google/protobuf/unittest_lite.proto
@@ -391,6 +391,12 @@
   }
 }
 
+// Test that the correct exception is thrown by parseFrom in a corner case
+// involving merging, extensions, and required fields.
+message TestMergeExceptionLite {
+  optional TestAllExtensionsLite all_extensions = 1;
+}
+
 // TestEmptyMessageLite is used to test unknown fields support in lite mode.
 message TestEmptyMessageLite {}
 
@@ -463,6 +469,12 @@
   }
 }
 
+message TestMessageSetLite {
+  option message_set_wire_format = true;
+
+  extensions 100 to max;
+}
+
 // The following four messages are set up to test for wire compatibility between
 // packed and non-packed repeated fields. We use the field number 2048, because
 // that is large enough to require a 3-byte varint for the tag.
diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto
index 4e7a8c5..3294994 100644
--- a/src/google/protobuf/unittest_mset.proto
+++ b/src/google/protobuf/unittest_mset.proto
@@ -48,6 +48,11 @@
   optional proto2_wireformat_unittest.TestMessageSet message_set = 1;
 }
 
+message NestedTestMessageSetContainer {
+  optional TestMessageSetContainer container = 1;
+  optional NestedTestMessageSetContainer child = 2;
+}
+
 message TestMessageSetExtension1 {
   extend proto2_wireformat_unittest.TestMessageSet {
     optional TestMessageSetExtension1 message_set_extension = 1545008;
@@ -64,6 +69,18 @@
   optional string str = 25;
 }
 
+message NestedTestInt {
+  optional fixed32 a = 1;
+  optional NestedTestInt child = 2;
+}
+
+message TestMessageSetExtension3 {
+  extend proto2_wireformat_unittest.TestMessageSet {
+    optional TestMessageSetExtension3 message_set_extension = 195273129;
+  }
+  optional NestedTestInt msg = 35;
+}
+
 // 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/src/google/protobuf/unittest_no_generic_services.proto b/src/google/protobuf/unittest_no_generic_services.proto
index c2f042b..57a0d16 100644
--- a/src/google/protobuf/unittest_no_generic_services.proto
+++ b/src/google/protobuf/unittest_no_generic_services.proto
@@ -31,6 +31,7 @@
 // Author: kenton@google.com (Kenton Varda)
 
 syntax = "proto2";
+
 package protobuf_unittest.no_generic_services_test;
 
 
@@ -41,14 +42,12 @@
   extensions 1000 to max;
 }
 
-enum TestEnum {
-  FOO = 1;
-}
+enum TestEnum { FOO = 1; }
 
 extend TestMessage {
   optional int32 test_extension = 1000;
 }
 
 service TestService {
-  rpc Foo(TestMessage) returns(TestMessage);
+  rpc Foo(TestMessage) returns (TestMessage);
 }
diff --git a/src/google/protobuf/unittest_proto3.proto b/src/google/protobuf/unittest_proto3.proto
index 89c8799..8b78075 100644
--- a/src/google/protobuf/unittest_proto3.proto
+++ b/src/google/protobuf/unittest_proto3.proto
@@ -76,7 +76,7 @@
   //   optional int32 a = 17;
   // }
 
-  NestedMessage optional_nested_message = 18;
+  optional NestedMessage optional_nested_message = 18;
   ForeignMessage optional_foreign_message = 19;
   protobuf_unittest_import.ImportMessage optional_import_message = 20;
 
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 423f3e7..e592093 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -36,17 +36,19 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/parse_context.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>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_tctable_decl.h>
 #include <google/protobuf/generated_message_tctable_impl.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/stubs/stl_util.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -238,6 +240,20 @@
   return ParseFromZeroCopyStream(&input);
 }
 
+bool UnknownFieldSet::SerializeToString(std::string* output) const {
+  const size_t size =
+      google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(*this);
+  STLStringResizeUninitializedAmortized(output, size);
+  google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+      *this, reinterpret_cast<uint8_t*>(const_cast<char*>(output->data())));
+  return true;
+}
+
+bool UnknownFieldSet::SerializeToCodedStream(
+    io::CodedOutputStream* output) const {
+  google::protobuf::internal::WireFormat::SerializeUnknownFields(*this, output);
+  return !output->HadError();
+}
 void UnknownField::Delete() {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index c5ca06b..9aa2cbb 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -38,6 +38,7 @@
 #ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
 #define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
 
+
 #include <assert.h>
 
 #include <string>
@@ -45,12 +46,13 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -172,6 +174,9 @@
   template <typename MessageType>
   bool MergeFromMessage(const MessageType& message);
 
+  // Serialization.
+  bool SerializeToString(std::string* output) const;
+  bool SerializeToCodedStream(io::CodedOutputStream* output) const;
   static const UnknownFieldSet& default_instance();
 
  private:
@@ -259,15 +264,6 @@
   inline std::string* mutable_length_delimited();
   inline UnknownFieldSet* mutable_group();
 
-  // Serialization API.
-  // These methods can take advantage of the underlying implementation and may
-  // archieve a better performance than using getters to retrieve the data and
-  // do the serialization yourself.
-  void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const {
-    output->SetCur(InternalSerializeLengthDelimitedNoTag(output->Cur(),
-                                                         output->EpsCopy()));
-  }
-
   inline size_t GetLengthDelimitedSize() const;
   uint8_t* InternalSerializeLengthDelimitedNoTag(
       uint8_t* target, io::EpsCopyOutputStream* stream) const;
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index 3a6968f..de07d7c 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -50,6 +50,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/wire_format.h>
+#include <gmock/gmock.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/time.h>
@@ -62,7 +63,7 @@
 
 class UnknownFieldSetTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     descriptor_ = unittest::TestAllTypes::descriptor();
     TestUtil::SetAllFields(&all_fields_);
     all_fields_.SerializeToString(&all_fields_data_);
@@ -130,12 +131,12 @@
     }
   }
 
-  std::unordered_set<uint32> unknown_tags;
+  std::unordered_set<uint32_t> unknown_tags;
   for (int i = 0; i < unknown_fields_->field_count(); i++) {
     unknown_tags.insert(unknown_fields_->field(i).number());
   }
 
-  for (uint32 t : unknown_tags) {
+  for (uint32_t t : unknown_tags) {
     EXPECT_NE(descriptor_->FindFieldByNumber(t), nullptr);
   }
 
@@ -200,8 +201,9 @@
   slow_buffer.resize(size);
   fast_buffer.resize(size);
 
-  uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&fast_buffer));
-  uint8* result = WireFormat::SerializeUnknownFieldsToArray(
+  uint8_t* target =
+      reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&fast_buffer));
+  uint8_t* result = WireFormat::SerializeUnknownFieldsToArray(
       empty_message_.unknown_fields(), target);
   EXPECT_EQ(size, result - target);
 
@@ -646,6 +648,7 @@
                       MAKE_VECTOR(kExpectedFieldNumbers5));
 }
 #undef MAKE_VECTOR
+
 }  // namespace
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/util/delimited_message_util.h b/src/google/protobuf/util/delimited_message_util.h
index d3f7dbe..78625cf 100644
--- a/src/google/protobuf/util/delimited_message_util.h
+++ b/src/google/protobuf/util/delimited_message_util.h
@@ -41,6 +41,7 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h
index dd1a486..5706da3 100644
--- a/src/google/protobuf/util/field_comparator.h
+++ b/src/google/protobuf/util/field_comparator.h
@@ -33,12 +33,15 @@
 #ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
 #define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
 
+
 #include <cstdint>
 #include <map>
 #include <string>
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc
index 90a5caf..b680277 100644
--- a/src/google/protobuf/util/field_comparator_test.cc
+++ b/src/google/protobuf/util/field_comparator_test.cc
@@ -48,7 +48,7 @@
 
 class DefaultFieldComparatorTest : public ::testing::Test {
  protected:
-  void SetUp() { descriptor_ = TestAllTypes::descriptor(); }
+  void SetUp() override { descriptor_ = TestAllTypes::descriptor(); }
 
   const Descriptor* descriptor_;
   DefaultFieldComparator comparator_;
@@ -58,22 +58,25 @@
 
 TEST_F(DefaultFieldComparatorTest, RecursesIntoGroup) {
   const FieldDescriptor* field = descriptor_->FindFieldByName("optionalgroup");
-  EXPECT_EQ(FieldComparator::RECURSE,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::RECURSE,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, RecursesIntoNestedMessage) {
   const FieldDescriptor* field =
       descriptor_->FindFieldByName("optional_nested_message");
-  EXPECT_EQ(FieldComparator::RECURSE,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::RECURSE,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, RecursesIntoForeignMessage) {
   const FieldDescriptor* field =
       descriptor_->FindFieldByName("optional_foreign_message");
-  EXPECT_EQ(FieldComparator::RECURSE,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::RECURSE,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, Int32Comparison) {
@@ -81,12 +84,13 @@
   message_1_.set_optional_int32(1);
   message_2_.set_optional_int32(1);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_int32(-1);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, Int64Comparison) {
@@ -94,12 +98,13 @@
   message_1_.set_optional_int64(1L);
   message_2_.set_optional_int64(1L);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_int64(-1L);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, UInt32Comparison) {
@@ -108,12 +113,13 @@
   message_1_.set_optional_uint32(1);
   message_2_.set_optional_uint32(1);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_uint32(2);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, UInt64Comparison) {
@@ -122,12 +128,13 @@
   message_1_.set_optional_uint64(1L);
   message_2_.set_optional_uint64(1L);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_uint64(2L);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, BooleanComparison) {
@@ -135,12 +142,13 @@
   message_1_.set_optional_bool(true);
   message_2_.set_optional_bool(true);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_bool(false);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, EnumComparison) {
@@ -149,12 +157,13 @@
   message_1_.set_optional_nested_enum(TestAllTypes::BAR);
   message_2_.set_optional_nested_enum(TestAllTypes::BAR);
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_nested_enum(TestAllTypes::BAZ);
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, StringComparison) {
@@ -163,12 +172,13 @@
   message_1_.set_optional_string("foo");
   message_2_.set_optional_string("foo");
 
-  EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
+                                                       field, -1, -1, nullptr));
 
   message_2_.set_optional_string("bar");
-  EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, -1, -1, NULL));
+  EXPECT_EQ(
+      FieldComparator::DIFFERENT,
+      comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonExact) {
@@ -182,22 +192,22 @@
   message_1_.set_optional_double(0.1);
   message_2_.set_optional_double(0.1);
 
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   message_2_.set_optional_float(0.2f);
   message_2_.set_optional_double(0.2);
 
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonApproximate) {
@@ -222,21 +232,21 @@
 
   // DefaultFieldComparator's default float comparison mode is EXACT.
   ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
 
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonTreatNaNsAsEqual) {
@@ -254,36 +264,36 @@
   // treating NaNs as different.
   ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
   ASSERT_EQ(false, comparator_.treat_nan_as_equal());
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
   comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   comparator_.set_treat_nan_as_equal(true);
   ASSERT_EQ(true, comparator_.treat_nan_as_equal());
   comparator_.set_float_comparison(DefaultFieldComparator::EXACT);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
   comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 }
 
 TEST_F(DefaultFieldComparatorTest,
@@ -299,62 +309,62 @@
   message_2_.set_optional_double(109.9);
 
   comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Should fail since the fraction is too low.
   comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
   comparator_.SetFractionAndMargin(field_double, 0.01, 0.0);
 
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Should fail since the margin is too low.
   comparator_.SetFractionAndMargin(field_float, 0.0, 9.0);
   comparator_.SetFractionAndMargin(field_double, 0.0, 9.0);
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Should succeed since the fraction is high enough.
   comparator_.SetFractionAndMargin(field_float, 0.2, 0.0);
   comparator_.SetFractionAndMargin(field_double, 0.2, 0.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Should succeed since the margin is high enough.
   comparator_.SetFractionAndMargin(field_float, 0.0, 10.0);
   comparator_.SetFractionAndMargin(field_double, 0.0, 10.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Setting values for one of the fields should not affect the other.
   comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // +inf should be equal even though they are not technically within margin or
   // fraction.
@@ -364,12 +374,12 @@
   message_2_.set_optional_double(std::numeric_limits<double>::infinity());
   comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
   comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // -inf should be equal even though they are not technically within margin or
   // fraction.
@@ -379,12 +389,12 @@
   message_2_.set_optional_double(-std::numeric_limits<double>::infinity());
   comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
   comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Finite values and inf should not be equal, even for a positive fraction.
   message_1_.set_optional_float(std::numeric_limits<float>::infinity());
@@ -414,23 +424,23 @@
   message_2_.set_optional_double(109.9);
 
   comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Set default fraction and margin.
   comparator_.SetDefaultFractionAndMargin(0.01, 0.0);
 
   // Float comparisons should fail since the fraction is too low.
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Set field-specific fraction and margin for one field (field_float) but not
   // the other (field_double)
@@ -438,37 +448,37 @@
 
   // The field with the override should succeed, since its field-specific
   // fraction is high enough.
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
   // The field with no override should fail, since the default fraction is too
   // low
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // Set the default fraction and margin high enough so that fields that use
   // the default should succeed
   comparator_.SetDefaultFractionAndMargin(0.2, 0.0);
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 
   // The field with an override should still be OK
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
 
   // Set fraction and margin for the field with an override to be too low
   comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
 
   // Now our default is high enough but field_float's override is too low.
-  EXPECT_EQ(
-      FieldComparator::DIFFERENT,
-      comparator_.Compare(message_1_, message_2_, field_float, -1, -1, NULL));
-  EXPECT_EQ(
-      FieldComparator::SAME,
-      comparator_.Compare(message_1_, message_2_, field_double, -1, -1, NULL));
+  EXPECT_EQ(FieldComparator::DIFFERENT,
+            comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
+                                nullptr));
+  EXPECT_EQ(FieldComparator::SAME,
+            comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
+                                nullptr));
 }
 
 // Simple test checking whether we compare values at correct indices.
@@ -482,11 +492,11 @@
   message_2_.add_repeated_string("baz");
 
   EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, 0, 0, NULL));
+            comparator_.Compare(message_1_, message_2_, field, 0, 0, nullptr));
   EXPECT_EQ(FieldComparator::DIFFERENT,
-            comparator_.Compare(message_1_, message_2_, field, 1, 1, NULL));
+            comparator_.Compare(message_1_, message_2_, field, 1, 1, nullptr));
   EXPECT_EQ(FieldComparator::SAME,
-            comparator_.Compare(message_1_, message_2_, field, 1, 0, NULL));
+            comparator_.Compare(message_1_, message_2_, field, 1, 0, nullptr));
 }
 
 }  // namespace
diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc
index c80ae21..3c6e490 100644
--- a/src/google/protobuf/util/field_mask_util.cc
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -339,7 +339,7 @@
       return;
     }
     Node*& child = node->children[node_name];
-    if (child == NULL) {
+    if (child == nullptr) {
       new_branch = true;
       child = new Node();
     }
@@ -423,7 +423,7 @@
       return;
     }
     const Node* result = FindPtrOrNull(node->children, node_name);
-    if (result == NULL) {
+    if (result == nullptr) {
       // No intersection found.
       return;
     }
@@ -459,7 +459,7 @@
     const std::string& field_name = it->first;
     const Node* child = it->second;
     const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
-    if (field == NULL) {
+    if (field == nullptr) {
       GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
                  << descriptor->full_name();
       continue;
diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h
index dd8be8d..0bc744f 100644
--- a/src/google/protobuf/util/field_mask_util.h
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -96,8 +96,9 @@
   template <typename T>
   static bool IsValidFieldMask(const FieldMask& mask) {
     for (int i = 0; i < mask.paths_size(); ++i) {
-      if (!GetFieldDescriptors(T::descriptor(), mask.paths(i), nullptr))
+      if (!GetFieldDescriptors(T::descriptor(), mask.paths(i), nullptr)) {
         return false;
+      }
     }
     return true;
   }
diff --git a/src/google/protobuf/util/internal/constants.h b/src/google/protobuf/util/internal/constants.h
index 65f1a34..8bded86 100644
--- a/src/google/protobuf/util/internal/constants.h
+++ b/src/google/protobuf/util/internal/constants.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_UTIL_CONVERTER_CONSTANTS_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_CONSTANTS_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
 
 #include <cstdint>
 
@@ -98,4 +98,4 @@
 }  // namespace util
 }  // namespace protobuf
 }  // namespace google
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_CONSTANTS_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_CONSTANTS_H__
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index 52c335d..f0fbf5d 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -37,9 +37,9 @@
 #include <google/protobuf/struct.pb.h>
 #include <google/protobuf/type.pb.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/mathutil.h>
 
 namespace google {
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index efd9aba..6d08349 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.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_UTIL_CONVERTER_DATAPIECE_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_DATAPIECE_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
 
 #include <cstdint>
 #include <string>
@@ -40,6 +40,7 @@
 #include <google/protobuf/stubs/statusor.h>
 #include <google/protobuf/stubs/strutil.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -215,4 +216,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_DATAPIECE_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_DATAPIECE_H__
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
index 8236f0a..a9e1673 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.h
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.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_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
 
 #include <cstdint>
 #include <functional>
@@ -38,12 +38,12 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/util/internal/datapiece.h>
 #include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
 #include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/util/type_resolver.h>
-#include <google/protobuf/stubs/strutil.h>
 
 // Must be included last.
 #include <google/protobuf/port_def.inc>
@@ -81,7 +81,7 @@
                            const google::protobuf::Type& type,
                            ObjectWriter* ow);
 
-  virtual ~DefaultValueObjectWriter();
+  ~DefaultValueObjectWriter() override;
 
   // ObjectWriter methods.
   DefaultValueObjectWriter* StartObject(StringPiece name) override;
@@ -329,4 +329,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_DEFAULT_VALUE_OBJECTWRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_DEFAULT_VALUE_OBJECTWRITER_H__
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 7af3579..21046d9 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -57,7 +57,7 @@
         &mock_));
   }
 
-  virtual ~BaseDefaultValueObjectWriterTest() {}
+  ~BaseDefaultValueObjectWriterTest() override {}
 
   TypeInfoTestHelper helper_;
   MockObjectWriter mock_;
@@ -71,7 +71,7 @@
  protected:
   DefaultValueObjectWriterTest()
       : BaseDefaultValueObjectWriterTest(DefaultValueTest::descriptor()) {}
-  virtual ~DefaultValueObjectWriterTest() {}
+  ~DefaultValueObjectWriterTest() override {}
 };
 
 INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h
index 745b66a..8c9c501 100644
--- a/src/google/protobuf/util/internal/error_listener.h
+++ b/src/google/protobuf/util/internal/error_listener.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_UTIL_CONVERTER_ERROR_LISTENER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
 
 #include <algorithm>
 #include <memory>
@@ -39,8 +39,8 @@
 #include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/util/internal/location_tracker.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/location_tracker.h>
 
 // Must be included last.
 #include <google/protobuf/port_def.inc>
@@ -106,4 +106,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_ERROR_LISTENER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_ERROR_LISTENER_H__
diff --git a/src/google/protobuf/util/internal/expecting_objectwriter.h b/src/google/protobuf/util/internal/expecting_objectwriter.h
index b40ef0c..cb0f2aa 100644
--- a/src/google/protobuf/util/internal/expecting_objectwriter.h
+++ b/src/google/protobuf/util/internal/expecting_objectwriter.h
@@ -102,7 +102,7 @@
  public:
   explicit ExpectingObjectWriter(MockObjectWriter* mock) : mock_(mock) {}
 
-  virtual ObjectWriter* StartObject(StringPiece name) {
+  ObjectWriter* StartObject(StringPiece name) override {
     (name.empty() ? EXPECT_CALL(*mock_, StartObject(IsEmpty()))
                   : EXPECT_CALL(*mock_, StartObject(Eq(std::string(name)))))
         .WillOnce(Return(mock_))
@@ -110,14 +110,14 @@
     return this;
   }
 
-  virtual ObjectWriter* EndObject() {
+  ObjectWriter* EndObject() override {
     EXPECT_CALL(*mock_, EndObject())
         .WillOnce(Return(mock_))
         .RetiresOnSaturation();
     return this;
   }
 
-  virtual ObjectWriter* StartList(StringPiece name) {
+  ObjectWriter* StartList(StringPiece name) override {
     (name.empty() ? EXPECT_CALL(*mock_, StartList(IsEmpty()))
                   : EXPECT_CALL(*mock_, StartList(Eq(std::string(name)))))
         .WillOnce(Return(mock_))
@@ -125,14 +125,14 @@
     return this;
   }
 
-  virtual ObjectWriter* EndList() {
+  ObjectWriter* EndList() override {
     EXPECT_CALL(*mock_, EndList())
         .WillOnce(Return(mock_))
         .RetiresOnSaturation();
     return this;
   }
 
-  virtual ObjectWriter* RenderBool(StringPiece name, bool value) {
+  ObjectWriter* RenderBool(StringPiece name, bool value) override {
     (name.empty()
          ? EXPECT_CALL(*mock_, RenderBool(IsEmpty(), TypedEq<bool>(value)))
          : EXPECT_CALL(*mock_,
@@ -142,7 +142,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderInt32(StringPiece name, int32_t value) {
+  ObjectWriter* RenderInt32(StringPiece name, int32_t value) override {
     (name.empty()
          ? EXPECT_CALL(*mock_, RenderInt32(IsEmpty(), TypedEq<int32_t>(value)))
          : EXPECT_CALL(*mock_, RenderInt32(Eq(std::string(name)),
@@ -152,7 +152,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderUint32(StringPiece name, uint32_t value) {
+  ObjectWriter* RenderUint32(StringPiece name, uint32_t value) override {
     (name.empty() ? EXPECT_CALL(*mock_, RenderUint32(IsEmpty(),
                                                      TypedEq<uint32_t>(value)))
                   : EXPECT_CALL(*mock_, RenderUint32(Eq(std::string(name)),
@@ -162,7 +162,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderInt64(StringPiece name, int64_t value) {
+  ObjectWriter* RenderInt64(StringPiece name, int64_t value) override {
     (name.empty()
          ? EXPECT_CALL(*mock_, RenderInt64(IsEmpty(), TypedEq<int64_t>(value)))
          : EXPECT_CALL(*mock_, RenderInt64(Eq(std::string(name)),
@@ -172,7 +172,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderUint64(StringPiece name, uint64_t value) {
+  ObjectWriter* RenderUint64(StringPiece name, uint64_t value) override {
     (name.empty() ? EXPECT_CALL(*mock_, RenderUint64(IsEmpty(),
                                                      TypedEq<uint64_t>(value)))
                   : EXPECT_CALL(*mock_, RenderUint64(Eq(std::string(name)),
@@ -182,7 +182,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderDouble(StringPiece name, double value) {
+  ObjectWriter* RenderDouble(StringPiece name, double value) override {
     (name.empty()
          ? EXPECT_CALL(*mock_,
                        RenderDouble(IsEmpty(), NanSensitiveDoubleEq(value)))
@@ -193,7 +193,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderFloat(StringPiece name, float value) {
+  ObjectWriter* RenderFloat(StringPiece name, float value) override {
     (name.empty()
          ? EXPECT_CALL(*mock_,
                        RenderFloat(IsEmpty(), NanSensitiveFloatEq(value)))
@@ -204,8 +204,8 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderString(StringPiece name,
-                                     StringPiece value) {
+  ObjectWriter* RenderString(StringPiece name,
+                             StringPiece value) override {
     (name.empty() ? EXPECT_CALL(*mock_, RenderString(IsEmpty(),
                                                      TypedEq<StringPiece>(
                                                          std::string(value))))
@@ -228,7 +228,7 @@
     return this;
   }
 
-  virtual ObjectWriter* RenderNull(StringPiece name) {
+  ObjectWriter* RenderNull(StringPiece name) override {
     (name.empty() ? EXPECT_CALL(*mock_, RenderNull(IsEmpty()))
                   : EXPECT_CALL(*mock_, RenderNull(Eq(std::string(name))))
                         .WillOnce(Return(mock_))
diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc
index f211a54..521bf48 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.cc
+++ b/src/google/protobuf/util/internal/field_mask_utility.cc
@@ -30,9 +30,9 @@
 
 #include <google/protobuf/util/internal/field_mask_utility.h>
 
-#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/status_macros.h>
 
 // Must be included last.
diff --git a/src/google/protobuf/util/internal/field_mask_utility.h b/src/google/protobuf/util/internal/field_mask_utility.h
index bc41321..1882333 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.h
+++ b/src/google/protobuf/util/internal/field_mask_utility.h
@@ -30,8 +30,8 @@
 
 // FieldMask related utility methods.
 
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
 
 #include <functional>
 #include <stack>
@@ -71,4 +71,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_FIELD_MASK_UTILITY_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_FIELD_MASK_UTILITY_H__
diff --git a/src/google/protobuf/util/internal/json_escaping.h b/src/google/protobuf/util/internal/json_escaping.h
index 38cb645..7d54f22 100644
--- a/src/google/protobuf/util/internal/json_escaping.h
+++ b/src/google/protobuf/util/internal/json_escaping.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_UTIL_INTERNAL__JSON_ESCAPING_H__
-#define GOOGLE_PROTOBUF_UTIL_INTERNAL__JSON_ESCAPING_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
 
 #include <cstdint>
 
@@ -95,4 +95,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL__JSON_ESCAPING_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_ESCAPING_H__
diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc
index c03eb1d..1a86f00 100644
--- a/src/google/protobuf/util/internal/json_objectwriter.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -38,8 +38,8 @@
 #include <google/protobuf/stubs/logging.h>
 #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/strutil.h>
+#include <google/protobuf/util/internal/json_escaping.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h
index 2e9c684..cb7dff6 100644
--- a/src/google/protobuf/util/internal/json_objectwriter.h
+++ b/src/google/protobuf/util/internal/json_objectwriter.h
@@ -28,16 +28,16 @@
 // (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_JSON_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
 
 #include <cstdint>
 #include <memory>
 #include <string>
 
 #include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/util/internal/structured_objectwriter.h>
 #include <google/protobuf/stubs/bytestream.h>
+#include <google/protobuf/util/internal/structured_objectwriter.h>
 
 // clang-format off
 #include <google/protobuf/port_def.inc>
@@ -111,7 +111,7 @@
       }
     }
   }
-  virtual ~JsonObjectWriter();
+  ~JsonObjectWriter() override;
 
   // ObjectWriter methods.
   JsonObjectWriter* StartObject(StringPiece name) override;
@@ -275,4 +275,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc
index 03395da..8acf2c5 100644
--- a/src/google/protobuf/util/internal/json_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc
@@ -33,8 +33,8 @@
 #include <cstdint>
 
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/util/internal/utility.h>
 #include <gtest/gtest.h>
+#include <google/protobuf/util/internal/utility.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index f52c544..f4a972b 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -41,8 +41,8 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/status.h>
-#include <google/protobuf/util/internal/object_writer.h>
 #include <google/protobuf/util/internal/json_escaping.h>
+#include <google/protobuf/util/internal/object_writer.h>
 
 
 namespace google {
@@ -485,7 +485,7 @@
   }
   GOOGLE_DCHECK_EQ('\\', p_.data()[0]);
   GOOGLE_DCHECK_EQ('u', p_.data()[1]);
-  uint32 code = 0;
+  uint32_t code = 0;
   for (int i = 2; i < kUnicodeEscapedLength; ++i) {
     if (!isxdigit(p_.data()[i])) {
       return ReportFailure("Invalid escape sequence.",
@@ -505,7 +505,7 @@
       }
     } else if (p_.data()[kUnicodeEscapedLength] == '\\' &&
                p_.data()[kUnicodeEscapedLength + 1] == 'u') {
-      uint32 low_code = 0;
+      uint32_t low_code = 0;
       for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength;
            ++i) {
         if (!isxdigit(p_.data()[i])) {
@@ -626,7 +626,7 @@
     return status;
   }
 
-  // Positive non-floating point number, parse as a uint64.
+  // Positive non-floating point number, parse as a uint64_t.
   if (!negative) {
     // Octal/Hex numbers are not valid JSON values.
     if (number.length() >= 2 && number[0] == '0') {
@@ -654,7 +654,7 @@
         "Octal/hex numbers are not valid JSON values.",
         ParseErrorType::OCTAL_OR_HEX_ARE_NOT_VALID_JSON_VALUES);
   }
-  // Negative non-floating point number, parse as an int64.
+  // Negative non-floating point number, parse as an int64_t.
   if (safe_strto64(number, &result->int_val)) {
     result->type = NumberResult::INT;
     p_.remove_prefix(index);
diff --git a/src/google/protobuf/util/internal/json_stream_parser.h b/src/google/protobuf/util/internal/json_stream_parser.h
index 47dfe82..09f17ad 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.h
+++ b/src/google/protobuf/util/internal/json_stream_parser.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_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
 
 #include <cstdint>
 #include <stack>
@@ -40,6 +40,7 @@
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/status.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -346,4 +347,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_STREAM_PARSER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_JSON_STREAM_PARSER_H__
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 4bb1025..093be0c 100644
--- a/src/google/protobuf/util/internal/json_stream_parser_test.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc
@@ -85,7 +85,7 @@
 class JsonStreamParserTest : public ::testing::Test {
  protected:
   JsonStreamParserTest() : mock_(), ow_(&mock_) {}
-  virtual ~JsonStreamParserTest() {}
+  ~JsonStreamParserTest() override {}
 
   util::Status RunTest(StringPiece json, int split,
                        std::function<void(JsonStreamParser*)> setup) {
diff --git a/src/google/protobuf/util/internal/location_tracker.h b/src/google/protobuf/util/internal/location_tracker.h
index c29a75a..68fefcc 100644
--- a/src/google/protobuf/util/internal/location_tracker.h
+++ b/src/google/protobuf/util/internal/location_tracker.h
@@ -28,13 +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.
 
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
 
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -66,4 +67,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_LOCATION_TRACKER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_LOCATION_TRACKER_H__
diff --git a/src/google/protobuf/util/internal/mock_error_listener.h b/src/google/protobuf/util/internal/mock_error_listener.h
index 4f5b0a2..a00fab0 100644
--- a/src/google/protobuf/util/internal/mock_error_listener.h
+++ b/src/google/protobuf/util/internal/mock_error_listener.h
@@ -44,7 +44,7 @@
 class MockErrorListener : public ErrorListener {
  public:
   MockErrorListener() {}
-  virtual ~MockErrorListener() {}
+  ~MockErrorListener() override {}
 
   MOCK_METHOD(void, InvalidName,
               (const LocationTrackerInterface& loc,
diff --git a/src/google/protobuf/util/internal/object_location_tracker.h b/src/google/protobuf/util/internal/object_location_tracker.h
index 571279d..47821e6 100644
--- a/src/google/protobuf/util/internal/object_location_tracker.h
+++ b/src/google/protobuf/util/internal/object_location_tracker.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_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
 
 #include <string>
 
@@ -61,4 +61,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_LOCATION_TRACKER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_LOCATION_TRACKER_H__
diff --git a/src/google/protobuf/util/internal/object_source.h b/src/google/protobuf/util/internal/object_source.h
index de548c1..fc7672e 100644
--- a/src/google/protobuf/util/internal/object_source.h
+++ b/src/google/protobuf/util/internal/object_source.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_UTIL_CONVERTER_OBJECT_SOURCE_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_SOURCE_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/status.h>
@@ -82,4 +82,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_SOURCE_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_SOURCE_H__
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
index 917a280..bc4095b 100644
--- a/src/google/protobuf/util/internal/object_writer.h
+++ b/src/google/protobuf/util/internal/object_writer.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_UTIL_CONVERTER_OBJECT_WRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
 
 #include <cstdint>
 
@@ -148,4 +148,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_OBJECT_WRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_OBJECT_WRITER_H__
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 717cee4..afa5e2e 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -33,19 +33,21 @@
 #include <cstdint>
 #include <functional>
 #include <stack>
+#include <unordered_set>
 
 #include <google/protobuf/stubs/once.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/statusor.h>
 #include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/map_util.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -269,9 +271,9 @@
 }
 
 // Given a google::protobuf::Type, returns the set of all required fields.
-std::set<const google::protobuf::Field*> GetRequiredFields(
+std::unordered_set<const google::protobuf::Field*> GetRequiredFields(
     const google::protobuf::Type& type) {
-  std::set<const google::protobuf::Field*> required;
+  std::unordered_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_REQUIRED) {
@@ -346,7 +348,7 @@
   if (!proto3_) {
     // Calls the registered error listener for any required field(s) not yet
     // seen.
-    for (std::set<const google::protobuf::Field*>::iterator it =
+    for (std::unordered_set<const google::protobuf::Field*>::iterator it =
              required_fields_.begin();
          it != required_fields_.end(); ++it) {
       ow_->MissingField(ow_->use_json_name_in_missing_fields_
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
index 109c198..7b36954 100644
--- a/src/google/protobuf/util/internal/proto_writer.h
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -28,26 +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.
 
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
 
 #include <cstdint>
 #include <deque>
 #include <string>
 #include <vector>
+#include <unordered_set>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/type.pb.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/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.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/internal/type_info.h>
 #include <google/protobuf/util/type_resolver.h>
-#include <google/protobuf/stubs/bytestream.h>
-#include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/status.h>
 
@@ -235,7 +236,7 @@
     // 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_;
+    std::unordered_set<const google::protobuf::Field*> required_fields_;
     const int size_index_;
 
     // Tracks position in repeated fields, needed for LocationTrackerInterface.
@@ -385,4 +386,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTO_WRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTO_WRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 221c42f..99db593 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -44,19 +44,21 @@
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/util/internal/field_mask_utility.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/casts.h>
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/status_macros.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
+
 namespace google {
 namespace protobuf {
 namespace util {
@@ -782,7 +784,7 @@
     }
     case google::protobuf::Field::TYPE_INT64: {
       stream_->ReadVarint64(&buffer64);
-      ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
       break;
     }
     case google::protobuf::Field::TYPE_UINT32: {
@@ -792,7 +794,7 @@
     }
     case google::protobuf::Field::TYPE_UINT64: {
       stream_->ReadVarint64(&buffer64);
-      ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
       break;
     }
     case google::protobuf::Field::TYPE_SINT32: {
@@ -812,7 +814,7 @@
     }
     case google::protobuf::Field::TYPE_SFIXED64: {
       stream_->ReadLittleEndian64(&buffer64);
-      ow->RenderInt64(field_name, bit_cast<int64>(buffer64));
+      ow->RenderInt64(field_name, bit_cast<int64_t>(buffer64));
       break;
     }
     case google::protobuf::Field::TYPE_FIXED32: {
@@ -822,7 +824,7 @@
     }
     case google::protobuf::Field::TYPE_FIXED64: {
       stream_->ReadLittleEndian64(&buffer64);
-      ow->RenderUint64(field_name, bit_cast<uint64>(buffer64));
+      ow->RenderUint64(field_name, bit_cast<uint64_t>(buffer64));
       break;
     }
     case google::protobuf::Field::TYPE_FLOAT: {
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index 60eaf4e..8ed2ca9 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.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_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
 
 #include <cstdint>
 #include <functional>
@@ -40,16 +40,17 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/type.pb.h>
-#include <google/protobuf/util/internal/type_info.h>
-#include <google/protobuf/util/internal/object_source.h>
-#include <google/protobuf/util/internal/object_writer.h>
-#include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/statusor.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/object_source.h>
+#include <google/protobuf/util/internal/object_writer.h>
+#include <google/protobuf/util/internal/type_info.h>
+#include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/status.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -325,4 +326,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTSOURCE_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTSOURCE_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
index 6ea8b29..f75ed4c 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -103,7 +103,7 @@
     helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor());
   }
 
-  virtual ~ProtostreamObjectSourceTest() {}
+  ~ProtostreamObjectSourceTest() override {}
 
   void DoTest(const Message& msg, const Descriptor* descriptor) {
     util::Status status = ExecuteTest(msg, descriptor);
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index ec9a2ce..22f53a4 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -38,17 +38,18 @@
 
 #include <google/protobuf/stubs/once.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/status.h>
 #include <google/protobuf/stubs/statusor.h>
 #include <google/protobuf/stubs/time.h>
+#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/internal/field_mask_utility.h>
+#include <google/protobuf/util/internal/object_location_tracker.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/map_util.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -139,7 +140,7 @@
   }
   int32_t 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
+  // "0." + s_nanos.ToString() seconds. An int32_t 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, &i_nanos)) {
@@ -158,7 +159,7 @@
     // point in "0." + s_nanos.ToString()
     int32_t scale = num_leading_zeros + s_nanos.size();
     // 'conversion' converts i_nanos into nanoseconds.
-    // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
+    // conversion = kNanosPerSecond / static_cast<int32_t>(std::pow(10, scale))
     // For efficiency, we precompute the conversion factor.
     int32_t conversion = 0;
     switch (scale) {
@@ -1031,8 +1032,8 @@
 
   StringPiece value(data.str());
 
-  int64 seconds;
-  int32 nanos;
+  int64_t seconds;
+  int32_t nanos;
   if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
                                                &nanos)) {
     return util::InvalidArgumentError(StrCat("Invalid time format: ", value));
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index 0befd1c..ce2517f 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.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_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
 
 #include <deque>
 #include <string>
@@ -41,16 +41,17 @@
 #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/stubs/bytestream.h>
+#include <google/protobuf/stubs/status.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/internal/type_info.h>
 #include <google/protobuf/util/type_resolver.h>
-#include <google/protobuf/stubs/bytestream.h>
-#include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/hash.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -449,4 +450,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_PROTOSTREAM_OBJECTWRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_PROTOSTREAM_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 2232bec..ace166a 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -134,7 +134,7 @@
     ResetTypeInfo(descriptors);
   }
 
-  virtual ~BaseProtoStreamObjectWriterTest() {}
+  ~BaseProtoStreamObjectWriterTest() override {}
 
   void CheckOutput(const Message& expected, int expected_length) {
     size_t nbytes;
@@ -178,7 +178,7 @@
 
   void ResetProtoWriter() { ResetTypeInfo(Book::descriptor()); }
 
-  virtual ~ProtoStreamObjectWriterTest() {}
+  ~ProtoStreamObjectWriterTest() override {}
 };
 
 INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
diff --git a/src/google/protobuf/util/internal/structured_objectwriter.h b/src/google/protobuf/util/internal/structured_objectwriter.h
index 01cbb9e..f6f7c89 100644
--- a/src/google/protobuf/util/internal/structured_objectwriter.h
+++ b/src/google/protobuf/util/internal/structured_objectwriter.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_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
 
 #include <memory>
 
@@ -37,6 +37,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/util/internal/object_writer.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -57,7 +58,7 @@
 // Derived classes could be thread-unsafe.
 class PROTOBUF_EXPORT StructuredObjectWriter : public ObjectWriter {
  public:
-  virtual ~StructuredObjectWriter() {}
+  ~StructuredObjectWriter() override {}
 
  protected:
   // A base element class for subclasses to extend, makes tracking state easier.
@@ -117,4 +118,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_STRUCTURED_OBJECTWRITER_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_STRUCTURED_OBJECTWRITER_H__
diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc
index aaa37d1..b6cf536 100644
--- a/src/google/protobuf/util/internal/type_info.cc
+++ b/src/google/protobuf/util/internal/type_info.cc
@@ -35,10 +35,10 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/type.pb.h>
-#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/statusor.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/utility.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/status.h>
 
@@ -54,7 +54,7 @@
   explicit TypeInfoForTypeResolver(TypeResolver* type_resolver)
       : type_resolver_(type_resolver) {}
 
-  virtual ~TypeInfoForTypeResolver() {
+  ~TypeInfoForTypeResolver() override {
     DeleteCachedTypes(&cached_types_);
     DeleteCachedTypes(&cached_enums_);
   }
diff --git a/src/google/protobuf/util/internal/type_info.h b/src/google/protobuf/util/internal/type_info.h
index d8d679e..257df5b 100644
--- a/src/google/protobuf/util/internal/type_info.h
+++ b/src/google/protobuf/util/internal/type_info.h
@@ -28,14 +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.
 
-#ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/type.pb.h>
-#include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/statusor.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/status.h>
 
 // Must be included last.
@@ -94,4 +94,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_TYPE_INFO_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_TYPE_INFO_H__
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 17ff6dd..918ee17 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -41,8 +41,8 @@
 #include <google/protobuf/wrappers.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/util/internal/constants.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/internal/constants.h>
 #include <google/protobuf/stubs/map_util.h>
 
 // clang-format off
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index b689e84..79d6779 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.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_UTIL_CONVERTER_UTILITY_H__
-#define GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__
+#ifndef GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
+#define GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
 
 #include <cstdint>
 #include <memory>
@@ -201,4 +201,4 @@
 
 #include <google/protobuf/port_undef.inc>
 
-#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_UTILITY_H__
+#endif  // GOOGLE_PROTOBUF_UTIL_INTERNAL_UTILITY_H__
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 3597f9e..5a84c7d 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -218,7 +218,7 @@
 
 namespace {
 const char* kTypeUrlPrefix = "type.googleapis.com";
-TypeResolver* generated_type_resolver_ = NULL;
+TypeResolver* generated_type_resolver_ = nullptr;
 PROTOBUF_NAMESPACE_ID::internal::once_flag generated_type_resolver_init_;
 
 std::string GetTypeUrl(const Message& message) {
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index 73f2783..d95b8f7 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -39,6 +39,7 @@
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/strutil.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -181,8 +182,8 @@
 class PROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
  public:
   explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
-      : stream_(stream), buffer_(NULL), buffer_size_(0) {}
-  ~ZeroCopyStreamByteSink();
+      : stream_(stream), buffer_(nullptr), buffer_size_(0) {}
+  ~ZeroCopyStreamByteSink() override;
 
   void Append(const char* bytes, size_t len) override;
 
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index 76d3a70..a1f8264 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -41,9 +41,9 @@
 #include <google/protobuf/util/internal/testdata/maps.pb.h>
 #include <google/protobuf/util/json_format.pb.h>
 #include <google/protobuf/util/json_format_proto3.pb.h>
+#include <gtest/gtest.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/util/type_resolver_util.h>
-#include <gtest/gtest.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index bf933ab..56e927e 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -55,8 +55,8 @@
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
-#include <google/protobuf/util/field_comparator.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/util/field_comparator.h>
 
 // Always include as last one, otherwise it can break compilation
 #include <google/protobuf/port_def.inc>
@@ -331,9 +331,14 @@
   message_field_comparison_ = comparison;
 }
 
+MessageDifferencer::MessageFieldComparison
+MessageDifferencer::message_field_comparison() const {
+  return message_field_comparison_;
+}
+
 void MessageDifferencer::set_scope(Scope scope) { scope_ = scope; }
 
-MessageDifferencer::Scope MessageDifferencer::scope() { return scope_; }
+MessageDifferencer::Scope MessageDifferencer::scope() const { return scope_; }
 
 void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
   default_field_comparator_.set_float_comparison(
@@ -347,7 +352,7 @@
 }
 
 MessageDifferencer::RepeatedFieldComparison
-MessageDifferencer::repeated_field_comparison() {
+MessageDifferencer::repeated_field_comparison() const {
   return repeated_field_comparison_;
 }
 
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index fbb5d20..4bdf2cb 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -43,6 +43,7 @@
 #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
 #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
 
+
 #include <functional>
 #include <map>
 #include <memory>
@@ -544,6 +545,9 @@
   // to compare fields in messages.
   void set_message_field_comparison(MessageFieldComparison comparison);
 
+  // Returns the current message field comparison used in this differencer.
+  MessageFieldComparison message_field_comparison() const;
+
   // Tells the differencer whether or not to report matches. This method must
   // be called before Compare. The default for a new differencer is false.
   void set_report_matches(bool report_matches) {
@@ -567,7 +571,7 @@
   void set_scope(Scope scope);
 
   // Returns the current scope used by this differencer.
-  Scope scope();
+  Scope scope() const;
 
   // DEPRECATED. Pass a DefaultFieldComparator instance instead.
   // Sets the type of comparison (as defined in the FloatComparison enumeration
@@ -583,7 +587,7 @@
   void set_repeated_field_comparison(RepeatedFieldComparison comparison);
 
   // Returns the current repeated field comparison used by this differencer.
-  RepeatedFieldComparison repeated_field_comparison();
+  RepeatedFieldComparison repeated_field_comparison() const;
 
   // Compares the two specified messages, returning true if they are the same,
   // false otherwise. If this method returns false, any changes between the
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 2304743..f8e44df 100644
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -70,7 +70,7 @@
   std::vector<std::string> field_path =
       Split(field_name, ".", true);
   const Descriptor* descriptor = message.GetDescriptor();
-  const FieldDescriptor* field = NULL;
+  const FieldDescriptor* field = nullptr;
   for (int i = 0; i < field_path.size(); i++) {
     field = descriptor->FindFieldByName(field_path[i]);
     descriptor = field->message_type();
@@ -1034,9 +1034,9 @@
       desc->FindFieldByName("optional_int64");
   const FieldDescriptor* default_int64_desc =
       desc->FindFieldByName("default_int64");
-  ASSERT_TRUE(optional_int32_desc != NULL);
-  ASSERT_TRUE(optional_int64_desc != NULL);
-  ASSERT_TRUE(default_int64_desc != NULL);
+  ASSERT_TRUE(optional_int32_desc != nullptr);
+  ASSERT_TRUE(optional_int64_desc != nullptr);
+  ASSERT_TRUE(default_int64_desc != nullptr);
   msg1.set_optional_int32(0);
   msg2.set_optional_int64(0);
   msg1.set_default_int64(default_int64_desc->default_value_int64());
@@ -1860,11 +1860,10 @@
 
 class TestIgnorer : public util::MessageDifferencer::IgnoreCriteria {
  public:
-  virtual bool IsIgnored(
-      const Message& message1, const Message& message2,
-      const FieldDescriptor* field,
-      const std::vector<util::MessageDifferencer::SpecificField>&
-          parent_fields) {
+  bool IsIgnored(const Message& message1, const Message& message2,
+                 const FieldDescriptor* field,
+                 const std::vector<util::MessageDifferencer::SpecificField>&
+                     parent_fields) override {
     std::string name = "";
     for (int i = 0; i < parent_fields.size(); ++i) {
       name += parent_fields[i].field->name() + ".";
@@ -1907,8 +1906,8 @@
     : public util::MessageDifferencer::MapKeyComparator {
  public:
   typedef util::MessageDifferencer::SpecificField SpecificField;
-  virtual bool IsMatch(const Message& message1, const Message& message2,
-                       const std::vector<SpecificField>& parent_fields) const {
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
     const Reflection* reflection1 = message1.GetReflection();
     const Reflection* reflection2 = message2.GetReflection();
     // FieldDescriptor for item.ra
@@ -1968,8 +1967,8 @@
     : public util::MessageDifferencer::MapKeyComparator {
  public:
   typedef util::MessageDifferencer::SpecificField SpecificField;
-  virtual bool IsMatch(const Message& message1, const Message& message2,
-                       const std::vector<SpecificField>& parent_fields) const {
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
     return parent_fields.back().index + 1 == parent_fields.back().new_index;
   }
 };
@@ -2366,11 +2365,10 @@
  public:
   ParentSavingFieldComparator() {}
 
-  virtual ComparisonResult Compare(const Message& message_1,
-                                   const Message& message_2,
-                                   const FieldDescriptor* field, int index_1,
-                                   int index_2,
-                                   const util::FieldContext* field_context) {
+  ComparisonResult Compare(const Message& message_1, const Message& message_2,
+                           const FieldDescriptor* field, int index_1,
+                           int index_2,
+                           const util::FieldContext* field_context) override {
     if (field_context) parent_fields_ = *(field_context->parent_fields());
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       return RECURSE;
@@ -2423,7 +2421,7 @@
     unknown2_ = empty2_.mutable_unknown_fields();
   }
 
-  ~ComparisonTest() {}
+  ~ComparisonTest() override {}
 
   void SetSpecialFieldOption(const Message& message,
                              util::MessageDifferencer* d) {
@@ -3403,12 +3401,11 @@
     : public util::MessageDifferencer::MapKeyComparator {
  public:
   typedef util::MessageDifferencer::SpecificField SpecificField;
-  virtual bool IsMatch(const Message& message1, const Message& message2,
-                       const std::vector<SpecificField>& parent_fields) const {
+  bool IsMatch(const Message& message1, const Message& message2,
+               const std::vector<SpecificField>& parent_fields) const override {
     const Reflection* reflection1 = message1.GetReflection();
     const Reflection* reflection2 = message2.GetReflection();
-    const FieldDescriptor* key_field =
-        message1.GetDescriptor()->map_key();
+    const FieldDescriptor* key_field = message1.GetDescriptor()->map_key();
     return reflection1->GetString(message1, key_field).size() ==
            reflection2->GetString(message2, key_field).size();
   }
@@ -3452,7 +3449,7 @@
  protected:
   MatchingTest() {}
 
-  ~MatchingTest() {}
+  ~MatchingTest() override {}
 
   std::string RunWithResult(MessageDifferencer* differencer,
                             const Message& msg1, const Message& msg2,
@@ -3717,7 +3714,7 @@
   const FieldDescriptor* nested_key;
   descriptor = msg1.GetDescriptor()->file();
   desc = descriptor->FindExtensionByName("repeated_nested_message_extension");
-  ASSERT_FALSE(desc == NULL);
+  ASSERT_FALSE(desc == nullptr);
   nested_key = desc->message_type()->FindFieldByName("bb");
 
   MessageDifferencer differencer;
diff --git a/src/google/protobuf/util/time_util.h b/src/google/protobuf/util/time_util.h
index 96b1aac..95cc645 100644
--- a/src/google/protobuf/util/time_util.h
+++ b/src/google/protobuf/util/time_util.h
@@ -53,6 +53,7 @@
 #include <google/protobuf/duration.pb.h>
 #include <google/protobuf/timestamp.pb.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/util/time_util_test.cc b/src/google/protobuf/util/time_util_test.cc
index d38a27d..79e2427 100644
--- a/src/google/protobuf/util/time_util_test.cc
+++ b/src/google/protobuf/util/time_util_test.cc
@@ -222,7 +222,7 @@
 }
 
 TEST(TimeUtilTest, TimeTConversion) {
-  time_t value = time(NULL);
+  time_t value = time(nullptr);
   EXPECT_EQ(value,
             TimeUtil::TimestampToTimeT(TimeUtil::TimeTToTimestamp(value)));
   EXPECT_EQ(
diff --git a/src/google/protobuf/util/type_resolver.h b/src/google/protobuf/util/type_resolver.h
index 2bda5c8..b2e7b43 100644
--- a/src/google/protobuf/util/type_resolver.h
+++ b/src/google/protobuf/util/type_resolver.h
@@ -40,6 +40,7 @@
 #include <google/protobuf/stubs/status.h>
 #include <google/protobuf/stubs/status.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index c5d4fdf..8be0efb 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -34,10 +34,10 @@
 #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>
+#include <google/protobuf/util/internal/utility.h>
+#include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/status.h>
 
 // clang-format off
diff --git a/src/google/protobuf/util/type_resolver_util.h b/src/google/protobuf/util/type_resolver_util.h
index fa912b6..7f6a4b9 100644
--- a/src/google/protobuf/util/type_resolver_util.h
+++ b/src/google/protobuf/util/type_resolver_util.h
@@ -41,6 +41,7 @@
 namespace util {
 class TypeResolver;
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 // Creates a TypeResolver that serves type information in the given descriptor
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index f0a0a74..2780a39 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -76,13 +76,13 @@
         return &field;
       }
     }
-    return NULL;
+    return nullptr;
   }
 
   bool HasField(const Type& type, Field::Cardinality cardinality,
                 Field::Kind kind, const std::string& name, int number) {
     const Field* field = FindField(type, name);
-    if (field == NULL) {
+    if (field == nullptr) {
       return false;
     }
     return field->cardinality() == cardinality && field->kind() == kind &&
@@ -92,7 +92,7 @@
   bool CheckFieldTypeUrl(const Type& type, const std::string& name,
                          const std::string& type_url) {
     const Field* field = FindField(type, name);
-    if (field == NULL) {
+    if (field == nullptr) {
       return false;
     }
     return field->type_url() == type_url;
@@ -101,7 +101,7 @@
   bool FieldInOneof(const Type& type, const std::string& name,
                     const std::string& oneof_name) {
     const Field* field = FindField(type, name);
-    if (field == NULL || field->oneof_index() <= 0 ||
+    if (field == nullptr || field->oneof_index() <= 0 ||
         field->oneof_index() > type.oneofs_size()) {
       return false;
     }
@@ -110,7 +110,7 @@
 
   bool IsPacked(const Type& type, const std::string& name) {
     const Field* field = FindField(type, name);
-    if (field == NULL) {
+    if (field == nullptr) {
       return false;
     }
     return field->packed();
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index e68af89..e44c6eb 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -40,21 +40,21 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/parse_context.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>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message_lite.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/unknown_field_set.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 const size_t kMapEntryTagByteSize = 2;
@@ -1125,10 +1125,11 @@
     case FieldDescriptor::TYPE_BYTES:
       target = stream->WriteString(2, value.GetStringValue(), target);
       break;
-    case FieldDescriptor::TYPE_MESSAGE:
-      target = WireFormatLite::InternalWriteMessage(2, value.GetMessageValue(),
+    case FieldDescriptor::TYPE_MESSAGE: {
+      auto& msg = value.GetMessageValue();
+      target = WireFormatLite::InternalWriteMessage(2, msg, msg.GetCachedSize(),
                                                     target, stream);
-      break;
+    } break;
     case FieldDescriptor::TYPE_GROUP:
       target = WireFormatLite::InternalWriteGroup(2, value.GetMessageValue(),
                                                   target, stream);
@@ -1320,6 +1321,16 @@
     return target;
   }
 
+  auto get_message_from_field = [&message, &map_entries, message_reflection](
+                                    const FieldDescriptor* field, int j) {
+    if (!field->is_repeated()) {
+      return &message_reflection->GetMessage(message, field);
+    }
+    if (!map_entries.empty()) {
+      return map_entries[j];
+    }
+    return &message_reflection->GetRepeatedMessage(message, field, j);
+  };
   for (int j = 0; j < count; j++) {
     target = stream->EnsureSpace(target);
     switch (field->type()) {
@@ -1353,22 +1364,17 @@
       HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
 #undef HANDLE_PRIMITIVE_TYPE
 
-#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD)                         \
-  case FieldDescriptor::TYPE_##TYPE:                                           \
-    target = WireFormatLite::InternalWrite##TYPE_METHOD(                       \
-        field->number(),                                                       \
-        field->is_repeated()                                                   \
-            ? (map_entries.empty()                                             \
-                   ? message_reflection->GetRepeated##CPPTYPE_METHOD(message,  \
-                                                                     field, j) \
-                   : *map_entries[j])                                          \
-            : message_reflection->Get##CPPTYPE_METHOD(message, field),         \
-        target, stream);                                                       \
-    break;
+      case FieldDescriptor::TYPE_GROUP: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteGroup(field->number(), *msg,
+                                                    target, stream);
+      } break;
 
-      HANDLE_TYPE(GROUP, Group, Message)
-      HANDLE_TYPE(MESSAGE, Message, Message)
-#undef HANDLE_TYPE
+      case FieldDescriptor::TYPE_MESSAGE: {
+        auto* msg = get_message_from_field(field, j);
+        target = WireFormatLite::InternalWriteMessage(
+            field->number(), *msg, msg->GetCachedSize(), target, stream);
+      } break;
 
       case FieldDescriptor::TYPE_ENUM: {
         const EnumValueDescriptor* value =
@@ -1432,9 +1438,10 @@
   target = WireFormatLite::WriteUInt32ToArray(
       WireFormatLite::kMessageSetTypeIdNumber, field->number(), target);
   // Write message.
+  auto& msg = message_reflection->GetMessage(message, field);
   target = WireFormatLite::InternalWriteMessage(
-      WireFormatLite::kMessageSetMessageNumber,
-      message_reflection->GetMessage(message, field), target, stream);
+      WireFormatLite::kMessageSetMessageNumber, msg, msg.GetCachedSize(),
+      target, stream);
   // End group.
   target = stream->EnsureSpace(target);
   target = io::CodedOutputStream::WriteTagToArray(
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index 3628be3..7ecc0e7 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -39,22 +39,24 @@
 #ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_H__
 #define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
 
+
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/wire_format_lite.h>
-#include <google/protobuf/stubs/casts.h>
 
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index b16edb4..5252577 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -47,6 +47,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -527,6 +528,28 @@
   value.SerializeWithCachedSizes(output);
 }
 
+uint8_t* WireFormatLite::InternalWriteGroup(int field_number,
+                                            const MessageLite& value,
+                                            uint8_t* target,
+                                            io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
+  target = value._InternalSerialize(target, stream);
+  target = stream->EnsureSpace(target);
+  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
+}
+
+uint8_t* WireFormatLite::InternalWriteMessage(int field_number,
+                                              const MessageLite& value,
+                                              int cached_size, uint8_t* target,
+                                              io::EpsCopyOutputStream* stream) {
+  target = stream->EnsureSpace(target);
+  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(
+      static_cast<uint32_t>(cached_size), target);
+  return value._InternalSerialize(target, stream);
+}
+
 void WireFormatLite::WriteSubMessageMaybeToArray(
     int /*size*/, const MessageLite& value, io::CodedOutputStream* output) {
   output->SetCur(value._InternalSerialize(output->Cur(), output->EpsCopy()));
@@ -570,18 +593,29 @@
   return ReadBytesToString(input, *p);
 }
 
-void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
+void PrintUTF8ErrorLog(StringPiece message_name,
+                       StringPiece field_name, const char* operation_str,
                        bool emit_stacktrace) {
   std::string stacktrace;
   (void)emit_stacktrace;  // Parameter is used by Google-internal code.
   std::string quoted_field_name = "";
-  if (field_name != nullptr) {
-    quoted_field_name = StringPrintf(" '%s'", field_name);
+  if (!field_name.empty()) {
+    if (!message_name.empty()) {
+      quoted_field_name =
+          StrCat(" '", message_name, ".", field_name, "'");
+    } else {
+      quoted_field_name = StrCat(" '", field_name, "'");
+    }
   }
-  GOOGLE_LOG(ERROR) << "String field" << quoted_field_name << " contains invalid "
-             << "UTF-8 data when " << operation_str << " a protocol "
-             << "buffer. Use the 'bytes' type if you intend to send raw "
-             << "bytes. " << stacktrace;
+  std::string error_message =
+      StrCat("String field", quoted_field_name,
+                   " contains invalid UTF-8 data "
+                   "when ",
+                   operation_str,
+                   " a protocol buffer. Use the 'bytes' type if you intend to "
+                   "send raw bytes. ",
+                   stacktrace);
+  GOOGLE_LOG(ERROR) << error_message;
 }
 
 bool WireFormatLite::VerifyUtf8String(const char* data, int size, Operation op,
@@ -597,7 +631,7 @@
         break;
         // no default case: have the compiler warn if a case is not covered.
     }
-    PrintUTF8ErrorLog(field_name, operation_str, false);
+    PrintUTF8ErrorLog("", field_name, operation_str, false);
     return false;
   }
   return true;
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index b04d17b..32fe0c7 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -40,16 +40,17 @@
 #ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
 #define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
 
+
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/port.h>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/message_lite.h>
-#include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
-#include <google/protobuf/stubs/casts.h>
 
 // Do UTF-8 validation on string type in Debug build only
 #ifndef NDEBUG
@@ -67,6 +68,7 @@
 #undef TYPE_BOOL
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -622,14 +624,13 @@
   // of serialization, the "ToArray" variants may be invoked.  But they don't
   // have a CodedOutputStream available, so they get an additional parameter
   // telling them whether to serialize deterministically.
-  template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteGroup(
-      int field_number, const MessageType& value, uint8_t* target,
-      io::EpsCopyOutputStream* stream);
-  template <typename MessageType>
-  PROTOBUF_NDEBUG_INLINE static uint8_t* InternalWriteMessage(
-      int field_number, const MessageType& value, uint8_t* target,
-      io::EpsCopyOutputStream* stream);
+  static uint8_t* InternalWriteGroup(int field_number, const MessageLite& value,
+                                     uint8_t* target,
+                                     io::EpsCopyOutputStream* stream);
+  static uint8_t* InternalWriteMessage(int field_number,
+                                       const MessageLite& value,
+                                       int cached_size, uint8_t* target,
+                                       io::EpsCopyOutputStream* stream);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
@@ -662,7 +663,8 @@
                                     static_cast<uint32_t>(field_number) << 3) +
                                 io::CodedOutputStream::VarintSize32(size)),
         io::CodedOutputStream::IsDefaultSerializationDeterministic());
-    return InternalWriteMessage(field_number, value, target, &stream);
+    return InternalWriteMessage(field_number, value, value.GetCachedSize(),
+                                target, &stream);
   }
 
   // Compute the byte size of a field.  The XxSize() functions do NOT include
@@ -1705,25 +1707,6 @@
 }
 
 
-template <typename MessageType>
-inline uint8_t* WireFormatLite::InternalWriteGroup(
-    int field_number, const MessageType& value, uint8_t* target,
-    io::EpsCopyOutputStream* stream) {
-  target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
-  target = value._InternalSerialize(target, stream);
-  target = stream->EnsureSpace(target);
-  return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
-}
-template <typename MessageType>
-inline uint8_t* WireFormatLite::InternalWriteMessage(
-    int field_number, const MessageType& value, uint8_t* target,
-    io::EpsCopyOutputStream* stream) {
-  target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
-  target = io::CodedOutputStream::WriteVarint32ToArrayOutOfLine(
-      static_cast<uint32_t>(value.GetCachedSize()), target);
-  return value._InternalSerialize(target, stream);
-}
-
 // See comment on ReadGroupNoVirtual to understand the need for this template
 // parameter name.
 template <typename MessageType_WorkAroundCppLookupDefect>
diff --git a/src/google/protobuf/wire_format_unittest.inc b/src/google/protobuf/wire_format_unittest.inc
index 3f3ddff..4b7862c 100644
--- a/src/google/protobuf/wire_format_unittest.inc
+++ b/src/google/protobuf/wire_format_unittest.inc
@@ -493,8 +493,9 @@
 
   // Serialize to flat array
   {
-    uint8* target = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&flat_data));
-    uint8* end = message_set.SerializeWithCachedSizesToArray(target);
+    uint8_t* target =
+        reinterpret_cast<uint8_t*>(::google::protobuf::string_as_array(&flat_data));
+    uint8_t* end = message_set.SerializeWithCachedSizesToArray(target);
     EXPECT_EQ(size, end - target);
   }
 
@@ -574,7 +575,7 @@
 
   // Also parse using WireFormat.
   PROTO2_WIREFORMAT_UNITTEST::TestMessageSet dynamic_message_set;
-  io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
+  io::CodedInputStream input(reinterpret_cast<const uint8_t*>(data.data()),
                              data.size());
   ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set));
   EXPECT_EQ(message_set.DebugString(), dynamic_message_set.DebugString());
@@ -597,7 +598,7 @@
     coded_output.WriteVarint32(message.ByteSizeLong());
     message.SerializeWithCachedSizes(&coded_output);
     // Write the type id.
-    uint32 type_id = message.GetDescriptor()->extension(0)->number();
+    uint32_t type_id = message.GetDescriptor()->extension(0)->number();
     WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
                                 type_id, &coded_output);
     coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag);
@@ -615,7 +616,7 @@
   {
     // Test parse the message via Reflection.
     PROTO2_WIREFORMAT_UNITTEST::TestMessageSet message_set;
-    io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
+    io::CodedInputStream input(reinterpret_cast<const uint8_t*>(data.data()),
                                data.size());
     EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
     EXPECT_TRUE(input.ConsumedEntireMessage());
@@ -660,7 +661,7 @@
   coded_output->WriteVarint32(message.GetCachedSize());
   SerializeReverseOrder(message, coded_output);
   // Write the type id.
-  uint32 type_id = message.GetDescriptor()->extension(0)->number();
+  uint32_t type_id = message.GetDescriptor()->extension(0)->number();
   WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, type_id,
                               coded_output);
   coded_output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
@@ -776,6 +777,43 @@
   }
 }
 
+TEST(WireFormatTest, LargeRecursionLimit) {
+  const int kLargeLimit = io::CodedInputStream::GetDefaultRecursionLimit() + 50;
+  UNITTEST::TestRecursiveMessage src, dst, *a;
+  a = src.mutable_a();
+  for (int i = 0; i < kLargeLimit - 1; i++) {
+    a = a->mutable_a();
+  }
+  a->set_i(1);
+
+  std::string data = src.SerializeAsString();
+  {
+    // Parse with default recursion limit. Should fail.
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    ASSERT_FALSE(dst.ParseFromCodedStream(&input));
+  }
+
+  {
+    // Parse with custom recursion limit. Should pass.
+    io::ArrayInputStream raw_input(data.data(), data.size());
+    io::CodedInputStream input(&raw_input);
+    input.SetRecursionLimit(kLargeLimit);
+    ASSERT_TRUE(dst.ParseFromCodedStream(&input));
+  }
+
+  // Verifies the recursion depth.
+  int depth = 1;
+  a = dst.mutable_a();
+  while (a->has_a()) {
+    a = a->mutable_a();
+    depth++;
+  }
+
+  EXPECT_EQ(a->i(), 1);
+  EXPECT_EQ(depth, kLargeLimit);
+}
+
 TEST(WireFormatTest, UnknownFieldRecursionLimit) {
   UNITTEST::TestEmptyMessage message;
   message.mutable_unknown_fields()
@@ -913,7 +951,7 @@
 }
 
 TEST(WireFormatTest, CompatibleTypes) {
-  const int64 data = 0x100000000LL;
+  const int64_t data = 0x100000000LL;
   UNITTEST::Int64Message msg1;
   msg1.set_data(data);
   std::string serialized;
@@ -927,17 +965,17 @@
   // Test int64 is compatible with uint64
   UNITTEST::Uint64Message msg3;
   ASSERT_TRUE(msg3.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<uint64>(data), msg3.data());
+  ASSERT_EQ(static_cast<uint64_t>(data), msg3.data());
 
   // Test int64 is compatible with int32
   UNITTEST::Int32Message msg4;
   ASSERT_TRUE(msg4.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<int32>(data), msg4.data());
+  ASSERT_EQ(static_cast<int32_t>(data), msg4.data());
 
   // Test int64 is compatible with uint32
   UNITTEST::Uint32Message msg5;
   ASSERT_TRUE(msg5.ParseFromString(serialized));
-  ASSERT_EQ(static_cast<uint32>(data), msg5.data());
+  ASSERT_EQ(static_cast<uint32_t>(data), msg5.data());
 }
 
 class Proto3PrimitiveRepeatedWireFormatTest : public ::testing::Test {
@@ -1079,7 +1117,7 @@
 
     message->Clear();
     io::CodedInputStream input(
-        reinterpret_cast<const uint8*>(compatible_data.data()),
+        reinterpret_cast<const uint8_t*>(compatible_data.data()),
         compatible_data.size());
     WireFormat::ParseAndMergePartial(&input, message);
     ExpectProto3PrimitiveRepeatedFieldsSet(*message);
@@ -1289,8 +1327,8 @@
 class Utf8ValidationTest : public ::testing::Test {
  protected:
   Utf8ValidationTest() {}
-  virtual ~Utf8ValidationTest() {}
-  virtual void SetUp() {
+  ~Utf8ValidationTest() override {}
+  void SetUp() override {
   }
 
 };
@@ -1447,7 +1485,7 @@
 
 
 TEST(RepeatedVarint, Int32) {
-  RepeatedField<int32> v;
+  RepeatedField<int32_t> v;
 
   // Insert -2^n, 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
@@ -1466,7 +1504,7 @@
 }
 
 TEST(RepeatedVarint, Int64) {
-  RepeatedField<int64> v;
+  RepeatedField<int64_t> v;
 
   // Insert -2^n, 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
@@ -1485,7 +1523,7 @@
 }
 
 TEST(RepeatedVarint, SInt32) {
-  RepeatedField<int32> v;
+  RepeatedField<int32_t> v;
 
   // Insert -2^n, 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
@@ -1504,7 +1542,7 @@
 }
 
 TEST(RepeatedVarint, SInt64) {
-  RepeatedField<int64> v;
+  RepeatedField<int64_t> v;
 
   // Insert -2^n, 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
@@ -1523,7 +1561,7 @@
 }
 
 TEST(RepeatedVarint, UInt32) {
-  RepeatedField<uint32> v;
+  RepeatedField<uint32_t> v;
 
   // Insert 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
@@ -1541,7 +1579,7 @@
 }
 
 TEST(RepeatedVarint, UInt64) {
-  RepeatedField<uint64> v;
+  RepeatedField<uint64_t> v;
 
   // Insert 2^n and 2^n-1.
   for (int n = 0; n < 10; n++) {
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 2ce0df1..24aafb3 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -16,119 +16,123 @@
 #include <google/protobuf/port_def.inc>
 
 PROTOBUF_PRAGMA_INIT_SEG
+
+namespace _pb = ::PROTOBUF_NAMESPACE_ID;
+namespace _pbi = _pb::internal;
+
 PROTOBUF_NAMESPACE_OPEN
 constexpr DoubleValue::DoubleValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(0){}
 struct DoubleValueDefaultTypeInternal {
   constexpr DoubleValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~DoubleValueDefaultTypeInternal() {}
   union {
     DoubleValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 DoubleValueDefaultTypeInternal _DoubleValue_default_instance_;
 constexpr FloatValue::FloatValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(0){}
 struct FloatValueDefaultTypeInternal {
   constexpr FloatValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~FloatValueDefaultTypeInternal() {}
   union {
     FloatValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT FloatValueDefaultTypeInternal _FloatValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 FloatValueDefaultTypeInternal _FloatValue_default_instance_;
 constexpr Int64Value::Int64Value(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(int64_t{0}){}
 struct Int64ValueDefaultTypeInternal {
   constexpr Int64ValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~Int64ValueDefaultTypeInternal() {}
   union {
     Int64Value _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int64ValueDefaultTypeInternal _Int64Value_default_instance_;
 constexpr UInt64Value::UInt64Value(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(uint64_t{0u}){}
 struct UInt64ValueDefaultTypeInternal {
   constexpr UInt64ValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~UInt64ValueDefaultTypeInternal() {}
   union {
     UInt64Value _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt64ValueDefaultTypeInternal _UInt64Value_default_instance_;
 constexpr Int32Value::Int32Value(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(0){}
 struct Int32ValueDefaultTypeInternal {
   constexpr Int32ValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~Int32ValueDefaultTypeInternal() {}
   union {
     Int32Value _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 Int32ValueDefaultTypeInternal _Int32Value_default_instance_;
 constexpr UInt32Value::UInt32Value(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(0u){}
 struct UInt32ValueDefaultTypeInternal {
   constexpr UInt32ValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~UInt32ValueDefaultTypeInternal() {}
   union {
     UInt32Value _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 UInt32ValueDefaultTypeInternal _UInt32Value_default_instance_;
 constexpr BoolValue::BoolValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(false){}
 struct BoolValueDefaultTypeInternal {
   constexpr BoolValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~BoolValueDefaultTypeInternal() {}
   union {
     BoolValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT BoolValueDefaultTypeInternal _BoolValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BoolValueDefaultTypeInternal _BoolValue_default_instance_;
 constexpr StringValue::StringValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){}
 struct StringValueDefaultTypeInternal {
   constexpr StringValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~StringValueDefaultTypeInternal() {}
   union {
     StringValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT StringValueDefaultTypeInternal _StringValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 StringValueDefaultTypeInternal _StringValue_default_instance_;
 constexpr BytesValue::BytesValue(
-  ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized)
+    ::_pbi::ConstantInitialized)
   : value_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){}
 struct BytesValueDefaultTypeInternal {
   constexpr BytesValueDefaultTypeInternal()
-    : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {}
+      : _instance(::_pbi::ConstantInitialized{}) {}
   ~BytesValueDefaultTypeInternal() {}
   union {
     BytesValue _instance;
   };
 };
-PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT BytesValueDefaultTypeInternal _BytesValue_default_instance_;
+PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 BytesValueDefaultTypeInternal _BytesValue_default_instance_;
 PROTOBUF_NAMESPACE_CLOSE
-static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
-static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
-static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
+static constexpr ::_pb::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
 
 const uint32_t TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -195,7 +199,7 @@
   ~0u,  // no _inlined_string_donated_
   PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::BytesValue, value_),
 };
-static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
+static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   { 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::DoubleValue)},
   { 7, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::FloatValue)},
   { 14, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Int64Value)},
@@ -207,16 +211,16 @@
   { 56, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::BytesValue)},
 };
 
-static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = {
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_DoubleValue_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_FloatValue_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Int64Value_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_UInt64Value_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_Int32Value_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_UInt32Value_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_BoolValue_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_StringValue_default_instance_),
-  reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::PROTOBUF_NAMESPACE_ID::_BytesValue_default_instance_),
+static const ::_pb::Message* const file_default_instances[] = {
+  &::PROTOBUF_NAMESPACE_ID::_DoubleValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_FloatValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt64Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_Int32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_UInt32Value_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BoolValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_StringValue_default_instance_._instance,
+  &::PROTOBUF_NAMESPACE_ID::_BytesValue_default_instance_._instance,
 };
 
 const char descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
@@ -233,19 +237,21 @@
   "erspb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKno"
   "wnTypesb\006proto3"
   ;
-static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once;
-const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
-  false, false, 455, descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto, "google/protobuf/wrappers.proto", 
-  &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once, nullptr, 0, 9,
-  schemas, file_default_instances, TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets,
-  file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto, file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once;
+const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+    false, false, 455, descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
+    "google/protobuf/wrappers.proto",
+    &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once, nullptr, 0, 9,
+    schemas, file_default_instances, TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets,
+    file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto,
+    file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
 };
-PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter() {
+PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter() {
   return &descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
 }
 
 // Force running AddDescriptors() at dynamic initialization time.
-PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fwrappers_2eproto(&descriptor_table_google_2fprotobuf_2fwrappers_2eproto);
+PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fwrappers_2eproto(&descriptor_table_google_2fprotobuf_2fwrappers_2eproto);
 PROTOBUF_NAMESPACE_OPEN
 
 // ===================================================================
@@ -258,9 +264,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.DoubleValue)
 }
 DoubleValue::DoubleValue(const DoubleValue& from)
@@ -276,21 +279,17 @@
 
 DoubleValue::~DoubleValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.DoubleValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void DoubleValue::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void DoubleValue::ArenaDtor(void* object) {
-  DoubleValue* _this = reinterpret_cast< DoubleValue* >(object);
-  (void)_this;
-}
-void DoubleValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void DoubleValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -305,11 +304,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* DoubleValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* DoubleValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // double value = 1;
       case 1:
@@ -355,11 +354,11 @@
   memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
   if (raw_value != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DoubleValue)
@@ -433,7 +432,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata DoubleValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[0]);
 }
@@ -448,9 +447,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.FloatValue)
 }
 FloatValue::FloatValue(const FloatValue& from)
@@ -466,21 +462,17 @@
 
 FloatValue::~FloatValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.FloatValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void FloatValue::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void FloatValue::ArenaDtor(void* object) {
-  FloatValue* _this = reinterpret_cast< FloatValue* >(object);
-  (void)_this;
-}
-void FloatValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void FloatValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -495,11 +487,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* FloatValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* FloatValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // float value = 1;
       case 1:
@@ -545,11 +537,11 @@
   memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
   if (raw_value != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FloatValue)
@@ -623,7 +615,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata FloatValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[1]);
 }
@@ -638,9 +630,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Int64Value)
 }
 Int64Value::Int64Value(const Int64Value& from)
@@ -656,21 +645,17 @@
 
 Int64Value::~Int64Value() {
   // @@protoc_insertion_point(destructor:google.protobuf.Int64Value)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Int64Value::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void Int64Value::ArenaDtor(void* object) {
-  Int64Value* _this = reinterpret_cast< Int64Value* >(object);
-  (void)_this;
-}
-void Int64Value::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Int64Value::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -685,11 +670,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Int64Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Int64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // int64 value = 1;
       case 1:
@@ -731,11 +716,11 @@
   // int64 value = 1;
   if (this->_internal_value() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteInt64ToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int64Value)
@@ -752,7 +737,7 @@
 
   // int64 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int64SizePlusOne(this->_internal_value());
+    total_size += ::_pbi::WireFormatLite::Int64SizePlusOne(this->_internal_value());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -801,7 +786,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Int64Value::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[2]);
 }
@@ -816,9 +801,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt64Value)
 }
 UInt64Value::UInt64Value(const UInt64Value& from)
@@ -834,21 +816,17 @@
 
 UInt64Value::~UInt64Value() {
   // @@protoc_insertion_point(destructor:google.protobuf.UInt64Value)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void UInt64Value::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void UInt64Value::ArenaDtor(void* object) {
-  UInt64Value* _this = reinterpret_cast< UInt64Value* >(object);
-  (void)_this;
-}
-void UInt64Value::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void UInt64Value::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -863,11 +841,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* UInt64Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* UInt64Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // uint64 value = 1;
       case 1:
@@ -909,11 +887,11 @@
   // uint64 value = 1;
   if (this->_internal_value() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteUInt64ToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt64Value)
@@ -930,7 +908,7 @@
 
   // uint64 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_value());
+    total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_value());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -979,7 +957,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata UInt64Value::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[3]);
 }
@@ -994,9 +972,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.Int32Value)
 }
 Int32Value::Int32Value(const Int32Value& from)
@@ -1012,21 +987,17 @@
 
 Int32Value::~Int32Value() {
   // @@protoc_insertion_point(destructor:google.protobuf.Int32Value)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void Int32Value::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void Int32Value::ArenaDtor(void* object) {
-  Int32Value* _this = reinterpret_cast< Int32Value* >(object);
-  (void)_this;
-}
-void Int32Value::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void Int32Value::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1041,11 +1012,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* Int32Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* Int32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // int32 value = 1;
       case 1:
@@ -1087,11 +1058,11 @@
   // int32 value = 1;
   if (this->_internal_value() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteInt32ToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int32Value)
@@ -1108,7 +1079,7 @@
 
   // int32 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_value());
+    total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_value());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -1157,7 +1128,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata Int32Value::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[4]);
 }
@@ -1172,9 +1143,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.UInt32Value)
 }
 UInt32Value::UInt32Value(const UInt32Value& from)
@@ -1190,21 +1158,17 @@
 
 UInt32Value::~UInt32Value() {
   // @@protoc_insertion_point(destructor:google.protobuf.UInt32Value)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void UInt32Value::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void UInt32Value::ArenaDtor(void* object) {
-  UInt32Value* _this = reinterpret_cast< UInt32Value* >(object);
-  (void)_this;
-}
-void UInt32Value::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void UInt32Value::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1219,11 +1183,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* UInt32Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* UInt32Value::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // uint32 value = 1;
       case 1:
@@ -1265,11 +1229,11 @@
   // uint32 value = 1;
   if (this->_internal_value() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteUInt32ToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt32Value)
@@ -1286,7 +1250,7 @@
 
   // uint32 value = 1;
   if (this->_internal_value() != 0) {
-    total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_value());
+    total_size += ::_pbi::WireFormatLite::UInt32SizePlusOne(this->_internal_value());
   }
 
   return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);
@@ -1335,7 +1299,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata UInt32Value::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[5]);
 }
@@ -1350,9 +1314,6 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.BoolValue)
 }
 BoolValue::BoolValue(const BoolValue& from)
@@ -1368,21 +1329,17 @@
 
 BoolValue::~BoolValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.BoolValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void BoolValue::SharedDtor() {
   GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
 }
 
-void BoolValue::ArenaDtor(void* object) {
-  BoolValue* _this = reinterpret_cast< BoolValue* >(object);
-  (void)_this;
-}
-void BoolValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void BoolValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1397,11 +1354,11 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* BoolValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* BoolValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // bool value = 1;
       case 1:
@@ -1443,11 +1400,11 @@
   // bool value = 1;
   if (this->_internal_value() != 0) {
     target = stream->EnsureSpace(target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->_internal_value(), target);
+    target = ::_pbi::WireFormatLite::WriteBoolToArray(1, this->_internal_value(), target);
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BoolValue)
@@ -1513,7 +1470,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata BoolValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[6]);
 }
@@ -1528,15 +1485,12 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.StringValue)
 }
 StringValue::StringValue(const StringValue& from)
   : ::PROTOBUF_NAMESPACE_ID::Message() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1548,7 +1502,7 @@
 }
 
 inline void StringValue::SharedCtor() {
-value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1556,9 +1510,11 @@
 
 StringValue::~StringValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.StringValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void StringValue::SharedDtor() {
@@ -1566,12 +1522,6 @@
   value_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void StringValue::ArenaDtor(void* object) {
-  StringValue* _this = reinterpret_cast< StringValue* >(object);
-  (void)_this;
-}
-void StringValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void StringValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1586,19 +1536,19 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* StringValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* StringValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // string value = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
-          CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "google.protobuf.StringValue.value"));
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
+          CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.StringValue.value"));
         } else
           goto handle_unusual;
         continue;
@@ -1642,7 +1592,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.StringValue)
@@ -1716,7 +1666,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata StringValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[7]);
 }
@@ -1731,15 +1681,12 @@
                          bool is_message_owned)
   : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
   SharedCtor();
-  if (!is_message_owned) {
-    RegisterArenaDtor(arena);
-  }
   // @@protoc_insertion_point(arena_constructor:google.protobuf.BytesValue)
 }
 BytesValue::BytesValue(const BytesValue& from)
   : ::PROTOBUF_NAMESPACE_ID::Message() {
   _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
-  value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+  value_.InitDefault();
   #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1751,7 +1698,7 @@
 }
 
 inline void BytesValue::SharedCtor() {
-value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
+value_.InitDefault();
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
   value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1759,9 +1706,11 @@
 
 BytesValue::~BytesValue() {
   // @@protoc_insertion_point(destructor:google.protobuf.BytesValue)
-  if (GetArenaForAllocation() != nullptr) return;
+  if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
+  (void)arena;
+    return;
+  }
   SharedDtor();
-  _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
 inline void BytesValue::SharedDtor() {
@@ -1769,12 +1718,6 @@
   value_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
 }
 
-void BytesValue::ArenaDtor(void* object) {
-  BytesValue* _this = reinterpret_cast< BytesValue* >(object);
-  (void)_this;
-}
-void BytesValue::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) {
-}
 void BytesValue::SetCachedSize(int size) const {
   _cached_size_.Set(size);
 }
@@ -1789,17 +1732,17 @@
   _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
 }
 
-const char* BytesValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
+const char* BytesValue::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
 #define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
   while (!ctx->Done(&ptr)) {
     uint32_t tag;
-    ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
+    ptr = ::_pbi::ReadTag(ptr, &tag);
     switch (tag >> 3) {
       // bytes value = 1;
       case 1:
         if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
           auto str = _internal_mutable_value();
-          ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx);
+          ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
           CHK_(ptr);
         } else
           goto handle_unusual;
@@ -1840,7 +1783,7 @@
   }
 
   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+    target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
         _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BytesValue)
@@ -1914,7 +1857,7 @@
 }
 
 ::PROTOBUF_NAMESPACE_ID::Metadata BytesValue::GetMetadata() const {
-  return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(
+  return ::_pbi::AssignDescriptors(
       &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_getter, &descriptor_table_google_2fprotobuf_2fwrappers_2eproto_once,
       file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[8]);
 }
@@ -1922,31 +1865,40 @@
 // @@protoc_insertion_point(namespace_scope)
 PROTOBUF_NAMESPACE_CLOSE
 PROTOBUF_NAMESPACE_OPEN
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DoubleValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::DoubleValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::DoubleValue >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FloatValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FloatValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::FloatValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::FloatValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::FloatValue >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int64Value* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int64Value >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int64Value >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int64Value >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt64Value* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt64Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt64Value >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int32Value* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int32Value >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Int32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Int32Value >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Int32Value >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt32Value* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::UInt32Value*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::UInt32Value >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BoolValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BoolValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BoolValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BoolValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BoolValue >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::StringValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::StringValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::StringValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::StringValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::StringValue >(arena);
 }
-template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BytesValue* Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BytesValue >(Arena* arena) {
+template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::BytesValue*
+Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::BytesValue >(Arena* arena) {
   return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::BytesValue >(arena);
 }
 PROTOBUF_NAMESPACE_CLOSE
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 36e906c..d15281c 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -23,7 +23,6 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
-#include <google/protobuf/generated_message_table_driven.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/generated_message_reflection.h>
@@ -42,14 +41,6 @@
 
 // Internal implementation detail -- do not use these members.
 struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fwrappers_2eproto {
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[9]
-    PROTOBUF_SECTION_VARIABLE(protodesc_cold);
-  static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
-  static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
   static const uint32_t offsets[];
 };
 PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto;
@@ -204,9 +195,6 @@
   protected:
   explicit DoubleValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -350,9 +338,6 @@
   protected:
   explicit FloatValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -496,9 +481,6 @@
   protected:
   explicit Int64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -642,9 +624,6 @@
   protected:
   explicit UInt64Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -788,9 +767,6 @@
   protected:
   explicit Int32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -934,9 +910,6 @@
   protected:
   explicit UInt32Value(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1080,9 +1053,6 @@
   protected:
   explicit BoolValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1226,9 +1196,6 @@
   protected:
   explicit StringValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1377,9 +1344,6 @@
   protected:
   explicit BytesValue(::PROTOBUF_NAMESPACE_ID::Arena* arena,
                        bool is_message_owned = false);
-  private:
-  static void ArenaDtor(void* object);
-  inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
   public:
 
   static const ClassData _class_data_;
@@ -1642,7 +1606,7 @@
   value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (value_.IsDefault()) {
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
@@ -1697,7 +1661,7 @@
   value_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value,
       GetArenaForAllocation());
 #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
-  if (value_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) {
+  if (value_.IsDefault()) {
     value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation());
   }
 #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING